Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
case.f90
Go to the documentation of this file.
1! Copyright (c) 2020-2026, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
34module case
35 use num_types, only : rp, sp, dp
36 use fluid_pnpn, only : fluid_pnpn_t
38 use fluid_scheme_base, only: fluid_scheme_base_t, fluid_scheme_base_factory
40 use chkp_output, only : chkp_output_t
41 use mesh_field, only : mesh_fld_t
43 use redist, only : redist_mesh
45 use flow_ic, only : set_flow_ic
46 use file, only : file_t
48 use mesh, only : mesh_t
49 use checkpoint, only: chkp_t
51 use logger, only : neko_log, neko_log_quiet
53 use user_intf, only : user_t
54 use scalar_pnpn, only : scalar_pnpn_t
56 use time_state, only : time_state_t
57 use json_module, only : json_file
62 use scalars, only : scalars_t
63 use comm, only : neko_comm, pe_rank, pe_size
64 use mpi_f08, only : mpi_bcast, mpi_character, mpi_integer, mpi_logical
66 use vector, only : vector_t
67
68 implicit none
69 private
70
71 type, public :: case_t
72 type(mesh_t) :: msh
73 type(json_file) :: params
74 character(len=:), allocatable :: output_directory
76 type(fluid_output_t) :: f_out
77 type(time_state_t) :: time
78 type(chkp_output_t) :: chkp_out
79 type(chkp_t) :: chkp
80 type(user_t) :: user
81 class(fluid_scheme_base_t), allocatable :: fluid
82 type(scalars_t), allocatable :: scalars
83 contains
84 procedure, private, pass(this) :: case_init_from_file
85 procedure, private, pass(this) :: case_init_from_json
86 procedure, pass(this) :: free => case_free
88 end type case_t
89
90contains
91
93 subroutine case_init_from_file(this, case_file)
94 class(case_t), target, intent(inout) :: this
95 character(len=*), intent(in) :: case_file
96 integer :: ierr, integer_val
97 character(len=:), allocatable :: json_buffer
98 logical :: exist
99
100 ! Check if the file exists
101 inquire(file = trim(case_file), exist = exist)
102 if (.not. exist) then
103 call neko_error('The case file '//trim(case_file)//' does not exist.')
104 end if
105
106 call neko_log%section('Case')
107 call neko_log%message('Reading case file ' // trim(case_file), &
109
110 call this%params%initialize()
111 if (pe_rank .eq. 0) then
112 call this%params%load_file(filename = trim(case_file))
113 call this%params%print_to_string(json_buffer)
114 integer_val = len(json_buffer)
115 end if
116
117 call mpi_bcast(integer_val, 1, mpi_integer, 0, neko_comm, ierr)
118 if (pe_rank .ne. 0) allocate(character(len = integer_val) :: json_buffer)
119 call mpi_bcast(json_buffer, integer_val, mpi_character, 0, neko_comm, ierr)
120 call this%params%load_from_string(json_buffer)
121
122 deallocate(json_buffer)
123
124 call case_init_common(this)
125
126 end subroutine case_init_from_file
127
129 subroutine case_init_from_json(this, case_json)
130 class(case_t), target, intent(inout) :: this
131 type(json_file), intent(in) :: case_json
132
133 call neko_log%section('Case')
134 call neko_log%message('Creating case from JSON object', neko_log_quiet)
135
136 this%params = case_json
137
138 call case_init_common(this)
139
140 end subroutine case_init_from_json
141
143 subroutine case_init_common(this)
144 type(case_t), target, intent(inout) :: this
145 integer :: lx = 0
146 logical :: scalar = .false.
147 type(file_t) :: msh_file, bdry_file, part_file
148 type(mesh_fld_t) :: msh_part, parts
149 logical :: found, logical_val, load_balance
150 logical :: write_at_start
151 integer :: integer_val, var_type
152 real(kind=rp) :: real_val
153 real(kind=dp) :: double_val
154 real(kind=rp), allocatable :: real_vals(:)
155 type(vector_t), pointer :: vec
156 character(len=:), allocatable :: string_val, name, file_format
157 character(len=NEKO_FNAME_LEN) :: lb_file, lb_name, lb_path, lb_ext
158 integer :: output_dir_len
159 integer :: precision, layout
160 type(json_file) :: scalar_params, numerics_params
161 type(json_file) :: json_subdict
162 integer :: n_scalars, i
163 logical :: tmp_feature
164
165 !
166 ! Setup user defined functions
167 !
168 call this%user%init()
169
170 ! Run user startup routine
171 call this%user%startup(this%params)
172
173 ! Check if default value fill-in is allowed
174 if (this%params%valid_path('case.no_defaults')) then
175 call json_get(this%params, 'case.no_defaults', json_no_defaults)
176 end if
177
178
179 !
180 ! Populate const registry with global data from the case file
181 !
182 if (this%params%valid_path('case.constants')) then
183 call this%params%info('case.constants', &
184 n_children = integer_val)
185 do i = 1, integer_val
186 call json_extract_item(this%params, &
187 'case.constants', i, json_subdict)
188 call json_get(json_subdict, 'name', string_val)
189
190 call json_subdict%info('value', found = found, var_type = var_type)
191
192 select case (var_type)
193 case (5) ! integer
194 call json_get(json_subdict, 'value', integer_val)
195 call neko_const_registry%add_integer_scalar(integer_val, &
196 trim(string_val))
197 case (6) ! real
198 call json_get(json_subdict, 'value', real_val)
199 call neko_const_registry%add_real_scalar(real_val, &
200 trim(string_val))
201 case (3) ! array
202 call json_get(json_subdict, 'value', real_vals)
203 call neko_const_registry%add_vector(size(real_vals), &
204 trim(string_val))
205 vec => neko_const_registry%get_vector(trim(string_val))
206 vec%x = real_vals
207 case default
208 call neko_error('case_init_common: Unsupported constant ' // &
209 'type in case.constants for entry '//trim(string_val)//'.')
210 end select
211 end do
212 end if
213
214 !
215 ! Load mesh and perform load balancing if requested
216 !
217 call json_get_or_default(this%params, 'case.mesh_file', string_val, &
218 'no mesh')
219 call json_get_or_default(this%params, 'case.load_balancing', load_balance, &
220 .false.)
221
222 if (trim(string_val) .eq. 'no mesh') then
223 call neko_error('The mesh_file keyword could not be found in the .' // &
224 'case file. Often caused by incorrectly formatted json.')
225 end if
226
227 if (pe_rank .eq. 0) then
228 inquire(file = trim(string_val), exist = found)
229 end if
230 call mpi_bcast(found, 1, mpi_logical, 0, neko_comm)
231
232 if (.not. found) then
233 call neko_error('The mesh file ' // trim(string_val) // &
234 ' does not exist.')
235 end if
236
237 if (.not. load_balance .or. pe_size .eq. 1) then
238 if (load_balance) then
239 call neko_log%message('Load balancing requested but only one ' // &
240 'MPI rank found, ignoring.')
241 end if
242
243 call msh_file%init(string_val)
244 call msh_file%read(this%msh)
245
246 else if (load_balance) then
247 call neko_log%section('Load Balancing')
248
249 call filename_split(trim(string_val), lb_path, lb_name, lb_ext)
250 write(lb_file, '(A,A,A,I0,A)') &
251 trim(lb_path), trim(lb_name), "_lb_", pe_size, trim(lb_ext)
252
253 if (pe_rank .eq. 0) then
254 inquire(file = trim(lb_file), exist = found)
255 end if
256 call mpi_bcast(found, 1, mpi_logical, 0, neko_comm)
257
258 if (found) then
259 call neko_log%message('Reading balanced mesh')
260 call msh_file%init(lb_file)
261 call msh_file%read(this%msh)
262 else
263 call msh_file%init(string_val)
264 call msh_file%read(this%msh)
265
266 call neko_log%message('Performing load balancing with ParMETIS')
267 call parmetis_partmeshkway(this%msh, parts)
268 call redist_mesh(this%msh, parts)
269
270 ! store the balanced mesh (for e.g. restarts)
271 call msh_file%init(lb_file)
272 call msh_file%write(this%msh)
273 end if
274
275 call neko_log%end_section()
276 end if
277
278 ! Run user mesh motion routine
279 call this%user%mesh_setup(this%msh, this%time)
280
281 !
282 ! Time control
283 !
284 call json_get(this%params, 'case.time', json_subdict)
285 call this%time%init(json_subdict)
286
287 !
288 ! Initialize point_zones registry
289 !
290 call neko_point_zone_registry%init(this%params, this%msh)
291
292 !
293 ! Setup fluid scheme
294 !
295 call json_get(this%params, 'case.fluid.scheme', string_val)
296 call fluid_scheme_base_factory(this%fluid, trim(string_val))
297
298 call json_get_or_lookup(this%params, 'case.numerics.polynomial_order', lx)
299 lx = lx + 1 ! add 1 to get number of gll points
300 ! Set time lags in chkp
301 call this%chkp%init()
302 call this%chkp%add_time_state(this%time)
303 call this%fluid%init(this%msh, lx, this%params, this%user, this%chkp)
304
305
306 !
307 ! Setup scratch registry
308 !
309 call neko_scratch_registry%set_dofmap(this%fluid%dm_Xh)
310
311 !
312 ! Setup scalar scheme
313 !
314 ! @todo no scalar factory for now, probably not needed
315 scalar = .false.
316 n_scalars = 0
317 if (this%params%valid_path('case.scalar')) then
318 call json_get_or_default(this%params, 'case.scalar.enabled', scalar, &
319 .true.)
320 n_scalars = 1
321 else if (this%params%valid_path('case.scalars')) then
322 call this%params%info('case.scalars', n_children = n_scalars)
323 if (n_scalars > 0) then
324 scalar = .true.
325 end if
326 end if
327
328 if (scalar) then
329 allocate(this%scalars)
330 call json_get(this%params, 'case.numerics', numerics_params)
331 if (this%params%valid_path('case.scalar')) then
332 ! For backward compatibility
333 call json_get(this%params, 'case.scalar', scalar_params)
334 call this%scalars%init(this%msh, this%fluid%c_Xh, this%fluid%gs_Xh, &
335 scalar_params, numerics_params, this%user, this%chkp, &
336 this%fluid%ulag, this%fluid%vlag, this%fluid%wlag, &
337 this%fluid%ext_bdf, this%fluid%rho)
338 else
339 ! Multiple scalars
340 call json_get(this%params, 'case.scalars', json_subdict)
341 call this%scalars%init(n_scalars, this%msh, this%fluid%c_Xh, &
342 this%fluid%gs_Xh, json_subdict, numerics_params, this%user, &
343 this%chkp, this%fluid%ulag, this%fluid%vlag, this%fluid%wlag, &
344 this%fluid%ext_bdf, this%fluid%rho)
345 end if
346 end if
347
348 !
349 ! Setup initial conditions
350 !
351 call json_get(this%params, 'case.fluid.initial_condition.type', &
352 string_val)
353 call json_get(this%params, 'case.fluid.initial_condition', &
354 json_subdict)
355
356 call neko_log%section("Fluid initial condition ")
357
358 if (this%params%valid_path('case.restart_file')) then
359 call neko_log%message("Restart file specified, " // &
360 "initial conditions ignored")
361 else if (trim(string_val) .ne. 'user') then
362 call set_flow_ic(this%fluid%u, this%fluid%v, this%fluid%w, &
363 this%fluid%p, this%fluid%c_Xh, this%fluid%gs_Xh, string_val, &
364 json_subdict)
365 else
366 call json_get(this%params, 'case.fluid.scheme', string_val)
367 if (trim(string_val) .eq. 'compressible') then
368 call set_flow_ic(this%fluid%rho, &
369 this%fluid%u, this%fluid%v, this%fluid%w, this%fluid%p, &
370 this%fluid%c_Xh, this%fluid%gs_Xh, &
371 this%user%initial_conditions, this%fluid%name)
372 else
373 call set_flow_ic(this%fluid%u, this%fluid%v, this%fluid%w, &
374 this%fluid%p, this%fluid%c_Xh, this%fluid%gs_Xh, &
375 this%user%initial_conditions, this%fluid%name)
376 end if
377 end if
378
379 call neko_log%end_section()
380
381 if (scalar) then
382 call this%scalars%set_initial_conditions(this%user, &
383 this%params%valid_path('case.restart_file'))
384 end if
385
386 ! Add initial conditions to BDF scheme (if present)
387 select type (f => this%fluid)
388 type is (fluid_pnpn_t)
389 call f%ulag%set(f%u)
390 call f%vlag%set(f%v)
391 call f%wlag%set(f%w)
392 end select
393
394 !
395 ! Validate that the case is properly setup for time-stepping
396 !
397 call this%fluid%validate
398
399 if (scalar) then
400 call this%scalars%validate()
401 end if
402
403 !
404 ! Get and process output directory
405 !
406 call json_get_or_default(this%params, 'case.output_directory',&
407 this%output_directory, '')
408
409 output_dir_len = len(trim(this%output_directory))
410 if (output_dir_len .gt. 0) then
411 if (this%output_directory(output_dir_len:output_dir_len) .ne. "/") then
412 this%output_directory = trim(this%output_directory)//"/"
413 end if
414 if (pe_rank .eq. 0) then
415 call mkdir(trim(this%output_directory))
416 end if
417 end if
418
419 !
420 ! Save mesh partitions (if requested)
421 !
422 call json_get_or_default(this%params, 'case.output_partitions',&
423 logical_val, .false.)
424 if (logical_val) then
425 call msh_part%init(this%msh, 'MPI_Rank')
426 msh_part%data = pe_rank
427 call part_file%init(trim(this%output_directory)//'partitions.vtk')
428 call part_file%write(msh_part)
429 call msh_part%free()
430 end if
431
432 !
433 ! Setup output precision of the field files
434 !
435 call json_get_or_default(this%params, 'case.output_precision', string_val,&
436 'single')
437
438 if (trim(string_val) .eq. 'double') then
439 precision = dp
440 else
441 precision = sp
442 end if
443
444 !
445 ! Setup output layout of the field bp file
446 !
447 call json_get_or_lookup_or_default(this%params, 'case.output_layout', &
448 layout, 1)
449
450 !
451 ! Setup output_controller
452 !
453 call json_get_or_default(this%params, 'case.fluid.output_filename', &
454 name, "field")
455 call json_get_or_default(this%params, 'case.fluid.output_format', &
456 file_format, 'fld')
457 call json_get_or_default(this%params, &
458 'case.fluid.output_mesh_in_all_files', &
459 logical_val, .false.)
460
461 ! To ensure we don't miss saving the mesh for ALE.
462 call json_get_or_default(this%params, 'case.fluid.ale.enabled', &
463 tmp_feature, .false.)
464 if (tmp_feature) logical_val = .true.
465
466 ! Whether the initial state of the simulation is written.
467 call json_get_or_default(this%params, 'case.output_at_start', &
468 write_at_start, .true.)
469
470 call this%output_controller%init(this%time%end_time, &
471 time_start = this%time%start_time, write_at_start = write_at_start)
472 if (scalar) then
473 call this%f_out%init(precision, this%fluid, this%scalars, name = name, &
474 path = trim(this%output_directory), &
475 fmt = trim(file_format), layout = layout, &
476 always_write_mesh = logical_val)
477 else
478 call this%f_out%init(precision, this%fluid, name = name, &
479 path = trim(this%output_directory), &
480 fmt = trim(file_format), layout = layout, &
481 always_write_mesh = logical_val)
482 end if
483
484 call json_get_or_default(this%params, 'case.fluid.output_subdivide', &
485 logical_val, .false.)
486 call this%f_out%file_%set_subdivide(logical_val)
487
488 call json_get(this%params, 'case.fluid.output_control', string_val)
489
490 if (trim(string_val) .eq. 'org') then
491 ! yes, it should be real_val below for type compatibility
492 call json_get_or_lookup(this%params, 'case.nsamples', integer_val)
493 double_val = real(integer_val, kind=dp)
494 call this%output_controller%add(this%f_out, double_val, 'nsamples')
495 else if (trim(string_val) .eq. 'never') then
496 call this%output_controller%add(this%f_out, 0.0_dp, 'never')
497 else if (trim(string_val) .eq. 'tsteps' .or. &
498 trim(string_val) .eq. 'nsamples') then
499 call json_get_or_lookup(this%params, 'case.fluid.output_value', &
500 integer_val)
501 double_val = real(integer_val, kind=dp)
502 call this%output_controller%add(this%f_out, double_val, string_val)
503 else if (trim(string_val) .eq. 'simulationtime') then
504 call json_get_or_lookup(this%params, 'case.fluid.output_value', &
505 double_val)
506 call this%output_controller%add(this%f_out, double_val, string_val)
507 else
508 call neko_log%error('Unknown output control type for the fluid: ' // &
509 trim(string_val))
510 end if
511
512 !
513 ! Save checkpoints (if nothing specified, default to saving at end of sim)
514 !
515 call json_get(this%params, 'case.output_checkpoints', logical_val)
516 if (logical_val) then
517 call json_get_or_default(this%params, 'case.checkpoint_filename', &
518 name, "fluid")
519 call json_get_or_default(this%params, 'case.checkpoint_format', &
520 string_val, "chkp")
521 call this%chkp_out%init(this%chkp, name = name,&
522 path = this%output_directory, fmt = trim(string_val))
523 call json_get(this%params, 'case.checkpoint_control', &
524 string_val)
525 if (trim(string_val) .eq. 'tsteps' .or. &
526 trim(string_val) .eq. 'nsamples') then
527 call json_get_or_lookup(this%params, 'case.checkpoint_value', &
528 integer_val)
529 double_val = real(integer_val, kind=dp)
530 else if (trim(string_val) .eq. 'simulationtime') then
531 call json_get_or_lookup(this%params, 'case.checkpoint_value', &
532 double_val)
533 else if (trim(string_val) .eq. 'never') then
534 double_val = 0.0_rp
535 end if
536
537 ! A checkpoint of the initial condition is of no use, so the first
538 ! point of the schedule is skipped.
539 call this%output_controller%add(this%chkp_out, double_val, string_val, &
540 write_at_start = .false.)
541 end if
542
543 !
544 ! Setup joblimit
545 !
546 if (this%params%valid_path('case.job_timelimit')) then
547 call json_get(this%params, 'case.job_timelimit', string_val)
548 call jobctrl_set_time_limit(string_val)
549 end if
550
551 call neko_log%end_section()
552
553 call scalar_params%destroy()
554 call numerics_params%destroy()
555 call json_subdict%destroy()
556
557 nullify(vec)
558
559 end subroutine case_init_common
560
562 subroutine case_free(this)
563 class(case_t), intent(inout) :: this
564
565 if (allocated(this%fluid)) then
566 call this%fluid%free()
567 deallocate(this%fluid)
568 end if
569
570 if (allocated(this%scalars)) then
571 call this%scalars%free()
572 deallocate(this%scalars)
573 end if
574
575 call this%msh%free()
576
577 call this%f_out%free()
578
579 call this%output_controller%free()
580
581 if (allocated(this%output_directory)) then
582 deallocate(this%output_directory)
583 end if
584
585 end subroutine case_free
586
587end module case
double real
Retrieves a parameter by name or assigns a provided default value. In the latter case also adds the m...
Retrieves a parameter by name or throws an error.
Defines a simulation case.
Definition case.f90:34
subroutine case_init_from_file(this, case_file)
Initialize a case from an input file case_file.
Definition case.f90:94
subroutine case_free(this)
Deallocate a case.
Definition case.f90:563
subroutine case_init_from_json(this, case_json)
Initialize a case from a JSON object describing a case.
Definition case.f90:130
subroutine case_init_common(this)
Initialize a case from its (loaded) params object.
Definition case.f90:144
Defines format-independent checkpoint registration and restart state.
Defines an output for a checkpoint.
Definition comm.F90:1
integer, public pe_size
MPI size of communicator.
Definition comm.F90:62
integer, public pe_rank
MPI rank.
Definition comm.F90:59
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:46
Module for file I/O operations.
Definition file.f90:34
Initial flow condition.
Definition flow_ic.f90:34
Defines an output for a fluid.
Modular version of the Classic Nek5000 Pn/Pn formulation for fluids.
Job control.
Definition jobctrl.f90:34
Utilities for retrieving parameters from the case files.
logical, public json_no_defaults
If true, the json_get_or_default routines will not add missing parameters.
Logging routines.
Definition log.f90:34
integer, parameter, public neko_log_quiet
Always.
Definition log.f90:52
type(log_t), public neko_log
Global log stream.
Definition log.f90:91
Defines a mesh field.
Defines a mesh.
Definition mesh.f90:34
integer, parameter, public dp
Definition num_types.f90:10
integer, parameter, public sp
Definition num_types.f90:8
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Implements output_controller_t
Interface to ParMETIS.
Definition parmetis.F90:34
subroutine, public parmetis_partmeshkway(msh, parts, weights, nprts)
Compute a k-way partitioning of a mesh msh.
Definition parmetis.F90:112
type(point_zone_registry_t), target, public neko_point_zone_registry
Global point_zone registry.
Redistribution routines.
Definition redist.f90:34
subroutine, public redist_mesh(msh, parts)
Redistribute a mesh msh according to new partitions.
Definition redist.f90:59
Defines a registry for storing solution fields.
Definition registry.f90:34
type(registry_t), target, public neko_registry
Global field registry.
Definition registry.f90:158
type(registry_t), target, public neko_const_registry
This registry is used to store user-defined scalars and vectors, provided under the constants section...
Definition registry.f90:164
Contains the scalar_pnpn_t type.
Contains the scalar_scheme_t type.
Contains the scalars_t type that manages multiple scalar fields.
Definition scalars.f90:35
Defines a registry for storing and requesting temporary objects This can be used when you have a func...
type(scratch_registry_t), target, public neko_scratch_registry
Global scratch registry.
Compound scheme for the advection and diffusion operators in a transport equation.
Module with things related to the simulation time.
Interfaces for user interaction with NEKO.
Definition user_intf.f90:34
Utilities.
Definition utils.f90:35
integer, parameter, public neko_fname_len
Definition utils.f90:42
subroutine, public filename_split(fname, path, name, suffix)
Extract file name components.
Definition utils.f90:168
recursive subroutine, public mkdir(path, mode)
Recursively create a directory and all parent directories if they do not exist. This should be safer ...
Definition utils.f90:211
Defines a vector.
Definition vector.f90:34
Collection of live simulation data registered for checkpointing.
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Definition file.f90:56
Base type of all fluid formulations.
Centralized controller for a list of outputs.
Base type for a scalar advection-diffusion solver.
Type to manage multiple scalar transport equations.
Definition scalars.f90:60
Implements the logic to compute the time coefficients for the advection and diffusion operators in a ...
A struct that contains all info about the time, expand as needed.
A type collecting all the overridable user routines and flag to suppress type injection from custom m...