MPI-AMRVAC 3.2
The MPI - Adaptive Mesh Refinement - Versatile Advection Code (development version)
Loading...
Searching...
No Matches
mod_input_output.t
Go to the documentation of this file.
1!> Module for reading input and writing output
3 use mod_comm_lib, only: mpistop
5
6 implicit none
7 public
8
9
10 !> coefficient for rk2_alfa
11 double precision, private :: rk2_alfa
12
13 !> debug field-dump variable names (set by debug_alloc, used by save_wdebug)
14 character(len=name_len), allocatable :: wdebug_names(:)
15
16 !> List of compatible versions
17 integer, parameter :: compatible_versions(3) = [3, 4, 5]
18
19 !> number of w found in dat files
20 integer :: nw_found
21
22 !> tag for MPI message
23 integer, private :: itag
24
25 !> whether staggered field is in dat
26 logical, private :: stagger_mark_dat=.false.
27
28 ! Formats used in output
29 character(len=*), parameter :: fmt_r = 'es16.8' ! Default precision
30 character(len=*), parameter :: fmt_r2 = 'es10.2' ! Two digits
31 character(len=*), parameter :: fmt_i = 'i8' ! Integer format
32
33 ! public methods
34 public :: snapshot_write_header
35
36contains
37
38 !> Read the command line arguments passed to amrvac
39 subroutine read_arguments()
41
42 integer :: len, stat, n, i, ipars
43 integer, parameter :: max_files = 20 ! Maximum number of par files
44 integer :: n_par_files
45 logical :: unknown_arg, help, morepars
46 character(len=max_files*std_len) :: all_par_files
47 character(len=std_len) :: tmp_files(max_files), arg
48
49 if (mype == 0) then
50 print *, '-----------------------------------------------------------------------------'
51 print *, '-----------------------------------------------------------------------------'
52 print *, '| __ __ ____ ___ _ __ __ ______ ___ ____ |'
53 print *, '| | \/ | _ \_ _| / \ | \/ | _ \ \ / / \ / ___| |'
54 print *, '| | |\/| | |_) | |_____ / _ \ | |\/| | |_) \ \ / / _ \| | |'
55 print *, '| | | | | __/| |_____/ ___ \| | | | _ < \ V / ___ \ |___ |'
56 print *, '| |_| |_|_| |___| /_/ \_\_| |_|_| \_\ \_/_/ \_\____| |'
57 print *, '-----------------------------------------------------------------------------'
58 print *, '-----------------------------------------------------------------------------'
59 end if
60
61 ! =============== Fortran 2003 command line reading ================
62
63 ! Default command line arguments
64 all_par_files="amrvac.par"
67 slicenext=-1
69 help=.false.
70 convert=.false.
72
73 ! Argument 0 is program name, so we start from one
74 i = 1
75 unknown_arg=.false.
76 DO
77 CALL get_command_argument(i, arg)
78 IF (len_trim(arg) == 0) EXIT
79 select case(arg)
80 case("-i")
81 i = i+1
82 CALL get_command_argument(i, arg)
83 !if(mype==0)print *,'found argument=',arg
84 all_par_files=trim(arg)
85 morepars=.true.
86 ipars=1
87 do while (ipars<max_files.and.morepars)
88 CALL get_command_argument(i+ipars,arg)
89 !if(mype==0)print *,'found argument=',arg
90 if (index(trim(arg),"-")==1.or.len_trim(arg)==0) then
91 morepars=.false.
92 else
93 ipars=ipars+1
94 all_par_files=trim(all_par_files)//" "//trim(arg)
95 !if(mype==0)print *,'now all_par_files=',TRIM(all_par_files)
96 endif
97 end do
98 !if(mype==0)print *,'-i identified ',ipars, ' par-file arguments'
99 i=i+ipars-1
100 !if(mype==0)print *,'-i arguments passed to all_par_files=',TRIM(all_par_files)
101 case("-if")
102 i = i+1
103 CALL get_command_argument(i, arg)
104 restart_from_file=trim(arg)
105 !if(mype==0)print *,'-if has argument=',TRIM(arg),' passed to restart_from_file=',TRIM(restart_from_file)
106 case("-slicenext")
107 i = i+1
108 CALL get_command_argument(i, arg)
109 read(arg,*,iostat=stat) slicenext
110 !if(mype==0)print *,'-slicenext has argument=',arg,' passed to slicenext=',slicenext
111 case("-collapsenext")
112 i = i+1
113 CALL get_command_argument(i, arg)
114 read(arg,*,iostat=stat) collapsenext
115 !if(mype==0)print *,'-collapsenext has argument=',arg,' passed to collapsenext=',collapsenext
116 case("-snapshotnext")
117 i = i+1
118 CALL get_command_argument(i, arg)
119 read(arg,*,iostat=stat) snapshotnext
120 !if(mype==0)print *,'-snapshotnext has argument=',arg,' passed to snapshotnext=',snapshotnext
121 case("-resume")
123 !if(mype==0)print *,'resume specified: resume_previous_run=T'
124 case("-convert")
125 convert=.true.
126 if(mype==0)print *,'convert specified: convert=T'
127 case("--help","-help")
128 help=.true.
129 EXIT
130 case default
131 unknown_arg=.true.
132 help=.true.
133 EXIT
134 end select
135 i = i+1
136 END DO
137
138 if (unknown_arg) then
139 print*,"======================================="
140 print*,"Error: Command line argument ' ",trim(arg)," ' not recognized"
141 print*,"======================================="
142 help=.true.
143 end if
144
145 ! Show the usage if the help flag was given, or no par file was specified
146 if (help) then
147 if (mype == 0) then
148 print *, 'Usage example:'
149 print *, 'mpirun -np 4 ./amrvac -i file.par [file2.par ...]'
150 print *, ' (later .par files override earlier ones)'
151 print *, ''
152 print *, 'Optional arguments:'
153 print *, '-convert Convert snapshot files'
154 print *, '-if file0001.dat Use this snapshot to restart from'
155 print *, ' (you can modify e.g. output names)'
156 print *, '-resume Automatically resume previous run'
157 print *, ' (useful for long runs on HPC systems)'
158 print *, '-snapshotnext N Manual index for next snapshot'
159 print *, '-slicenext N Manual index for next slice output'
160 print *, '-collapsenext N Manual index for next collapsed output'
161 print *, ''
162 end if
163 call mpi_finalize(ierrmpi)
164 stop
165 end if
166
167 ! Split the input files, in case multiple were given
168 call get_fields_string(all_par_files, " ,'"""//char(9), max_files, &
169 tmp_files, n_par_files)
170
171 allocate(par_files(n_par_files))
172 par_files = tmp_files(1:n_par_files)
173
174 end subroutine read_arguments
175
176 !> Read in the user-supplied parameter-file
177 subroutine read_par_files()
181 use mod_limiter
182 use mod_slice
183 use mod_geometry
184 use mod_source
187
188 double precision, dimension(nsavehi) :: tsave_log, tsave_dat, tsave_slice, &
189 tsave_collapsed, tsave_custom
190 double precision :: dtsave_log, dtsave_dat, dtsave_slice, &
191 dtsave_collapsed, dtsave_custom
192 double precision :: tsavestart_log, tsavestart_dat, tsavestart_slice, &
193 tsavestart_collapsed, tsavestart_custom
194 double precision :: sizeuniformpart^D
195 double precision :: im_delta,im_nu,rka54,rka51,rkb54,rka55
196 double precision :: dx_vec(^ND)
197 integer :: ditsave_log, ditsave_dat, ditsave_slice, &
198 ditsave_collapsed, ditsave_custom
199 integer :: windex, ipower
200 integer :: i, j, k, ifile, io_state
201 integer :: iB, isave, iw, level, idim, islice
202 integer :: nx_vec(^ND), block_nx_vec(^ND)
203 integer :: my_unit, iostate
204 integer :: ilev
205 logical :: fileopen, file_exists
206
207 character :: c_ndim
208 character(len=80) :: fmt_string
209 character(len=std_len) :: err_msg, restart_from_file_arg
210 character(len=std_len) :: basename_full, basename_prev, dummy_file
211 character(len=std_len), dimension(:), allocatable :: &
212 typeboundary_min^D, typeboundary_max^D
213 character(len=std_len), allocatable :: limiter(:)
214 character(len=std_len), allocatable :: gradient_limiter(:)
215 character(len=name_len) :: stretch_dim(ndim)
216 !> How to apply dimensional splitting to the source terms, see
217 !> @ref discretization.md
218 character(len=std_len) :: typesourcesplit
219 !> Which flux scheme of spatial discretization to use (per grid level)
220 character(len=std_len), allocatable :: flux_scheme(:)
221 !> Which type of the maximal bound speed of Riemann fan to use
222 character(len=std_len) :: typeboundspeed
223 !> Which time stepper to use
224 character(len=std_len) :: time_stepper
225 !> Which time integrator to use
226 character(len=std_len) :: time_integrator
227 !> type of curl operator
228 character(len=std_len) :: typecurl
229 !> Limiter used for prolongation to refined grids and ghost cells
230 character(len=std_len) :: typeprolonglimit
231 !> How to compute the CFL-limited time step.
232 !> Options are 'maxsum': max(sum(c/dx)); 'summax': sum(max(c/dx)) and
233 !> 'minimum: max(c/dx), where the summations loop over the grid dimensions and
234 !> c is the velocity. The default 'maxsum' is the conventiontal way of
235 !> computing CFL-limited time steps.
236 character(len=std_len) :: typecourant
237
238
239 namelist /filelist/ base_filename,restart_from_file, &
248
249 namelist /savelist/ tsave,itsave,dtsave,ditsave,nslices,slicedir, &
251 tsave_log, tsave_dat, tsave_slice, tsave_collapsed, tsave_custom, &
252 dtsave_log, dtsave_dat, dtsave_slice, dtsave_collapsed, dtsave_custom, &
253 ditsave_log, ditsave_dat, ditsave_slice, ditsave_collapsed, ditsave_custom,&
254 tsavestart_log, tsavestart_dat, tsavestart_slice, tsavestart_collapsed,&
255 tsavestart_custom, tsavestart, &
257
260
261 namelist /methodlist/ time_stepper, time_integrator, &
262 source_split_usr, typesourcesplit, local_timestep, &
263 dimsplit, typedimsplit, flux_scheme, limit_on_wold, &
264 limiter, gradient_limiter, cada3_radius, &
265 loglimit, typeboundspeed, h_correction, &
267 typegrad, typediv, typecurl, &
276
277 namelist /boundlist/ nghostcells,ghost_copy,&
279
280 namelist /meshlist/ refine_max_level,nbufferx^d,refine_threshold,&
282 stretch_dim, stretch_uncentered, &
286 typeprolonglimit, &
289 namelist /paramlist/ courantpar, dtpar, dtdiffpar, &
290 typecourant, slowsteps
291
292 namelist /emissionlist/ filename_euv,wavelength,&
306
307 ! default maximum number of grid blocks in a processor
308 max_blocks=4000
309
310 ! allocate cell size of all levels
311 allocate(dx(ndim,nlevelshi))
312 {allocate(dg^d(nlevelshi))\}
313 {allocate(ng^d(nlevelshi))\}
314
315 ! default block size excluding ghost cells
316 {block_nx^d = 16\}
317
318 ! default resolution of level-1 mesh (full domain)
319 {domain_nx^d = 32\}
320
321 !! default number of ghost-cell layers at each boundary of a block
322 ! this is now done when the variable is defined in mod_global_parameters
323 ! the physics modules might set this variable in their init subroutine called earlier
324 nghostcells = 2
325
326 ! Allocate boundary conditions arrays in new and old style
327 {
328 allocate(typeboundary_min^d(nwfluxbc))
329 allocate(typeboundary_max^d(nwfluxbc))
330 typeboundary_min^d = undefined
331 typeboundary_max^d = undefined
332 }
333
334 allocate(typeboundary(nwflux+nwaux,2*ndim))
336
337 ! not save physical boundary in dat files by default
338 save_physical_boundary = .false.
339
340 internalboundary = .false.
341
342 ! defaults for specific options
343 typegrad = 'central'
344 typediv = 'central'
345 typecurl = 'central'
346
347 ! defaults for smallest physical values allowed
348 small_temperature = 0.d0
349 small_pressure = 0.d0
350 small_density = 0.d0
351
352 allocate(small_values_fix_iw(nw))
353 small_values_fix_iw(:) = .true.
354
355 ! defaults for convert behavior
356
357 ! store the -if value from argument in command line
358 restart_from_file_arg = restart_from_file
359 nwauxio = 0
360 nocartesian = .false.
361 saveprim = .false.
362 autoconvert = .false.
363 convert_type = 'vtuBCCmpi'
364 slice_type = 'vtuCC'
365 collapse_type = 'vti'
366 allocate(w_write(nw))
367 w_write(1:nw) = .true.
368 allocate(writelevel(nlevelshi))
369 writelevel(1:nlevelshi) = .true.
370 writespshift(1:ndim,1:2) = zero
371 level_io = -1
372 level_io_min = 1
374 ! endianness: littleendian (default) is 1, bigendian otherwise
375 type_endian = 1
376
377 ! normalization of primitive variables: only for output
378 ! note that length_convert_factor is for length
379 ! this scaling is optional, and must be set consistently if used
380 allocate(w_convert_factor(nw))
381 w_convert_factor(:) = 1.0d0
382 time_convert_factor = 1.0d0
384
385 ! AMR related defaults
387 {nbufferx^d = 0\}
388 allocate(refine_threshold(nlevelshi))
389 refine_threshold(1:nlevelshi) = 0.1d0
390 allocate(derefine_ratio(nlevelshi))
391 derefine_ratio(1:nlevelshi) = 1.0d0/8.0d0
392 typeprolonglimit = 'default'
394 allocate(w_refine_weight(nw+1))
395 w_refine_weight = 0.d0
396 allocate(logflag(nw+1))
397 logflag = .false.
398 allocate(amr_wavefilter(nlevelshi))
399 amr_wavefilter(1:nlevelshi) = 1.0d-2
400 tfixgrid = bigdouble
401 itfixgrid = biginteger
402 ditregrid = 1
403
404 ! Grid stretching defaults
405 stretch_uncentered = .true.
406 stretch_dim(1:ndim) = undefined
407 qstretch_baselevel(1:ndim) = bigdouble
409
410 ! IO defaults
411 it_init = 0
412 it_max = biginteger
413 time_init = 0.d0
414 time_max = bigdouble
415 wall_time_max = bigdouble
416 if(local_timestep) then
417 final_dt_reduction=.false.
418 else
419 final_dt_reduction=.true.
420 endif
421 final_dt_exit=.false.
422 dtmin = 1.0d-10
423 nslices = 0
424 collapse = .false.
425 collapselevel = 1
426 time_between_print = 30.0d0 ! Print status every 30 seconds
427
428 do ifile=1,nfile
429 do isave=1,nsavehi
430 tsave(isave,ifile) = bigdouble ! global_time of saves into the output files
431 itsave(isave,ifile) = biginteger ! it of saves into the output files
432 end do
433 dtsave(ifile) = bigdouble ! time between saves
434 ditsave(ifile) = biginteger ! timesteps between saves
435 isavet(ifile) = 1 ! index for saves by global_time
436 isaveit(ifile) = 1 ! index for saves by it
437 tsavestart(ifile) = 0.0d0
438 end do
439
440 tsave_log = bigdouble
441 tsave_dat = bigdouble
442 tsave_slice = bigdouble
443 tsave_collapsed = bigdouble
444 tsave_custom = bigdouble
445
446 dtsave_log = bigdouble
447 dtsave_dat = bigdouble
448 dtsave_slice = bigdouble
449 dtsave_collapsed = bigdouble
450 dtsave_custom = bigdouble
451
452 ditsave_log = biginteger
453 ditsave_dat = biginteger
454 ditsave_slice = biginteger
455 ditsave_collapsed = biginteger
456 ditsave_custom = biginteger
457
458 tsavestart_log = bigdouble
459 tsavestart_dat = bigdouble
460 tsavestart_slice = bigdouble
461 tsavestart_collapsed = bigdouble
462 tsavestart_custom = bigdouble
463
464 typefilelog = 'default'
465
466 ! defaults for input
467 reset_time = .false.
468 reset_it = .false.
469 firstprocess = .false.
470 reset_grid = .false.
471 allow_ndir_change = .false.
472 base_filename = 'data'
473 usr_filename = ''
474
475
476 ! Defaults for discretization methods
477 typeaverage = 'default'
478 tvdlfeps = one
482 nxdiffusehllc = 0
483 flathllc = .false.
484 slowsteps = -1
485 courantpar = 0.8d0
486 typecourant = 'maxsum'
487 dimsplit = .false.
488 typedimsplit = 'default'
489 if(physics_type=='mhd') then
490 cada3_radius = 0.1d0
491 else
492 cada3_radius = 0.1d0
493 end if
494 typetvd = 'roe'
495 typeboundspeed = 'Einfeldt'
496 source_split_usr= .false.
497 time_stepper = 'twostep'
498 time_integrator = 'default'
499 limit_on_wold = .false.
500 ! default PC or explicit midpoint, hence alfa=0.5
501 rk2_alfa = half
502 ! default IMEX-RK22Ln hence lambda = 1 - 1/sqrt(2)
503 imex222_lambda = 1.0d0 - 1.0d0 / dsqrt(2.0d0)
504 ! default SSPRK(3,3) or Gottlieb-Shu 1998 for threestep
505 ! default SSPRK(4,3) or Spireti-Ruuth for fourstep
506 ! default SSPRK(5,4) using Gottlieb coeffs
507 ssprk_order = 3
508 ! default RK3 butcher table: Heun 3rd order
509 rk3_switch = 3
510 ! default IMEX threestep is IMEX_ARK(232)
511 imex_switch = 1
512
513 ! Defaults for synthesing emission
514 los_theta = 0.d0
515 los_phi = 0.d0
516 image_rotate = 0.d0
517 x_origin = 0.d0
518 big_image = .false.
519 location_slit = 0.d0
520 radiation_transfer = 'thin'
521 ray_method = 'auto'
522 dat_resolution_mode = 'nominal'
523 emission_model = 'auto'
525 radio_frequency = 17.d9
526 radio_beam_fwhm = 0.d0
532 radsyn_verbose = .false.
533 direction_slit = -1
536 whitelight_instrument='LASCO/C2'
537 r_occultor=-1.d0
538 r_opt_thick=1.d0
539 dat_resolution=.false.
540 output_tau=.false.
542
543 allocate(flux_scheme(nlevelshi),typepred1(nlevelshi),flux_method(nlevelshi))
544 allocate(limiter(nlevelshi),gradient_limiter(nlevelshi))
545 do level=1,nlevelshi
546 flux_scheme(level) = 'tvdlf'
547 typepred1(level) = 0
548 limiter(level) = 'minmod'
549 gradient_limiter(level) = 'minmod'
550 end do
551
552 ppm_avisc = 0.0d0
553 ppm_rjv = 0.0d0
554 flatcd = .false.
555 flatsh = .false.
556 typesourcesplit = 'sfs'
557 allocate(loglimit(nw))
558 loglimit(1:nw) = .false.
559
560 allocate(typeentropy(nw))
561
562 do iw=1,nw
563 typeentropy(iw)='nul' ! Entropy fix type
564 end do
565
566 dtdiffpar = 0.5d0
567 dtpar = -1.d0
568
569 ! problem setup defaults
570 iprob = 1
571
572 ! end defaults
573
574 ! Initialize Kronecker delta, and Levi-Civita tensor
575 do i=1,3
576 do j=1,3
577 if(i==j)then
578 kr(i,j)=1
579 else
580 kr(i,j)=0
581 endif
582 do k=1,3
583 if(i==j.or.j==k.or.k==i)then
584 lvc(i,j,k)=0
585 else if(i+1==j.or.i-2==j)then
586 lvc(i,j,k)=1
587 else
588 lvc(i,j,k)=-1
589 endif
590 enddo
591 enddo
592 enddo
593
594 ! These are used to construct file and log names from multiple par files
595 basename_full = ''
596 basename_prev = ''
597
598 do i = 1, size(par_files)
599 if (mype == 0) print *, "Reading " // trim(par_files(i))
600
601 ! Check whether the file exists
602 inquire(file=trim(par_files(i)), exist=file_exists)
603
604 if (.not. file_exists) then
605 write(err_msg, *) "The parameter file " // trim(par_files(i)) // &
606 " does not exist"
607 call mpistop(trim(err_msg))
608 end if
609
610 open(unitpar, file=trim(par_files(i)), status='old')
611
612 ! Try to read in the namelists. They can be absent or in a different
613 ! order, since we rewind before each read.
614 rewind(unitpar)
615 read(unitpar, filelist, end=101)
616
617101 rewind(unitpar)
618 read(unitpar, savelist, end=102)
619
620102 rewind(unitpar)
621 read(unitpar, stoplist, end=103)
622
623103 rewind(unitpar)
624 read(unitpar, methodlist, end=104)
625
626104 rewind(unitpar)
627 read(unitpar, boundlist, end=105)
628
629105 rewind(unitpar)
630 read(unitpar, meshlist, end=106)
631
632106 rewind(unitpar)
633 read(unitpar, paramlist, end=107)
634
635107 rewind(unitpar)
636 read(unitpar, emissionlist, end=108)
637
638108 close(unitpar)
639
640 ! Append the log and file names given in the par files
641 if (base_filename /= basename_prev) &
642 basename_full = trim(basename_full) // trim(base_filename)
643 basename_prev = base_filename
644 end do
645
646 base_filename = basename_full
647
648 ! Check whether output directory is writable
649 if(mype==0) then
650 dummy_file = trim(base_filename)//"DUMMY"
651 open(newunit=my_unit, file=trim(dummy_file), iostat=iostate)
652 if (iostate /= 0) then
653 call mpistop("Can't write to output directory (" // &
654 trim(base_filename) // ")")
655 else
656 close(my_unit, status='delete')
657 end if
658 end if
659
660 if(source_split_usr) any_source_split=.true.
661
662 ! restart filename from command line overwrites the one in par file
663 if(restart_from_file_arg /= undefined) &
664 restart_from_file=restart_from_file_arg
665
666 ! Root process will search snapshot
667 if (mype == 0) then
668 if(restart_from_file == undefined) then
669 ! search file from highest index
670 file_exists=.false.
671 do index_latest_data = 9999, 0, -1
672 if(snapshot_exists(index_latest_data)) then
673 file_exists=.true.
674 exit
675 end if
676 end do
677 if(.not.file_exists) index_latest_data=-1
678 else
679 ! get index of the given data restarted from
680 index_latest_data=get_snapshot_index(trim(restart_from_file))
681 end if
682 end if
683 call mpi_bcast(index_latest_data, 1, mpi_integer, 0, icomm, ierrmpi)
684
685 if (resume_previous_run) then
686 if (index_latest_data == -1) then
687 if(mype==0) write(*,*) "No snapshots found to resume from, start a new run..."
688 else
689 ! Set file name to restart from
690 write(restart_from_file, "(a,i4.4,a)") trim(base_filename),index_latest_data, ".dat"
691 end if
692 end if
693
694 if (restart_from_file == undefined) then
695 snapshotnext = 0
696 slicenext = 0
697 collapsenext = 0
698 if (firstprocess) &
699 call mpistop("Please restart from a snapshot when firstprocess=T")
700 if (convert) &
701 call mpistop('Change convert to .false. for a new run!')
702 end if
703
704 if (small_pressure < 0.d0) call mpistop("small_pressure should be positive.")
705 if (small_density < 0.d0) call mpistop("small_density should be positive.")
706 if (ghostcell_comm_batched .and. ghostcell_comm_batch_size < 1) &
707 call mpistop("ghostcell_comm_batch_size should be positive.")
708 ! Give priority to non-zero small temperature
709 if (small_temperature>0.d0) small_pressure=small_density*small_temperature
710
711 if(convert) autoconvert=.false.
712
713 where (tsave_log < bigdouble) tsave(:, 1) = tsave_log
714 where (tsave_dat < bigdouble) tsave(:, 2) = tsave_dat
715 where (tsave_slice < bigdouble) tsave(:, 3) = tsave_slice
716 where (tsave_collapsed < bigdouble) tsave(:, 4) = tsave_collapsed
717 where (tsave_custom < bigdouble) tsave(:, 5) = tsave_custom
718
719 if (dtsave_log < bigdouble) dtsave(1) = dtsave_log
720 if (dtsave_dat < bigdouble) dtsave(2) = dtsave_dat
721 if (dtsave_slice < bigdouble) dtsave(3) = dtsave_slice
722 if (dtsave_collapsed < bigdouble) dtsave(4) = dtsave_collapsed
723 if (dtsave_custom < bigdouble) dtsave(5) = dtsave_custom
724
725 if (tsavestart_log < bigdouble) tsavestart(1) = tsavestart_log
726 if (tsavestart_dat < bigdouble) tsavestart(2) = tsavestart_dat
727 if (tsavestart_slice < bigdouble) tsavestart(3) = tsavestart_slice
728 if (tsavestart_collapsed < bigdouble) tsavestart(4) = tsavestart_collapsed
729 if (tsavestart_custom < bigdouble) tsavestart(5) = tsavestart_custom
730
731 if (ditsave_log < bigdouble) ditsave(1) = ditsave_log
732 if (ditsave_dat < bigdouble) ditsave(2) = ditsave_dat
733 if (ditsave_slice < bigdouble) ditsave(3) = ditsave_slice
734 if (ditsave_collapsed < bigdouble) ditsave(4) = ditsave_collapsed
735 if (ditsave_custom < bigdouble) ditsave(5) = ditsave_custom
736 ! convert hours to seconds for ending wall time
737 if (wall_time_max < bigdouble) wall_time_max=wall_time_max*3600.d0
738
739 if (mype == 0) then
740 write(unitterm, *) ''
741 write(unitterm, *) 'Output type | tsavestart | dtsave | ditsave | itsave(1) | tsave(1)'
742 write(fmt_string, *) '(A12," | ",E9.3E2," | ",E9.3E2," | ",I6," | "'//&
743 ',I6, " | ",E9.3E2)'
744 end if
745
746 do ifile = 1, nfile
747 if (mype == 0) write(unitterm, fmt_string) trim(output_names(ifile)), &
748 tsavestart(ifile), dtsave(ifile), ditsave(ifile), itsave(1, ifile), tsave(1, ifile)
749 end do
750
751 if (mype == 0) write(unitterm, *) ''
752
753 do islice=1,nslices
754 if(slicedir(islice) > ndim) &
755 write(uniterr,*)'Warning in read_par_files: ', &
756 'Slice ', islice,' direction',slicedir(islice),'larger than ndim=',ndim
757 if(slicedir(islice) < 1) &
758 write(uniterr,*)'Warning in read_par_files: ', &
759 'Slice ', islice,' direction',slicedir(islice),'too small, should be [',1,ndim,']'
760 end do
761
762 if(it_max==biginteger .and. time_max==bigdouble.and.mype==0) write(uniterr,*) &
763 'Warning in read_par_files: it_max or time_max not given!'
764
765 select case (typecourant)
766 case ('maxsum')
767 type_courant=type_maxsum
768 case ('summax')
769 type_courant=type_summax
770 if (local_timestep) then
771 call mpistop("Type courant summax incompatible with local_timestep")
772 endif
773 case ('minimum')
774 type_courant=type_minimum
775 if (local_timestep) then
776 call mpistop("Type courant minimum incompatible with local_timestep")
777 endif
778 case default
779 write(unitterm,*)'Unknown typecourant=',typecourant
780 call mpistop("Error from read_par_files: no such typecourant!")
781 end select
782
783
784 do level=1,nlevelshi
785 select case (flux_scheme(level))
786 case ('hll')
787 flux_method(level)=fs_hll
788 case ('hllc')
789 flux_method(level)=fs_hllc
790 case ('hlld')
791 flux_method(level)=fs_hlld
792 case ('hllcd')
793 flux_method(level)=fs_hllcd
794 case ('tvdlf')
795 flux_method(level)=fs_tvdlf
796 case ('tvdmu')
797 flux_method(level)=fs_tvdmu
798 case ('tvd')
799 flux_method(level)=fs_tvd
800 case ('cd')
801 flux_method(level)=fs_cd
802 case ('cd4')
803 flux_method(level)=fs_cd4
804 case ('fd')
805 flux_method(level)=fs_fd
806 case ('source')
807 flux_method(level)=fs_source
808 case ('nul','null')
809 flux_method(level)=fs_nul
810 case default
811 call mpistop("unkown or bad flux scheme")
812 end select
813 if(flux_scheme(level)=='tvd'.and.time_stepper/='onestep') &
814 call mpistop(" tvd is onestep method, reset time_stepper='onestep'")
815 if(flux_scheme(level)=='tvd')then
816 if(mype==0.and.(.not.dimsplit)) write(unitterm,*) &
817 'Warning: setting dimsplit=T for tvd, as used for level=',level
818 dimsplit=.true.
819 endif
820 if(flux_scheme(level)=='hlld'.and.physics_type/='mhd' .and. physics_type/='twofl') &
821 call mpistop("Cannot use hlld flux if not using MHD or 2FL only charges physics!")
822
823 if(flux_scheme(level)=='hlld'.and. .not.phys_total_energy) &
824 call mpistop("Cannot use hlld flux if not solving total energy equation!")
825
826 if(flux_scheme(level)=='hllc'.and.physics_type=='mf') &
827 call mpistop("Cannot use hllc flux if using magnetofriction physics!")
828
829 if(flux_scheme(level)=='tvd'.and.physics_type=='mf') &
830 call mpistop("Cannot use tvd flux if using magnetofriction physics!")
831
832 if(flux_scheme(level)=='tvdmu'.and.physics_type=='mf') &
833 call mpistop("Cannot use tvdmu flux if using magnetofriction physics!")
834
835 if (typepred1(level)==0) then
836 select case (flux_scheme(level))
837 case ('cd')
838 typepred1(level)=fs_cd
839 case ('cd4')
840 typepred1(level)=fs_cd4
841 case ('fd')
842 typepred1(level)=fs_fd
843 case ('tvdlf','tvdmu')
844 typepred1(level)=fs_hancock
845 case ('hll')
846 typepred1(level)=fs_hll
847 case ('hllc')
848 typepred1(level)=fs_hllc
849 case ('hllcd')
850 typepred1(level)=fs_hllcd
851 case ('hlld')
852 typepred1(level)=fs_hlld
853 case ('nul','source','tvd')
854 typepred1(level)=fs_nul
855 case default
856 call mpistop("No default predictor for this full step")
857 end select
858 end if
859 end do
860
861 ! finite difference scheme fd need global maximal speed
862 if(any(flux_scheme=='fd')) need_global_cmax=.true.
863
864 ! initialize type_curl
865 select case (typecurl)
866 case ("central")
867 type_curl=central
868 case ("Gaussbased")
869 type_curl=gaussbased
870 case ("Stokesbased")
871 type_curl=stokesbased
872 case default
873 write(unitterm,*) "typecurl=",typecurl
874 call mpistop("unkown type of curl operator in read_par_files")
875 end select
876
877 ! initialize types of time stepper and time integrator
878 select case (time_stepper)
879 case ("onestep")
880 t_stepper=onestep
881 nstep=1
882 if (time_integrator=='default') then
883 time_integrator="Forward_Euler"
884 end if
885 select case (time_integrator)
886 case ("Forward_Euler")
887 t_integrator=forward_euler
888 case ("IMEX_Euler")
889 t_integrator=imex_euler
890 case ("IMEX_SP")
891 t_integrator=imex_sp
892 case default
893 write(unitterm,*) "time_integrator=",time_integrator,"time_stepper=",time_stepper
894 call mpistop("unkown onestep time_integrator in read_par_files")
895 end select
896 use_imex_scheme=(t_integrator==imex_euler.or.t_integrator==imex_sp)
897 case ("twostep")
898 t_stepper=twostep
899 nstep=2
900 if (time_integrator=='default') then
901 time_integrator="Predictor_Corrector"
902 endif
903 select case (time_integrator)
904 case ("Predictor_Corrector")
905 t_integrator=predictor_corrector
906 case ("RK2_alfa")
907 t_integrator=rk2_alf
908 case ("ssprk2")
909 t_integrator=ssprk2
910 case ("IMEX_Midpoint")
911 t_integrator=imex_midpoint
912 case ("IMEX_Trapezoidal")
913 t_integrator=imex_trapezoidal
914 case ("IMEX_222")
915 t_integrator=imex_222
916 case default
917 write(unitterm,*) "time_integrator=",time_integrator,"time_stepper=",time_stepper
918 call mpistop("unkown twostep time_integrator in read_par_files")
919 end select
920 use_imex_scheme=(t_integrator==imex_midpoint.or.t_integrator==imex_trapezoidal&
921 .or.t_integrator==imex_222)
922 if (t_integrator==rk2_alf) then
923 if(rk2_alfa<smalldouble.or.rk2_alfa>one)call mpistop("set rk2_alfa within [0,1]")
924 rk_a21=rk2_alfa
925 rk_b2=1.0d0/(2.0d0*rk2_alfa)
926 rk_b1=1.0d0-rk_b2
927 endif
928 case ("threestep")
929 t_stepper=threestep
930 nstep=3
931 if (time_integrator=='default') then
932 time_integrator='ssprk3'
933 endif
934 select case (time_integrator)
935 case ("ssprk3")
936 t_integrator=ssprk3
937 case ("RK3_BT")
938 t_integrator=rk3_bt
939 case ("IMEX_ARS3")
940 t_integrator=imex_ars3
941 case ("IMEX_232")
942 t_integrator=imex_232
943 case ("IMEX_CB3a")
944 t_integrator=imex_cb3a
945 case default
946 write(unitterm,*) "time_integrator=",time_integrator,"time_stepper=",time_stepper
947 call mpistop("unkown threestep time_integrator in read_par_files")
948 end select
949 if(t_integrator==rk3_bt) then
950 select case(rk3_switch)
951 case(1)
952 ! we code up Ralston 3rd order here
953 rk3_a21=1.0d0/2.0d0
954 rk3_a31=0.0d0
955 rk3_a32=3.0d0/4.0d0
956 rk3_b1=2.0d0/9.0d0
957 rk3_b2=1.0d0/3.0d0
958 case(2)
959 ! we code up RK-Wray 3rd order here
960 rk3_a21=8.0d0/15.0d0
961 rk3_a31=1.0d0/4.0d0
962 rk3_a32=5.0d0/12.0d0
963 rk3_b1=1.0d0/4.0d0
964 rk3_b2=0.0d0
965 case(3)
966 ! we code up Heun 3rd order here
967 rk3_a21=1.0d0/3.0d0
968 rk3_a31=0.0d0
969 rk3_a32=2.0d0/3.0d0
970 rk3_b1=1.0d0/4.0d0
971 rk3_b2=0.0d0
972 case(4)
973 ! we code up Nystrom 3rd order here
974 rk3_a21=2.0d0/3.0d0
975 rk3_a31=0.0d0
976 rk3_a32=2.0d0/3.0d0
977 rk3_b1=1.0d0/4.0d0
978 rk3_b2=3.0d0/8.0d0
979 case default
980 call mpistop("Unknown rk3_switch")
981 end select
982 ! the rest is fixed from above
983 rk3_b3=1.0d0-rk3_b1-rk3_b2
984 rk3_c2=rk3_a21
985 rk3_c3=rk3_a31+rk3_a32
986 endif
987 if(t_integrator==ssprk3) then
988 select case(ssprk_order)
989 case(3) ! this is SSPRK(3,3) Gottlieb-Shu
990 rk_beta11=1.0d0
991 rk_beta22=1.0d0/4.0d0
992 rk_beta33=2.0d0/3.0d0
993 rk_alfa21=3.0d0/4.0d0
994 rk_alfa31=1.0d0/3.0d0
995 rk_c2=1.0d0
996 rk_c3=1.0d0/2.0d0
997 case(2) ! this is SSP(3,2)
998 rk_beta11=1.0d0/2.0d0
999 rk_beta22=1.0d0/2.0d0
1000 rk_beta33=1.0d0/3.0d0
1001 rk_alfa21=0.0d0
1002 rk_alfa31=1.0d0/3.0d0
1003 rk_c2=1.0d0/2.0d0
1004 rk_c3=1.0d0
1005 case default
1006 call mpistop("Unknown ssprk3_order")
1007 end select
1008 rk_alfa22=1.0d0-rk_alfa21
1009 rk_alfa33=1.0d0-rk_alfa31
1010 endif
1011 if(t_integrator==imex_ars3) then
1012 ars_gamma=(3.0d0+dsqrt(3.0d0))/6.0d0
1013 endif
1014 if(t_integrator==imex_232) then
1015 select case(imex_switch)
1016 case(1) ! this is IMEX_ARK(232)
1017 im_delta=1.0d0-1.0d0/dsqrt(2.0d0)
1018 im_nu=(3.0d0+2.0d0*dsqrt(2.0d0))/6.0d0
1019 imex_a21=2.0d0*im_delta
1020 imex_a31=1.0d0-im_nu
1021 imex_a32=im_nu
1022 imex_b1=1.0d0/(2.0d0*dsqrt(2.0d0))
1023 imex_b2=1.0d0/(2.0d0*dsqrt(2.0d0))
1024 imex_ha21=im_delta
1025 imex_ha22=im_delta
1026 case(2) ! this is IMEX_SSP(232)
1027 ! doi 10.1002/2017MS001065 Rokhzadi et al
1028 imex_a21=0.711664700366941d0
1029 imex_a31=0.077338168947683d0
1030 imex_a32=0.917273367886007d0
1031 imex_b1=0.398930808264688d0
1032 imex_b2=0.345755244189623d0
1033 imex_ha21=0.353842865099275d0
1034 imex_ha22=0.353842865099275d0
1035 case default
1036 call mpistop("Unknown imex_siwtch")
1037 end select
1038 imex_c2=imex_a21
1039 imex_c3=imex_a31+imex_a32
1040 imex_b3=1.0d0-imex_b1-imex_b2
1041 endif
1042 if(t_integrator==imex_cb3a) then
1043 imex_c2 = 0.8925502329346865
1044 imex_a22 = imex_c2
1045 imex_ha21 = imex_c2
1046 imex_c3 = imex_c2 / (6.0d0*imex_c2**2 - 3.0d0*imex_c2 + 1.0d0)
1047 imex_ha32 = imex_c3
1048 imex_b2 = (3.0d0*imex_c2 - 1.0d0) / (6.0d0*imex_c2**2)
1049 imex_b3 = (6.0d0*imex_c2**2 - 3.0d0*imex_c2 + 1.0d0) / (6.0d0*imex_c2**2)
1050 imex_a33 = (1.0d0/6.0d0 - imex_b2*imex_c2**2 - imex_b3*imex_c2*imex_c3) / (imex_b3*(imex_c3-imex_c2))
1051 imex_a32 = imex_c3 - imex_a33
1052 ! if (mype == 0) then
1053 ! write(*,*) "================================="
1054 ! write(*,*) "Asserting the order conditions..."
1055 ! ! First order convergence: OK
1056 ! ! Second order convergence
1057 ! write(*,*) -1.0d0/2.0d0 + imex_b2*imex_c2 + imex_b3*imex_c3
1058 ! ! Third order convergence
1059 ! write(*,*) -1.0d0/3.0d0 + imex_b2*imex_c2**2 + imex_b3*imex_c3**2
1060 ! write(*,*) -1.0d0/6.0d0 + imex_b3*imex_ha32*imex_c2
1061 ! write(*,*) -1.0d0/6.0d0 + imex_b2*imex_a22*imex_c2 + imex_b3*imex_a32*imex_c2 + imex_b3*imex_a33*imex_c3
1062 ! write(*,*) "================================="
1063 ! end if
1064 end if
1065 use_imex_scheme=(t_integrator==imex_ars3.or.t_integrator==imex_232.or.t_integrator==imex_cb3a)
1066 case ("fourstep")
1067 t_stepper=fourstep
1068 nstep=4
1069 if (time_integrator=='default') then
1070 time_integrator="ssprk4"
1071 endif
1072 select case (time_integrator)
1073 case ("ssprk4")
1074 t_integrator=ssprk4
1075 case ("rk4")
1076 t_integrator=rk4
1077 case default
1078 write(unitterm,*) "time_integrator=",time_integrator,"time_stepper=",time_stepper
1079 call mpistop("unkown fourstep time_integrator in read_par_files")
1080 end select
1081 if(t_integrator==ssprk4) then
1082 select case(ssprk_order)
1083 case(3) ! this is SSPRK(4,3) Spireti-Ruuth
1084 rk_beta11=1.0d0/2.0d0
1085 rk_beta22=1.0d0/2.0d0
1086 rk_beta33=1.0d0/6.0d0
1087 rk_beta44=1.0d0/2.0d0
1088 rk_alfa21=0.0d0
1089 rk_alfa31=2.0d0/3.0d0
1090 rk_alfa41=0.0d0
1091 rk_c2=1.0d0/2.0d0
1092 rk_c3=1.0d0
1093 rk_c4=1.0d0/2.0d0
1094 case(2) ! this is SSP(4,2)
1095 rk_beta11=1.0d0/3.0d0
1096 rk_beta22=1.0d0/3.0d0
1097 rk_beta33=1.0d0/3.0d0
1098 rk_beta44=1.0d0/4.0d0
1099 rk_alfa21=0.0d0
1100 rk_alfa31=0.0d0
1101 rk_alfa41=1.0d0/4.0d0
1102 rk_c2=1.0d0/3.0d0
1103 rk_c3=2.0d0/3.0d0
1104 rk_c4=1.0d0
1105 case default
1106 call mpistop("Unknown ssprk_order")
1107 end select
1108 rk_alfa22=1.0d0-rk_alfa21
1109 rk_alfa33=1.0d0-rk_alfa31
1110 rk_alfa44=1.0d0-rk_alfa41
1111 endif
1112 case ("fivestep")
1113 t_stepper=fivestep
1114 nstep=5
1115 if (time_integrator=='default') then
1116 time_integrator="ssprk5"
1117 end if
1118 select case (time_integrator)
1119 case ("ssprk5")
1120 t_integrator=ssprk5
1121 case default
1122 write(unitterm,*) "time_integrator=",time_integrator,"time_stepper=",time_stepper
1123 call mpistop("unkown fivestep time_integrator in read_par_files")
1124 end select
1125 if(t_integrator==ssprk5) then
1126 select case(ssprk_order)
1127 ! we use ssprk_order to intercompare the different coefficient choices
1128 case(3) ! From Gottlieb 2005
1129 rk_beta11=0.391752226571890d0
1130 rk_beta22=0.368410593050371d0
1131 rk_beta33=0.251891774271694d0
1132 rk_beta44=0.544974750228521d0
1133 rk_beta54=0.063692468666290d0
1134 rk_beta55=0.226007483236906d0
1135 rk_alfa21=0.444370493651235d0
1136 rk_alfa31=0.620101851488403d0
1137 rk_alfa41=0.178079954393132d0
1138 rk_alfa53=0.517231671970585d0
1139 rk_alfa54=0.096059710526147d0
1140
1141 rk_alfa22=0.555629506348765d0
1142 rk_alfa33=0.379898148511597d0
1143 rk_alfa44=0.821920045606868d0
1144 rk_alfa55=0.386708617503269d0
1145 rk_alfa22=1.0d0-rk_alfa21
1146 rk_alfa33=1.0d0-rk_alfa31
1147 rk_alfa44=1.0d0-rk_alfa41
1148 rk_alfa55=1.0d0-rk_alfa53-rk_alfa54
1149 rk_c2=rk_beta11
1150 rk_c3=rk_alfa22*rk_c2+rk_beta22
1151 rk_c4=rk_alfa33*rk_c3+rk_beta33
1152 rk_c5=rk_alfa44*rk_c4+rk_beta44
1153 case(2) ! From Spireti-Ruuth
1154 rk_beta11=0.39175222700392d0
1155 rk_beta22=0.36841059262959d0
1156 rk_beta33=0.25189177424738d0
1157 rk_beta44=0.54497475021237d0
1158 !rk_beta54=0.06369246925946d0
1159 !rk_beta55=0.22600748319395d0
1160 rk_alfa21=0.44437049406734d0
1161 rk_alfa31=0.62010185138540d0
1162 rk_alfa41=0.17807995410773d0
1163 rk_alfa53=0.51723167208978d0
1164 !rk_alfa54=0.09605971145044d0
1165
1166 rk_alfa22=1.0d0-rk_alfa21
1167 rk_alfa33=1.0d0-rk_alfa31
1168 rk_alfa44=1.0d0-rk_alfa41
1169
1170 rka51=0.00683325884039d0
1171 rka54=0.12759831133288d0
1172 rkb54=0.08460416338212d0
1173 rk_beta54=rkb54-rk_beta44*rka51/rk_alfa41
1174 rk_alfa54=rka54-rk_alfa44*rka51/rk_alfa41
1175
1176 rk_alfa55=1.0d0-rk_alfa53-rk_alfa54
1177 rk_c2=rk_beta11
1178 rk_c3=rk_alfa22*rk_c2+rk_beta22
1179 rk_c4=rk_alfa33*rk_c3+rk_beta33
1180 rk_c5=rk_alfa44*rk_c4+rk_beta44
1181 rk_beta55=1.0d0-rk_beta54-rk_alfa53*rk_c3-rk_alfa54*rk_c4-rk_alfa55*rk_c5
1182 case default
1183 call mpistop("Unknown ssprk_order")
1184 end select
1185 ! the following combinations must be unity
1186 !print *,rk_beta55+rk_beta54+rk_alfa53*rk_c3+rk_alfa54*rk_c4+rk_alfa55*rk_c5
1187 !print *,rk_alfa22+rk_alfa21
1188 !print *,rk_alfa33+rk_alfa31
1189 !print *,rk_alfa44+rk_alfa41
1190 !print *,rk_alfa55+rk_alfa53+rk_alfa54
1191 endif
1192 use_imex_scheme=.false.
1193 case default
1194 call mpistop("Unknown time_stepper in read_par_files")
1195 end select
1196
1197 do i = 1, ndim
1198 select case (stretch_dim(i))
1199 case (undefined, 'none')
1200 stretch_type(i) = stretch_none
1201 stretched_dim(i) = .false.
1202 case ('uni','uniform')
1203 stretch_type(i) = stretch_uni
1204 stretched_dim(i) = .true.
1205 case ('symm', 'symmetric')
1206 stretch_type(i) = stretch_symm
1207 stretched_dim(i) = .true.
1208 case default
1209 stretch_type(i) = stretch_none
1210 stretched_dim(i) = .false.
1211 if (mype == 0) print *, 'Got stretch_type = ', stretch_type(i)
1212 call mpistop('Unknown stretch type')
1213 end select
1214 end do
1215
1216 ! Harmonize the parameters for dimensional splitting and source splitting
1217 if(typedimsplit =='default'.and. dimsplit) typedimsplit='xyyx'
1218 if(typedimsplit =='default'.and..not.dimsplit) typedimsplit='unsplit'
1219 dimsplit = typedimsplit /='unsplit'
1220
1221 ! initialize types of split-source addition
1222 select case (typesourcesplit)
1223 case ('sfs')
1224 sourcesplit=sourcesplit_sfs
1225 case ('sf')
1226 sourcesplit=sourcesplit_sf
1227 case ('ssf')
1228 sourcesplit=sourcesplit_ssf
1229 case ('ssfss')
1230 sourcesplit=sourcesplit_ssfss
1231 case default
1232 write(unitterm,*)'No such typesourcesplit=',typesourcesplit
1233 call mpistop("Error: Unknown typesourcesplit!")
1234 end select
1235
1236 if(coordinate==-1) then
1237 coordinate=cartesian
1238 if(mype==0) then
1239 write(*,*) 'Warning: coordinate system is not specified!'
1240 write(*,*) 'call set_coordinate_system in usr_init in mod_usr.t'
1241 write(*,*) 'Now use Cartesian coordinate'
1242 end if
1243 end if
1244
1245 if(coordinate==cartesian) then
1246 slab=.true.
1247 slab_uniform=.true.
1248 if(any(stretched_dim)) then
1249 coordinate=cartesian_stretched
1250 slab_uniform=.false.
1251 end if
1252 else
1253 slab=.false.
1254 slab_uniform=.false.
1255 end if
1256
1257 if(coordinate==spherical) then
1258 if(dimsplit) then
1259 if(mype==0)print *,'Warning: spherical symmetry needs dimsplit=F, resetting'
1260 dimsplit=.false.
1261 end if
1262 end if
1263
1264 if (ndim==1) dimsplit=.false.
1265
1266 ! type limiter of prolongation
1267 select case(typeprolonglimit)
1268 case('unlimit')
1269 ! unlimited
1270 prolong_limiter=1
1271 case('minmod')
1272 prolong_limiter=2
1273 case('woodward')
1274 prolong_limiter=3
1275 case('koren')
1276 prolong_limiter=4
1277 case default
1278 prolong_limiter=0
1279 end select
1280
1281 ! Type limiter is of integer type for performance
1282 allocate(type_limiter(nlevelshi))
1283 allocate(type_gradient_limiter(nlevelshi))
1284
1285 do level=1,nlevelshi
1286 type_limiter(level) = limiter_type(limiter(level))
1287 type_gradient_limiter(level) = limiter_type(gradient_limiter(level))
1288 end do
1289
1290 if (any(limiter(1:nlevelshi)== 'ppm')&
1291 .and.(flatsh.and.physics_type=='rho')) then
1292 call mpistop(" PPM with flatsh=.true. can not be used with physics_type='rho'!")
1293 end if
1294
1295 ! Copy boundary conditions to typeboundary, which is used internally
1296 {
1297 do iw=1,nwfluxbc
1298 select case(typeboundary_min^d(iw))
1299 case("special")
1300 typeboundary(iw,2*^d-1)=bc_special
1301 case("cont")
1302 typeboundary(iw,2*^d-1)=bc_cont
1303 case("symm")
1304 typeboundary(iw,2*^d-1)=bc_symm
1305 case("asymm")
1306 typeboundary(iw,2*^d-1)=bc_asymm
1307 case("periodic")
1308 typeboundary(iw,2*^d-1)=bc_periodic
1309 case("aperiodic")
1310 typeboundary(iw,2*^d-1)=bc_aperiodic
1311 case("noinflow")
1312 typeboundary(iw,2*^d-1)=bc_noinflow
1313 case("pole")
1314 typeboundary(iw,2*^d-1)=12
1315 case("bc_data")
1316 typeboundary(iw,2*^d-1)=bc_data
1317 case("bc_icarus")
1318 typeboundary(iw,2*^d-1)=bc_icarus
1319 case("character")
1320 typeboundary(iw,2*^d-1)=bc_character
1321 case default
1322 write (unitterm,*) "Undefined boundarytype found in read_par_files", &
1323 typeboundary_min^d(iw),"for variable iw=",iw," and side iB=",2*^d-1
1324 end select
1325 end do
1326 do iw=1,nwfluxbc
1327 select case(typeboundary_max^d(iw))
1328 case("special")
1329 typeboundary(iw,2*^d)=bc_special
1330 case("cont")
1331 typeboundary(iw,2*^d)=bc_cont
1332 case("symm")
1333 typeboundary(iw,2*^d)=bc_symm
1334 case("asymm")
1335 typeboundary(iw,2*^d)=bc_asymm
1336 case("periodic")
1337 typeboundary(iw,2*^d)=bc_periodic
1338 case("aperiodic")
1339 typeboundary(iw,2*^d)=bc_aperiodic
1340 case("noinflow")
1341 typeboundary(iw,2*^d)=bc_noinflow
1342 case("pole")
1343 typeboundary(iw,2*^d)=12
1344 case("bc_data")
1345 typeboundary(iw,2*^d)=bc_data
1346 case("bc_icarus")
1347 typeboundary(iw,2*^d-1)=bc_icarus
1348 case("bc_character")
1349 typeboundary(iw,2*^d)=bc_character
1350 case default
1351 write (unitterm,*) "Undefined boundarytype found in read_par_files", &
1352 typeboundary_max^d(iw),"for variable iw=",iw," and side iB=",2*^d
1353 end select
1354 end do
1355 }
1356
1357 ! psi, tracers take the same boundary type as the first variable
1358 if (nwfluxbc<nwflux) then
1359 do iw=nwfluxbc+1,nwflux
1360 typeboundary(iw,:) = typeboundary(1, :)
1361 end do
1362 end if
1363 ! auxiliary variables take the same boundary type as the first variable
1364 if (nwaux>0) then
1365 do iw=nwflux+1, nwflux+nwaux
1366 typeboundary(iw,:) = typeboundary(1, :)
1367 end do
1368 end if
1369
1370 if (any(typeboundary == 0)) then
1371 call mpistop("Not all boundary conditions have been defined")
1372 end if
1373
1374 do idim=1,ndim
1375 periodb(idim)=(any(typeboundary(:,2*idim-1:2*idim)==bc_periodic))
1376 aperiodb(idim)=(any(typeboundary(:,2*idim-1:2*idim)==bc_aperiodic))
1377 if (periodb(idim).or.aperiodb(idim)) then
1378 do iw=1,nwflux
1379 if (typeboundary(iw,2*idim-1) .ne. typeboundary(iw,2*idim)) &
1380 call mpistop("Wrong counterpart in periodic boundary")
1381
1382 if (typeboundary(iw,2*idim-1) /= bc_periodic .and. &
1383 typeboundary(iw,2*idim-1) /= bc_aperiodic) then
1384 call mpistop("Each dimension should either have all "//&
1385 "or no variables periodic, some can be aperiodic")
1386 end if
1387 end do
1388 end if
1389 end do
1390 {^nooned
1391 do idim=1,ndim
1392 if(any(typeboundary(:,2*idim-1)==12)) then
1393 if(any(typeboundary(:,2*idim-1)/=12)) typeboundary(:,2*idim-1)=12
1394 select case(physics_type)
1395 case ('rho','ard','nonlinear','ffhd')
1396 ! all symmetric at pole
1397 typeboundary(:,2*idim-1)=bc_symm
1398 if(mype==0) print *,'symmetric minimal pole'
1399 case ('hd','rhd','srhd','mhd','rmhd')
1400 typeboundary(:,2*idim-1)=bc_symm
1401 ! here we assume the ordering of variables is fixed to rho-mom-[e]-B
1402 if(phys_energy) then
1403 windex=2
1404 else
1405 windex=1
1406 end if
1407 select case(coordinate)
1408 case(cylindrical)
1409 ! across r=0 both the radial and azimuthal components flip sign
1410 typeboundary(r_+1,2*idim-1)=bc_asymm
1411 typeboundary(phi_+1,2*idim-1)=bc_asymm
1412 if(physics_type=='mhd'.or.physics_type=='rmhd') then
1413 typeboundary(ndir+windex+r_,2*idim-1)=bc_asymm
1414 typeboundary(ndir+windex+phi_,2*idim-1)=bc_asymm
1415 end if
1416 case(spherical)
1417 typeboundary(3:ndir+1,2*idim-1)=bc_asymm
1418 if(physics_type=='mhd'.or.physics_type=='rmhd') typeboundary(ndir+windex+2:ndir+windex+ndir,2*idim-1)=bc_asymm
1419 case default
1420 call mpistop('Pole is in cylindrical, polar, spherical coordinates!')
1421 end select
1422 case ('twofl')
1423 call mpistop('Pole treatment for twofl not implemented yet')
1424 case ('mf')
1425 if (ndim /= 3 .or. coordinate /= spherical .or. idim /= 2) &
1426 call mpistop("MF pole requires a 3D spherical theta boundary")
1427 {^ifthreed
1428 ! Spherical angles are still in turns at this point in the parser.
1429 if (.not. periodb(3) .or. abs(xprobmax3-xprobmin3-one) >= smalldouble) &
1430 call mpistop("MF pole requires full periodic longitude")
1431 if (abs(xprobmin2) >= smalldouble) &
1432 call mpistop("MF pole requires a true theta pole")
1433 ! Radial components and scalars (including GLM psi) are even.
1434 typeboundary(:,2*idim-1)=bc_symm
1435 typeboundary(iw_mom(2:3),2*idim-1)=bc_asymm
1436 typeboundary(iw_mag(2:3),2*idim-1)=bc_asymm
1437 }
1438 case default
1439 call mpistop('unknown physics type for setting minimal pole boundary treatment')
1440 end select
1441 end if
1442 if(any(typeboundary(:,2*idim)==12)) then
1443 if(any(typeboundary(:,2*idim)/=12)) typeboundary(:,2*idim)=12
1444 select case(physics_type)
1445 case ('rho','ard','nonlinear','ffhd')
1446 ! all symmetric at pole
1447 typeboundary(:,2*idim)=bc_symm
1448 if(mype==0) print *,'symmetric maximal pole'
1449 case ('hd','rhd','srhd','mhd','rmhd')
1450 typeboundary(:,2*idim)=bc_symm
1451 ! here we assume the ordering of variables is fixed to rho-mom-[e]-B
1452 if(phys_energy) then
1453 windex=2
1454 else
1455 windex=1
1456 end if
1457 select case(coordinate)
1458 case(cylindrical)
1459 ! across r=0 both the radial and azimuthal components flip sign
1460 typeboundary(r_+1,2*idim)=bc_asymm
1461 typeboundary(phi_+1,2*idim)=bc_asymm
1462 if(physics_type=='mhd'.or.physics_type=='rmhd') then
1463 typeboundary(ndir+windex+r_,2*idim)=bc_asymm
1464 typeboundary(ndir+windex+phi_,2*idim)=bc_asymm
1465 end if
1466 case(spherical)
1467 typeboundary(3:ndir+1,2*idim)=bc_asymm
1468 if(physics_type=='mhd'.or.physics_type=='rmhd') typeboundary(ndir+windex+2:ndir+windex+ndir,2*idim)=bc_asymm
1469 case default
1470 call mpistop('Pole is in cylindrical, polar, spherical coordinates!')
1471 end select
1472 case ('twofl')
1473 call mpistop('Pole treatment for twofl not implemented yet')
1474 case ('mf')
1475 if (ndim /= 3 .or. coordinate /= spherical .or. idim /= 2) &
1476 call mpistop("MF pole requires a 3D spherical theta boundary")
1477 {^ifthreed
1478 ! Spherical angles are still in turns at this point in the parser.
1479 if (.not. periodb(3) .or. abs(xprobmax3-xprobmin3-one) >= smalldouble) &
1480 call mpistop("MF pole requires full periodic longitude")
1481 if (abs(xprobmax2-half) >= smalldouble) &
1482 call mpistop("MF pole requires a true theta pole")
1483 ! Radial components and scalars (including GLM psi) are even.
1484 typeboundary(:,2*idim)=bc_symm
1485 typeboundary(iw_mom(2:3),2*idim)=bc_asymm
1486 typeboundary(iw_mag(2:3),2*idim)=bc_asymm
1487 }
1488 case default
1489 call mpistop('unknown physics type for setting maximal pole boundary treatment')
1490 end select
1491 end if
1492 end do
1493 }
1494
1495 if(.not.phys_energy) then
1496 flatcd=.false.
1497 flatsh=.false.
1498 end if
1499
1500 if(any(limiter(1:nlevelshi)=='mp5')) then
1501 nghostcells=max(nghostcells,3)
1502 end if
1503
1504 if(any(limiter(1:nlevelshi)=='weno5')) then
1505 nghostcells=max(nghostcells,3)
1506 end if
1507
1508 if(any(limiter(1:nlevelshi)=='weno5nm')) then
1509 nghostcells=max(nghostcells,3)
1510 end if
1511
1512 if(any(limiter(1:nlevelshi)=='wenoz5')) then
1513 nghostcells=max(nghostcells,3)
1514 end if
1515
1516 if(any(limiter(1:nlevelshi)=='wenoz5nm')) then
1517 nghostcells=max(nghostcells,3)
1518 end if
1519
1520 if(any(limiter(1:nlevelshi)=='wenozp5')) then
1521 nghostcells=max(nghostcells,3)
1522 end if
1523
1524 if(any(limiter(1:nlevelshi)=='wenozp5nm')) then
1525 nghostcells=max(nghostcells,3)
1526 end if
1527
1528 if(any(limiter(1:nlevelshi)=='teno5ad')) then
1529 nghostcells=max(nghostcells,3)
1530 end if
1531
1532 if(any(limiter(1:nlevelshi)=='weno5cu6')) then
1533 nghostcells=max(nghostcells,3)
1534 end if
1535
1536 if(any(limiter(1:nlevelshi)=='ppm')) then
1537 if(flatsh .or. flatcd) then
1538 nghostcells=max(nghostcells,4)
1539 else
1540 nghostcells=max(nghostcells,3)
1541 end if
1542 end if
1543
1544 if(any(limiter(1:nlevelshi)=='weno7')) then
1545 nghostcells=max(nghostcells,4)
1546 end if
1547
1548 if(any(limiter(1:nlevelshi)=='mpweno7')) then
1549 nghostcells=max(nghostcells,4)
1550 end if
1551
1552 ! If a wider stencil is used, extend the number of ghost cells
1553 nghostcells = nghostcells + phys_wider_stencil
1554
1555 ! prolongation in AMR for constrained transport MHD needs even number ghosts
1556 if(stagger_grid .and. refine_max_level>1 .and. mod(nghostcells,2)/=0) then
1557 nghostcells=nghostcells+1
1558 end if
1559
1560 select case (coordinate)
1561 {^nooned
1562 case (spherical)
1563 xprob^lim^de=xprob^lim^de*two*dpi;
1564 \}
1565 case (cylindrical)
1566 {
1567 if (^d==phi_) then
1568 xprob^lim^d=xprob^lim^d*two*dpi;
1569 end if
1570 \}
1571 end select
1572
1573 ! full block size including ghostcells
1574 {ixghi^d = block_nx^d + 2*nghostcells\}
1575 {ixgshi^d = ixghi^d\}
1576
1577 nx_vec = [{domain_nx^d|, }]
1578 block_nx_vec = [{block_nx^d|, }]
1579
1580 if (any(nx_vec < 4) .or. any(mod(nx_vec, 2) == 1)) &
1581 call mpistop('Grid size (domain_nx^D) has to be even and >= 4')
1582
1583 if (any(block_nx_vec < 4) .or. any(mod(block_nx_vec, 2) == 1)) &
1584 call mpistop('Block size (block_nx^D) has to be even and >= 4')
1585
1586 { if(mod(domain_nx^d,block_nx^d)/=0) &
1587 call mpistop('Grid (domain_nx^D) and block (block_nx^D) must be consistent') \}
1588
1589 if(refine_max_level>nlevelshi.or.refine_max_level<1)then
1590 write(unitterm,*)'Error: refine_max_level',refine_max_level,'>nlevelshi ',nlevelshi
1591 call mpistop("Reset nlevelshi and recompile!")
1592 endif
1593
1594 if (any(stretched_dim)) then
1595 allocate(qstretch(0:nlevelshi,1:ndim),dxfirst(0:nlevelshi,1:ndim),&
1596 dxfirst_1mq(0:nlevelshi,1:ndim),dxmid(0:nlevelshi,1:ndim))
1597 allocate(nstretchedblocks(1:nlevelshi,1:ndim))
1598 qstretch(0:nlevelshi,1:ndim)=0.0d0
1599 dxfirst(0:nlevelshi,1:ndim)=0.0d0
1600 nstretchedblocks(1:nlevelshi,1:ndim)=0
1601 {if (stretch_type(^d) == stretch_uni) then
1602 ! first some sanity checks
1603 if(qstretch_baselevel(^d)<1.0d0.or.qstretch_baselevel(^d)==bigdouble) then
1604 if(mype==0) then
1605 write(*,*) 'stretched grid needs finite qstretch_baselevel>1'
1606 write(*,*) 'will try default value for qstretch_baselevel in dimension', ^d
1607 endif
1608 if(xprobmin^d>smalldouble)then
1609 qstretch_baselevel(^d)=(xprobmax^d/xprobmin^d)**(1.d0/dble(domain_nx^d))
1610 else
1611 call mpistop("can not set qstretch_baselevel automatically")
1612 endif
1613 endif
1614 if(mod(block_nx^d,2)==1) &
1615 call mpistop("stretched grid needs even block size block_nxD")
1616 if(mod(domain_nx^d/block_nx^d,2)/=0) &
1617 call mpistop("number level 1 blocks in D must be even")
1618 qstretch(1,^d)=qstretch_baselevel(^d)
1619 dxfirst(1,^d)=(xprobmax^d-xprobmin^d) &
1620 *(1.0d0-qstretch(1,^d))/(1.0d0-qstretch(1,^d)**domain_nx^d)
1621 qstretch(0,^d)=qstretch(1,^d)**2
1622 dxfirst(0,^d)=dxfirst(1,^d)*(1.0d0+qstretch(1,^d))
1623 if(refine_max_level>1)then
1624 do ilev=2,refine_max_level
1625 qstretch(ilev,^d)=dsqrt(qstretch(ilev-1,^d))
1626 dxfirst(ilev,^d)=dxfirst(ilev-1,^d) &
1627 /(1.0d0+dsqrt(qstretch(ilev-1,^d)))
1628 enddo
1629 endif
1630 endif \}
1631 if(mype==0) then
1632 {if(stretch_type(^d) == stretch_uni) then
1633 write(*,*) 'Stretched dimension ', ^d
1634 write(*,*) 'Using stretched grid with qs=',qstretch(0:refine_max_level,^d)
1635 write(*,*) ' and first cell sizes=',dxfirst(0:refine_max_level,^d)
1636 endif\}
1637 end if
1638 {if(stretch_type(^d) == stretch_symm) then
1639 if(mype==0) then
1640 write(*,*) 'will apply symmetric stretch in dimension', ^d
1641 endif
1642 if(mod(block_nx^d,2)==1) &
1643 call mpistop("stretched grid needs even block size block_nxD")
1644 ! checks on the input variable nstretchedblocks_baselevel
1645 if(nstretchedblocks_baselevel(^d)==0) &
1646 call mpistop("need finite even number of stretched blocks at baselevel")
1647 if(mod(nstretchedblocks_baselevel(^d),2)==1) &
1648 call mpistop("need even number of stretched blocks at baselevel")
1649 if(qstretch_baselevel(^d)<1.0d0.or.qstretch_baselevel(^d)==bigdouble) &
1650 call mpistop('stretched grid needs finite qstretch_baselevel>1')
1651 ! compute stretched part to ensure uniform center
1652 ipower=(nstretchedblocks_baselevel(^d)/2)*block_nx^d
1653 if(nstretchedblocks_baselevel(^d)==domain_nx^d/block_nx^d)then
1654 xstretch^d=0.5d0*(xprobmax^d-xprobmin^d)
1655 else
1656 xstretch^d=(xprobmax^d-xprobmin^d) &
1657 /(2.0d0+dble(domain_nx^d-nstretchedblocks_baselevel(^d)*block_nx^d) &
1658 *(1.0d0-qstretch_baselevel(^d))/(1.0d0-qstretch_baselevel(^d)**ipower))
1659 endif
1660 if(xstretch^d>(xprobmax^d-xprobmin^d)*0.5d0) &
1661 call mpistop(" stretched grid part should not exceed full domain")
1662 dxfirst(1,^d)=xstretch^d*(1.0d0-qstretch_baselevel(^d)) &
1663 /(1.0d0-qstretch_baselevel(^d)**ipower)
1664 nstretchedblocks(1,^d)=nstretchedblocks_baselevel(^d)
1665 qstretch(1,^d)=qstretch_baselevel(^d)
1666 qstretch(0,^d)=qstretch(1,^d)**2
1667 dxfirst(0,^d)=dxfirst(1,^d)*(1.0d0+qstretch(1,^d))
1668 dxmid(1,^d)=dxfirst(1,^d)
1669 dxmid(0,^d)=dxfirst(1,^d)*2.0d0
1670 if(refine_max_level>1)then
1671 do ilev=2,refine_max_level
1672 nstretchedblocks(ilev,^d)=2*nstretchedblocks(ilev-1,^d)
1673 qstretch(ilev,^d)=dsqrt(qstretch(ilev-1,^d))
1674 dxfirst(ilev,^d)=dxfirst(ilev-1,^d) &
1675 /(1.0d0+dsqrt(qstretch(ilev-1,^d)))
1676 dxmid(ilev,^d)=dxmid(ilev-1,^d)/2.0d0
1677 enddo
1678 endif
1679 ! sanity check on total domain size:
1680 sizeuniformpart^d=dxfirst(1,^d) &
1681 *(domain_nx^d-nstretchedblocks_baselevel(^d)*block_nx^d)
1682 if(mype==0) then
1683 print *,'uniform part of size=',sizeuniformpart^d
1684 print *,'setting of domain is then=',2*xstretch^d+sizeuniformpart^d
1685 print *,'versus=',xprobmax^d-xprobmin^d
1686 endif
1687 if(dabs(xprobmax^d-xprobmin^d-2*xstretch^d-sizeuniformpart^d)>smalldouble) then
1688 call mpistop('mismatch in domain size!')
1689 endif
1690 endif \}
1691 dxfirst_1mq(0:refine_max_level,1:ndim)=dxfirst(0:refine_max_level,1:ndim) &
1692 /(1.0d0-qstretch(0:refine_max_level,1:ndim))
1693 end if
1694
1695 dx_vec = [{xprobmax^d-xprobmin^d|, }] / nx_vec
1696
1697 if (mype==0) then
1698 write(c_ndim, '(I1)') ^nd
1699 write(unitterm, '(A30,' // c_ndim // '(I0," "))') &
1700 ' Domain size (cells): ', nx_vec
1701 write(unitterm, '(A30,' // c_ndim // '(E9.3," "))') &
1702 ' Level one dx: ', dx_vec
1703 end if
1704
1705 if (any(dx_vec < smalldouble)) &
1706 call mpistop("Incorrect domain size (too small grid spacing)")
1707
1708 dx(:, 1) = dx_vec
1709
1710 if(sum(w_refine_weight(:))==0) w_refine_weight(1) = 1.d0
1711 if(dabs(sum(w_refine_weight(:))-1.d0)>smalldouble) then
1712 write(unitterm,*) "Sum of all elements in w_refine_weight be 1.d0"
1713 call mpistop("Reset w_refine_weight so the sum is 1.d0")
1714 end if
1715
1716 select case (typeboundspeed)
1717 case('Einfeldt')
1718 boundspeed=1
1719 case('cmaxmean')
1720 boundspeed=2
1721 case('cmaxleftright')
1722 boundspeed=3
1723 case('pvrs')
1724 boundspeed=4
1725 case default
1726 call mpistop("set typeboundspeed='Einfeldt' or 'cmaxmean' or 'cmaxleftright' or 'pvrs'")
1727 end select
1728
1729 if (mype==0) write(unitterm, '(A30)', advance='no') 'Refine estimation: '
1730
1731 select case (refine_criterion)
1732 case (0)
1733 if (mype==0) write(unitterm, '(A)') "user defined"
1734 case (1)
1735 if (mype==0) write(unitterm, '(A)') "relative error"
1736 case (2)
1737 if (mype==0) write(unitterm, '(A)') "Lohner's original scheme"
1738 case (3)
1739 if (mype==0) write(unitterm, '(A)') "Lohner's scheme"
1740 case default
1741 call mpistop("Unknown error estimator, change refine_criterion")
1742 end select
1743
1744 if (tfixgrid<bigdouble/2.0d0) then
1745 if(mype==0)print*,'Warning, at time=',tfixgrid,'the grid will be fixed'
1746 end if
1747 if (itfixgrid<biginteger/2) then
1748 if(mype==0)print*,'Warning, at iteration=',itfixgrid,'the grid will be fixed'
1749 end if
1750 if (ditregrid>1) then
1751 if(mype==0)print*,'Note, Grid is reconstructed once every',ditregrid,'iterations'
1752 end if
1753
1754
1755 do islice=1,nslices
1756 select case(slicedir(islice))
1757 {case(^d)
1758 if(slicecoord(islice)<xprobmin^d.or.slicecoord(islice)>xprobmax^d) &
1759 write(uniterr,*)'Warning in read_par_files: ', &
1760 'Slice ', islice, ' coordinate',slicecoord(islice),'out of bounds for dimension ',slicedir(islice)
1761 \}
1762 end select
1763 end do
1764
1765 if (mype==0) then
1766 write(unitterm, '(A30,A,A)') 'restart_from_file: ', ' ', trim(restart_from_file)
1767 write(unitterm, '(A30,L1)') 'converting: ', convert
1768 write(unitterm, '(A)') ''
1769 endif
1770
1771 deallocate(flux_scheme)
1772
1773 end subroutine read_par_files
1774
1775 !> Routine to find entries in a string
1776 subroutine get_fields_string(line, delims, n_max, fields, n_found, fully_read)
1777 !> The line from which we want to read
1778 character(len=*), intent(in) :: line
1779 !> A string with delimiters. For example delims = " ,'"""//char(9)
1780 character(len=*), intent(in) :: delims
1781 !> Maximum number of entries to read in
1782 integer, intent(in) :: n_max
1783 !> Number of entries found
1784 integer, intent(inout) :: n_found
1785 !> Fields in the strings
1786 character(len=*), intent(inout) :: fields(n_max)
1787 logical, intent(out), optional :: fully_read
1788
1789 integer :: ixs_start(n_max)
1790 integer :: ixs_end(n_max)
1791 integer :: ix, ix_prev
1792
1793 ix_prev = 0
1794 n_found = 0
1795
1796 do while (n_found < n_max)
1797 ! Find the starting point of the next entry (a non-delimiter value)
1798 ix = verify(line(ix_prev+1:), delims)
1799 if (ix == 0) exit
1800
1801 n_found = n_found + 1
1802 ixs_start(n_found) = ix_prev + ix ! This is the absolute position in 'line'
1803
1804 ! Get the end point of the current entry (next delimiter index minus one)
1805 ix = scan(line(ixs_start(n_found)+1:), delims) - 1
1806
1807 if (ix == -1) then ! If there is no last delimiter,
1808 ixs_end(n_found) = len(line) ! the end of the line is the endpoint
1809 else
1810 ixs_end(n_found) = ixs_start(n_found) + ix
1811 end if
1812
1813 fields(n_found) = line(ixs_start(n_found):ixs_end(n_found))
1814 ix_prev = ixs_end(n_found) ! We continue to search from here
1815 end do
1816
1817 if (present(fully_read)) then
1818 ix = verify(line(ix_prev+1:), delims)
1819 fully_read = (ix == 0) ! Are there only delimiters?
1820 end if
1821
1822 end subroutine get_fields_string
1823
1824 subroutine saveamrfile(ifile)
1825
1828 use mod_particles, only: write_particles_snapshot
1829 use mod_slice, only: write_slice
1830 use mod_collapse, only: write_collapsed
1832 integer:: ifile
1833
1834 select case (ifile)
1835 case (fileout_)
1836 ! Write .dat snapshot
1837 call write_snapshot()
1838
1839 ! Generate formatted output (e.g., VTK)
1841
1842 if(use_particles) call write_particles_snapshot()
1843
1845 case (fileslice_)
1846 call write_slice
1847 case (filecollapse_)
1848 call write_collapsed
1849 case (filelog_)
1850 select case (typefilelog)
1851 case ('default')
1852 call printlog_default
1853 case ('regression_test')
1855 case ('special')
1856 if (.not. associated(usr_print_log)) then
1857 call mpistop("usr_print_log not defined")
1858 else
1859 call usr_print_log()
1860 end if
1861 case default
1862 call mpistop("Error in SaveFile: Unknown typefilelog")
1863 end select
1864 case (fileanalysis_)
1865 if (associated(usr_write_analysis)) then
1866 call usr_write_analysis()
1867 end if
1868 case default
1869 write(*,*) 'No save method is defined for ifile=',ifile
1870 call mpistop("")
1871 end select
1872
1873 ! opedit: Flush stdout and stderr from time to time.
1874 flush(unit=unitterm)
1875
1876 end subroutine saveamrfile
1877
1878
1879 ! Check if a snapshot exists
1880 logical function snapshot_exists(ix)
1882 integer, intent(in) :: ix !< Index of snapshot
1883 character(len=std_len) :: filename
1884
1885 write(filename, "(a,i4.4,a)") trim(base_filename), ix, ".dat"
1886 inquire(file=trim(filename), exist=snapshot_exists)
1887 end function snapshot_exists
1888
1889 integer function get_snapshot_index(filename)
1890 character(len=*), intent(in) :: filename
1891 integer :: i
1892
1893 ! Try to parse index in restart_from_file string (e.g. basename0000.dat)
1894 i = len_trim(filename) - 7
1895 read(filename(i:i+3), '(I4)') get_snapshot_index
1896 end function get_snapshot_index
1897
1898
1899
1900 !> Write header for a snapshot
1901 !>
1902 !> If you edit the header, don't forget to update: snapshot_write_header(),
1903 !> snapshot_read_header(), doc/fileformat.md, tools/python/dat_reader.py
1904 subroutine snapshot_write_header(fh, offset_tree, offset_block)
1905 use mod_forest
1906 use mod_physics
1909 integer, intent(in) :: fh !< File handle
1910 integer(kind=MPI_OFFSET_KIND), intent(in) :: offset_tree !< Offset of tree info
1911 integer(kind=MPI_OFFSET_KIND), intent(in) :: offset_block !< Offset of block data
1912 call snapshot_write_header1(fh, offset_tree, offset_block, cons_wnames, nw)
1913 end subroutine snapshot_write_header
1914
1915 !> Read header for a snapshot
1916 !>
1917 !> If you edit the header, don't forget to update: snapshot_write_header(),
1918 !> snapshot_read_header(), doc/fileformat.md, tools/python/dat_reader.py
1919 subroutine snapshot_read_header(fh, offset_tree, offset_block)
1920 use mod_forest
1922 use mod_physics, only: physics_type
1923 integer, intent(in) :: fh !< File handle
1924 integer(MPI_OFFSET_KIND), intent(out) :: offset_tree !< Offset of tree info
1925 integer(MPI_OFFSET_KIND), intent(out) :: offset_block !< Offset of block data
1926
1927 double precision :: rbuf(ndim)
1928 double precision, allocatable :: params(:)
1929 integer :: i, version
1930 integer :: ibuf(ndim), iw
1931 integer :: er, n_par, tmp_int
1932 integer, dimension(MPI_STATUS_SIZE) :: st
1933 logical :: periodic(ndim)
1934 character(len=name_len), allocatable :: var_names(:), param_names(:)
1935 character(len=name_len) :: phys_name, geom_name
1936
1937 ! Version number
1938 call mpi_file_read(fh, version, 1, mpi_integer, st, er)
1939 if (all(compatible_versions /= version)) then
1940 call mpistop("Incompatible file version (maybe old format?)")
1941 end if
1942
1943 ! offset_tree
1944 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1945 offset_tree = ibuf(1)
1946
1947 ! offset_block
1948 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1949 offset_block = ibuf(1)
1950
1951 ! nw
1952 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1953 nw_found=ibuf(1)
1954 if (nw /= ibuf(1)) then
1955 write(*,*) "nw=",nw," and nw found in restart file=",ibuf(1)
1956 write(*,*) "Please be aware of changes in w at restart."
1957 !call mpistop("currently, changing nw at restart is not allowed")
1958 end if
1959
1960 ! ndir
1961 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1962 if (ibuf(1) /= ndir) then
1963 if (allow_ndir_change) then
1964 if (mype==0) then
1965 write(*,*) "WARNING: ndir in restart file = ",ibuf(1)," but current ndir = ",ndir
1966 write(*,*) "allow_ndir_change=T: loading anyway (block I/O is ndim-based)."
1967 write(*,*) "Ensure usr_transform_w maps the source vars into the right slots."
1968 end if
1969 else
1970 write(*,*) "ndir in restart file = ",ibuf(1)
1971 write(*,*) "ndir = ",ndir
1972 call mpistop("reset ndir to ndir in restart file (or set allow_ndir_change=T)")
1973 end if
1974 end if
1975
1976 ! ndim
1977 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1978 if (ibuf(1) /= ndim) then
1979 write(*,*) "ndim in restart file = ",ibuf(1)
1980 write(*,*) "ndim = ",ndim
1981 call mpistop("reset ndim to ndim in restart file")
1982 end if
1983
1984 ! levmax
1985 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1986 if (ibuf(1) > refine_max_level) then
1987 write(*,*) "number of levels in restart file = ",ibuf(1)
1988 write(*,*) "refine_max_level = ",refine_max_level
1989 call mpistop("refine_max_level < num. levels in restart file")
1990 end if
1991
1992 ! nleafs
1993 call mpi_file_read(fh, nleafs, 1, mpi_integer, st, er)
1994
1995 ! nparents
1996 call mpi_file_read(fh, nparents, 1, mpi_integer, st, er)
1997
1998 ! it
1999 call mpi_file_read(fh, it, 1, mpi_integer, st, er)
2000
2001 ! global time
2002 call mpi_file_read(fh, global_time, 1, mpi_double_precision, st, er)
2003
2004 ! xprobmin^D
2005 call mpi_file_read(fh,rbuf(1:ndim),ndim,mpi_double_precision,st,er)
2006 if (maxval(abs(rbuf(1:ndim) - [ xprobmin^d ])) > 0) then
2007 write(*,*) "Error: xprobmin differs from restart data: ", rbuf(1:ndim)
2008 call mpistop("change xprobmin^D in par file")
2009 end if
2010
2011 ! xprobmax^D
2012 call mpi_file_read(fh,rbuf(1:ndim),ndim,mpi_double_precision,st,er)
2013 if (maxval(abs(rbuf(1:ndim) - [ xprobmax^d ])) > 0) then
2014 write(*,*) "Error: xprobmax differs from restart data: ", rbuf(1:ndim)
2015 call mpistop("change xprobmax^D in par file")
2016 end if
2017
2018 ! domain_nx^D
2019 call mpi_file_read(fh,ibuf(1:ndim), ndim, mpi_integer,st,er)
2020 if (any(ibuf(1:ndim) /= [ domain_nx^d ])) then
2021 write(*,*) "Error: mesh size differs from restart data: ", ibuf(1:ndim)
2022 call mpistop("change domain_nx^D in par file")
2023 end if
2024
2025 ! block_nx^D
2026 call mpi_file_read(fh,ibuf(1:ndim), ndim, mpi_integer,st,er)
2027 if (any(ibuf(1:ndim) /= [ block_nx^d ])) then
2028 write(*,*) "Error: block size differs from restart data:", ibuf(1:ndim)
2029 call mpistop("change block_nx^D in par file")
2030 end if
2031
2032 ! From version 5, read more info about the grid
2033 if (version > 4) then
2034 call mpi_file_read(fh, periodic, ndim, mpi_logical, st, er)
2035 if ({periodic(^d) .and. .not.periodb(^d) .or. .not.periodic(^d) .and. periodb(^d)| .or. }) &
2036 call mpistop("change in periodicity in par file")
2037
2038 call mpi_file_read(fh, geom_name, name_len, mpi_character, st, er)
2039
2040 if (geom_name /= geometry_name(1:name_len)) then
2041 if (allow_ndir_change) then
2042 if (mype==0) write(*,*) "WARNING: coordinates in data = ",trim(geom_name), &
2043 " vs current ",trim(geometry_name),"; allow_ndir_change=T (e.g. Cartesian_2D->2.5D), loading anyway."
2044 else
2045 write(*,*) "type of coordinates in data is: ", geom_name
2046 call mpistop("select the correct coordinates in mod_usr.t file")
2047 end if
2048 end if
2049
2050 call mpi_file_read(fh, stagger_mark_dat, 1, mpi_logical, st, er)
2051 if (stagger_grid .and. .not. stagger_mark_dat .or. .not.stagger_grid.and.stagger_mark_dat) then
2052 write(*,*) "Warning: stagger grid flag differs from restart data:", stagger_mark_dat
2053 !call mpistop("change parameter to use stagger grid")
2054 end if
2055 end if
2056
2057 ! From version 4 onwards, the later parts of the header must be present
2058 if (version > 3) then
2059 ! w_names (not used here)
2060 allocate(var_names(nw_found))
2061 do iw = 1, nw_found
2062 call mpi_file_read(fh, var_names(iw), name_len, mpi_character, st, er)
2063 end do
2064
2065 ! Physics related information
2066 call mpi_file_read(fh, phys_name, name_len, mpi_character, st, er)
2067
2068 if (phys_name /= physics_type) then
2069! call mpistop("Cannot restart with a different physics type")
2070 end if
2071
2072 call mpi_file_read(fh, n_par, 1, mpi_integer, st, er)
2073 allocate(params(n_par))
2074 allocate(param_names(n_par))
2075 call mpi_file_read(fh, params, n_par, mpi_double_precision, st, er)
2076 call mpi_file_read(fh, param_names, name_len * n_par, mpi_character, st, er)
2077
2078 ! Read snapshotnext etc. for restarting
2079 call mpi_file_read(fh, tmp_int, 1, mpi_integer, st, er)
2080
2081 ! Only set snapshotnext if the user hasn't specified it
2082 if (snapshotnext == -1) snapshotnext = tmp_int
2083
2084 call mpi_file_read(fh, tmp_int, 1, mpi_integer, st, er)
2085 if (slicenext == -1) slicenext = tmp_int
2086
2087 call mpi_file_read(fh, tmp_int, 1, mpi_integer, st, er)
2088 if (collapsenext == -1) collapsenext = tmp_int
2089 else
2090 ! Guess snapshotnext from file name if not set
2091 if (snapshotnext == -1) &
2093 ! Set slicenext and collapsenext if not set
2094 if (slicenext == -1) slicenext = 0
2095 if (collapsenext == -1) collapsenext = 0
2096 end if
2097
2098 ! Still used in convert
2100
2101 end subroutine snapshot_read_header
2102
2104 use mod_forest
2106 use mod_physics
2109
2110 double precision, allocatable :: w_buffer(:)
2111 integer :: file_handle, igrid, Morton_no, iwrite
2112 integer :: ipe, ix_buffer(2*ndim+1), n_values
2113 integer :: ixO^L, n_ghost(2*ndim)
2114 integer :: ixOs^L,n_values_stagger
2115 integer :: iorecvstatus(MPI_STATUS_SIZE)
2116 integer :: ioastatus(MPI_STATUS_SIZE)
2117 integer :: igrecvstatus(MPI_STATUS_SIZE)
2118 integer :: istatus(MPI_STATUS_SIZE)
2119 integer(kind=MPI_OFFSET_KIND) :: offset_tree_info
2120 integer(kind=MPI_OFFSET_KIND) :: offset_block_data
2121 integer(kind=MPI_OFFSET_KIND) :: offset_offsets
2122 integer, allocatable :: block_ig(:, :)
2123 integer, allocatable :: block_lvl(:)
2124 integer(kind=MPI_OFFSET_KIND), allocatable :: block_offset(:)
2125 type(tree_node), pointer :: pnode
2126
2127 call mpi_barrier(icomm, ierrmpi)
2128
2129 ! Allocate send/receive buffer
2130 n_values = count_ix(ixg^ll) * nw
2131 if(stagger_grid) then
2132 n_values = n_values + count_ix(ixgs^ll) * nws
2133 end if
2134 allocate(w_buffer(n_values))
2135
2136 ! Allocate arrays with information about grid blocks
2137 allocate(block_ig(ndim, nleafs))
2138 allocate(block_lvl(nleafs))
2139 allocate(block_offset(nleafs+1))
2140
2141 ! master processor
2142 if (mype==0) then
2143 call create_output_file(file_handle, snapshotnext, ".dat")
2144
2145 ! Don't know offsets yet, we will write header again later
2146 offset_tree_info = -1
2147 offset_block_data = -1
2148 call snapshot_write_header(file_handle, offset_tree_info, &
2149 offset_block_data)
2150
2151 call mpi_file_get_position(file_handle, offset_tree_info, ierrmpi)
2152
2153 call write_forest(file_handle)
2154
2155 ! Collect information about the spatial index (ig^D) and refinement level
2156 ! of leaves
2157 do morton_no = morton_start(0), morton_stop(npe-1)
2158 igrid = sfc(1, morton_no)
2159 ipe = sfc(2, morton_no)
2160 pnode => igrid_to_node(igrid, ipe)%node
2161
2162 block_ig(:, morton_no) = [ pnode%ig^d ]
2163 block_lvl(morton_no) = pnode%level
2164 block_offset(morton_no) = 0 ! Will be determined later
2165 end do
2166
2167 call mpi_file_write(file_handle, block_lvl, size(block_lvl), &
2168 mpi_integer, istatus, ierrmpi)
2169
2170 call mpi_file_write(file_handle, block_ig, size(block_ig), &
2171 mpi_integer, istatus, ierrmpi)
2172
2173 ! Block offsets are currently unknown, but will be overwritten later
2174 call mpi_file_get_position(file_handle, offset_offsets, ierrmpi)
2175 call mpi_file_write(file_handle, block_offset(1:nleafs), nleafs, &
2176 mpi_offset, istatus, ierrmpi)
2177
2178 call mpi_file_get_position(file_handle, offset_block_data, ierrmpi)
2179
2180 ! Check whether data was written as expected
2181 if (offset_block_data - offset_tree_info /= &
2182 (nleafs + nparents) * size_logical + &
2183 nleafs * ((1+ndim) * size_int + 2 * size_int)) then
2184 if (mype == 0) then
2185 print *, "Warning: MPI_OFFSET type /= 8 bytes"
2186 print *, "This *could* cause problems when reading .dat files"
2187 end if
2188 end if
2189
2190 block_offset(1) = offset_block_data
2191 iwrite = 0
2192 end if
2193
2194 do morton_no=morton_start(mype), morton_stop(mype)
2195 igrid = sfc_to_igrid(morton_no)
2196 itag = morton_no
2197
2198 call block_shape_io(igrid, n_ghost, ixo^l, n_values)
2199 if(stagger_grid) then
2200 w_buffer(1:n_values) = pack(ps(igrid)%w(ixo^s, 1:nw), .true.)
2201 {ixosmin^d = ixomin^d -1\}
2202 {ixosmax^d = ixomax^d \}
2203 n_values_stagger= count_ix(ixos^l)*nws
2204 w_buffer(n_values+1:n_values+n_values_stagger) = pack(ps(igrid)%ws(ixos^s, 1:nws), .true.)
2205 n_values=n_values+n_values_stagger
2206 else
2207 w_buffer(1:n_values) = pack(ps(igrid)%w(ixo^s, 1:nw), .true.)
2208 end if
2209 ix_buffer(1) = n_values
2210 ix_buffer(2:) = n_ghost
2211
2212 if (mype /= 0) then
2213 call mpi_send(ix_buffer, 2*ndim+1, &
2214 mpi_integer, 0, itag, icomm, ierrmpi)
2215 call mpi_send(w_buffer, n_values, &
2216 mpi_double_precision, 0, itag, icomm, ierrmpi)
2217 else
2218 iwrite = iwrite+1
2219 call mpi_file_write(file_handle, ix_buffer(2:), &
2220 2*ndim, mpi_integer, istatus, ierrmpi)
2221 call mpi_file_write(file_handle, w_buffer, &
2222 n_values, mpi_double_precision, istatus, ierrmpi)
2223
2224 ! Set offset of next block
2225 block_offset(iwrite+1) = block_offset(iwrite) + &
2226 int(n_values, mpi_offset_kind) * size_double + &
2227 2 * ndim * size_int
2228 end if
2229 end do
2230
2231 ! Write data communicated from other processors
2232 if (mype == 0) then
2233 do ipe = 1, npe-1
2234 do morton_no=morton_start(ipe), morton_stop(ipe)
2235 iwrite=iwrite+1
2236 itag=morton_no
2237
2238 call mpi_recv(ix_buffer, 2*ndim+1, mpi_integer, ipe, itag, icomm,&
2239 igrecvstatus, ierrmpi)
2240 n_values = ix_buffer(1)
2241
2242 call mpi_recv(w_buffer, n_values, mpi_double_precision,&
2243 ipe, itag, icomm, iorecvstatus, ierrmpi)
2244
2245 call mpi_file_write(file_handle, ix_buffer(2:), &
2246 2*ndim, mpi_integer, istatus, ierrmpi)
2247 call mpi_file_write(file_handle, w_buffer, &
2248 n_values, mpi_double_precision, istatus, ierrmpi)
2249
2250 ! Set offset of next block
2251 block_offset(iwrite+1) = block_offset(iwrite) + &
2252 int(n_values, mpi_offset_kind) * size_double + &
2253 2 * ndim * size_int
2254 end do
2255 end do
2256
2257 ! Write block offsets (now we know them)
2258 call mpi_file_seek(file_handle, offset_offsets, mpi_seek_set, ierrmpi)
2259 call mpi_file_write(file_handle, block_offset(1:nleafs), nleafs, &
2260 mpi_offset, istatus, ierrmpi)
2261
2262 ! Write header again, now with correct offsets
2263 call mpi_file_seek(file_handle, 0_mpi_offset_kind, mpi_seek_set, ierrmpi)
2264 call snapshot_write_header(file_handle, offset_tree_info, &
2265 offset_block_data)
2266
2267 call mpi_file_close(file_handle, ierrmpi)
2268 end if
2269
2270 call mpi_barrier(icomm, ierrmpi)
2271 end subroutine write_snapshot
2272
2273 !> Enable the debug field dump: register n named slots. Capture fields with
2274 !> ps(igrid)%wdebug(...,islot) anywhere in a block loop (lazy per-block
2275 !> allocation at the capture site), then flush with save_wdebug.
2276 subroutine debug_alloc(n, names)
2278 integer, intent(in) :: n
2279 character(len=*), intent(in) :: names(n)
2280 integer :: i
2281 n_wdebug = n
2282 if (allocated(wdebug_names)) deallocate(wdebug_names)
2283 allocate(wdebug_names(n))
2284 do i = 1, n
2285 wdebug_names(i) = trim(adjustl(names(i)))
2286 end do
2287 wdebug_on = .true.
2288 end subroutine debug_alloc
2289
2290 !> Flush ps(:)%wdebug to a standalone cell-centred .dat (no staggered),
2291 !> readable by the standard AMRVAC .dat readers. Collective; call at a
2292 !> barrier-safe point (end of a step), NOT inside a block loop.
2293 subroutine save_wdebug(suffix)
2294 use mod_forest
2296 use mod_physics
2299 character(len=*), intent(in) :: suffix
2300 logical :: stagger_save
2301 double precision, allocatable :: w_buffer(:)
2302 integer :: file_handle, igrid, Morton_no, iwrite
2303 integer :: ipe, ix_buffer(2*ndim+1), n_values
2304 integer :: ixO^L, n_ghost(2*ndim)
2305 integer :: iorecvstatus(MPI_STATUS_SIZE)
2306 integer :: igrecvstatus(MPI_STATUS_SIZE)
2307 integer :: istatus(MPI_STATUS_SIZE)
2308 integer(kind=MPI_OFFSET_KIND) :: offset_tree_info, offset_block_data, offset_offsets
2309 integer, allocatable :: block_ig(:, :), block_lvl(:)
2310 integer(kind=MPI_OFFSET_KIND), allocatable :: block_offset(:)
2311 type(tree_node), pointer :: pnode
2312
2313 if (n_wdebug <= 0) return
2314 call mpi_barrier(icomm, ierrmpi)
2315
2316 n_values = count_ix(ixg^ll) * n_wdebug
2317 allocate(w_buffer(n_values))
2318 allocate(block_ig(ndim, nleafs), block_lvl(nleafs), block_offset(nleafs+1))
2319
2320 if (mype == 0) then
2321 call create_output_file(file_handle, it, ".dat", trim(suffix))
2322 offset_tree_info = -1; offset_block_data = -1
2323 stagger_save = stagger_grid; stagger_grid = .false.
2324 call snapshot_write_header1(file_handle, offset_tree_info, offset_block_data, wdebug_names, n_wdebug)
2325 stagger_grid = stagger_save
2326 call mpi_file_get_position(file_handle, offset_tree_info, ierrmpi)
2327 call write_forest(file_handle)
2328 do morton_no = morton_start(0), morton_stop(npe-1)
2329 igrid = sfc(1, morton_no); ipe = sfc(2, morton_no)
2330 pnode => igrid_to_node(igrid, ipe)%node
2331 block_ig(:, morton_no) = [ pnode%ig^d ]
2332 block_lvl(morton_no) = pnode%level
2333 block_offset(morton_no) = 0
2334 end do
2335 call mpi_file_write(file_handle, block_lvl, size(block_lvl), mpi_integer, istatus, ierrmpi)
2336 call mpi_file_write(file_handle, block_ig, size(block_ig), mpi_integer, istatus, ierrmpi)
2337 call mpi_file_get_position(file_handle, offset_offsets, ierrmpi)
2338 call mpi_file_write(file_handle, block_offset(1:nleafs), nleafs, mpi_offset, istatus, ierrmpi)
2339 call mpi_file_get_position(file_handle, offset_block_data, ierrmpi)
2340 block_offset(1) = offset_block_data
2341 iwrite = 0
2342 end if
2343
2344 do morton_no = morton_start(mype), morton_stop(mype)
2345 igrid = sfc_to_igrid(morton_no); itag = morton_no
2346 call block_shape_io(igrid, n_ghost, ixo^l, n_values)
2347 n_values = count_ix(ixo^l) * n_wdebug
2348 if (allocated(ps(igrid)%wdebug)) then
2349 w_buffer(1:n_values) = pack(ps(igrid)%wdebug(ixo^s, 1:n_wdebug), .true.)
2350 else
2351 w_buffer(1:n_values) = 0.0d0
2352 end if
2353 ix_buffer(1) = n_values
2354 ix_buffer(2:) = n_ghost
2355 if (mype /= 0) then
2356 call mpi_send(ix_buffer, 2*ndim+1, mpi_integer, 0, itag, icomm, ierrmpi)
2357 call mpi_send(w_buffer, n_values, mpi_double_precision, 0, itag, icomm, ierrmpi)
2358 else
2359 iwrite = iwrite+1
2360 call mpi_file_write(file_handle, ix_buffer(2:), 2*ndim, mpi_integer, istatus, ierrmpi)
2361 call mpi_file_write(file_handle, w_buffer, n_values, mpi_double_precision, istatus, ierrmpi)
2362 block_offset(iwrite+1) = block_offset(iwrite) + &
2363 int(n_values, mpi_offset_kind) * size_double + 2 * ndim * size_int
2364 end if
2365 end do
2366
2367 if (mype == 0) then
2368 do ipe = 1, npe-1
2369 do morton_no = morton_start(ipe), morton_stop(ipe)
2370 iwrite = iwrite+1; itag = morton_no
2371 call mpi_recv(ix_buffer, 2*ndim+1, mpi_integer, ipe, itag, icomm, igrecvstatus, ierrmpi)
2372 n_values = ix_buffer(1)
2373 call mpi_recv(w_buffer, n_values, mpi_double_precision, ipe, itag, icomm, iorecvstatus, ierrmpi)
2374 call mpi_file_write(file_handle, ix_buffer(2:), 2*ndim, mpi_integer, istatus, ierrmpi)
2375 call mpi_file_write(file_handle, w_buffer, n_values, mpi_double_precision, istatus, ierrmpi)
2376 block_offset(iwrite+1) = block_offset(iwrite) + &
2377 int(n_values, mpi_offset_kind) * size_double + 2 * ndim * size_int
2378 end do
2379 end do
2380 call mpi_file_seek(file_handle, offset_offsets, mpi_seek_set, ierrmpi)
2381 call mpi_file_write(file_handle, block_offset(1:nleafs), nleafs, mpi_offset, istatus, ierrmpi)
2382 call mpi_file_seek(file_handle, 0_mpi_offset_kind, mpi_seek_set, ierrmpi)
2383 stagger_save = stagger_grid; stagger_grid = .false.
2384 call snapshot_write_header1(file_handle, offset_tree_info, offset_block_data, wdebug_names, n_wdebug)
2385 stagger_grid = stagger_save
2386 call mpi_file_close(file_handle, ierrmpi)
2387 end if
2388 deallocate(w_buffer, block_ig, block_lvl, block_offset)
2389 call mpi_barrier(icomm, ierrmpi)
2390 if (mype==0) write(*,*) 'save_wdebug: wrote ', n_wdebug, ' field(s) suffix=', trim(suffix), ' it=', it
2391 end subroutine save_wdebug
2392
2393
2394 !> Routine to read in snapshots (.dat files). When it cannot recognize the
2395 !> file version, it will automatically try the 'old' reader.
2396 subroutine read_snapshot
2399 use mod_forest
2403
2404 double precision :: ws(ixGs^T,1:ndim)
2405 double precision, allocatable :: w_buffer(:)
2406 double precision, dimension(:^D&,:), allocatable :: w
2407 integer :: ix_buffer(2*ndim+1), n_values, n_values_stagger
2408 integer :: ixO^L, ixOs^L
2409 integer :: file_handle, amode, igrid, Morton_no, iread
2410 integer :: istatus(MPI_STATUS_SIZE)
2411 integer :: iorecvstatus(MPI_STATUS_SIZE)
2412 integer :: ipe,inrecv,nrecv, file_version
2413 integer(MPI_OFFSET_KIND) :: offset_tree_info
2414 integer(MPI_OFFSET_KIND) :: offset_block_data
2415 logical :: fexist
2416
2417 if (mype==0) then
2418 inquire(file=trim(restart_from_file), exist=fexist)
2419 if (.not.fexist) call mpistop(trim(restart_from_file)//" not found!")
2420
2421 call mpi_file_open(mpi_comm_self,restart_from_file,mpi_mode_rdonly, &
2422 mpi_info_null,file_handle,ierrmpi)
2423 call mpi_file_read(file_handle, file_version, 1, mpi_integer, &
2424 istatus, ierrmpi)
2425 end if
2426
2427 call mpi_bcast(file_version,1,mpi_integer,0,icomm,ierrmpi)
2428
2429 if (all(compatible_versions /= file_version)) then
2430 if (mype == 0) print *, "Unknown version, trying old snapshot reader..."
2431 call mpi_file_close(file_handle,ierrmpi)
2432 call read_snapshot_old()
2433
2434 ! Guess snapshotnext from file name if not set
2435 if (snapshotnext == -1) &
2437 ! Set slicenext and collapsenext if not set
2438 if (slicenext == -1) slicenext = 0
2439 if (collapsenext == -1) collapsenext = 0
2440
2441 ! Still used in convert
2443
2444 return ! Leave this routine
2445 else if (mype == 0) then
2446 call mpi_file_seek(file_handle, 0_mpi_offset_kind, mpi_seek_set, ierrmpi)
2447 call snapshot_read_header(file_handle, offset_tree_info, &
2448 offset_block_data)
2449 end if
2450
2451 ! Share information about restart file
2452 call mpi_bcast(nw_found,1,mpi_integer,0,icomm,ierrmpi)
2453 call mpi_bcast(nleafs,1,mpi_integer,0,icomm,ierrmpi)
2454 call mpi_bcast(nparents,1,mpi_integer,0,icomm,ierrmpi)
2455 call mpi_bcast(it,1,mpi_integer,0,icomm,ierrmpi)
2456 call mpi_bcast(global_time,1,mpi_double_precision,0,icomm,ierrmpi)
2457
2458 call mpi_bcast(snapshotnext,1,mpi_integer,0,icomm,ierrmpi)
2459 call mpi_bcast(slicenext,1,mpi_integer,0,icomm,ierrmpi)
2460 call mpi_bcast(collapsenext,1,mpi_integer,0,icomm,ierrmpi)
2461 call mpi_bcast(stagger_mark_dat,1,mpi_logical,0,icomm,ierrmpi)
2462
2463 ! Allocate send/receive buffer
2464 n_values = count_ix(ixg^ll) * nw_found
2465 if(stagger_mark_dat) then
2466 n_values = n_values + count_ix(ixgs^ll) * nws
2467 end if
2468 allocate(w_buffer(n_values))
2469 allocate(w(ixg^t,1:nw_found))
2470
2472
2473 if (mype == 0) then
2474 call mpi_file_seek(file_handle, offset_tree_info, &
2475 mpi_seek_set, ierrmpi)
2476 end if
2477
2478 call read_forest(file_handle)
2479
2480 do morton_no=morton_start(mype),morton_stop(mype)
2481 igrid=sfc_to_igrid(morton_no)
2482 call alloc_node(igrid)
2483 end do
2484
2485 if (mype==0) then
2486 call mpi_file_seek(file_handle, offset_block_data, mpi_seek_set, ierrmpi)
2487
2488 iread = 0
2489 do ipe = 0, npe-1
2490 do morton_no=morton_start(ipe),morton_stop(ipe)
2491 iread=iread+1
2492 itag=morton_no
2493
2494 call mpi_file_read(file_handle,ix_buffer(1:2*ndim), 2*ndim, &
2495 mpi_integer, istatus,ierrmpi)
2496
2497 ! Construct ixO^L array from number of ghost cells
2498 {ixomin^d = ixmlo^d - ix_buffer(^d)\}
2499 {ixomax^d = ixmhi^d + ix_buffer(ndim+^d)\}
2500 n_values = count_ix(ixo^l) * nw_found
2501 if(stagger_mark_dat) then
2502 {ixosmin^d = ixomin^d - 1\}
2503 {ixosmax^d = ixomax^d\}
2504 n_values_stagger = n_values
2505 n_values = n_values + count_ix(ixos^l) * nws
2506 end if
2507
2508 call mpi_file_read(file_handle, w_buffer, n_values, &
2509 mpi_double_precision, istatus, ierrmpi)
2510
2511 if (mype == ipe) then ! Root task
2512 igrid=sfc_to_igrid(morton_no)
2513 block=>ps(igrid)
2514 if(stagger_mark_dat) then
2515 w(ixo^s, 1:nw_found) = reshape(w_buffer(1:n_values_stagger), &
2516 shape(w(ixo^s, 1:nw_found)))
2517 if(stagger_grid) &
2518 ps(igrid)%ws(ixos^s,1:nws)=reshape(w_buffer(n_values_stagger+1:n_values), &
2519 shape(ws(ixos^s, 1:nws)))
2520 else
2521 w(ixo^s, 1:nw_found) = reshape(w_buffer(1:n_values), &
2522 shape(w(ixo^s, 1:nw_found)))
2523 end if
2524 if (nw_found<nw) then
2525 if (associated(usr_transform_w)) then
2526 call usr_transform_w(ixg^ll,ixm^ll,nw_found,w,ps(igrid)%x,ps(igrid)%w)
2527 else
2528 ps(igrid)%w(ixo^s,1:nw_found)=w(ixo^s,1:nw_found)
2529 end if
2530 else if (nw_found>nw) then
2531 if (associated(usr_transform_w)) then
2532 call usr_transform_w(ixg^ll,ixm^ll,nw_found,w,ps(igrid)%x,ps(igrid)%w)
2533 else
2534 ps(igrid)%w(ixo^s,1:nw)=w(ixo^s,1:nw)
2535 end if
2536 else
2537 ps(igrid)%w(ixo^s,1:nw)=w(ixo^s,1:nw)
2538 end if
2539 else
2540 call mpi_send([ ixo^l, n_values ], 2*ndim+1, &
2541 mpi_integer, ipe, itag, icomm, ierrmpi)
2542 call mpi_send(w_buffer, n_values, &
2543 mpi_double_precision, ipe, itag, icomm, ierrmpi)
2544 end if
2545 end do
2546 end do
2547
2548 call mpi_file_close(file_handle,ierrmpi)
2549
2550 else ! mype > 0
2551
2552 do morton_no=morton_start(mype),morton_stop(mype)
2553 igrid=sfc_to_igrid(morton_no)
2554 block=>ps(igrid)
2555 itag=morton_no
2556
2557 call mpi_recv(ix_buffer, 2*ndim+1, mpi_integer, 0, itag, icomm,&
2558 iorecvstatus, ierrmpi)
2559 {ixomin^d = ix_buffer(^d)\}
2560 {ixomax^d = ix_buffer(ndim+^d)\}
2561 n_values = ix_buffer(2*ndim+1)
2562
2563 call mpi_recv(w_buffer, n_values, mpi_double_precision,&
2564 0, itag, icomm, iorecvstatus, ierrmpi)
2565
2566 if(stagger_mark_dat) then
2567 n_values_stagger = count_ix(ixo^l) * nw_found
2568 {ixosmin^d = ixomin^d - 1\}
2569 {ixosmax^d = ixomax^d\}
2570 w(ixo^s, 1:nw_found) = reshape(w_buffer(1:n_values_stagger), &
2571 shape(w(ixo^s, 1:nw_found)))
2572 if(stagger_grid) &
2573 ps(igrid)%ws(ixos^s,1:nws)=reshape(w_buffer(n_values_stagger+1:n_values), &
2574 shape(ws(ixos^s, 1:nws)))
2575 else
2576 w(ixo^s, 1:nw_found) = reshape(w_buffer(1:n_values), &
2577 shape(w(ixo^s, 1:nw_found)))
2578 end if
2579 if (nw_found<nw) then
2580 if (associated(usr_transform_w)) then
2581 call usr_transform_w(ixg^ll,ixm^ll,nw_found,w,ps(igrid)%x,ps(igrid)%w)
2582 else
2583 ps(igrid)%w(ixo^s,1:nw_found)=w(ixo^s,1:nw_found)
2584 end if
2585 else if (nw_found>nw) then
2586 if (associated(usr_transform_w)) then
2587 call usr_transform_w(ixg^ll,ixm^ll,nw_found,w,ps(igrid)%x,ps(igrid)%w)
2588 else
2589 ps(igrid)%w(ixo^s,1:nw)=w(ixo^s,1:nw)
2590 end if
2591 else
2592 ps(igrid)%w(ixo^s,1:nw)=w(ixo^s,1:nw)
2593 end if
2594 end do
2595 end if
2596
2597 call mpi_barrier(icomm,ierrmpi)
2598
2599 end subroutine read_snapshot
2600
2602 use mod_forest
2606
2607 double precision :: wio(ixG^T,1:nw)
2608 double precision :: eqpar_dummy(100)
2609 integer :: fh, igrid, Morton_no, iread
2610 integer :: levmaxini, ndimini, ndirini
2611 integer :: nwini, neqparini, nxini^D
2612 integer(kind=MPI_OFFSET_KIND) :: offset
2613 integer :: istatus(MPI_STATUS_SIZE)
2614 integer, allocatable :: iorecvstatus(:,:)
2615 integer :: ipe,inrecv,nrecv
2616 integer :: sendini(7+^ND)
2617 logical :: fexist
2618 character(len=80) :: filename
2619
2620 if (mype==0) then
2621 call mpi_file_open(mpi_comm_self,trim(restart_from_file), &
2622 mpi_mode_rdonly,mpi_info_null,fh,ierrmpi)
2623
2624 offset=-int(7*size_int+size_double,kind=mpi_offset_kind)
2625 call mpi_file_seek(fh,offset,mpi_seek_end,ierrmpi)
2626
2627 call mpi_file_read(fh,nleafs,1,mpi_integer,istatus,ierrmpi)
2629 call mpi_file_read(fh,levmaxini,1,mpi_integer,istatus,ierrmpi)
2630 call mpi_file_read(fh,ndimini,1,mpi_integer,istatus,ierrmpi)
2631 call mpi_file_read(fh,ndirini,1,mpi_integer,istatus,ierrmpi)
2632 call mpi_file_read(fh,nwini,1,mpi_integer,istatus,ierrmpi)
2633 call mpi_file_read(fh,neqparini,1,mpi_integer,istatus,ierrmpi)
2634 call mpi_file_read(fh,it,1,mpi_integer,istatus,ierrmpi)
2635 call mpi_file_read(fh,global_time,1,mpi_double_precision,istatus,ierrmpi)
2636
2637 ! check if settings are suitable for restart
2638 if (levmaxini>refine_max_level) then
2639 write(*,*) "number of levels in restart file = ",levmaxini
2640 write(*,*) "refine_max_level = ",refine_max_level
2641 call mpistop("refine_max_level < number of levels in restart file")
2642 end if
2643 if (ndimini/=ndim) then
2644 write(*,*) "ndim in restart file = ",ndimini
2645 write(*,*) "ndim = ",ndim
2646 call mpistop("reset ndim to ndim in restart file")
2647 end if
2648 if (ndirini/=ndir) then
2649 write(*,*) "ndir in restart file = ",ndirini
2650 write(*,*) "ndir = ",ndir
2651 call mpistop("reset ndir to ndir in restart file")
2652 end if
2653 if (nw/=nwini) then
2654 write(*,*) "nw=",nw," and nw in restart file=",nwini
2655 call mpistop("currently, changing nw at restart is not allowed")
2656 end if
2657
2658 offset=offset-int(ndimini*size_int+neqparini*size_double,kind=mpi_offset_kind)
2659 call mpi_file_seek(fh,offset,mpi_seek_end,ierrmpi)
2660
2661 {call mpi_file_read(fh,nxini^d,1,mpi_integer,istatus,ierrmpi)\}
2662 if (ixghi^d/=nxini^d+2*nghostcells|.or.) then
2663 write(*,*) "Error: reset resolution to ",nxini^d+2*nghostcells
2664 call mpistop("change with setamrvac")
2665 end if
2666
2667 call mpi_file_read(fh,eqpar_dummy,neqparini, &
2668 mpi_double_precision,istatus,ierrmpi)
2669 end if
2670
2671 ! broadcast the global parameters first
2672 if (npe>1) then
2673 if (mype==0) then
2674 sendini=(/nleafs,levmaxini,ndimini,ndirini,nwini,neqparini,it ,^d&nxini^d /)
2675 end if
2676 call mpi_bcast(sendini,7+^nd,mpi_integer,0,icomm,ierrmpi)
2677 nleafs=sendini(1);levmaxini=sendini(2);ndimini=sendini(3);
2678 ndirini=sendini(4);nwini=sendini(5);
2679 neqparini=sendini(6);it=sendini(7);
2680 nxini^d=sendini(7+^d);
2682 call mpi_bcast(global_time,1,mpi_double_precision,0,icomm,ierrmpi)
2683 end if
2684
2685 if (mype == 0) then
2686 offset = int(size_block_io,kind=mpi_offset_kind) * &
2687 int(nleafs,kind=mpi_offset_kind)
2688 call mpi_file_seek(fh,offset,mpi_seek_set,ierrmpi)
2689 end if
2690
2691 call read_forest(fh)
2692
2693 do morton_no=morton_start(mype),morton_stop(mype)
2694 igrid=sfc_to_igrid(morton_no)
2695 call alloc_node(igrid)
2696 end do
2697
2698 if (mype==0)then
2699 iread=0
2700
2701 do morton_no=morton_start(0),morton_stop(0)
2702 igrid=sfc_to_igrid(morton_no)
2703 iread=iread+1
2704 offset=int(size_block_io,kind=mpi_offset_kind) &
2705 *int(morton_no-1,kind=mpi_offset_kind)
2706 call mpi_file_read_at(fh,offset,ps(igrid)%w,1,type_block_io, &
2707 istatus,ierrmpi)
2708 end do
2709 if (npe>1) then
2710 do ipe=1,npe-1
2711 do morton_no=morton_start(ipe),morton_stop(ipe)
2712 iread=iread+1
2713 itag=morton_no
2714 offset=int(size_block_io,kind=mpi_offset_kind)&
2715 *int(morton_no-1,kind=mpi_offset_kind)
2716 call mpi_file_read_at(fh,offset,wio,1,type_block_io,&
2717 istatus,ierrmpi)
2718 call mpi_send(wio,1,type_block_io,ipe,itag,icomm,ierrmpi)
2719 end do
2720 end do
2721 end if
2722 call mpi_file_close(fh,ierrmpi)
2723 else
2724 nrecv=(morton_stop(mype)-morton_start(mype)+1)
2725 allocate(iorecvstatus(mpi_status_size,nrecv))
2726 inrecv=0
2727 do morton_no=morton_start(mype),morton_stop(mype)
2728 igrid=sfc_to_igrid(morton_no)
2729 itag=morton_no
2730 inrecv=inrecv+1
2731 call mpi_recv(ps(igrid)%w,1,type_block_io,0,itag,icomm,&
2732 iorecvstatus(:,inrecv),ierrmpi)
2733 end do
2734 deallocate(iorecvstatus)
2735 end if
2736
2737 call mpi_barrier(icomm,ierrmpi)
2738
2739 end subroutine read_snapshot_old
2740
2741 !> Write volume-averaged values and other information to the log file
2743
2744 use mod_timing
2747
2748 double precision :: dtTimeLast, now, cellupdatesPerSecond
2749 double precision :: activeBlocksPerCore, wctPerCodeTime, timeToFinish
2750 double precision :: wmean(1:nw), total_volume
2751 double precision :: volume_coverage(refine_max_level)
2752 integer :: i, iw, level
2753 integer :: nx^D, nc, ncells, dit
2754 integer :: amode, istatus(MPI_STATUS_SIZE)
2755 integer, parameter :: my_unit = 20
2756 logical, save :: opened = .false.
2757 logical :: fileopen
2758 character(len=40) :: fmt_string
2759 character(len=80) :: filename
2760 character(len=2048) :: line
2761
2762 ! Compute the volume-average of w**1 = w
2763 call get_volume_average(1, wmean, total_volume)
2764
2765 ! Compute the volume coverage
2766 call get_volume_coverage(volume_coverage)
2767
2768 if (mype == 0) then
2769
2770 ! To compute cell updates per second, we do the following:
2771 nx^d=ixmhi^d-ixmlo^d+1;
2772 nc={nx^d*}
2773 ncells = nc * nleafs_active
2774
2775 ! assumes the number of active leafs haven't changed since last compute.
2776 now = mpi_wtime()
2777 dit = it - ittimelast
2778 dttimelast = now - timelast
2779 ittimelast = it
2780 timelast = now
2781 cellupdatespersecond = dble(ncells) * dble(nstep) * &
2782 dble(dit) / (dttimelast * dble(npe))
2783
2784 ! blocks per core:
2785 activeblockspercore = dble(nleafs_active) / dble(npe)
2786
2787 ! Wall clock time per code time unit in seconds:
2788 wctpercodetime = dttimelast / max(dit * dt, epsilon(1.0d0))
2789
2790 ! Wall clock time to finish in hours:
2791 timetofinish = (time_max - global_time) * wctpercodetime / 3600.0d0
2792
2793 ! On first entry, open the file and generate the header
2794 if (.not. opened) then
2795
2796 filename = trim(base_filename) // ".log"
2797
2798 ! Delete the log when not doing a restart run
2799 if (restart_from_file == undefined) then
2800 open(unit=my_unit,file=trim(filename),status='replace')
2801 close(my_unit, status='delete')
2802 end if
2803
2804 amode = ior(mpi_mode_create,mpi_mode_wronly)
2805 amode = ior(amode,mpi_mode_append)
2806
2807 call mpi_file_open(mpi_comm_self, filename, amode, &
2808 mpi_info_null, log_fh, ierrmpi)
2809
2810 opened = .true.
2811
2812 ! Start of file headern
2813 line = "it global_time dt"
2814 do level=1,nw
2815 i = len_trim(line) + 2
2816 write(line(i:),"(a,a)") trim(cons_wnames(level)), " "
2817 end do
2818
2819 ! Volume coverage per level
2820 do level = 1, refine_max_level
2821 i = len_trim(line) + 2
2822 write(line(i:), "(a,i0)") "c", level
2823 end do
2824
2825 ! Cell counts per level
2826 do level=1,refine_max_level
2827 i = len_trim(line) + 2
2828 write(line(i:), "(a,i0)") "n", level
2829 end do
2830
2831 ! Rest of file header
2832 line = trim(line) // " | Xload Xmemory 'Cell_Updates /second/core'"
2833 line = trim(line) // " 'Active_Blocks/Core' 'Wct Per Code Time [s]'"
2834 line = trim(line) // " 'TimeToFinish [hrs]'"
2835
2836 ! Only write header if not restarting
2837 if (restart_from_file == undefined .or. reset_time) then
2838 call mpi_file_write(log_fh, trim(line) // new_line('a'), &
2839 len_trim(line)+1, mpi_character, istatus, ierrmpi)
2840 end if
2841 end if
2842
2843 ! Construct the line to be added to the log
2844
2845 fmt_string = '(' // fmt_i // ',2' // fmt_r // ')'
2846 write(line, fmt_string) it, global_time, dt
2847 i = len_trim(line) + 2
2848
2849 write(fmt_string, '(a,i0,a)') '(', nw, fmt_r // ')'
2850 write(line(i:), fmt_string) wmean(1:nw)
2851 i = len_trim(line) + 2
2852
2853 write(fmt_string, '(a,i0,a)') '(', refine_max_level, fmt_r // ')'
2854 write(line(i:), fmt_string) volume_coverage(1:refine_max_level)
2855 i = len_trim(line) + 2
2856
2857 write(fmt_string, '(a,i0,a)') '(', refine_max_level, fmt_i // ')'
2858 write(line(i:), fmt_string) nleafs_level(1:refine_max_level)
2859 i = len_trim(line) + 2
2860
2861 fmt_string = '(a,6' // fmt_r2 // ')'
2862 write(line(i:), fmt_string) '| ', xload, xmemory, cellupdatespersecond, &
2863 activeblockspercore, wctpercodetime, timetofinish
2864
2865 call mpi_file_write(log_fh, trim(line) // new_line('a') , &
2866 len_trim(line)+1, mpi_character, istatus, ierrmpi)
2867 end if
2868
2869 end subroutine printlog_default
2870
2871 !> Print a log that can be used to check whether the code still produces the
2872 !> same output (regression test)
2875
2876 double precision :: modes(nw, 2), volume
2877 integer, parameter :: n_modes = 2
2878 integer :: power
2879 integer :: amode, istatus(MPI_STATUS_SIZE)
2880 logical, save :: file_open = .false.
2881 character(len=40) :: fmt_string
2882 character(len=2048) :: line
2883 character(len=80) :: filename
2884
2885 do power = 1, n_modes
2886 call get_volume_average(power, modes(:, power), volume)
2887 end do
2888
2889 if (mype == 0) then
2890 if (.not. file_open) then
2891 filename = trim(base_filename) // ".log"
2892 amode = ior(mpi_mode_create,mpi_mode_wronly)
2893 amode = ior(amode,mpi_mode_append)
2894
2895 call mpi_file_open(mpi_comm_self, filename, amode, &
2896 mpi_info_null, log_fh, ierrmpi)
2897 file_open = .true.
2898
2899 line= "# time mean(w) mean(w**2)"
2900 call mpi_file_write(log_fh, trim(line) // new_line('a'), &
2901 len_trim(line)+1, mpi_character, istatus, ierrmpi)
2902 end if
2903
2904 write(fmt_string, "(a,i0,a)") "(", nw * n_modes + 1, fmt_r // ")"
2905 write(line, fmt_string) global_time, modes
2906 call mpi_file_write(log_fh, trim(line) // new_line('a') , &
2907 len_trim(line)+1, mpi_character, istatus, ierrmpi)
2908 end if
2909 end subroutine printlog_regression_test
2910
2911 !> Compute mean(w**power) over the leaves of the grid. The first mode
2912 !> (power=1) corresponds to the mean, the second to the mean squared values
2913 !> and so on.
2914 subroutine get_volume_average(power, mode, volume)
2916
2917 integer, intent(in) :: power !< Which mode to compute
2918 double precision, intent(out) :: mode(nw) !< The computed mode
2919 double precision, intent(out) :: volume !< The total grid volume
2920
2921 double precision :: wsum(nw+1)
2922 double precision :: dsum_recv(1:nw+1)
2923 integer :: iigrid, igrid, iw
2924
2925 wsum(:) = 0
2926
2927 ! Loop over all the grids
2928 do iigrid = 1, igridstail
2929 igrid = igrids(iigrid)
2930
2931 ! Store total volume in last element
2932 wsum(nw+1) = wsum(nw+1) + sum(ps(igrid)%dvolume(ixm^t))
2933
2934 ! Compute the modes of the cell-centered variables, weighted by volume
2935 do iw = 1, nw
2936 wsum(iw) = wsum(iw) + &
2937 sum(ps(igrid)%dvolume(ixm^t)*ps(igrid)%w(ixm^t,iw)**power)
2938 end do
2939 end do
2940
2941 ! Make the information available on all tasks
2942 call mpi_allreduce(wsum, dsum_recv, nw+1, mpi_double_precision, &
2943 mpi_sum, icomm, ierrmpi)
2944
2945 ! Set the volume and the average
2946 volume = dsum_recv(nw+1)
2947 mode = dsum_recv(1:nw) / volume
2948
2949 end subroutine get_volume_average
2950
2951 !> Compute how much of the domain is covered by each grid level. This routine
2952 !> does not take a non-Cartesian geometry into account.
2953 subroutine get_volume_coverage(vol_cov)
2955
2956 double precision, intent(out) :: vol_cov(1:refine_max_level)
2957 double precision :: dsum_recv(1:refine_max_level)
2958 integer :: iigrid, igrid, iw, level
2959
2960 ! First determine the total 'flat' volume in each level
2961 vol_cov(1:refine_max_level)=zero
2962
2963 do iigrid = 1, igridstail
2964 igrid = igrids(iigrid);
2965 level = node(plevel_,igrid)
2966 vol_cov(level) = vol_cov(level)+ &
2967 {(rnode(rpxmax^d_,igrid)-rnode(rpxmin^d_,igrid))|*}
2968 end do
2969
2970 ! Make the information available on all tasks
2971 call mpi_allreduce(vol_cov, dsum_recv, refine_max_level, mpi_double_precision, &
2972 mpi_sum, icomm, ierrmpi)
2973
2974 ! Normalize
2975 vol_cov = dsum_recv / sum(dsum_recv)
2976 end subroutine get_volume_coverage
2977
2978 !> Compute the volume average of func(w) over the leaves of the grid.
2979 subroutine get_volume_average_func(func, f_avg, volume)
2981
2982 interface
2983 pure function func(w_vec, w_size) result(val)
2984 integer, intent(in) :: w_size
2985 double precision, intent(in) :: w_vec(w_size)
2986 double precision :: val
2987 end function func
2988 end interface
2989 double precision, intent(out) :: f_avg !< The volume average of func
2990 double precision, intent(out) :: volume !< The total grid volume
2991 double precision :: wsum(2)
2992 double precision :: dsum_recv(2)
2993 integer :: iigrid, igrid, i^D
2994
2995 wsum(:) = 0
2996
2997 ! Loop over all the grids
2998 do iigrid = 1, igridstail
2999 igrid = igrids(iigrid)
3000
3001 ! Store total volume in last element
3002 wsum(2) = wsum(2) + sum(ps(igrid)%dvolume(ixm^t))
3003
3004 ! Compute the modes of the cell-centered variables, weighted by volume
3005 {do i^d = ixmlo^d, ixmhi^d\}
3006 wsum(1) = wsum(1) + ps(igrid)%dvolume(i^d) * &
3007 func(ps(igrid)%w(i^d, :), nw)
3008 {end do\}
3009 end do
3010
3011 ! Make the information available on all tasks
3012 call mpi_allreduce(wsum, dsum_recv, 2, mpi_double_precision, &
3013 mpi_sum, icomm, ierrmpi)
3014
3015 ! Set the volume and the average
3016 volume = dsum_recv(2)
3017 f_avg = dsum_recv(1) / volume
3018
3019 end subroutine get_volume_average_func
3020
3021 !> Compute global maxima of iw variables over the leaves of the grid.
3022 subroutine get_global_maxima(wmax,psa)
3024
3025 double precision, intent(out) :: wmax(nw) !< The global maxima
3026 type(state), target :: psa(max_blocks)
3027
3028 double precision :: wmax_mype(nw),wmax_recv(nw)
3029 integer :: iigrid, igrid, iw
3030
3031 wmax_mype(1:nw) = -bigdouble
3032
3033 ! Loop over all the grids
3034 do iigrid = 1, igridstail
3035 igrid = igrids(iigrid)
3036 do iw = 1, nw
3037 wmax_mype(iw)=max(wmax_mype(iw),maxval(psa(igrid)%w(ixm^t,iw)))
3038 end do
3039 end do
3040
3041 ! Make the information available on all tasks
3042 call mpi_allreduce(wmax_mype, wmax_recv, nw, mpi_double_precision, &
3043 mpi_max, icomm, ierrmpi)
3044
3045 wmax(1:nw)=wmax_recv(1:nw)
3046
3047 end subroutine get_global_maxima
3048
3049 !> Compute global minima of iw variables over the leaves of the grid.
3050 subroutine get_global_minima(wmin,psa)
3052
3053 double precision, intent(out) :: wmin(nw) !< The global maxima
3054 type(state), target :: psa(max_blocks)
3055
3056 double precision :: wmin_mype(nw),wmin_recv(nw)
3057 integer :: iigrid, igrid, iw
3058
3059 wmin_mype(1:nw) = bigdouble
3060
3061 ! Loop over all the grids
3062 do iigrid = 1, igridstail
3063 igrid = igrids(iigrid)
3064 do iw = 1, nw
3065 wmin_mype(iw)=min(wmin_mype(iw),minval(psa(igrid)%w(ixm^t,iw)))
3066 end do
3067 end do
3068
3069 ! Make the information available on all tasks
3070 call mpi_allreduce(wmin_mype, wmin_recv, nw, mpi_double_precision, &
3071 mpi_min, icomm, ierrmpi)
3072
3073 wmin(1:nw)=wmin_recv(1:nw)
3074
3075 end subroutine get_global_minima
3076
3077end module mod_input_output
subroutine, public alloc_node(igrid)
allocate arrays on igrid node
Module with basic data types used in amrvac.
integer, parameter name_len
Default length for names (of e.g. variables).
Collapses D-dimensional output to D-1 view by line-of-sight integration.
Definition mod_collapse.t:4
subroutine write_collapsed
subroutine, public mpistop(message)
Exit MPI-AMRVAC with an error message.
subroutine generate_plotfile
Module with basic grid data structures.
Definition mod_forest.t:2
integer, dimension(:), allocatable, save nleafs_level
How many leaves are present per refinement level.
Definition mod_forest.t:84
integer, dimension(:), allocatable, save sfc_to_igrid
Go from a Morton number to an igrid index (for a single processor).
Definition mod_forest.t:56
integer nleafs_active
Definition mod_forest.t:81
integer, dimension(:), allocatable, save morton_start
First Morton number per processor.
Definition mod_forest.t:65
integer, save nleafs
Number of leaf block.
Definition mod_forest.t:79
integer, dimension(:), allocatable, save morton_stop
Last Morton number per processor.
Definition mod_forest.t:68
integer, dimension(:,:), allocatable, save sfc
Array to go from a Morton number to an igrid and processor index. Sfc(1:3,MN) contains [igrid,...
Definition mod_forest.t:46
integer, save nparents
Number of parent blocks.
Definition mod_forest.t:76
type(tree_node_ptr), dimension(:,:), allocatable, save igrid_to_node
Array to go from an [igrid, ipe] index to a node pointer.
Definition mod_forest.t:35
subroutine, public write_forest(file_handle)
subroutine, public read_forest(file_handle)
Module with geometry-related routines (e.g., divergence, curl).
Definition mod_geometry.t:2
This module contains definitions of global parameters and variables and some generic functions/subrou...
character(len=std_len), dimension(:), allocatable typeentropy
Which type of entropy fix to use with Riemann-type solvers.
double precision, dimension(:), allocatable w_convert_factor
Conversion factors the primitive variables.
type(state), pointer block
Block pointer for using one block and its previous state.
double precision xload
Stores the memory and load imbalance, used in printlog.
integer nstep
How many sub-steps the time integrator takes.
logical h_correction
If true, do H-correction to fix the carbuncle problem at grid-aligned shocks.
integer it_max
Stop the simulation after this many time steps have been taken.
logical internalboundary
if there is an internal boundary
double precision r_opt_thick
for spherical coordinate, region below it (unit=Rsun) is treated as not transparent
character(len=std_len) filename_sxr
Base file name for synthetic SXR emission output.
integer spectrum_wl
wave length for spectrum
logical nocartesian
IO switches for conversion.
double precision ppm_rjv
Residual-jump velocity reconstruction (RJV). 0 = off (default), 1 = full strength.
integer, dimension(:), allocatable typepred1
The spatial discretization for the predictor step when using a two step PC method.
double precision dtdiffpar
For resistive MHD, the time step is also limited by the diffusion time: .
character(len=std_len) typegrad
logical reset_it
If true, reset iteration count to 0.
integer ixghi
Upper index of grid block arrays.
character(len=std_len) geometry_name
integer, dimension(3, 3, 3) lvc
Levi-Civita tensor.
logical activate_unit_arcsec
use arcsec as length unit of images/spectra
logical source_split_usr
Use split or unsplit way to add user's source terms, default: unsplit.
logical lb_diagnose
Per-rank load-balance timing diagnostic toggle (off by default). When .true., per-rank wall times are...
integer domain_nx
number of cells for each dimension in level-one mesh
integer, parameter unitpar
file handle for IO
character(len=std_len) filename_spectrum
Base file name for synthetic EUV spectrum output.
logical resume_previous_run
If true, restart a previous run from the latest snapshot.
double precision global_time
The global simulation time.
integer, dimension(nsavehi, nfile) itsave
Save output of type N on iterations itsave(:, N).
double precision time_max
End time for the simulation.
logical output_absorption_fraction
output absorption fraction for thick/thin EUV synthesis when available
double precision radio_beam_fwhm
Gaussian radio beam full width at half maximum in arcsec.
integer, dimension(3, 3) kr
Kronecker delta tensor.
double precision lb_max_block_ratio
Bound on the memory imbalance get_Morton_range_costed may create: no rank may hold more than lb_max_b...
logical, dimension(:), allocatable logflag
double precision time_init
Start time for the simulation.
logical stretch_uncentered
If true, adjust mod_geometry routines to account for grid stretching (but the flux computation will n...
logical firstprocess
If true, call initonegrid_usr upon restarting.
integer snapshotini
Resume from the snapshot with this index.
double precision small_temperature
error handling
double precision xprob
minimum and maximum domain boundaries for each dimension
integer it
Number of time steps taken.
character(len=std_len) filename_euv
Base file name for synthetic EUV emission output.
logical, dimension(:), allocatable loglimit
double precision, dimension(:), allocatable dg
extent of grid blocks in domain per dimension, in array over levels
integer it_init
initial iteration count
integer, dimension(:, :), allocatable typeboundary
Array indicating the type of boundary condition per variable and per physical boundary.
integer ditregrid
Reconstruct the AMR grid once every ditregrid iteration(s).
logical instrument_postprocess
Post-process dat-resolution EUV images onto the instrument pixel grid.
logical saveprim
If true, convert from conservative to primitive variables in output.
double precision flux_adaptive_diffusion_min
character(len=std_len) filename_whitelight
Base file name for synthetic white light.
character(len=std_len) convert_type
Which format to use when converting.
integer, parameter ndim
Number of spatial dimensions for grid variables.
integer itfixgrid
Fix the AMR grid after this many time steps.
integer, parameter filecollapse_
Constant indicating collapsed output.
double precision, dimension(:), allocatable amr_wavefilter
refinement: lohner estimate wavefilter setting
integer, parameter nlevelshi
The maximum number of levels in the grid refinement.
double precision location_slit
location of the slit
logical save_physical_boundary
True for save physical boundary cells in dat files.
logical stagger_grid
True for using stagger grid.
double precision time_convert_factor
Conversion factor for time unit.
logical use_particles
Use particles module or not.
character(len=std_len), dimension(:), allocatable par_files
Which par files are used as input.
integer icomm
The MPI communicator.
logical coarsenprimitive
coarsen primitive variables in level-jump ghost cells
integer, dimension(:), allocatable ng
number of grid blocks in domain per dimension, in array over levels
logical reset_time
If true, reset iteration count and global_time to original values, and start writing snapshots at ind...
integer, parameter nsavehi
Maximum number of saves that can be defined by tsave or itsave.
logical ghostcell_comm_batched
Limit outstanding ghost-cell send requests to avoid MPI request pressure. In large-scale MHD tests,...
character(len=std_len) whitelight_instrument
white light observation instrument
integer mype
The rank of the current MPI task.
double precision dtpar
If dtpar is positive, it sets the timestep dt, otherwise courantpar is used to limit the time step ba...
character(len=std_len) typediv
integer block_nx
number of cells for each dimension in grid block excluding ghostcells
integer type_block_io
MPI type for IO: block excluding ghost cells.
double precision, dimension(nfile) tsavestart
Start of read out (not counting specified read outs).
integer, dimension(nfile) ditsave
Repeatedly save output of type N when ditsave(N) time steps have passed.
logical, dimension(ndim) collapse
If collapse(DIM) is true, generate output integrated over DIM.
logical local_timestep
each cell has its own timestep or not
double precision dt
global time step
double precision radio_frequency
Observing frequency for radio free-free synthesis in Hz.
integer refine_criterion
select types of refine criterion
character(len=std_len) usr_filename
User parameter file.
logical ghost_copy
whether copy values instead of interpolation in ghost cells of finer blocks
integer slicenext
IO: slice output number/label.
double precision length_convert_factor
Conversion factor for length unit.
integer ndir
Number of spatial dimensions (components) for vector variables.
double precision imex222_lambda
IMEX-222(lambda) one-parameter family of schemes.
double precision courantpar
The Courant (CFL) number used for the simulation.
double precision wall_time_max
Ending wall time (in hours) for the simulation.
integer ixm
the mesh range of a physical block without ghost cells
integer ierrmpi
A global MPI error return code.
logical autoconvert
If true, already convert to output format during the run.
integer, dimension(:), allocatable flux_method
Which flux scheme of spatial discretization to use (per grid level).
double precision, dimension(:), allocatable, parameter d
character(len=std_len) collapse_type
integer slowsteps
If > 1, then in the first slowsteps-1 time steps dt is reduced by a factor .
integer ssprk_order
SSPRK choice of methods (both threestep and fourstep, Shu-Osher 2N* implementation) also fivestep SSP...
double precision image_rotate
rotation of image
double precision radio_beam_pixel_size
Output pixel size for radio beam post-processing in arcsec; <=0 uses FWHM/3.
integer snapshotnext
IO: snapshot and collapsed views output numbers/labels.
logical dat_resolution
resolution of the images
double precision r_occultor
the white light emission below it (unit=Rsun) is not visible
integer, dimension(ndim) nstretchedblocks_baselevel
(even) number of (symmetrically) stretched blocks at AMR level 1, per dimension
logical limit_on_wold
VAC-type MUSCL-Hancock: limit the corrector slopes on w^n (typelimited='previous'),...
integer npe
The number of MPI tasks.
logical output_tau
output optical-depth map for synthetic emission when available
double precision, dimension(^nd) qstretch_baselevel
stretch factor between cells at AMR level 1, per dimension
integer nwauxio
Number of auxiliary variables that are only included in output.
integer imex_switch
IMEX_232 choice and parameters.
double precision time_between_print
to monitor timeintegration loop at given wall-clock time intervals
integer, parameter unitterm
Unit for standard output.
logical lb_automatic
Cost-weighted automatic load balancer toggle (off by default). When .true., the SFC partitioner cuts ...
double precision, dimension(nfile) dtsave
Repeatedly save output of type N when dtsave(N) simulation time has passed.
integer lb_interval
Rebalance every lb_interval cycles when lb_automatic is on.
logical, dimension(:), allocatable w_write
if true write the w variable in output
logical prolongprimitive
prolongate primitive variables in level-jump ghost cells
integer iprob
problem switch allowing different setups in same usr_mod.t
character(len=std_len) restart_from_file
If not 'unavailable', resume from snapshot with this base file name.
logical, dimension(ndim) periodb
True for dimensions with periodic boundaries.
integer radsyn_segment_batch_factor
Maximum ray segments per pixel batch, as a factor of radsyn_pixel_batch; <=0 uses memory budget....
double precision, dimension(:,:), allocatable rnode
Corner coordinates.
integer, parameter filelog_
Constant indicating log output.
logical final_dt_reduction
If true, allow final dt reduction for matching time_max on output.
logical, dimension(:), allocatable writelevel
integer, parameter fileout_
Constant indicating regular output.
double precision los_theta
direction of the line of sight (LOS)
character(len=std_len) typetvd
Which type of TVD method to use.
integer nbufferx
Number of cells as buffer zone.
double precision, dimension(:), allocatable entropycoef
double precision, dimension(:,:), allocatable dx
spatial steps for all dimensions at all levels
double precision tfixgrid
Fix the AMR grid after this time.
character(len=std_len) dat_resolution_mode
Data-resolution image spacing: nominal or minimum actual cell size.
character(len=std_len) radiation_transfer
Synthetic emission transfer mode: thin or thick.
integer nghostcells
Number of ghost cells surrounding a grid.
double precision, dimension(:), allocatable w_refine_weight
Weights of variables used to calculate error for mesh refinement.
double precision flux_adaptive_diffusion_scale
character(len=std_len) typedimsplit
character(len=std_len) typeaverage
character(len= *), parameter undefined
double precision, dimension(nsavehi, nfile) tsave
Save output of type N on times tsave(:, N).
double precision spectrum_window_max
logical convert
If true and restart_from_file is given, convert snapshots to other file formats.
logical fix_small_values
fix small values with average or replace methods
integer wavelength
wavelength for output
integer collapselevel
The level at which to produce line-integrated / collapsed output.
logical reset_grid
If true, rebuild the AMR grid upon restarting.
integer radsyn_pixel_batch
Number of image pixels processed in one ray-segment MPI batch.
logical radsyn_verbose
Print synthetic-emission ray-tracing profiling counters.
double precision, dimension(:), allocatable refine_threshold
Error tolerance for refinement decision.
character(len=std_len) base_filename
Base file name for simulation output, which will be followed by a number.
double precision instrument_resolution_factor
times for enhancing spatial resolution for EUV image/spectra
double precision ppm_avisc
Coefficient alpha of the explicit diffusive flux of Mignone et al. 2005 eq. B19-B21,...
double precision radsyn_segment_memory_mb
Approximate per-rank temporary memory budget, in MiB, for automatic ray-segment batch sizing.
double precision spectrum_window_min
spectral window
double precision dtmin
Stop the simulation when the time step becomes smaller than this value.
integer refine_max_level
Maximal number of AMR levels.
integer, parameter fileslice_
Constant indicating slice output.
character(len=std_len) ray_method
Synthetic emission ray traversal method.
double precision, dimension(:), allocatable derefine_ratio
Error tolerance ratio for derefinement decision.
integer, parameter nfile
Number of output methods.
integer max_blocks
The maximum number of grid blocks in a processor.
integer, parameter fileanalysis_
Constant indicating analysis output (see Writing a custom analysis subroutine).
logical allow_ndir_change
If true, allow a restart from a snapshot whose ndir differs from the current run (e....
integer rk3_switch
RK3 Butcher table.
character(len=std_len) typefilelog
Which type of log to write: 'normal', 'special', 'regression_test'.
integer direction_slit
direction of the slit (for dat resolution only)
double precision, dimension(1:3) x_origin
where the is the origin (X=0,Y=0) of image
double precision, dimension(^nd, 2) writespshift
domain percentage cut off shifted from each boundary when converting data
character(len=std_len) emission_model
Synthetic emission physical model selector.
logical final_dt_exit
Force timeloop exit when final dt < dtmin.
integer, dimension(nfile) isaveit
integer, dimension(:,:), allocatable node
integer radsyn_segment_comm_factor
Maximum ray segments per segmented MPI all-to-all round, as a factor of radsyn_pixel_batch.
double precision lb_alpha
Exponential-moving-average decay for the per-block cost. costlist <- lb_alpha*costlist + (1-lb_alpha)...
integer, dimension(nfile) isavet
logical check_small_values
check and optionally fix unphysical small values (density, gas pressure)
integer log_fh
MPI file handle for logfile.
subroutine, public create_output_file(fh, ix, extension, suffix)
Standard method for creating a new output file.
subroutine, public block_shape_io(igrid, n_ghost, ixol, n_values)
Determine the shape of a block for output (whether to include ghost cells, and on which sides).
subroutine, public snapshot_write_header1(fh, offset_tree, offset_block, dataset_names, nw_vars)
Write header for a snapshot, generalize cons_wnames and nw.
character(len=name_len) function, dimension(1:nwc), public get_names_from_string(aux_variable_names, nwc)
pure integer function, public count_ix(ixol)
Compute number of elements in index range.
Module for reading input and writing output.
subroutine saveamrfile(ifile)
logical function snapshot_exists(ix)
integer function get_snapshot_index(filename)
subroutine read_par_files()
Read in the user-supplied parameter-file.
character(len= *), parameter fmt_r
character(len=name_len), dimension(:), allocatable wdebug_names
debug field-dump variable names (set by debug_alloc, used by save_wdebug)
subroutine get_volume_average_func(func, f_avg, volume)
Compute the volume average of func(w) over the leaves of the grid.
subroutine save_wdebug(suffix)
Flush ps(:)wdebug to a standalone cell-centred .dat (no staggered), readable by the standard AMRVAC ....
subroutine printlog_regression_test()
Print a log that can be used to check whether the code still produces the same output (regression tes...
subroutine read_arguments()
Read the command line arguments passed to amrvac.
subroutine get_volume_average(power, mode, volume)
Compute mean(w**power) over the leaves of the grid. The first mode (power=1) corresponds to the mean,...
subroutine read_snapshot
Routine to read in snapshots (.dat files). When it cannot recognize the file version,...
integer nw_found
number of w found in dat files
character(len= *), parameter fmt_r2
subroutine get_fields_string(line, delims, n_max, fields, n_found, fully_read)
Routine to find entries in a string.
subroutine get_volume_coverage(vol_cov)
Compute how much of the domain is covered by each grid level. This routine does not take a non-Cartes...
character(len= *), parameter fmt_i
subroutine get_global_minima(wmin, psa)
Compute global minima of iw variables over the leaves of the grid.
subroutine printlog_default
Write volume-averaged values and other information to the log file.
subroutine, public snapshot_write_header(fh, offset_tree, offset_block)
Write header for a snapshot.
subroutine debug_alloc(n, names)
Enable the debug field dump: register n named slots. Capture fields with ps(igrid)wdebug(....
subroutine snapshot_read_header(fh, offset_tree, offset_block)
Read header for a snapshot.
subroutine get_global_maxima(wmax, psa)
Compute global maxima of iw variables over the leaves of the grid.
integer, dimension(3), parameter compatible_versions
List of compatible versions.
subroutine read_snapshot_old()
Module with slope/flux limiters.
Definition mod_limiter.t:2
double precision cada3_radius
radius of the asymptotic region [0.001, 10], larger means more accurate in smooth region but more ove...
Definition mod_limiter.t:13
Module containing all the particle routines.
This module defines the procedures of a physics module. It contains function pointers for the various...
Definition mod_physics.t:4
logical phys_total_energy
Solve total energy equation or not.
Definition mod_physics.t:40
integer phys_wider_stencil
To use wider stencils in flux calculations. A value of 1 will extend it by one cell in both direction...
Definition mod_physics.t:17
character(len=name_len) physics_type
String describing the physics type of the simulation.
Definition mod_physics.t:49
logical phys_energy
Solve energy equation or not.
Definition mod_physics.t:37
Writes D-1 slice, can do so in various formats, depending on slice_type.
Definition mod_slice.t:2
subroutine write_slice
Definition mod_slice.t:31
double precision, dimension(1000) slicecoord
Slice coordinates, see Slice output.
Definition mod_slice.t:8
character(len=std_len) slice_type
choose data type of slice: vtu, vtuCC, dat, or csv
Definition mod_slice.t:23
integer, dimension(nslicemax) slicedir
The slice direction for each slice.
Definition mod_slice.t:17
integer nslices
Number of slices to output.
Definition mod_slice.t:14
Module for handling problematic values in simulations, such as negative pressures.
integer, public small_values_daverage
Average over this many cells in each direction.
logical, public trace_small_values
trace small values in the source file using traceback flag of compiler
logical, dimension(:), allocatable, public small_values_fix_iw
Whether to apply small value fixes to certain variables.
character(len=20), public small_values_method
How to handle small values.
Module for handling split source terms (split from the fluxes).
Definition mod_source.t:2
integer timing_log_interval
Write timing log every N iterations (default 10).
Definition mod_timing.t:35
integer ittimelast
Definition mod_timing.t:29
double precision timelast
Definition mod_timing.t:22
logical write_timing_log
Enable writing of detailed timing breakdown log (set via savelist).
Definition mod_timing.t:33
Module with all the methods that users can customize in AMRVAC.
procedure(p_no_args), pointer usr_print_log
procedure(p_no_args), pointer usr_write_analysis
procedure(transform_w), pointer usr_transform_w
The data structure that contains information about a tree node/grid block.
Definition mod_forest.t:14