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