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