-- |-- Module : Simulation.Aivika.Dynamics.Internal.Dynamics-- Copyright : Copyright (c) 2009-2012, David Sorokin <david.sorokin@gmail.com>-- License : BSD3-- Maintainer : David Sorokin <david.sorokin@gmail.com>-- Stability : experimental-- Tested with: GHC 7.4.1---- The module defines the 'Dynamics' monad representing an abstract dynamic -- process, i.e. a time varying polymorphic function. --moduleSimulation.Aivika.Dynamics.Internal.Dynamics(-- * DynamicsDynamics(..),DynamicsLift(..),Point(..),runDynamicsInStartTime,runDynamicsInStopTime,runDynamicsInIntegTimes,runDynamicsInTime,runDynamicsInTimes,-- * Error HandlingcatchDynamics,finallyDynamics,throwDynamics,-- * UtilitiesbasicTime,iterationBnds,iterationHiBnd,iterationLoBnd,phaseBnds,phaseHiBnd,phaseLoBnd)whereimportqualifiedControl.ExceptionasCimportControl.Exception(IOException,throw,finally)importControl.MonadimportControl.Monad.TransimportSimulation.Aivika.Dynamics.Internal.Simulation---- The Dynamics Monad---- A value of the Dynamics monad represents an abstract dynamic -- process, i.e. a time varying polymorphic function. This is -- a key point of the Aivika simulation library.---- | A value in the 'Dynamics' monad represents a dynamic process, i.e.-- a polymorphic time varying function.newtypeDynamicsa=Dynamics(Point->IOa)-- | It defines the simulation point appended with the additional information.dataPoint=Point{pointSpecs::Specs,-- ^ the simulation specspointRun::Run,-- ^ the simulation runpointTime::Double,-- ^ the current timepointIteration::Int,-- ^ the current iterationpointPhase::Int-- ^ the current phase}deriving(Eq,Ord,Show)-- | Returns the iterations starting from zero.iterations::Specs->[Int]iterationssc=[i1..i2]wherei1=0i2=round((spcStopTimesc-spcStartTimesc)/spcDTsc)-- | Returns the first and last iterations.iterationBnds::Specs->(Int,Int)iterationBndssc=(0,round((spcStopTimesc-spcStartTimesc)/spcDTsc))-- | Returns the first iteration, i.e. zero.iterationLoBnd::Specs->IntiterationLoBndsc=0-- | Returns the last iteration.iterationHiBnd::Specs->IntiterationHiBndsc=round((spcStopTimesc-spcStartTimesc)/spcDTsc)-- | Returns the phases for the specified simulation specs starting from zero.phases::Specs->[Int]phasessc=casespcMethodscofEuler->[0]RungeKutta2->[0,1]RungeKutta4->[0,1,2,3]-- | Returns the first and last phases.phaseBnds::Specs->(Int,Int)phaseBndssc=casespcMethodscofEuler->(0,0)RungeKutta2->(0,1)RungeKutta4->(0,3)-- | Returns the first phase, i.e. zero.phaseLoBnd::Specs->IntphaseLoBndsc=0-- | Returns the last phase, 1 for Euler's method, 2 for RK2 and 4 for RK4.phaseHiBnd::Specs->IntphaseHiBndsc=casespcMethodscofEuler->0RungeKutta2->1RungeKutta4->3-- | Returns a simulation time for the integration point specified by -- the specs, iteration and phase.basicTime::Specs->Int->Int->DoublebasicTimescnph=ifph<0thenerror"Incorrect phase: basicTime"elsespcStartTimesc+n'*spcDTsc+delta(spcMethodsc)phwheren'=fromInteger(toIntegern)deltaEuler0=0deltaRungeKutta20=0deltaRungeKutta21=spcDTscdeltaRungeKutta40=0deltaRungeKutta41=spcDTsc/2deltaRungeKutta42=spcDTsc/2deltaRungeKutta43=spcDTscinstanceMonadDynamicswherereturn=returnDm>>=k=bindDmkreturnD::a->DynamicsareturnDa=Dynamics(\p->returna)bindD::Dynamicsa->(a->Dynamicsb)->DynamicsbbindD(Dynamicsm)k=Dynamics$\p->doa<-mpletDynamicsm'=kam'p-- | Run the dynamic process in the initial simulation point.runDynamicsInStartTime::Dynamicsa->SimulationarunDynamicsInStartTime(Dynamicsm)=Simulation$\r->doletsc=runSpecsrn=0t=spcStartTimescmPoint{pointSpecs=sc,pointRun=r,pointTime=t,pointIteration=n,pointPhase=0}-- | Run the dynamic process in the final simulation point.runDynamicsInStopTime::Dynamicsa->SimulationarunDynamicsInStopTime(Dynamicsm)=Simulation$\r->doletsc=runSpecsrn=iterationHiBndsct=basicTimescn0mPoint{pointSpecs=sc,pointRun=r,pointTime=t,pointIteration=n,pointPhase=0}-- | Run the dynamic process in all integration time pointsrunDynamicsInIntegTimes::Dynamicsa->Simulation[IOa]runDynamicsInIntegTimes(Dynamicsm)=Simulation$\r->doletsc=runSpecsr(nl,nu)=iterationBndsscpointn=Point{pointSpecs=sc,pointRun=r,pointTime=basicTimescn0,pointIteration=n,pointPhase=0}return$map(m.point)[nl..nu]-- | Run the dynamic process in the specified time point.runDynamicsInTime::Double->Dynamicsa->SimulationarunDynamicsInTimet(Dynamicsm)=Simulation$\r->doletsc=runSpecsrt0=spcStartTimescdt=spcDTscn=fromInteger$toInteger$floor((t-t0)/dt)mPoint{pointSpecs=sc,pointRun=r,pointTime=t,pointIteration=n,pointPhase=-1}-- | Run the dynamic process in the specified time points.runDynamicsInTimes::[Double]->Dynamicsa->Simulation[IOa]runDynamicsInTimests(Dynamicsm)=Simulation$\r->doletsc=runSpecsrt0=spcStartTimescdt=spcDTscpointt=letn=fromInteger$toInteger$floor((t-t0)/dt)inPoint{pointSpecs=sc,pointRun=r,pointTime=t,pointIteration=n,pointPhase=-1}return$map(m.point)tsinstanceFunctorDynamicswherefmap=liftMDinstanceEq(Dynamicsa)wherex==y=error"Can't compare dynamics."instanceShow(Dynamicsa)whereshowsPrec_x=showString"<< Dynamics >>"liftMD::(a->b)->Dynamicsa->Dynamicsb{-# INLINE liftMD #-}liftMDf(Dynamicsx)=Dynamics$\p->do{a<-xp;return$fa}liftM2D::(a->b->c)->Dynamicsa->Dynamicsb->Dynamicsc{-# INLINE liftM2D #-}liftM2Df(Dynamicsx)(Dynamicsy)=Dynamics$\p->do{a<-xp;b<-yp;return$fab}instance(Numa)=>Num(Dynamicsa)wherex+y=liftM2D(+)xyx-y=liftM2D(-)xyx*y=liftM2D(*)xynegate=liftMDnegateabs=liftMDabssignum=liftMDsignumfromIntegeri=return$fromIntegeriinstance(Fractionala)=>Fractional(Dynamicsa)wherex/y=liftM2D(/)xyrecip=liftMDrecipfromRationalt=return$fromRationaltinstance(Floatinga)=>Floating(Dynamicsa)wherepi=returnpiexp=liftMDexplog=liftMDlogsqrt=liftMDsqrtx**y=liftM2D(**)xysin=liftMDsincos=liftMDcostan=liftMDtanasin=liftMDasinacos=liftMDacosatan=liftMDatansinh=liftMDsinhcosh=liftMDcoshtanh=liftMDtanhasinh=liftMDasinhacosh=liftMDacoshatanh=liftMDatanhinstanceMonadIODynamicswhereliftIOm=Dynamics$constminstanceSimulationLiftDynamicswhereliftSimulation=liftDSliftDS::Simulationa->Dynamicsa{-# INLINE liftDS #-}liftDS(Simulationm)=Dynamics$\p->m$pointRunp-- | A type class to lift the 'Dynamics' computations in other monads.classMonadm=>DynamicsLiftmwhere-- | Lift the specified 'Dynamics' computation in another monad.liftDynamics::Dynamicsa->ma-- | Exception handling within 'Dynamics' computations.catchDynamics::Dynamicsa->(IOException->Dynamicsa)->DynamicsacatchDynamics(Dynamicsm)h=Dynamics$\p->C.catch(mp)$\e->letDynamicsm'=heinm'p-- | A computation with finalization part like the 'finally' function.finallyDynamics::Dynamicsa->Dynamicsb->DynamicsafinallyDynamics(Dynamicsm)(Dynamicsm')=Dynamics$\p->C.finally(mp)(m'p)-- | Like the standard 'throw' function.throwDynamics::IOException->DynamicsathrowDynamics=throw