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