amun-code/src/driver.F90
Grzegorz Kowal 0e930499a1 Fix diffusion of Psi in MHD-GLM after last changes.
- the diffusion of Psi in MHD-GLM requires spacial step dxmin, so
   update the diffusion so it works after the last commit changes;

 - call find_new_timestep() after job restart, since some parameters
   could change;
2011-05-07 09:32:10 -03:00

415 lines
10 KiB
Fortran

!!******************************************************************************
!!
!! program: AMUN
!!
!! Copyright (C) 2008-2011 Grzegorz Kowal <grzegorz@amuncode.org>
!!
!!******************************************************************************
!!
!! This file is part of the AMUN code.
!!
!! This program is free software; you can redistribute it and/or
!! modify it under the terms of the GNU General Public License
!! as published by the Free Software Foundation; either version 2
!! of the License, or (at your option) any later version.
!!
!! This program is distributed in the hope that it will be useful,
!! but WITHOUT ANY WARRANTY; without even the implied warranty of
!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
!! GNU General Public License for more details.
!!
!! You should have received a copy of the GNU General Public License
!! along with this program; if not, write to the Free Software Foundation,
!! Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
!!
!!******************************************************************************
!!
!
program amun
! modules
!
use blocks , only : init_blocks, get_nleafs
use config , only : read_config, nmax, tmax, dtini, dtout, cfl, nres
#ifdef FORCE
use config , only : fdt
#endif /* FORCE */
use evolution, only : evolve, find_new_timestep, n, t, dt, dtn
#ifdef FORCE
use forcing , only : init_forcing, clear_forcing
#endif /* FORCE */
use integrals, only : init_integrals, clear_integrals, store_integrals
use io , only : nfile, write_data, write_restart_data, restart_job
use mesh , only : init_mesh, generate_mesh, store_mesh_stats, clear_mesh
use mpitools , only : ncpu, ncpus, init_mpi, clear_mpi, is_master, mfindmaxi
use random , only : init_generator
use timer , only : init_timers, start_timer, stop_timer, get_timer &
, get_timer_total
!
!-------------------------------------------------------------------------------
!
! local variables
!
character(len=60) :: fmt
integer(kind=4) :: iterm = 0
integer :: ed, eh, em, es, ec
real :: tall, tcur, tpre, per
#ifdef SIGNALS
! commons required to share iterm flag
!
common /signals/ iterm
! references to functions handling signals
!
intrinsic signal
external terminate
! signal definitions
!
integer, parameter :: SIGINT = 2, SIGABRT = 6, SIGTERM = 15
#endif /* SIGNALS */
!
!-------------------------------------------------------------------------------
!
#ifdef SIGNALS
! assign function terminate with signals
!
call signal(SIGINT , terminate)
call signal(SIGABRT, terminate)
call signal(SIGTERM, terminate)
#endif /* SIGNALS */
! initialize MPI
!
call init_mpi()
! print info message
!
if (is_master()) then
write (*,"(1x,78('-'))")
write (*,"(1x,18('='),4x,a,4x,19('='))") ' A M U N '
write (*,"(1x,16('='),4x,a,4x,16('='))") &
'Copyright (C) 2008-2011 Grzegorz Kowal'
#ifdef MPI
write (*,"(1x,18('='),4x,a,i5,a,4x,19('='))") 'MPI enabled with ', ncpus &
, ' processors'
#endif /* MPI */
write (*,"(1x,78('-'))")
write (*,*)
write (*,"(1x,a)" ) "Physics:"
write (*,"(4x,a,1x,a)" ) "equations =", &
#ifdef HYDRO
"HD"
#endif /* HYDRO */
#ifdef MHD
"MHD"
#endif /* MHD */
write (*,"(4x,a,1x,a)" ) "equation of state =", &
#ifdef ADI
"adiabatic"
#endif /* ADI */
#ifdef ISO
"isothermal"
#endif /* ISO */
write (*,"(4x,a,1x,a)" ) "geometry =", &
"rectangular"
end if
! read configuration file
!
call read_config()
! reset number of iterations and time, etc.
!
n = 0
t = 0.0
dt = cfl * dtini
dtn = dtini
ed = 9999
eh = 23
em = 59
es = 59
! initialize timers
!
call init_timers()
! start the initialization timer
!
call start_timer(1)
! initialize random number generator
!
call init_generator()
! initialize block module
!
call init_blocks()
! check if we initiate new problem or restart previous job
!
if (nres .lt. 0) then
! initialize the mesh module
!
call init_mesh(.true.)
! initialize the integrals module
!
call init_integrals(.true.)
! generate the initial mesh, refine that mesh to the desired level according to
! the initialized problem
!
call generate_mesh()
! store mesh statistics
!
call store_mesh_stats(n, t)
! find new time step
!
call find_new_timestep()
! store integrals
!
call store_integrals()
! write down the initial state
!
call write_data()
else
! initialize the mesh module
!
call init_mesh(.false.)
! initialize the integrals module
!
call init_integrals(.false.)
! reconstruct the meta and data block structures from a given restart file
!
call restart_job()
! find new time step
!
call find_new_timestep()
end if
#ifdef FORCE
! if the forcing time step is larger than the initial time step decrease it
!
fdt = min(fdt, 0.1d0 * dtini)
! round the initial time step to the integer number of forcing time steps
!
dt = fdt * floor(dt / fdt)
! initialize forcing module
!
call init_forcing()
#endif /* FORCE */
! stop the initialization timer
!
call stop_timer(1)
! print information
!
if (is_master()) then
write(*,* )
write(*,"(1x,a)" ) "Evolving the system:"
write(*,'(4x,a4,5x,a4,11x,a2,12x,a6,7x,a3)') 'step', 'time', 'dt' &
, 'blocks', 'ETA'
write(*,'(i8,2(1x,1pe14.6),2x,i8,2x,1i4.1,"d",1i2.2,"h",1i2.2,"m"' // &
',1i2.2,"s",a1,$)') n, t, dt, get_nleafs(), ed, eh, em, es, char(13)
end if
! set the previous time needed to estimate the execution time
!
tpre = get_timer_total()
! main loop
!
do while((n .lt. nmax) .and. (t .le. tmax) .and. (iterm .eq. 0))
! compute new time step
!
dt = min(cfl * dtn, 2.0d0 * dt)
#ifdef FORCE
! limit the time step to the integer number of forcing time steps
!
dt = fdt * floor(dt / fdt)
#endif /* FORCE */
! advance the iteration number and time
!
t = t + dt
n = n + 1
! performe one step evolution
!
call evolve()
! store mesh statistics
!
call store_mesh_stats(n, t)
! store integrals
!
call store_integrals()
! store data
!
if (dtout .gt. 0.0 .and. nfile .lt. (int(t/dtout))) then
call write_data()
end if
! get current time in seconds
!
tcur = get_timer_total()
ec = int((tmax - t) * (tcur - tpre) / dt, kind=4)
es = max(0, int(mod(ec,60)))
em = int(mod(ec/60,60))
eh = int(ec/3600)
ed = int(eh/24)
eh = int(mod(eh, 24))
ed = min(9999,ed)
tpre = tcur
! print progress information
!
if (is_master()) &
write(*,'(i8,2(1x,1pe14.6),2x,i8,2x,1i4.1,"d",1i2.2,"h",1i2.2,"m"' // &
',1i2.2,"s",a1,$)') n, t, dt, get_nleafs(), ed, eh, em, es &
, char(13)
#if defined SIGNALS && defined MPI
! reduce termination flag over all processors
!
call mfindmaxi(iterm)
#endif /* SIGNALS & MPI */
end do
! add one empty line
!
if (is_master()) write(*,*)
! write down the restart dump
!
call write_restart_data()
! start the initialization timer
!
call start_timer(1)
#ifdef FORCE
! finalize forcing module
!
call clear_forcing()
#endif /* FORCE */
! clear up the integrals module
!
call clear_integrals()
! deallocate and reset mesh
!
call clear_mesh()
! get total time
!
tall = get_timer_total()
per = 100.0 / tall
#ifdef SIGNALS
! print info about termination due to a signal
!
if (is_master()) then
if (iterm .eq. 1) then
write(*,*)
write(*,"(1x,a)") "Program terminated due to received signal."
write(*,"(1x,a)") "Restart files have been successfully written."
end if
end if
#endif /* SIGNALS */
! stop the initialization timer
!
call stop_timer(1)
! print info about execution times
!
if (is_master()) then
write(fmt,"(a,i2,a)") "(a27,1f", max(1, nint(alog10(tall))) + 5 &
, ".3,' secs = ',f6.2,' %')"
write (*,*)
write(*,"(1x,a)") "Job timings:"
write (*,fmt) "Initialization : ", get_timer(1), per * get_timer(1)
write (*,fmt) "Evolution : ", get_timer(2), per * get_timer(2)
write (*,fmt) "Data output : ", get_timer(3), per * get_timer(3)
write (*,fmt) "Boundary update : ", get_timer(4), per * get_timer(4)
write (*,fmt) "Mesh update : ", get_timer(5), per * get_timer(5)
write (*,fmt) "Maximum speed estim. : ", get_timer(6), per * get_timer(6)
#ifdef FORCE
write (*,fmt) "External forcing : ", get_timer(10), per * get_timer(10)
write (*,fmt) " - initialization : ", get_timer(11), per * get_timer(11)
write (*,fmt) " - evolution : ", get_timer(12), per * get_timer(12)
write (*,fmt) " - real to fourier : ", get_timer(13), per * get_timer(13)
write (*,fmt) " - fourier to real : ", get_timer(14), per * get_timer(14)
#endif /* FORCE */
write (*,fmt) "EXECUTION TIME : ", tall , 100.0
write (*,*)
end if
! close access to the MPI
!
call clear_mpi()
!-------------------------------------------------------------------------------
!
end program
#ifdef SIGNALS
!
!===============================================================================
!
! terminate: function handles properly the signals sent to the program
!
!===============================================================================
!
function terminate(snum)
implicit none
! input arguments
!
integer(4), intent(in) :: snum
! local and shared variables
!
integer(4) :: terminate, iterm
! commons to declate shared variables
!
common /signals/ iterm
!
!-------------------------------------------------------------------------------
!
iterm = 1
terminate = 1
!-------------------------------------------------------------------------------
!
end
#endif /* SIGNALS */
!===============================================================================
!