!------------------------------------------------------------------------- ! Subroutine : ppm_ode_step !------------------------------------------------------------------------- ! ! Purpose : integrates one stage of a mode ! ! Input : odeid (I) id of mode to advance ! xp(:,:) (F) xp (trad. coords) ! up(:,:) (F) function to integrate ! dup(:,:) (F) derivative of up (in time) ! lda (I) leading dimension of up ! Npart (I) numper of particles ! bfr(:,:) (F) buffer ! istage (I) which stage were in ! time(4) (F) time data: time(1) is the ! start time, time(2) the end ! time, time(3) the current ! time and time (4) the ! time step ! rhsfunc (I) function pointer to the rhs ! ipackdata(:,:) (I) optional storage array ! lpackdata(:,:) (L) optional storage array ! rpackdata(:,:) (F) optional storage array ! ! Output : info (I) return status ! ! Remarks : ! ! References : ! ! Revisions : !------------------------------------------------------------------------- ! $Log: ppm_ode_step.f,v $ ! Revision 1.1.1.1 2007/07/13 10:19:01 ivos ! CBL version of the PPM library ! ! Revision 1.20 2006/09/04 18:34:54 pchatela ! Fixes and cleanups to make it compile for ! release-1-0 ! ! Revision 1.19 2006/02/03 09:37:06 ivos ! Changed input arguments from INOUT to POINTER to allow for ghost_put. ! ! Revision 1.18 2005/08/05 09:30:06 ivos ! Added the flabbergsting STS of Michael. ! ! Revision 1.17 2005/07/22 08:03:43 pchatela ! Used a DO loop rather than a vector notation for the 1st step inside RK4. ! 2 reasons: ! 1) DO loops are used everywhere else in the file... ! 2) It apparently causes a seg fault for a system with moderate memory (like my personal laptop) ! ! Revision 1.16 2005/01/05 16:27:18 ivos ! fixed INTENT and POINTER attributes of the arguments. ! ! Revision 1.15 2004/10/11 06:53:14 hiebers ! cosmetics ! ! Revision 1.14 2004/10/01 15:15:11 hiebers ! added Runge Kutta 4th order ! ! Revision 1.13 2004/08/26 15:21:00 michaebe ! inserted 1:npart to be able to handle ghosts. ghosts? ! ! Revision 1.12 2004/08/13 15:30:45 michaebe ! added mid point runge kutta ! ! Revision 1.11 2004/08/12 13:45:23 michaebe ! modified ppm_ode_sent() = .. ! ! Revision 1.10 2004/07/27 10:29:20 michaebe ! renamed the scheme parameters from ppm_ode_scheme.. to ! ppm_param_ode_scheme.. ! ! Revision 1.9 2004/07/26 14:57:18 michaebe ! renamed the vector and scalar defines ! ! Revision 1.8 2004/07/26 13:49:19 ivos ! Removed Routines sections from the header comment. ! ! Revision 1.7 2004/07/26 11:49:01 michaebe ! added overloaded end subroutine ! ! Revision 1.6 2004/07/26 11:33:04 michaebe ! inserted the use of the ppm ode data module. ! ! Revision 1.5 2004/07/26 08:13:51 michaebe ! Added scalar code for lda=1. ! ! Revision 1.4 2004/07/26 07:59:51 michaebe ! Cosmetics. Lines partially too long. ! ! Revision 1.3 2004/07/26 07:54:57 michaebe ! Atomized. Furthermore added carrier arrays to transport auxillary data ! to the user-given right hand side function. ! ! Revision 1.2 2004/06/10 16:20:04 ivos ! Moved all xpp directtives to column 1. The NEC xpp did not recognize ! them otherwise!!! ! ! Revision 1.1 2004/02/19 08:33:57 michaebe ! initial implementation. ! !------------------------------------------------------------------------- ! Parallel Particle Mesh Library (PPM) ! Institute of Computational Science ! ETH Zentrum, Hirschengraben 84 ! CH-8092 Zurich, Switzerland !------------------------------------------------------------------------- #if __MODE == __SCA #if __KIND == __SINGLE_PRECISION SUBROUTINE ppm_ode_step_ss(odeid,xp,up,dup,lda,Npart,bfr,istage,time,& & rhsfunc, ipackdata, rpackdata, lpackdata, info) #elif __KIND == __DOUBLE_PRECISION SUBROUTINE ppm_ode_step_ds(odeid,xp,up,dup,lda,Npart,bfr,istage,time,& & rhsfunc, ipackdata, rpackdata, lpackdata, info) #endif #elif __MODE == __VEC #if __KIND == __SINGLE_PRECISION SUBROUTINE ppm_ode_step_sv(odeid,xp,up,dup,lda,Npart,bfr,istage,time,& & rhsfunc, ipackdata, rpackdata, lpackdata, info) #elif __KIND == __DOUBLE_PRECISION SUBROUTINE ppm_ode_step_dv(odeid,xp,up,dup,lda,Npart,bfr,istage,time,& & rhsfunc, ipackdata, rpackdata, lpackdata, info) #endif #endif !----------------------------------------------------------------------- ! Includes !----------------------------------------------------------------------- #include "ppm_define.h" !----------------------------------------------------------------------- ! Modules !----------------------------------------------------------------------- USE ppm_module_data_ode USE ppm_module_data USE ppm_module_check_id USE ppm_module_substart USE ppm_module_substop USE ppm_module_error USE ppm_module_alloc USE ppm_module_numerics_data IMPLICIT NONE #if __KIND == __SINGLE_PRECISION INTEGER, PARAMETER :: mk = ppm_kind_single #else INTEGER, PARAMETER :: mk = ppm_kind_double #endif #if __KIND == __SINGLE_PRECISION INTERFACE FUNCTION rhsfunc(topoid,xp,up,dup,lda,npart,ipack,& &lpack,rpack,info) INTEGER , INTENT(IN) :: topoid INTEGER , INTENT(IN) :: lda,npart INTEGER , INTENT(OUT) :: info #if __MODE == __SCA REAL(KIND(1.0E0)), DIMENSION(:,:), POINTER :: xp REAL(KIND(1.0E0)), DIMENSION(:), POINTER :: up REAL(KIND(1.0E0)), DIMENSION(:), POINTER :: dup #elif __MODE == __VEC REAL(KIND(1.0E0)), DIMENSION(:,:), POINTER :: xp,up REAL(KIND(1.0E0)), DIMENSION(:,:), POINTER :: dup #endif INTEGER, DIMENSION(:,:), INTENT(IN), OPTIONAL :: ipack LOGICAL, DIMENSION(:,:), INTENT(IN), OPTIONAL :: lpack REAL(kind(1.0E0)), DIMENSION(:,:), INTENT(IN), OPTIONAL :: rpack INTEGER :: rhsfunc END FUNCTION rhsfunc END INTERFACE #else INTERFACE FUNCTION rhsfunc(topoid,xp,up,dup,lda,npart,ipack,& &lpack,rpack,info) INTEGER , INTENT(IN) :: topoid INTEGER , INTENT(IN) :: lda,npart INTEGER , INTENT(OUT) :: info #if __MODE == __SCA REAL(KIND(1.0D0)), DIMENSION(:,:), POINTER :: xp REAL(KIND(1.0D0)), DIMENSION(:), POINTER :: up REAL(KIND(1.0D0)), DIMENSION(:), POINTER :: dup #elif __MODE == __VEC REAL(KIND(1.0D0)), DIMENSION(:,:), POINTER :: xp,up REAL(KIND(1.0D0)), DIMENSION(:,:), POINTER :: dup #endif INTEGER, DIMENSION(:,:), INTENT(IN), OPTIONAL :: ipack LOGICAL, DIMENSION(:,:), INTENT(IN), OPTIONAL :: lpack REAL(kind(1.0D0)), DIMENSION(:,:), INTENT(IN), OPTIONAL :: rpack INTEGER :: rhsfunc END FUNCTION rhsfunc END INTERFACE #endif !----------------------------------------------------------------------- ! Arguments !----------------------------------------------------------------------- INTEGER, INTENT( out) :: info INTEGER, INTENT(in ) :: odeid #if __MODE == __SCA REAL(mk), DIMENSION(: ), POINTER :: up,dup #elif __MODE == __VEC REAL(mk), DIMENSION(:,:), POINTER :: up,dup #endif REAL(mk), DIMENSION(:,:), POINTER :: xp REAL(mk), DIMENSION(:,:), POINTER :: bfr INTEGER, INTENT(in ) :: istage REAL(mk), DIMENSION(4), INTENT(inout) :: time INTEGER, INTENT(in ) :: lda, Npart INTEGER, DIMENSION(:,:), INTENT(IN), OPTIONAL :: ipackdata REAL(mk), DIMENSION(:,:), INTENT(IN), OPTIONAL :: rpackdata LOGICAL, DIMENSION(:,:), INTENT(IN), OPTIONAL :: lpackdata !----------------------------------------------------------------------- ! Local Variables !----------------------------------------------------------------------- REAL(mk) :: t, dt INTEGER :: scheme, throwaway, i, j INTEGER :: umidmin, umidmax INTEGER :: mid, ilda REAL(mk) :: M_PI INTEGER :: stsn REAL(mk), DIMENSION(20) :: stsnu REAL(mk) :: tau INTEGER :: topoid LOGICAL :: topo_valid !----------------------------------------------------------------------- ! fill the nu parameters for the sts scheme !----------------------------------------------------------------------- M_PI = ACOS(-1.0_MK) stsnu(1) = 0.0_mk stsnu(5) = 0.04_mk stsnu(7) = 0.0015_mk stsnu(9) = 0.04_mk stsnu(20) = 0.006_mk !----------------------------------------------------------------------- ! call substart !----------------------------------------------------------------------- CALL substart('ppm_ode_step',t0,info) !----------------------------------------------------------------------- ! check input arguments !----------------------------------------------------------------------- IF(Npart.EQ.0) THEN !-------------------------------------------------------------------- ! best case: nothing to do !-------------------------------------------------------------------- time(3) = time(3) + time(4) GOTO 9999 END IF IF(ppm_debug.GT.0) THEN IF(.NOT.ppm_initialized) THEN info = ppm_error_error CALL ppm_error(ppm_err_ppm_noinit,'ppm_ode_step',& & 'Please call ppm_init first!',__LINE__,info) GOTO 9999 END IF !-------------------------------------------------------------------- ! check odeid !-------------------------------------------------------------------- umidmin = LBOUND(ppm_internal_mid,1) umidmax = UBOUND(ppm_internal_mid,1) IF(odeid.LT.umidmin.OR.odeid.GT.umidmax) THEN !----------------------------------------------------------------- ! user mid does not exist !----------------------------------------------------------------- info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step', & & 'ODEID does not exist',__LINE__,info) GOTO 9999 ELSE IF(ppm_internal_mid(odeid).EQ.-HUGE(odeid)) THEN !-------------------------------------------------------------- ! user mid does not exist !-------------------------------------------------------------- info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step',& & 'ODEID does not exist',__LINE__,info) GOTO 9999 END IF END IF !-------------------------------------------------------------------- ! check dimension !-------------------------------------------------------------------- IF(Npart.LT.0) THEN info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step', & & 'Npart cannot be <0',__LINE__,info) GOTO 9999 END IF IF(lda.LE.0) THEN info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step', & & 'LDA must be >00',__LINE__,info) GOTO 9999 END IF IF(time(4).LE.0.0_mk) THEN info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step', & & 'dt must be >=0',__LINE__,info) GOTO 9999 END IF IF(time(3).LT.time(1)) THEN info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step', & & 'time must be >= tstart',__LINE__,info) GOTO 9999 END IF IF(scheme.EQ.ppm_param_ode_scheme_sts) THEN IF(.NOT.PRESENT(ipackdata)) THEN info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step', & & 'for STS you need to specify N in ipackdata(1,1)',& & __LINE__,info) GOTO 9999 ELSE IF(ipackdata(1,1).NE.1.AND.ipackdata(1,1).NE.7.AND. & & ipackdata(1,1).NE.9.AND.ipackdata(1,1).NE.20) THEN info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step', & & 'ipackdata(1,1) must be element of {1,7,9,20}',& & __LINE__,info) GOTO 9999 END IF END IF END IF !-------------------------------------------------------------------- ! check association of up, dup, bfr !-------------------------------------------------------------------- IF(.NOT.ASSOCIATED(up)) THEN info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step', & & 'UP is empty',__LINE__,info) GOTO 9999 END IF IF(.NOT.ASSOCIATED(dup)) THEN info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step', & & 'DUP is empty',__LINE__,info) GOTO 9999 END IF IF(.NOT.ASSOCIATED(bfr)) THEN info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step', & & 'BFR is empty',__LINE__,info) GOTO 9999 END IF CALL ppm_check_topoid(ppm_ode_topoid,topo_valid,info) IF (.NOT. topo_valid) THEN info = ppm_error_error CALL ppm_error(ppm_err_argument,'ppm_ode_step', & & 'topoid not valid',__LINE__,info) GOTO 9999 ENDIF END IF ! (ppm_debug.GT.0) topoid = ppm_ode_topoid mid = ppm_internal_mid(odeid) !----------------------------------------------------------------------- ! check state if finished, bail out !----------------------------------------------------------------------- IF(ppm_ode_state(mid).EQ.ppm_ode_state_finished) GOTO 9999 !----------------------------------------------------------------------- ! check istage, if greater that ppm_ode_stages, then ! bail out !----------------------------------------------------------------------- IF(ppm_ode_stages(mid).LT.istage) GOTO 9999 !----------------------------------------------------------------------- ! get times and scheme !----------------------------------------------------------------------- t = time(3) dt = time(4) IF(ppm_ode_state(mid).EQ.ppm_ode_state_kickoff) THEN scheme = ppm_ode_kscheme(mid) ELSE scheme = ppm_ode_ischeme(mid) END IF IF(ppm_ode_adaptive(mid)) THEN !-------------------------------------------------------------------- ! compute adaptive timestep [TODO] !-------------------------------------------------------------------- CALL ppm_error(ppm_err_argument,'ppm_ode_step',& & 'adaptivity not yet implemented',__LINE__,info) GOTO 9999 END IF SELECT CASE(scheme) CASE(ppm_param_ode_scheme_eulerf) !-------------------------------------------------------------------- !======= ! euler: !======= !-------------------------------------------------------------------- !-------------------------------------------------------------------- ! call right hand side and do an euler step !-------------------------------------------------------------------- #include "ppm_ode_rhsfunc_macro.h" #if __MODE == __SCA DO j=1,npart up(j) = up(j) + dt * dup(j) END DO #elif __MODE == __VEC DO i=1,lda DO j=1,npart up(i,j) = up(i,j) + dt * dup(i,j) END DO END DO #endif t = t + dt IF(ppm_ode_state(mid).EQ.ppm_ode_state_kickoff) THEN ppm_ode_state(mid) = ppm_ode_state_running END IF ! how much to save of this ppm_ode_sent(mid) = 0 CASE(ppm_param_ode_scheme_sts) !----------------------------------------------------- ! compute the new dt !----------------------------------------------------- stsn = ipackdata(1,1) if(present(rpackdata)) stsnu(stsn) = rpackdata(1,1) tau = dt/((stsnu(stsn)-1.0_mk)*& & COS((2.0_mk*REAL(istage,mk)-1.0_mk)/REAL(stsn,mk)*M_PI*0.5_mk)& & +1.0_mk+stsnu(stsn)) !----------------------------------------------------------------- !======= ! euler: !======= !----------------------------------------------------------------- ! call right hand side and do an euler step !----------------------------------------------------------------- #include "ppm_ode_rhsfunc_macro.h" #if __MODE == __SCA DO j=1,npart up(j) = up(j) + tau * dup(j) END DO #elif __MODE == __VEC DO i=1,lda DO j=1,npart up(i,j) = up(i,j) + tau * dup(i,j) END DO END DO #endif t = t + tau IF(ppm_ode_state(mid).EQ.ppm_ode_state_kickoff) THEN ppm_ode_state(mid) = ppm_ode_state_running END IF ! how much to save of this ppm_ode_sent(mid) = 0 CASE(ppm_param_ode_scheme_tvdrk2) !-------------------------------------------------------------------- !============ ! 2nd tvd rk: !============ !-------------------------------------------------------------------- SELECT CASE(istage) CASE(1) !----------------------------------------------------------------- ! call rhs, save the old up and do an euler step !----------------------------------------------------------------- #include "ppm_ode_rhsfunc_macro.h" #if __MODE == __SCA DO i=1,Npart bfr(1,i) = up(i) up(i) = up(i) + dt*dup(i) END DO #elif __MODE == __VEC DO i=1,Npart DO j=1,lda bfr(j,i) = up(j,i) up(j,i) = up(j,i) + dt*dup(j,i) END DO END DO #endif ppm_ode_sent(mid) = 1 CASE(2) !----------------------------------------------------------------- ! call rhs, and do another euler step !----------------------------------------------------------------- #include "ppm_ode_rhsfunc_macro.h" #if __MODE == __SCA DO i=1,Npart up(i) = up(i) + dt*dup(i) END DO #elif __MODE == __VEC DO i=1,Npart DO j=1,lda up(j,i) = up(j,i) + dt*dup(j,i) END DO END DO #endif !----------------------------------------------------------------- ! interpolate !----------------------------------------------------------------- #if __MODE == __SCA DO i=1,Npart up(i) = 0.5_mk * (up(i) + bfr(1,i) ) END DO #elif __MODE == __VEC DO i=1,Npart DO j=1,lda up(j,i) = 0.5_mk * (up(j,i) + bfr(j,i)) END DO END DO #endif t = t + dt ppm_ode_sent(mid) = 0 IF(ppm_ode_state(mid).EQ.ppm_ode_state_kickoff) THEN ppm_ode_state(mid) = ppm_ode_state_running END IF END SELECT CASE(ppm_param_ode_scheme_midrk2) !-------------------------------------------------------------------- !============= ! mid point rk !============= !-------------------------------------------------------------------- SELECT CASE(istage) CASE(1) !----------------------------------------------------------------- ! !----------------------------------------------------------------- #include "ppm_ode_rhsfunc_macro.h" #if __MODE == __SCA DO i=1,Npart bfr(1,i) = up(i) up(i) = up(i) + 0.5_mk* dt * dup(i) END DO #elif __MODE == __VEC DO j=1,lda DO i=1,Npart bfr(j,i) = up(j,i) up(j,i) = up(j,i) + 0.5_mk*dt*dup(j,i) END DO END DO #endif ppm_ode_sent(mid) = 1 CASE(2) #include "ppm_ode_rhsfunc_macro.h" #if __MODE == __SCA DO i=1,Npart up(i) = bfr(1,i) + dt * dup(i) END DO #elif __MODE == __VEC DO i=1,Npart DO j=1,lda up(j,i) = bfr(j,i) + dt * dup(j,i) END DO END DO #endif t = t + dt ppm_ode_sent(mid) = 0 IF(ppm_ode_state(mid).EQ.ppm_ode_state_kickoff) THEN ppm_ode_state(mid) = ppm_ode_state_running END IF END SELECT CASE(ppm_param_ode_scheme_rk4) !============= ! Runge Kutta 4 !============= SELECT CASE(istage) CASE(1) !----------------------------------------------------------------- ! x_n + 1/2 dt k1 !----------------------------------------------------------------- #include "ppm_ode_rhsfunc_macro.h" DO i=1,Npart #if __MODE == __SCA bfr(1,i) = up(i) bfr(2,i) = dup(i) ! k1 #elif __MODE == __VEC bfr(1:lda,i) = up(:,i) bfr((lda+1):2*lda,i) = dup(:,i) !k1 #endif END DO DO i=1,Npart #if __MODE == __SCA up(i) = up(i) + 0.5_mk* dt * dup(i) #elif __MODE == __VEC DO ilda=1,lda up(ilda,i) = up(ilda,i) + 0.5_mk*dt*dup(ilda,i) END DO #endif END DO ppm_ode_sent(mid) = 2 CASE(2) !----------------------------------------------------------------- #include "ppm_ode_rhsfunc_macro.h" !----------------------------------------------------------------- ! x_n + 1/2 dt k2 !----------------------------------------------------------------- DO i=1,Npart #if __MODE == __SCA bfr(3,i) = dup(i) !k2 #elif __MODE == __VEC DO ilda=1,lda bfr((2*lda+ilda),i) = dup(ilda,i) !k2 END DO #endif #if __MODE == __SCA up(i) = bfr(1,i) + 0.5_mk* dt * dup(i) #elif __MODE == __VEC DO ilda=1,lda up(ilda,i) = bfr(ilda,i) + 0.5_mk*dt * dup(ilda,i) END DO #endif END DO ppm_ode_sent(mid) = 3 CASE(3) !----------------------------------------------------------------- ! !----------------------------------------------------------------- #include "ppm_ode_rhsfunc_macro.h" !----------------------------------------------------------------- ! x_n + dt k3 !----------------------------------------------------------------- DO i=1,Npart #if __MODE == __SCA bfr(4,i) = dup(i) !k3 #elif __MODE == __VEC DO ilda=1,lda bfr((3*lda+ilda),i) = dup(ilda,i) !k3 END DO #endif #if __MODE == __SCA up(i) = bfr(1,i) + dt * dup(i) #elif __MODE == __VEC DO ilda=1,lda up(ilda,i) = bfr(ilda,i) + dt * dup(ilda,i) END DO #endif END DO ppm_ode_sent(mid) = 4 CASE(4) !----------------------------------------------------------------- #include "ppm_ode_rhsfunc_macro.h" !----------------------------------------------------------------- ! x_n + 1/6 dt (k1 + 2 k2 + 2k3 +k4) !----------------------------------------------------------------- DO i=1,Npart #if __MODE == __SCA up(i) = bfr(1,i) + 1.0_MK/6.0_MK*dt* & & (bfr(2,i) + 2.0_MK*bfr(3,i) + 2.0_MK*bfr(4,i) + up(i)) #elif __MODE == __VEC DO ilda=1,lda up(ilda,i) = bfr(ilda,i) + 1.0_MK/6.0_MK*dt* & & (bfr((lda+ilda),i) + 2.0_MK*bfr((2*lda+ilda),i) + & & 2.0_MK*bfr((3*lda+ilda),i)+ dup(ilda,i)) END DO #endif END DO t = t + dt ppm_ode_sent(mid) = 0 IF(ppm_ode_state(mid).EQ.ppm_ode_state_kickoff) THEN ppm_ode_state(mid) = ppm_ode_state_running END IF END SELECT END SELECT !----------------------------------------------------------------------- ! pass back dt and time !----------------------------------------------------------------------- time(3) = t time(4) = dt !----------------------------------------------------------------------- ! stop ode if were ready !----------------------------------------------------------------------- IF(time(3).GE.time(2)) THEN ppm_ode_state(mid) = ppm_ode_state_finished END IF 9999 CONTINUE !----------------------------------------------------------------------- ! substop !----------------------------------------------------------------------- CALL substop('ppm_ode_step',t0,info) RETURN #if __MODE == __SCA #if __KIND == __SINGLE_PRECISION END SUBROUTINE ppm_ode_step_ss #elif __KIND == __DOUBLE_PRECISION END SUBROUTINE ppm_ode_step_ds #endif #elif __MODE == __VEC #if __KIND == __SINGLE_PRECISION END SUBROUTINE ppm_ode_step_sv #elif __KIND == __DOUBLE_PRECISION END SUBROUTINE ppm_ode_step_dv #endif #endif