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