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 typeboundary(phi_+1,2*idim-1)=bc_asymm
1407 if(physics_type=='mhd'.or.physics_type=='rmhd') typeboundary(ndir+windex+phi_,2*idim-1)=bc_asymm
1408 case(spherical)
1409 typeboundary(3:ndir+1,2*idim-1)=bc_asymm
1410 if(physics_type=='mhd'.or.physics_type=='rmhd') typeboundary(ndir+windex+2:ndir+windex+ndir,2*idim-1)=bc_asymm
1411 case default
1412 call mpistop('Pole is in cylindrical, polar, spherical coordinates!')
1413 end select
1414 case ('twofl','mf')
1415 call mpistop('Pole treatment for twofl or mf not implemented yet')
1416 case default
1417 call mpistop('unknown physics type for setting minimal pole boundary treatment')
1418 end select
1419 end if
1420 if(any(typeboundary(:,2*idim)==12)) then
1421 if(any(typeboundary(:,2*idim)/=12)) typeboundary(:,2*idim)=12
1422 select case(physics_type)
1423 case ('rho','ard','rd','nonlinear','ffhd')
1424 ! all symmetric at pole
1425 typeboundary(:,2*idim)=bc_symm
1426 if(mype==0) print *,'symmetric maximal pole'
1427 case ('hd','rhd','srhd','mhd','rmhd')
1428 typeboundary(:,2*idim)=bc_symm
1429 ! here we assume the ordering of variables is fixed to rho-mom-[e]-B
1430 if(phys_energy) then
1431 windex=2
1432 else
1433 windex=1
1434 end if
1435 select case(coordinate)
1436 case(cylindrical)
1437 typeboundary(phi_+1,2*idim)=bc_asymm
1438 if(physics_type=='mhd'.or.physics_type=='rmhd') typeboundary(ndir+windex+phi_,2*idim)=bc_asymm
1439 case(spherical)
1440 typeboundary(3:ndir+1,2*idim)=bc_asymm
1441 if(physics_type=='mhd'.or.physics_type=='rmhd') typeboundary(ndir+windex+2:ndir+windex+ndir,2*idim)=bc_asymm
1442 case default
1443 call mpistop('Pole is in cylindrical, polar, spherical coordinates!')
1444 end select
1445 case ('twofl','mf')
1446 call mpistop('Pole treatment for twofl or mf not implemented yet')
1447 case default
1448 call mpistop('unknown physics type for setting maximal pole boundary treatment')
1449 end select
1450 end if
1451 end do
1452 }
1453
1454 if(.not.phys_energy) then
1455 flatcd=.false.
1456 flatsh=.false.
1457 end if
1458
1459 if(any(limiter(1:nlevelshi)=='mp5')) then
1460 nghostcells=max(nghostcells,3)
1461 end if
1462
1463 if(any(limiter(1:nlevelshi)=='weno5')) then
1464 nghostcells=max(nghostcells,3)
1465 end if
1466
1467 if(any(limiter(1:nlevelshi)=='weno5nm')) then
1468 nghostcells=max(nghostcells,3)
1469 end if
1470
1471 if(any(limiter(1:nlevelshi)=='wenoz5')) then
1472 nghostcells=max(nghostcells,3)
1473 end if
1474
1475 if(any(limiter(1:nlevelshi)=='wenoz5nm')) then
1476 nghostcells=max(nghostcells,3)
1477 end if
1478
1479 if(any(limiter(1:nlevelshi)=='wenozp5')) then
1480 nghostcells=max(nghostcells,3)
1481 end if
1482
1483 if(any(limiter(1:nlevelshi)=='wenozp5nm')) then
1484 nghostcells=max(nghostcells,3)
1485 end if
1486
1487 if(any(limiter(1:nlevelshi)=='teno5ad')) then
1488 nghostcells=max(nghostcells,3)
1489 end if
1490
1491 if(any(limiter(1:nlevelshi)=='weno5cu6')) then
1492 nghostcells=max(nghostcells,3)
1493 end if
1494
1495 if(any(limiter(1:nlevelshi)=='ppm')) then
1496 if(flatsh .or. flatcd) then
1497 nghostcells=max(nghostcells,4)
1498 else
1499 nghostcells=max(nghostcells,3)
1500 end if
1501 end if
1502
1503 if(any(limiter(1:nlevelshi)=='weno7')) then
1504 nghostcells=max(nghostcells,4)
1505 end if
1506
1507 if(any(limiter(1:nlevelshi)=='mpweno7')) then
1508 nghostcells=max(nghostcells,4)
1509 end if
1510
1511 ! If a wider stencil is used, extend the number of ghost cells
1512 nghostcells = nghostcells + phys_wider_stencil
1513
1514 ! prolongation in AMR for constrained transport MHD needs even number ghosts
1515 if(stagger_grid .and. refine_max_level>1 .and. mod(nghostcells,2)/=0) then
1516 nghostcells=nghostcells+1
1517 end if
1518
1519 select case (coordinate)
1520 {^nooned
1521 case (spherical)
1522 xprob^lim^de=xprob^lim^de*two*dpi;
1523 \}
1524 case (cylindrical)
1525 {
1526 if (^d==phi_) then
1527 xprob^lim^d=xprob^lim^d*two*dpi;
1528 end if
1529 \}
1530 end select
1531
1532 ! full block size including ghostcells
1533 {ixghi^d = block_nx^d + 2*nghostcells\}
1534 {ixgshi^d = ixghi^d\}
1535
1536 nx_vec = [{domain_nx^d|, }]
1537 block_nx_vec = [{block_nx^d|, }]
1538
1539 if (any(nx_vec < 4) .or. any(mod(nx_vec, 2) == 1)) &
1540 call mpistop('Grid size (domain_nx^D) has to be even and >= 4')
1541
1542 if (any(block_nx_vec < 4) .or. any(mod(block_nx_vec, 2) == 1)) &
1543 call mpistop('Block size (block_nx^D) has to be even and >= 4')
1544
1545 { if(mod(domain_nx^d,block_nx^d)/=0) &
1546 call mpistop('Grid (domain_nx^D) and block (block_nx^D) must be consistent') \}
1547
1548 if(refine_max_level>nlevelshi.or.refine_max_level<1)then
1549 write(unitterm,*)'Error: refine_max_level',refine_max_level,'>nlevelshi ',nlevelshi
1550 call mpistop("Reset nlevelshi and recompile!")
1551 endif
1552
1553 if (any(stretched_dim)) then
1554 allocate(qstretch(0:nlevelshi,1:ndim),dxfirst(0:nlevelshi,1:ndim),&
1555 dxfirst_1mq(0:nlevelshi,1:ndim),dxmid(0:nlevelshi,1:ndim))
1556 allocate(nstretchedblocks(1:nlevelshi,1:ndim))
1557 qstretch(0:nlevelshi,1:ndim)=0.0d0
1558 dxfirst(0:nlevelshi,1:ndim)=0.0d0
1559 nstretchedblocks(1:nlevelshi,1:ndim)=0
1560 {if (stretch_type(^d) == stretch_uni) then
1561 ! first some sanity checks
1562 if(qstretch_baselevel(^d)<1.0d0.or.qstretch_baselevel(^d)==bigdouble) then
1563 if(mype==0) then
1564 write(*,*) 'stretched grid needs finite qstretch_baselevel>1'
1565 write(*,*) 'will try default value for qstretch_baselevel in dimension', ^d
1566 endif
1567 if(xprobmin^d>smalldouble)then
1568 qstretch_baselevel(^d)=(xprobmax^d/xprobmin^d)**(1.d0/dble(domain_nx^d))
1569 else
1570 call mpistop("can not set qstretch_baselevel automatically")
1571 endif
1572 endif
1573 if(mod(block_nx^d,2)==1) &
1574 call mpistop("stretched grid needs even block size block_nxD")
1575 if(mod(domain_nx^d/block_nx^d,2)/=0) &
1576 call mpistop("number level 1 blocks in D must be even")
1577 qstretch(1,^d)=qstretch_baselevel(^d)
1578 dxfirst(1,^d)=(xprobmax^d-xprobmin^d) &
1579 *(1.0d0-qstretch(1,^d))/(1.0d0-qstretch(1,^d)**domain_nx^d)
1580 qstretch(0,^d)=qstretch(1,^d)**2
1581 dxfirst(0,^d)=dxfirst(1,^d)*(1.0d0+qstretch(1,^d))
1582 if(refine_max_level>1)then
1583 do ilev=2,refine_max_level
1584 qstretch(ilev,^d)=dsqrt(qstretch(ilev-1,^d))
1585 dxfirst(ilev,^d)=dxfirst(ilev-1,^d) &
1586 /(1.0d0+dsqrt(qstretch(ilev-1,^d)))
1587 enddo
1588 endif
1589 endif \}
1590 if(mype==0) then
1591 {if(stretch_type(^d) == stretch_uni) then
1592 write(*,*) 'Stretched dimension ', ^d
1593 write(*,*) 'Using stretched grid with qs=',qstretch(0:refine_max_level,^d)
1594 write(*,*) ' and first cell sizes=',dxfirst(0:refine_max_level,^d)
1595 endif\}
1596 end if
1597 {if(stretch_type(^d) == stretch_symm) then
1598 if(mype==0) then
1599 write(*,*) 'will apply symmetric stretch in dimension', ^d
1600 endif
1601 if(mod(block_nx^d,2)==1) &
1602 call mpistop("stretched grid needs even block size block_nxD")
1603 ! checks on the input variable nstretchedblocks_baselevel
1604 if(nstretchedblocks_baselevel(^d)==0) &
1605 call mpistop("need finite even number of stretched blocks at baselevel")
1606 if(mod(nstretchedblocks_baselevel(^d),2)==1) &
1607 call mpistop("need even number of stretched blocks at baselevel")
1608 if(qstretch_baselevel(^d)<1.0d0.or.qstretch_baselevel(^d)==bigdouble) &
1609 call mpistop('stretched grid needs finite qstretch_baselevel>1')
1610 ! compute stretched part to ensure uniform center
1611 ipower=(nstretchedblocks_baselevel(^d)/2)*block_nx^d
1612 if(nstretchedblocks_baselevel(^d)==domain_nx^d/block_nx^d)then
1613 xstretch^d=0.5d0*(xprobmax^d-xprobmin^d)
1614 else
1615 xstretch^d=(xprobmax^d-xprobmin^d) &
1616 /(2.0d0+dble(domain_nx^d-nstretchedblocks_baselevel(^d)*block_nx^d) &
1617 *(1.0d0-qstretch_baselevel(^d))/(1.0d0-qstretch_baselevel(^d)**ipower))
1618 endif
1619 if(xstretch^d>(xprobmax^d-xprobmin^d)*0.5d0) &
1620 call mpistop(" stretched grid part should not exceed full domain")
1621 dxfirst(1,^d)=xstretch^d*(1.0d0-qstretch_baselevel(^d)) &
1622 /(1.0d0-qstretch_baselevel(^d)**ipower)
1623 nstretchedblocks(1,^d)=nstretchedblocks_baselevel(^d)
1624 qstretch(1,^d)=qstretch_baselevel(^d)
1625 qstretch(0,^d)=qstretch(1,^d)**2
1626 dxfirst(0,^d)=dxfirst(1,^d)*(1.0d0+qstretch(1,^d))
1627 dxmid(1,^d)=dxfirst(1,^d)
1628 dxmid(0,^d)=dxfirst(1,^d)*2.0d0
1629 if(refine_max_level>1)then
1630 do ilev=2,refine_max_level
1631 nstretchedblocks(ilev,^d)=2*nstretchedblocks(ilev-1,^d)
1632 qstretch(ilev,^d)=dsqrt(qstretch(ilev-1,^d))
1633 dxfirst(ilev,^d)=dxfirst(ilev-1,^d) &
1634 /(1.0d0+dsqrt(qstretch(ilev-1,^d)))
1635 dxmid(ilev,^d)=dxmid(ilev-1,^d)/2.0d0
1636 enddo
1637 endif
1638 ! sanity check on total domain size:
1639 sizeuniformpart^d=dxfirst(1,^d) &
1640 *(domain_nx^d-nstretchedblocks_baselevel(^d)*block_nx^d)
1641 if(mype==0) then
1642 print *,'uniform part of size=',sizeuniformpart^d
1643 print *,'setting of domain is then=',2*xstretch^d+sizeuniformpart^d
1644 print *,'versus=',xprobmax^d-xprobmin^d
1645 endif
1646 if(dabs(xprobmax^d-xprobmin^d-2*xstretch^d-sizeuniformpart^d)>smalldouble) then
1647 call mpistop('mismatch in domain size!')
1648 endif
1649 endif \}
1650 dxfirst_1mq(0:refine_max_level,1:ndim)=dxfirst(0:refine_max_level,1:ndim) &
1651 /(1.0d0-qstretch(0:refine_max_level,1:ndim))
1652 end if
1653
1654 dx_vec = [{xprobmax^d-xprobmin^d|, }] / nx_vec
1655
1656 if (mype==0) then
1657 write(c_ndim, '(I1)') ^nd
1658 write(unitterm, '(A30,' // c_ndim // '(I0," "))') &
1659 ' Domain size (cells): ', nx_vec
1660 write(unitterm, '(A30,' // c_ndim // '(E9.3," "))') &
1661 ' Level one dx: ', dx_vec
1662 end if
1663
1664 if (any(dx_vec < smalldouble)) &
1665 call mpistop("Incorrect domain size (too small grid spacing)")
1666
1667 dx(:, 1) = dx_vec
1668
1669 if(sum(w_refine_weight(:))==0) w_refine_weight(1) = 1.d0
1670 if(dabs(sum(w_refine_weight(:))-1.d0)>smalldouble) then
1671 write(unitterm,*) "Sum of all elements in w_refine_weight be 1.d0"
1672 call mpistop("Reset w_refine_weight so the sum is 1.d0")
1673 end if
1674
1675 select case (typeboundspeed)
1676 case('Einfeldt')
1677 boundspeed=1
1678 case('cmaxmean')
1679 boundspeed=2
1680 case('cmaxleftright')
1681 boundspeed=3
1682 case('pvrs')
1683 boundspeed=4
1684 case default
1685 call mpistop("set typeboundspeed='Einfeldt' or 'cmaxmean' or 'cmaxleftright' or 'pvrs'")
1686 end select
1687
1688 if (mype==0) write(unitterm, '(A30)', advance='no') 'Refine estimation: '
1689
1690 select case (refine_criterion)
1691 case (0)
1692 if (mype==0) write(unitterm, '(A)') "user defined"
1693 case (1)
1694 if (mype==0) write(unitterm, '(A)') "relative error"
1695 case (2)
1696 if (mype==0) write(unitterm, '(A)') "Lohner's original scheme"
1697 case (3)
1698 if (mype==0) write(unitterm, '(A)') "Lohner's scheme"
1699 case default
1700 call mpistop("Unknown error estimator, change refine_criterion")
1701 end select
1702
1703 if (tfixgrid<bigdouble/2.0d0) then
1704 if(mype==0)print*,'Warning, at time=',tfixgrid,'the grid will be fixed'
1705 end if
1706 if (itfixgrid<biginteger/2) then
1707 if(mype==0)print*,'Warning, at iteration=',itfixgrid,'the grid will be fixed'
1708 end if
1709 if (ditregrid>1) then
1710 if(mype==0)print*,'Note, Grid is reconstructed once every',ditregrid,'iterations'
1711 end if
1712
1713
1714 do islice=1,nslices
1715 select case(slicedir(islice))
1716 {case(^d)
1717 if(slicecoord(islice)<xprobmin^d.or.slicecoord(islice)>xprobmax^d) &
1718 write(uniterr,*)'Warning in read_par_files: ', &
1719 'Slice ', islice, ' coordinate',slicecoord(islice),'out of bounds for dimension ',slicedir(islice)
1720 \}
1721 end select
1722 end do
1723
1724 if (mype==0) then
1725 write(unitterm, '(A30,A,A)') 'restart_from_file: ', ' ', trim(restart_from_file)
1726 write(unitterm, '(A30,L1)') 'converting: ', convert
1727 write(unitterm, '(A)') ''
1728 endif
1729
1730 deallocate(flux_scheme)
1731
1732 end subroutine read_par_files
1733
1734 !> Routine to find entries in a string
1735 subroutine get_fields_string(line, delims, n_max, fields, n_found, fully_read)
1736 !> The line from which we want to read
1737 character(len=*), intent(in) :: line
1738 !> A string with delimiters. For example delims = " ,'"""//char(9)
1739 character(len=*), intent(in) :: delims
1740 !> Maximum number of entries to read in
1741 integer, intent(in) :: n_max
1742 !> Number of entries found
1743 integer, intent(inout) :: n_found
1744 !> Fields in the strings
1745 character(len=*), intent(inout) :: fields(n_max)
1746 logical, intent(out), optional :: fully_read
1747
1748 integer :: ixs_start(n_max)
1749 integer :: ixs_end(n_max)
1750 integer :: ix, ix_prev
1751
1752 ix_prev = 0
1753 n_found = 0
1754
1755 do while (n_found < n_max)
1756 ! Find the starting point of the next entry (a non-delimiter value)
1757 ix = verify(line(ix_prev+1:), delims)
1758 if (ix == 0) exit
1759
1760 n_found = n_found + 1
1761 ixs_start(n_found) = ix_prev + ix ! This is the absolute position in 'line'
1762
1763 ! Get the end point of the current entry (next delimiter index minus one)
1764 ix = scan(line(ixs_start(n_found)+1:), delims) - 1
1765
1766 if (ix == -1) then ! If there is no last delimiter,
1767 ixs_end(n_found) = len(line) ! the end of the line is the endpoint
1768 else
1769 ixs_end(n_found) = ixs_start(n_found) + ix
1770 end if
1771
1772 fields(n_found) = line(ixs_start(n_found):ixs_end(n_found))
1773 ix_prev = ixs_end(n_found) ! We continue to search from here
1774 end do
1775
1776 if (present(fully_read)) then
1777 ix = verify(line(ix_prev+1:), delims)
1778 fully_read = (ix == 0) ! Are there only delimiters?
1779 end if
1780
1781 end subroutine get_fields_string
1782
1783 subroutine saveamrfile(ifile)
1784
1787 use mod_particles, only: write_particles_snapshot
1788 use mod_slice, only: write_slice
1789 use mod_collapse, only: write_collapsed
1791 integer:: ifile
1792
1793 select case (ifile)
1794 case (fileout_)
1795 ! Write .dat snapshot
1796 call write_snapshot()
1797
1798 ! Generate formatted output (e.g., VTK)
1800
1801 if(use_particles) call write_particles_snapshot()
1802
1804 case (fileslice_)
1805 call write_slice
1806 case (filecollapse_)
1807 call write_collapsed
1808 case (filelog_)
1809 select case (typefilelog)
1810 case ('default')
1811 call printlog_default
1812 case ('regression_test')
1814 case ('special')
1815 if (.not. associated(usr_print_log)) then
1816 call mpistop("usr_print_log not defined")
1817 else
1818 call usr_print_log()
1819 end if
1820 case default
1821 call mpistop("Error in SaveFile: Unknown typefilelog")
1822 end select
1823 case (fileanalysis_)
1824 if (associated(usr_write_analysis)) then
1825 call usr_write_analysis()
1826 end if
1827 case default
1828 write(*,*) 'No save method is defined for ifile=',ifile
1829 call mpistop("")
1830 end select
1831
1832 ! opedit: Flush stdout and stderr from time to time.
1833 flush(unit=unitterm)
1834
1835 end subroutine saveamrfile
1836
1837
1838 ! Check if a snapshot exists
1839 logical function snapshot_exists(ix)
1841 integer, intent(in) :: ix !< Index of snapshot
1842 character(len=std_len) :: filename
1843
1844 write(filename, "(a,i4.4,a)") trim(base_filename), ix, ".dat"
1845 inquire(file=trim(filename), exist=snapshot_exists)
1846 end function snapshot_exists
1847
1848 integer function get_snapshot_index(filename)
1849 character(len=*), intent(in) :: filename
1850 integer :: i
1851
1852 ! Try to parse index in restart_from_file string (e.g. basename0000.dat)
1853 i = len_trim(filename) - 7
1854 read(filename(i:i+3), '(I4)') get_snapshot_index
1855 end function get_snapshot_index
1856
1857
1858
1859 !> Write header for a snapshot
1860 !>
1861 !> If you edit the header, don't forget to update: snapshot_write_header(),
1862 !> snapshot_read_header(), doc/fileformat.md, tools/python/dat_reader.py
1863 subroutine snapshot_write_header(fh, offset_tree, offset_block)
1864 use mod_forest
1865 use mod_physics
1868 integer, intent(in) :: fh !< File handle
1869 integer(kind=MPI_OFFSET_KIND), intent(in) :: offset_tree !< Offset of tree info
1870 integer(kind=MPI_OFFSET_KIND), intent(in) :: offset_block !< Offset of block data
1871 call snapshot_write_header1(fh, offset_tree, offset_block, cons_wnames, nw)
1872 end subroutine snapshot_write_header
1873
1874 !> Read header for a snapshot
1875 !>
1876 !> If you edit the header, don't forget to update: snapshot_write_header(),
1877 !> snapshot_read_header(), doc/fileformat.md, tools/python/dat_reader.py
1878 subroutine snapshot_read_header(fh, offset_tree, offset_block)
1879 use mod_forest
1881 use mod_physics, only: physics_type
1882 integer, intent(in) :: fh !< File handle
1883 integer(MPI_OFFSET_KIND), intent(out) :: offset_tree !< Offset of tree info
1884 integer(MPI_OFFSET_KIND), intent(out) :: offset_block !< Offset of block data
1885
1886 double precision :: rbuf(ndim)
1887 double precision, allocatable :: params(:)
1888 integer :: i, version
1889 integer :: ibuf(ndim), iw
1890 integer :: er, n_par, tmp_int
1891 integer, dimension(MPI_STATUS_SIZE) :: st
1892 logical :: periodic(ndim)
1893 character(len=name_len), allocatable :: var_names(:), param_names(:)
1894 character(len=name_len) :: phys_name, geom_name
1895
1896 ! Version number
1897 call mpi_file_read(fh, version, 1, mpi_integer, st, er)
1898 if (all(compatible_versions /= version)) then
1899 call mpistop("Incompatible file version (maybe old format?)")
1900 end if
1901
1902 ! offset_tree
1903 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1904 offset_tree = ibuf(1)
1905
1906 ! offset_block
1907 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1908 offset_block = ibuf(1)
1909
1910 ! nw
1911 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1912 nw_found=ibuf(1)
1913 if (nw /= ibuf(1)) then
1914 write(*,*) "nw=",nw," and nw found in restart file=",ibuf(1)
1915 write(*,*) "Please be aware of changes in w at restart."
1916 !call mpistop("currently, changing nw at restart is not allowed")
1917 end if
1918
1919 ! ndir
1920 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1921 if (ibuf(1) /= ndir) then
1922 if (allow_ndir_change) then
1923 if (mype==0) then
1924 write(*,*) "WARNING: ndir in restart file = ",ibuf(1)," but current ndir = ",ndir
1925 write(*,*) "allow_ndir_change=T: loading anyway (block I/O is ndim-based)."
1926 write(*,*) "Ensure usr_transform_w maps the source vars into the right slots."
1927 end if
1928 else
1929 write(*,*) "ndir in restart file = ",ibuf(1)
1930 write(*,*) "ndir = ",ndir
1931 call mpistop("reset ndir to ndir in restart file (or set allow_ndir_change=T)")
1932 end if
1933 end if
1934
1935 ! ndim
1936 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1937 if (ibuf(1) /= ndim) then
1938 write(*,*) "ndim in restart file = ",ibuf(1)
1939 write(*,*) "ndim = ",ndim
1940 call mpistop("reset ndim to ndim in restart file")
1941 end if
1942
1943 ! levmax
1944 call mpi_file_read(fh, ibuf(1), 1, mpi_integer, st, er)
1945 if (ibuf(1) > refine_max_level) then
1946 write(*,*) "number of levels in restart file = ",ibuf(1)
1947 write(*,*) "refine_max_level = ",refine_max_level
1948 call mpistop("refine_max_level < num. levels in restart file")
1949 end if
1950
1951 ! nleafs
1952 call mpi_file_read(fh, nleafs, 1, mpi_integer, st, er)
1953
1954 ! nparents
1955 call mpi_file_read(fh, nparents, 1, mpi_integer, st, er)
1956
1957 ! it
1958 call mpi_file_read(fh, it, 1, mpi_integer, st, er)
1959
1960 ! global time
1961 call mpi_file_read(fh, global_time, 1, mpi_double_precision, st, er)
1962
1963 ! xprobmin^D
1964 call mpi_file_read(fh,rbuf(1:ndim),ndim,mpi_double_precision,st,er)
1965 if (maxval(abs(rbuf(1:ndim) - [ xprobmin^d ])) > 0) then
1966 write(*,*) "Error: xprobmin differs from restart data: ", rbuf(1:ndim)
1967 call mpistop("change xprobmin^D in par file")
1968 end if
1969
1970 ! xprobmax^D
1971 call mpi_file_read(fh,rbuf(1:ndim),ndim,mpi_double_precision,st,er)
1972 if (maxval(abs(rbuf(1:ndim) - [ xprobmax^d ])) > 0) then
1973 write(*,*) "Error: xprobmax differs from restart data: ", rbuf(1:ndim)
1974 call mpistop("change xprobmax^D in par file")
1975 end if
1976
1977 ! domain_nx^D
1978 call mpi_file_read(fh,ibuf(1:ndim), ndim, mpi_integer,st,er)
1979 if (any(ibuf(1:ndim) /= [ domain_nx^d ])) then
1980 write(*,*) "Error: mesh size differs from restart data: ", ibuf(1:ndim)
1981 call mpistop("change domain_nx^D in par file")
1982 end if
1983
1984 ! block_nx^D
1985 call mpi_file_read(fh,ibuf(1:ndim), ndim, mpi_integer,st,er)
1986 if (any(ibuf(1:ndim) /= [ block_nx^d ])) then
1987 write(*,*) "Error: block size differs from restart data:", ibuf(1:ndim)
1988 call mpistop("change block_nx^D in par file")
1989 end if
1990
1991 ! From version 5, read more info about the grid
1992 if (version > 4) then
1993 call mpi_file_read(fh, periodic, ndim, mpi_logical, st, er)
1994 if ({periodic(^d) .and. .not.periodb(^d) .or. .not.periodic(^d) .and. periodb(^d)| .or. }) &
1995 call mpistop("change in periodicity in par file")
1996
1997 call mpi_file_read(fh, geom_name, name_len, mpi_character, st, er)
1998
1999 if (geom_name /= geometry_name(1:name_len)) then
2000 if (allow_ndir_change) then
2001 if (mype==0) write(*,*) "WARNING: coordinates in data = ",trim(geom_name), &
2002 " vs current ",trim(geometry_name),"; allow_ndir_change=T (e.g. Cartesian_2D->2.5D), loading anyway."
2003 else
2004 write(*,*) "type of coordinates in data is: ", geom_name
2005 call mpistop("select the correct coordinates in mod_usr.t file")
2006 end if
2007 end if
2008
2009 call mpi_file_read(fh, stagger_mark_dat, 1, mpi_logical, st, er)
2010 if (stagger_grid .and. .not. stagger_mark_dat .or. .not.stagger_grid.and.stagger_mark_dat) then
2011 write(*,*) "Warning: stagger grid flag differs from restart data:", stagger_mark_dat
2012 !call mpistop("change parameter to use stagger grid")
2013 end if
2014 end if
2015
2016 ! From version 4 onwards, the later parts of the header must be present
2017 if (version > 3) then
2018 ! w_names (not used here)
2019 allocate(var_names(nw_found))
2020 do iw = 1, nw_found
2021 call mpi_file_read(fh, var_names(iw), name_len, mpi_character, st, er)
2022 end do
2023
2024 ! Physics related information
2025 call mpi_file_read(fh, phys_name, name_len, mpi_character, st, er)
2026
2027 if (phys_name /= physics_type) then
2028! call mpistop("Cannot restart with a different physics type")
2029 end if
2030
2031 call mpi_file_read(fh, n_par, 1, mpi_integer, st, er)
2032 allocate(params(n_par))
2033 allocate(param_names(n_par))
2034 call mpi_file_read(fh, params, n_par, mpi_double_precision, st, er)
2035 call mpi_file_read(fh, param_names, name_len * n_par, mpi_character, st, er)
2036
2037 ! Read snapshotnext etc. for restarting
2038 call mpi_file_read(fh, tmp_int, 1, mpi_integer, st, er)
2039
2040 ! Only set snapshotnext if the user hasn't specified it
2041 if (snapshotnext == -1) snapshotnext = tmp_int
2042
2043 call mpi_file_read(fh, tmp_int, 1, mpi_integer, st, er)
2044 if (slicenext == -1) slicenext = tmp_int
2045
2046 call mpi_file_read(fh, tmp_int, 1, mpi_integer, st, er)
2047 if (collapsenext == -1) collapsenext = tmp_int
2048 else
2049 ! Guess snapshotnext from file name if not set
2050 if (snapshotnext == -1) &
2052 ! Set slicenext and collapsenext if not set
2053 if (slicenext == -1) slicenext = 0
2054 if (collapsenext == -1) collapsenext = 0
2055 end if
2056
2057 ! Still used in convert
2059
2060 end subroutine snapshot_read_header
2061
2063 use mod_forest
2065 use mod_physics
2068
2069 double precision, allocatable :: w_buffer(:)
2070 integer :: file_handle, igrid, Morton_no, iwrite
2071 integer :: ipe, ix_buffer(2*ndim+1), n_values
2072 integer :: ixO^L, n_ghost(2*ndim)
2073 integer :: ixOs^L,n_values_stagger
2074 integer :: iorecvstatus(MPI_STATUS_SIZE)
2075 integer :: ioastatus(MPI_STATUS_SIZE)
2076 integer :: igrecvstatus(MPI_STATUS_SIZE)
2077 integer :: istatus(MPI_STATUS_SIZE)
2078 integer(kind=MPI_OFFSET_KIND) :: offset_tree_info
2079 integer(kind=MPI_OFFSET_KIND) :: offset_block_data
2080 integer(kind=MPI_OFFSET_KIND) :: offset_offsets
2081 integer, allocatable :: block_ig(:, :)
2082 integer, allocatable :: block_lvl(:)
2083 integer(kind=MPI_OFFSET_KIND), allocatable :: block_offset(:)
2084 type(tree_node), pointer :: pnode
2085
2086 call mpi_barrier(icomm, ierrmpi)
2087
2088 ! Allocate send/receive buffer
2089 n_values = count_ix(ixg^ll) * nw
2090 if(stagger_grid) then
2091 n_values = n_values + count_ix(ixgs^ll) * nws
2092 end if
2093 allocate(w_buffer(n_values))
2094
2095 ! Allocate arrays with information about grid blocks
2096 allocate(block_ig(ndim, nleafs))
2097 allocate(block_lvl(nleafs))
2098 allocate(block_offset(nleafs+1))
2099
2100 ! master processor
2101 if (mype==0) then
2102 call create_output_file(file_handle, snapshotnext, ".dat")
2103
2104 ! Don't know offsets yet, we will write header again later
2105 offset_tree_info = -1
2106 offset_block_data = -1
2107 call snapshot_write_header(file_handle, offset_tree_info, &
2108 offset_block_data)
2109
2110 call mpi_file_get_position(file_handle, offset_tree_info, ierrmpi)
2111
2112 call write_forest(file_handle)
2113
2114 ! Collect information about the spatial index (ig^D) and refinement level
2115 ! of leaves
2116 do morton_no = morton_start(0), morton_stop(npe-1)
2117 igrid = sfc(1, morton_no)
2118 ipe = sfc(2, morton_no)
2119 pnode => igrid_to_node(igrid, ipe)%node
2120
2121 block_ig(:, morton_no) = [ pnode%ig^d ]
2122 block_lvl(morton_no) = pnode%level
2123 block_offset(morton_no) = 0 ! Will be determined later
2124 end do
2125
2126 call mpi_file_write(file_handle, block_lvl, size(block_lvl), &
2127 mpi_integer, istatus, ierrmpi)
2128
2129 call mpi_file_write(file_handle, block_ig, size(block_ig), &
2130 mpi_integer, istatus, ierrmpi)
2131
2132 ! Block offsets are currently unknown, but will be overwritten later
2133 call mpi_file_get_position(file_handle, offset_offsets, ierrmpi)
2134 call mpi_file_write(file_handle, block_offset(1:nleafs), nleafs, &
2135 mpi_offset, istatus, ierrmpi)
2136
2137 call mpi_file_get_position(file_handle, offset_block_data, ierrmpi)
2138
2139 ! Check whether data was written as expected
2140 if (offset_block_data - offset_tree_info /= &
2141 (nleafs + nparents) * size_logical + &
2142 nleafs * ((1+ndim) * size_int + 2 * size_int)) then
2143 if (mype == 0) then
2144 print *, "Warning: MPI_OFFSET type /= 8 bytes"
2145 print *, "This *could* cause problems when reading .dat files"
2146 end if
2147 end if
2148
2149 block_offset(1) = offset_block_data
2150 iwrite = 0
2151 end if
2152
2153 do morton_no=morton_start(mype), morton_stop(mype)
2154 igrid = sfc_to_igrid(morton_no)
2155 itag = morton_no
2156
2157 call block_shape_io(igrid, n_ghost, ixo^l, n_values)
2158 if(stagger_grid) then
2159 w_buffer(1:n_values) = pack(ps(igrid)%w(ixo^s, 1:nw), .true.)
2160 {ixosmin^d = ixomin^d -1\}
2161 {ixosmax^d = ixomax^d \}
2162 n_values_stagger= count_ix(ixos^l)*nws
2163 w_buffer(n_values+1:n_values+n_values_stagger) = pack(ps(igrid)%ws(ixos^s, 1:nws), .true.)
2164 n_values=n_values+n_values_stagger
2165 else
2166 w_buffer(1:n_values) = pack(ps(igrid)%w(ixo^s, 1:nw), .true.)
2167 end if
2168 ix_buffer(1) = n_values
2169 ix_buffer(2:) = n_ghost
2170
2171 if (mype /= 0) then
2172 call mpi_send(ix_buffer, 2*ndim+1, &
2173 mpi_integer, 0, itag, icomm, ierrmpi)
2174 call mpi_send(w_buffer, n_values, &
2175 mpi_double_precision, 0, itag, icomm, ierrmpi)
2176 else
2177 iwrite = iwrite+1
2178 call mpi_file_write(file_handle, ix_buffer(2:), &
2179 2*ndim, mpi_integer, istatus, ierrmpi)
2180 call mpi_file_write(file_handle, w_buffer, &
2181 n_values, mpi_double_precision, istatus, ierrmpi)
2182
2183 ! Set offset of next block
2184 block_offset(iwrite+1) = block_offset(iwrite) + &
2185 int(n_values, mpi_offset_kind) * size_double + &
2186 2 * ndim * size_int
2187 end if
2188 end do
2189
2190 ! Write data communicated from other processors
2191 if (mype == 0) then
2192 do ipe = 1, npe-1
2193 do morton_no=morton_start(ipe), morton_stop(ipe)
2194 iwrite=iwrite+1
2195 itag=morton_no
2196
2197 call mpi_recv(ix_buffer, 2*ndim+1, mpi_integer, ipe, itag, icomm,&
2198 igrecvstatus, ierrmpi)
2199 n_values = ix_buffer(1)
2200
2201 call mpi_recv(w_buffer, n_values, mpi_double_precision,&
2202 ipe, itag, icomm, iorecvstatus, ierrmpi)
2203
2204 call mpi_file_write(file_handle, ix_buffer(2:), &
2205 2*ndim, mpi_integer, istatus, ierrmpi)
2206 call mpi_file_write(file_handle, w_buffer, &
2207 n_values, mpi_double_precision, istatus, ierrmpi)
2208
2209 ! Set offset of next block
2210 block_offset(iwrite+1) = block_offset(iwrite) + &
2211 int(n_values, mpi_offset_kind) * size_double + &
2212 2 * ndim * size_int
2213 end do
2214 end do
2215
2216 ! Write block offsets (now we know them)
2217 call mpi_file_seek(file_handle, offset_offsets, mpi_seek_set, ierrmpi)
2218 call mpi_file_write(file_handle, block_offset(1:nleafs), nleafs, &
2219 mpi_offset, istatus, ierrmpi)
2220
2221 ! Write header again, now with correct offsets
2222 call mpi_file_seek(file_handle, 0_mpi_offset_kind, mpi_seek_set, ierrmpi)
2223 call snapshot_write_header(file_handle, offset_tree_info, &
2224 offset_block_data)
2225
2226 call mpi_file_close(file_handle, ierrmpi)
2227 end if
2228
2229 call mpi_barrier(icomm, ierrmpi)
2230 end subroutine write_snapshot
2231
2232 !> Enable the debug field dump: register n named slots. Capture fields with
2233 !> ps(igrid)%wdebug(...,islot) anywhere in a block loop (lazy per-block
2234 !> allocation at the capture site), then flush with save_wdebug.
2235 subroutine debug_alloc(n, names)
2237 integer, intent(in) :: n
2238 character(len=*), intent(in) :: names(n)
2239 integer :: i
2240 n_wdebug = n
2241 if (allocated(wdebug_names)) deallocate(wdebug_names)
2242 allocate(wdebug_names(n))
2243 do i = 1, n
2244 wdebug_names(i) = trim(adjustl(names(i)))
2245 end do
2246 wdebug_on = .true.
2247 end subroutine debug_alloc
2248
2249 !> Flush ps(:)%wdebug to a standalone cell-centred .dat (no staggered),
2250 !> readable by the standard AMRVAC .dat readers. Collective; call at a
2251 !> barrier-safe point (end of a step), NOT inside a block loop.
2252 subroutine save_wdebug(suffix)
2253 use mod_forest
2255 use mod_physics
2258 character(len=*), intent(in) :: suffix
2259 logical :: stagger_save
2260 double precision, allocatable :: w_buffer(:)
2261 integer :: file_handle, igrid, Morton_no, iwrite
2262 integer :: ipe, ix_buffer(2*ndim+1), n_values
2263 integer :: ixO^L, n_ghost(2*ndim)
2264 integer :: iorecvstatus(MPI_STATUS_SIZE)
2265 integer :: igrecvstatus(MPI_STATUS_SIZE)
2266 integer :: istatus(MPI_STATUS_SIZE)
2267 integer(kind=MPI_OFFSET_KIND) :: offset_tree_info, offset_block_data, offset_offsets
2268 integer, allocatable :: block_ig(:, :), block_lvl(:)
2269 integer(kind=MPI_OFFSET_KIND), allocatable :: block_offset(:)
2270 type(tree_node), pointer :: pnode
2271
2272 if (n_wdebug <= 0) return
2273 call mpi_barrier(icomm, ierrmpi)
2274
2275 n_values = count_ix(ixg^ll) * n_wdebug
2276 allocate(w_buffer(n_values))
2277 allocate(block_ig(ndim, nleafs), block_lvl(nleafs), block_offset(nleafs+1))
2278
2279 if (mype == 0) then
2280 call create_output_file(file_handle, it, ".dat", trim(suffix))
2281 offset_tree_info = -1; offset_block_data = -1
2282 stagger_save = stagger_grid; stagger_grid = .false.
2283 call snapshot_write_header1(file_handle, offset_tree_info, offset_block_data, wdebug_names, n_wdebug)
2284 stagger_grid = stagger_save
2285 call mpi_file_get_position(file_handle, offset_tree_info, ierrmpi)
2286 call write_forest(file_handle)
2287 do morton_no = morton_start(0), morton_stop(npe-1)
2288 igrid = sfc(1, morton_no); ipe = sfc(2, morton_no)
2289 pnode => igrid_to_node(igrid, ipe)%node
2290 block_ig(:, morton_no) = [ pnode%ig^d ]
2291 block_lvl(morton_no) = pnode%level
2292 block_offset(morton_no) = 0
2293 end do
2294 call mpi_file_write(file_handle, block_lvl, size(block_lvl), mpi_integer, istatus, ierrmpi)
2295 call mpi_file_write(file_handle, block_ig, size(block_ig), mpi_integer, istatus, ierrmpi)
2296 call mpi_file_get_position(file_handle, offset_offsets, ierrmpi)
2297 call mpi_file_write(file_handle, block_offset(1:nleafs), nleafs, mpi_offset, istatus, ierrmpi)
2298 call mpi_file_get_position(file_handle, offset_block_data, ierrmpi)
2299 block_offset(1) = offset_block_data
2300 iwrite = 0
2301 end if
2302
2303 do morton_no = morton_start(mype), morton_stop(mype)
2304 igrid = sfc_to_igrid(morton_no); itag = morton_no
2305 call block_shape_io(igrid, n_ghost, ixo^l, n_values)
2306 n_values = count_ix(ixo^l) * n_wdebug
2307 if (allocated(ps(igrid)%wdebug)) then
2308 w_buffer(1:n_values) = pack(ps(igrid)%wdebug(ixo^s, 1:n_wdebug), .true.)
2309 else
2310 w_buffer(1:n_values) = 0.0d0
2311 end if
2312 ix_buffer(1) = n_values
2313 ix_buffer(2:) = n_ghost
2314 if (mype /= 0) then
2315 call mpi_send(ix_buffer, 2*ndim+1, mpi_integer, 0, itag, icomm, ierrmpi)
2316 call mpi_send(w_buffer, n_values, mpi_double_precision, 0, itag, icomm, ierrmpi)
2317 else
2318 iwrite = iwrite+1
2319 call mpi_file_write(file_handle, ix_buffer(2:), 2*ndim, mpi_integer, istatus, ierrmpi)
2320 call mpi_file_write(file_handle, w_buffer, n_values, mpi_double_precision, istatus, ierrmpi)
2321 block_offset(iwrite+1) = block_offset(iwrite) + &
2322 int(n_values, mpi_offset_kind) * size_double + 2 * ndim * size_int
2323 end if
2324 end do
2325
2326 if (mype == 0) then
2327 do ipe = 1, npe-1
2328 do morton_no = morton_start(ipe), morton_stop(ipe)
2329 iwrite = iwrite+1; itag = morton_no
2330 call mpi_recv(ix_buffer, 2*ndim+1, mpi_integer, ipe, itag, icomm, igrecvstatus, ierrmpi)
2331 n_values = ix_buffer(1)
2332 call mpi_recv(w_buffer, n_values, mpi_double_precision, ipe, itag, icomm, iorecvstatus, ierrmpi)
2333 call mpi_file_write(file_handle, ix_buffer(2:), 2*ndim, mpi_integer, istatus, ierrmpi)
2334 call mpi_file_write(file_handle, w_buffer, n_values, mpi_double_precision, istatus, ierrmpi)
2335 block_offset(iwrite+1) = block_offset(iwrite) + &
2336 int(n_values, mpi_offset_kind) * size_double + 2 * ndim * size_int
2337 end do
2338 end do
2339 call mpi_file_seek(file_handle, offset_offsets, mpi_seek_set, ierrmpi)
2340 call mpi_file_write(file_handle, block_offset(1:nleafs), nleafs, mpi_offset, istatus, ierrmpi)
2341 call mpi_file_seek(file_handle, 0_mpi_offset_kind, mpi_seek_set, ierrmpi)
2342 stagger_save = stagger_grid; stagger_grid = .false.
2343 call snapshot_write_header1(file_handle, offset_tree_info, offset_block_data, wdebug_names, n_wdebug)
2344 stagger_grid = stagger_save
2345 call mpi_file_close(file_handle, ierrmpi)
2346 end if
2347 deallocate(w_buffer, block_ig, block_lvl, block_offset)
2348 call mpi_barrier(icomm, ierrmpi)
2349 if (mype==0) write(*,*) 'save_wdebug: wrote ', n_wdebug, ' field(s) suffix=', trim(suffix), ' it=', it
2350 end subroutine save_wdebug
2351
2352
2353 !> Routine to read in snapshots (.dat files). When it cannot recognize the
2354 !> file version, it will automatically try the 'old' reader.
2355 subroutine read_snapshot
2358 use mod_forest
2362
2363 double precision :: ws(ixGs^T,1:ndim)
2364 double precision, allocatable :: w_buffer(:)
2365 double precision, dimension(:^D&,:), allocatable :: w
2366 integer :: ix_buffer(2*ndim+1), n_values, n_values_stagger
2367 integer :: ixO^L, ixOs^L
2368 integer :: file_handle, amode, igrid, Morton_no, iread
2369 integer :: istatus(MPI_STATUS_SIZE)
2370 integer :: iorecvstatus(MPI_STATUS_SIZE)
2371 integer :: ipe,inrecv,nrecv, file_version
2372 integer(MPI_OFFSET_KIND) :: offset_tree_info
2373 integer(MPI_OFFSET_KIND) :: offset_block_data
2374 logical :: fexist
2375
2376 if (mype==0) then
2377 inquire(file=trim(restart_from_file), exist=fexist)
2378 if (.not.fexist) call mpistop(trim(restart_from_file)//" not found!")
2379
2380 call mpi_file_open(mpi_comm_self,restart_from_file,mpi_mode_rdonly, &
2381 mpi_info_null,file_handle,ierrmpi)
2382 call mpi_file_read(file_handle, file_version, 1, mpi_integer, &
2383 istatus, ierrmpi)
2384 end if
2385
2386 call mpi_bcast(file_version,1,mpi_integer,0,icomm,ierrmpi)
2387
2388 if (all(compatible_versions /= file_version)) then
2389 if (mype == 0) print *, "Unknown version, trying old snapshot reader..."
2390 call mpi_file_close(file_handle,ierrmpi)
2391 call read_snapshot_old()
2392
2393 ! Guess snapshotnext from file name if not set
2394 if (snapshotnext == -1) &
2396 ! Set slicenext and collapsenext if not set
2397 if (slicenext == -1) slicenext = 0
2398 if (collapsenext == -1) collapsenext = 0
2399
2400 ! Still used in convert
2402
2403 return ! Leave this routine
2404 else if (mype == 0) then
2405 call mpi_file_seek(file_handle, 0_mpi_offset_kind, mpi_seek_set, ierrmpi)
2406 call snapshot_read_header(file_handle, offset_tree_info, &
2407 offset_block_data)
2408 end if
2409
2410 ! Share information about restart file
2411 call mpi_bcast(nw_found,1,mpi_integer,0,icomm,ierrmpi)
2412 call mpi_bcast(nleafs,1,mpi_integer,0,icomm,ierrmpi)
2413 call mpi_bcast(nparents,1,mpi_integer,0,icomm,ierrmpi)
2414 call mpi_bcast(it,1,mpi_integer,0,icomm,ierrmpi)
2415 call mpi_bcast(global_time,1,mpi_double_precision,0,icomm,ierrmpi)
2416
2417 call mpi_bcast(snapshotnext,1,mpi_integer,0,icomm,ierrmpi)
2418 call mpi_bcast(slicenext,1,mpi_integer,0,icomm,ierrmpi)
2419 call mpi_bcast(collapsenext,1,mpi_integer,0,icomm,ierrmpi)
2420 call mpi_bcast(stagger_mark_dat,1,mpi_logical,0,icomm,ierrmpi)
2421
2422 ! Allocate send/receive buffer
2423 n_values = count_ix(ixg^ll) * nw_found
2424 if(stagger_mark_dat) then
2425 n_values = n_values + count_ix(ixgs^ll) * nws
2426 end if
2427 allocate(w_buffer(n_values))
2428 allocate(w(ixg^t,1:nw_found))
2429
2431
2432 if (mype == 0) then
2433 call mpi_file_seek(file_handle, offset_tree_info, &
2434 mpi_seek_set, ierrmpi)
2435 end if
2436
2437 call read_forest(file_handle)
2438
2439 do morton_no=morton_start(mype),morton_stop(mype)
2440 igrid=sfc_to_igrid(morton_no)
2441 call alloc_node(igrid)
2442 end do
2443
2444 if (mype==0) then
2445 call mpi_file_seek(file_handle, offset_block_data, mpi_seek_set, ierrmpi)
2446
2447 iread = 0
2448 do ipe = 0, npe-1
2449 do morton_no=morton_start(ipe),morton_stop(ipe)
2450 iread=iread+1
2451 itag=morton_no
2452
2453 call mpi_file_read(file_handle,ix_buffer(1:2*ndim), 2*ndim, &
2454 mpi_integer, istatus,ierrmpi)
2455
2456 ! Construct ixO^L array from number of ghost cells
2457 {ixomin^d = ixmlo^d - ix_buffer(^d)\}
2458 {ixomax^d = ixmhi^d + ix_buffer(ndim+^d)\}
2459 n_values = count_ix(ixo^l) * nw_found
2460 if(stagger_mark_dat) then
2461 {ixosmin^d = ixomin^d - 1\}
2462 {ixosmax^d = ixomax^d\}
2463 n_values_stagger = n_values
2464 n_values = n_values + count_ix(ixos^l) * nws
2465 end if
2466
2467 call mpi_file_read(file_handle, w_buffer, n_values, &
2468 mpi_double_precision, istatus, ierrmpi)
2469
2470 if (mype == ipe) then ! Root task
2471 igrid=sfc_to_igrid(morton_no)
2472 block=>ps(igrid)
2473 if(stagger_mark_dat) then
2474 w(ixo^s, 1:nw_found) = reshape(w_buffer(1:n_values_stagger), &
2475 shape(w(ixo^s, 1:nw_found)))
2476 if(stagger_grid) &
2477 ps(igrid)%ws(ixos^s,1:nws)=reshape(w_buffer(n_values_stagger+1:n_values), &
2478 shape(ws(ixos^s, 1:nws)))
2479 else
2480 w(ixo^s, 1:nw_found) = reshape(w_buffer(1:n_values), &
2481 shape(w(ixo^s, 1:nw_found)))
2482 end if
2483 if (nw_found<nw) then
2484 if (associated(usr_transform_w)) then
2485 call usr_transform_w(ixg^ll,ixm^ll,nw_found,w,ps(igrid)%x,ps(igrid)%w)
2486 else
2487 ps(igrid)%w(ixo^s,1:nw_found)=w(ixo^s,1:nw_found)
2488 end if
2489 else if (nw_found>nw) then
2490 if (associated(usr_transform_w)) then
2491 call usr_transform_w(ixg^ll,ixm^ll,nw_found,w,ps(igrid)%x,ps(igrid)%w)
2492 else
2493 ps(igrid)%w(ixo^s,1:nw)=w(ixo^s,1:nw)
2494 end if
2495 else
2496 ps(igrid)%w(ixo^s,1:nw)=w(ixo^s,1:nw)
2497 end if
2498 else
2499 call mpi_send([ ixo^l, n_values ], 2*ndim+1, &
2500 mpi_integer, ipe, itag, icomm, ierrmpi)
2501 call mpi_send(w_buffer, n_values, &
2502 mpi_double_precision, ipe, itag, icomm, ierrmpi)
2503 end if
2504 end do
2505 end do
2506
2507 call mpi_file_close(file_handle,ierrmpi)
2508
2509 else ! mype > 0
2510
2511 do morton_no=morton_start(mype),morton_stop(mype)
2512 igrid=sfc_to_igrid(morton_no)
2513 block=>ps(igrid)
2514 itag=morton_no
2515
2516 call mpi_recv(ix_buffer, 2*ndim+1, mpi_integer, 0, itag, icomm,&
2517 iorecvstatus, ierrmpi)
2518 {ixomin^d = ix_buffer(^d)\}
2519 {ixomax^d = ix_buffer(ndim+^d)\}
2520 n_values = ix_buffer(2*ndim+1)
2521
2522 call mpi_recv(w_buffer, n_values, mpi_double_precision,&
2523 0, itag, icomm, iorecvstatus, ierrmpi)
2524
2525 if(stagger_mark_dat) then
2526 n_values_stagger = count_ix(ixo^l) * nw_found
2527 {ixosmin^d = ixomin^d - 1\}
2528 {ixosmax^d = ixomax^d\}
2529 w(ixo^s, 1:nw_found) = reshape(w_buffer(1:n_values_stagger), &
2530 shape(w(ixo^s, 1:nw_found)))
2531 if(stagger_grid) &
2532 ps(igrid)%ws(ixos^s,1:nws)=reshape(w_buffer(n_values_stagger+1:n_values), &
2533 shape(ws(ixos^s, 1:nws)))
2534 else
2535 w(ixo^s, 1:nw_found) = reshape(w_buffer(1:n_values), &
2536 shape(w(ixo^s, 1:nw_found)))
2537 end if
2538 if (nw_found<nw) then
2539 if (associated(usr_transform_w)) then
2540 call usr_transform_w(ixg^ll,ixm^ll,nw_found,w,ps(igrid)%x,ps(igrid)%w)
2541 else
2542 ps(igrid)%w(ixo^s,1:nw_found)=w(ixo^s,1:nw_found)
2543 end if
2544 else if (nw_found>nw) then
2545 if (associated(usr_transform_w)) then
2546 call usr_transform_w(ixg^ll,ixm^ll,nw_found,w,ps(igrid)%x,ps(igrid)%w)
2547 else
2548 ps(igrid)%w(ixo^s,1:nw)=w(ixo^s,1:nw)
2549 end if
2550 else
2551 ps(igrid)%w(ixo^s,1:nw)=w(ixo^s,1:nw)
2552 end if
2553 end do
2554 end if
2555
2556 call mpi_barrier(icomm,ierrmpi)
2557
2558 end subroutine read_snapshot
2559
2561 use mod_forest
2565
2566 double precision :: wio(ixG^T,1:nw)
2567 double precision :: eqpar_dummy(100)
2568 integer :: fh, igrid, Morton_no, iread
2569 integer :: levmaxini, ndimini, ndirini
2570 integer :: nwini, neqparini, nxini^D
2571 integer(kind=MPI_OFFSET_KIND) :: offset
2572 integer :: istatus(MPI_STATUS_SIZE)
2573 integer, allocatable :: iorecvstatus(:,:)
2574 integer :: ipe,inrecv,nrecv
2575 integer :: sendini(7+^ND)
2576 logical :: fexist
2577 character(len=80) :: filename
2578
2579 if (mype==0) then
2580 call mpi_file_open(mpi_comm_self,trim(restart_from_file), &
2581 mpi_mode_rdonly,mpi_info_null,fh,ierrmpi)
2582
2583 offset=-int(7*size_int+size_double,kind=mpi_offset_kind)
2584 call mpi_file_seek(fh,offset,mpi_seek_end,ierrmpi)
2585
2586 call mpi_file_read(fh,nleafs,1,mpi_integer,istatus,ierrmpi)
2588 call mpi_file_read(fh,levmaxini,1,mpi_integer,istatus,ierrmpi)
2589 call mpi_file_read(fh,ndimini,1,mpi_integer,istatus,ierrmpi)
2590 call mpi_file_read(fh,ndirini,1,mpi_integer,istatus,ierrmpi)
2591 call mpi_file_read(fh,nwini,1,mpi_integer,istatus,ierrmpi)
2592 call mpi_file_read(fh,neqparini,1,mpi_integer,istatus,ierrmpi)
2593 call mpi_file_read(fh,it,1,mpi_integer,istatus,ierrmpi)
2594 call mpi_file_read(fh,global_time,1,mpi_double_precision,istatus,ierrmpi)
2595
2596 ! check if settings are suitable for restart
2597 if (levmaxini>refine_max_level) then
2598 write(*,*) "number of levels in restart file = ",levmaxini
2599 write(*,*) "refine_max_level = ",refine_max_level
2600 call mpistop("refine_max_level < number of levels in restart file")
2601 end if
2602 if (ndimini/=ndim) then
2603 write(*,*) "ndim in restart file = ",ndimini
2604 write(*,*) "ndim = ",ndim
2605 call mpistop("reset ndim to ndim in restart file")
2606 end if
2607 if (ndirini/=ndir) then
2608 write(*,*) "ndir in restart file = ",ndirini
2609 write(*,*) "ndir = ",ndir
2610 call mpistop("reset ndir to ndir in restart file")
2611 end if
2612 if (nw/=nwini) then
2613 write(*,*) "nw=",nw," and nw in restart file=",nwini
2614 call mpistop("currently, changing nw at restart is not allowed")
2615 end if
2616
2617 offset=offset-int(ndimini*size_int+neqparini*size_double,kind=mpi_offset_kind)
2618 call mpi_file_seek(fh,offset,mpi_seek_end,ierrmpi)
2619
2620 {call mpi_file_read(fh,nxini^d,1,mpi_integer,istatus,ierrmpi)\}
2621 if (ixghi^d/=nxini^d+2*nghostcells|.or.) then
2622 write(*,*) "Error: reset resolution to ",nxini^d+2*nghostcells
2623 call mpistop("change with setamrvac")
2624 end if
2625
2626 call mpi_file_read(fh,eqpar_dummy,neqparini, &
2627 mpi_double_precision,istatus,ierrmpi)
2628 end if
2629
2630 ! broadcast the global parameters first
2631 if (npe>1) then
2632 if (mype==0) then
2633 sendini=(/nleafs,levmaxini,ndimini,ndirini,nwini,neqparini,it ,^d&nxini^d /)
2634 end if
2635 call mpi_bcast(sendini,7+^nd,mpi_integer,0,icomm,ierrmpi)
2636 nleafs=sendini(1);levmaxini=sendini(2);ndimini=sendini(3);
2637 ndirini=sendini(4);nwini=sendini(5);
2638 neqparini=sendini(6);it=sendini(7);
2639 nxini^d=sendini(7+^d);
2641 call mpi_bcast(global_time,1,mpi_double_precision,0,icomm,ierrmpi)
2642 end if
2643
2644 if (mype == 0) then
2645 offset = int(size_block_io,kind=mpi_offset_kind) * &
2646 int(nleafs,kind=mpi_offset_kind)
2647 call mpi_file_seek(fh,offset,mpi_seek_set,ierrmpi)
2648 end if
2649
2650 call read_forest(fh)
2651
2652 do morton_no=morton_start(mype),morton_stop(mype)
2653 igrid=sfc_to_igrid(morton_no)
2654 call alloc_node(igrid)
2655 end do
2656
2657 if (mype==0)then
2658 iread=0
2659
2660 do morton_no=morton_start(0),morton_stop(0)
2661 igrid=sfc_to_igrid(morton_no)
2662 iread=iread+1
2663 offset=int(size_block_io,kind=mpi_offset_kind) &
2664 *int(morton_no-1,kind=mpi_offset_kind)
2665 call mpi_file_read_at(fh,offset,ps(igrid)%w,1,type_block_io, &
2666 istatus,ierrmpi)
2667 end do
2668 if (npe>1) then
2669 do ipe=1,npe-1
2670 do morton_no=morton_start(ipe),morton_stop(ipe)
2671 iread=iread+1
2672 itag=morton_no
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,wio,1,type_block_io,&
2676 istatus,ierrmpi)
2677 call mpi_send(wio,1,type_block_io,ipe,itag,icomm,ierrmpi)
2678 end do
2679 end do
2680 end if
2681 call mpi_file_close(fh,ierrmpi)
2682 else
2683 nrecv=(morton_stop(mype)-morton_start(mype)+1)
2684 allocate(iorecvstatus(mpi_status_size,nrecv))
2685 inrecv=0
2686 do morton_no=morton_start(mype),morton_stop(mype)
2687 igrid=sfc_to_igrid(morton_no)
2688 itag=morton_no
2689 inrecv=inrecv+1
2690 call mpi_recv(ps(igrid)%w,1,type_block_io,0,itag,icomm,&
2691 iorecvstatus(:,inrecv),ierrmpi)
2692 end do
2693 deallocate(iorecvstatus)
2694 end if
2695
2696 call mpi_barrier(icomm,ierrmpi)
2697
2698 end subroutine read_snapshot_old
2699
2700 !> Write volume-averaged values and other information to the log file
2702
2703 use mod_timing
2706
2707 double precision :: dtTimeLast, now, cellupdatesPerSecond
2708 double precision :: activeBlocksPerCore, wctPerCodeTime, timeToFinish
2709 double precision :: wmean(1:nw), total_volume
2710 double precision :: volume_coverage(refine_max_level)
2711 integer :: i, iw, level
2712 integer :: nx^D, nc, ncells, dit
2713 integer :: amode, istatus(MPI_STATUS_SIZE)
2714 integer, parameter :: my_unit = 20
2715 logical, save :: opened = .false.
2716 logical :: fileopen
2717 character(len=40) :: fmt_string
2718 character(len=80) :: filename
2719 character(len=2048) :: line
2720
2721 ! Compute the volume-average of w**1 = w
2722 call get_volume_average(1, wmean, total_volume)
2723
2724 ! Compute the volume coverage
2725 call get_volume_coverage(volume_coverage)
2726
2727 if (mype == 0) then
2728
2729 ! To compute cell updates per second, we do the following:
2730 nx^d=ixmhi^d-ixmlo^d+1;
2731 nc={nx^d*}
2732 ncells = nc * nleafs_active
2733
2734 ! assumes the number of active leafs haven't changed since last compute.
2735 now = mpi_wtime()
2736 dit = it - ittimelast
2737 dttimelast = now - timelast
2738 ittimelast = it
2739 timelast = now
2740 cellupdatespersecond = dble(ncells) * dble(nstep) * &
2741 dble(dit) / (dttimelast * dble(npe))
2742
2743 ! blocks per core:
2744 activeblockspercore = dble(nleafs_active) / dble(npe)
2745
2746 ! Wall clock time per code time unit in seconds:
2747 wctpercodetime = dttimelast / max(dit * dt, epsilon(1.0d0))
2748
2749 ! Wall clock time to finish in hours:
2750 timetofinish = (time_max - global_time) * wctpercodetime / 3600.0d0
2751
2752 ! On first entry, open the file and generate the header
2753 if (.not. opened) then
2754
2755 filename = trim(base_filename) // ".log"
2756
2757 ! Delete the log when not doing a restart run
2758 if (restart_from_file == undefined) then
2759 open(unit=my_unit,file=trim(filename),status='replace')
2760 close(my_unit, status='delete')
2761 end if
2762
2763 amode = ior(mpi_mode_create,mpi_mode_wronly)
2764 amode = ior(amode,mpi_mode_append)
2765
2766 call mpi_file_open(mpi_comm_self, filename, amode, &
2767 mpi_info_null, log_fh, ierrmpi)
2768
2769 opened = .true.
2770
2771 ! Start of file headern
2772 line = "it global_time dt"
2773 do level=1,nw
2774 i = len_trim(line) + 2
2775 write(line(i:),"(a,a)") trim(cons_wnames(level)), " "
2776 end do
2777
2778 ! Volume coverage per level
2779 do level = 1, refine_max_level
2780 i = len_trim(line) + 2
2781 write(line(i:), "(a,i0)") "c", level
2782 end do
2783
2784 ! Cell counts per level
2785 do level=1,refine_max_level
2786 i = len_trim(line) + 2
2787 write(line(i:), "(a,i0)") "n", level
2788 end do
2789
2790 ! Rest of file header
2791 line = trim(line) // " | Xload Xmemory 'Cell_Updates /second/core'"
2792 line = trim(line) // " 'Active_Blocks/Core' 'Wct Per Code Time [s]'"
2793 line = trim(line) // " 'TimeToFinish [hrs]'"
2794
2795 ! Only write header if not restarting
2796 if (restart_from_file == undefined .or. reset_time) then
2797 call mpi_file_write(log_fh, trim(line) // new_line('a'), &
2798 len_trim(line)+1, mpi_character, istatus, ierrmpi)
2799 end if
2800 end if
2801
2802 ! Construct the line to be added to the log
2803
2804 fmt_string = '(' // fmt_i // ',2' // fmt_r // ')'
2805 write(line, fmt_string) it, global_time, dt
2806 i = len_trim(line) + 2
2807
2808 write(fmt_string, '(a,i0,a)') '(', nw, fmt_r // ')'
2809 write(line(i:), fmt_string) wmean(1:nw)
2810 i = len_trim(line) + 2
2811
2812 write(fmt_string, '(a,i0,a)') '(', refine_max_level, fmt_r // ')'
2813 write(line(i:), fmt_string) volume_coverage(1:refine_max_level)
2814 i = len_trim(line) + 2
2815
2816 write(fmt_string, '(a,i0,a)') '(', refine_max_level, fmt_i // ')'
2817 write(line(i:), fmt_string) nleafs_level(1:refine_max_level)
2818 i = len_trim(line) + 2
2819
2820 fmt_string = '(a,6' // fmt_r2 // ')'
2821 write(line(i:), fmt_string) '| ', xload, xmemory, cellupdatespersecond, &
2822 activeblockspercore, wctpercodetime, timetofinish
2823
2824 call mpi_file_write(log_fh, trim(line) // new_line('a') , &
2825 len_trim(line)+1, mpi_character, istatus, ierrmpi)
2826 end if
2827
2828 end subroutine printlog_default
2829
2830 !> Print a log that can be used to check whether the code still produces the
2831 !> same output (regression test)
2834
2835 double precision :: modes(nw, 2), volume
2836 integer, parameter :: n_modes = 2
2837 integer :: power
2838 integer :: amode, istatus(MPI_STATUS_SIZE)
2839 logical, save :: file_open = .false.
2840 character(len=40) :: fmt_string
2841 character(len=2048) :: line
2842 character(len=80) :: filename
2843
2844 do power = 1, n_modes
2845 call get_volume_average(power, modes(:, power), volume)
2846 end do
2847
2848 if (mype == 0) then
2849 if (.not. file_open) then
2850 filename = trim(base_filename) // ".log"
2851 amode = ior(mpi_mode_create,mpi_mode_wronly)
2852 amode = ior(amode,mpi_mode_append)
2853
2854 call mpi_file_open(mpi_comm_self, filename, amode, &
2855 mpi_info_null, log_fh, ierrmpi)
2856 file_open = .true.
2857
2858 line= "# time mean(w) mean(w**2)"
2859 call mpi_file_write(log_fh, trim(line) // new_line('a'), &
2860 len_trim(line)+1, mpi_character, istatus, ierrmpi)
2861 end if
2862
2863 write(fmt_string, "(a,i0,a)") "(", nw * n_modes + 1, fmt_r // ")"
2864 write(line, fmt_string) global_time, modes
2865 call mpi_file_write(log_fh, trim(line) // new_line('a') , &
2866 len_trim(line)+1, mpi_character, istatus, ierrmpi)
2867 end if
2868 end subroutine printlog_regression_test
2869
2870 !> Compute mean(w**power) over the leaves of the grid. The first mode
2871 !> (power=1) corresponds to the mean, the second to the mean squared values
2872 !> and so on.
2873 subroutine get_volume_average(power, mode, volume)
2875
2876 integer, intent(in) :: power !< Which mode to compute
2877 double precision, intent(out) :: mode(nw) !< The computed mode
2878 double precision, intent(out) :: volume !< The total grid volume
2879
2880 double precision :: wsum(nw+1)
2881 double precision :: dsum_recv(1:nw+1)
2882 integer :: iigrid, igrid, iw
2883
2884 wsum(:) = 0
2885
2886 ! Loop over all the grids
2887 do iigrid = 1, igridstail
2888 igrid = igrids(iigrid)
2889
2890 ! Store total volume in last element
2891 wsum(nw+1) = wsum(nw+1) + sum(ps(igrid)%dvolume(ixm^t))
2892
2893 ! Compute the modes of the cell-centered variables, weighted by volume
2894 do iw = 1, nw
2895 wsum(iw) = wsum(iw) + &
2896 sum(ps(igrid)%dvolume(ixm^t)*ps(igrid)%w(ixm^t,iw)**power)
2897 end do
2898 end do
2899
2900 ! Make the information available on all tasks
2901 call mpi_allreduce(wsum, dsum_recv, nw+1, mpi_double_precision, &
2902 mpi_sum, icomm, ierrmpi)
2903
2904 ! Set the volume and the average
2905 volume = dsum_recv(nw+1)
2906 mode = dsum_recv(1:nw) / volume
2907
2908 end subroutine get_volume_average
2909
2910 !> Compute how much of the domain is covered by each grid level. This routine
2911 !> does not take a non-Cartesian geometry into account.
2912 subroutine get_volume_coverage(vol_cov)
2914
2915 double precision, intent(out) :: vol_cov(1:refine_max_level)
2916 double precision :: dsum_recv(1:refine_max_level)
2917 integer :: iigrid, igrid, iw, level
2918
2919 ! First determine the total 'flat' volume in each level
2920 vol_cov(1:refine_max_level)=zero
2921
2922 do iigrid = 1, igridstail
2923 igrid = igrids(iigrid);
2924 level = node(plevel_,igrid)
2925 vol_cov(level) = vol_cov(level)+ &
2926 {(rnode(rpxmax^d_,igrid)-rnode(rpxmin^d_,igrid))|*}
2927 end do
2928
2929 ! Make the information available on all tasks
2930 call mpi_allreduce(vol_cov, dsum_recv, refine_max_level, mpi_double_precision, &
2931 mpi_sum, icomm, ierrmpi)
2932
2933 ! Normalize
2934 vol_cov = dsum_recv / sum(dsum_recv)
2935 end subroutine get_volume_coverage
2936
2937 !> Compute the volume average of func(w) over the leaves of the grid.
2938 subroutine get_volume_average_func(func, f_avg, volume)
2940
2941 interface
2942 pure function func(w_vec, w_size) result(val)
2943 integer, intent(in) :: w_size
2944 double precision, intent(in) :: w_vec(w_size)
2945 double precision :: val
2946 end function func
2947 end interface
2948 double precision, intent(out) :: f_avg !< The volume average of func
2949 double precision, intent(out) :: volume !< The total grid volume
2950 double precision :: wsum(2)
2951 double precision :: dsum_recv(2)
2952 integer :: iigrid, igrid, i^D
2953
2954 wsum(:) = 0
2955
2956 ! Loop over all the grids
2957 do iigrid = 1, igridstail
2958 igrid = igrids(iigrid)
2959
2960 ! Store total volume in last element
2961 wsum(2) = wsum(2) + sum(ps(igrid)%dvolume(ixm^t))
2962
2963 ! Compute the modes of the cell-centered variables, weighted by volume
2964 {do i^d = ixmlo^d, ixmhi^d\}
2965 wsum(1) = wsum(1) + ps(igrid)%dvolume(i^d) * &
2966 func(ps(igrid)%w(i^d, :), nw)
2967 {end do\}
2968 end do
2969
2970 ! Make the information available on all tasks
2971 call mpi_allreduce(wsum, dsum_recv, 2, mpi_double_precision, &
2972 mpi_sum, icomm, ierrmpi)
2973
2974 ! Set the volume and the average
2975 volume = dsum_recv(2)
2976 f_avg = dsum_recv(1) / volume
2977
2978 end subroutine get_volume_average_func
2979
2980 !> Compute global maxima of iw variables over the leaves of the grid.
2981 subroutine get_global_maxima(wmax,psa)
2983
2984 double precision, intent(out) :: wmax(nw) !< The global maxima
2985 type(state), target :: psa(max_blocks)
2986
2987 double precision :: wmax_mype(nw),wmax_recv(nw)
2988 integer :: iigrid, igrid, iw
2989
2990 wmax_mype(1:nw) = -bigdouble
2991
2992 ! Loop over all the grids
2993 do iigrid = 1, igridstail
2994 igrid = igrids(iigrid)
2995 do iw = 1, nw
2996 wmax_mype(iw)=max(wmax_mype(iw),maxval(psa(igrid)%w(ixm^t,iw)))
2997 end do
2998 end do
2999
3000 ! Make the information available on all tasks
3001 call mpi_allreduce(wmax_mype, wmax_recv, nw, mpi_double_precision, &
3002 mpi_max, icomm, ierrmpi)
3003
3004 wmax(1:nw)=wmax_recv(1:nw)
3005
3006 end subroutine get_global_maxima
3007
3008 !> Compute global minima of iw variables over the leaves of the grid.
3009 subroutine get_global_minima(wmin,psa)
3011
3012 double precision, intent(out) :: wmin(nw) !< The global maxima
3013 type(state), target :: psa(max_blocks)
3014
3015 double precision :: wmin_mype(nw),wmin_recv(nw)
3016 integer :: iigrid, igrid, iw
3017
3018 wmin_mype(1:nw) = bigdouble
3019
3020 ! Loop over all the grids
3021 do iigrid = 1, igridstail
3022 igrid = igrids(iigrid)
3023 do iw = 1, nw
3024 wmin_mype(iw)=min(wmin_mype(iw),minval(psa(igrid)%w(ixm^t,iw)))
3025 end do
3026 end do
3027
3028 ! Make the information available on all tasks
3029 call mpi_allreduce(wmin_mype, wmin_recv, nw, mpi_double_precision, &
3030 mpi_min, icomm, ierrmpi)
3031
3032 wmin(1:nw)=wmin_recv(1:nw)
3033
3034 end subroutine get_global_minima
3035
3036end 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