Neko 1.99.1
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-2023, 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
43 use redist, only : redist_mesh
45 use flow_ic, only : set_flow_ic
46 use scalar_ic, only : set_scalar_ic
47 use file, only : file_t
48 use utils, only : neko_error
49 use mesh, only : mesh_t
50 use math, only : neko_eps
51 use checkpoint, only: chkp_t
53 use logger, only : neko_log, neko_log_quiet
55 use user_intf, only : user_t
56 use scalar_pnpn, only : scalar_pnpn_t
58 use time_state, only : time_state_t
59 use json_module, only : json_file
63 use scalars, only : scalars_t
64 use comm, only : neko_comm, pe_rank, pe_size
65 use mpi_f08, only : mpi_bcast, mpi_character, mpi_integer
66
67 implicit none
68 private
69
70 type, public :: case_t
71 type(mesh_t) :: msh
72 type(json_file) :: params
73 character(len=:), allocatable :: output_directory
75 type(fluid_output_t) :: f_out
76 type(time_state_t) :: time
77 type(chkp_output_t) :: chkp_out
78 type(chkp_t) :: chkp
79 type(user_t) :: user
80 class(fluid_scheme_base_t), allocatable :: fluid
81 type(scalars_t), allocatable :: scalars
82 end type case_t
83
84 interface case_init
86 end interface case_init
87
88 public :: case_init, case_free
89
90contains
91
93 subroutine case_init_from_file(this, case_file)
94 type(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 if (pe_rank .eq. 0) then
111 call this%params%load_file(filename = trim(case_file))
112 call this%params%print_to_string(json_buffer)
113 integer_val = len(json_buffer)
114 end if
115
116 call mpi_bcast(integer_val, 1, mpi_integer, 0, neko_comm, ierr)
117 if (pe_rank .ne. 0) allocate(character(len = integer_val) :: json_buffer)
118 call mpi_bcast(json_buffer, integer_val, mpi_character, 0, neko_comm, ierr)
119 call this%params%load_from_string(json_buffer)
120
121 deallocate(json_buffer)
122
123 call case_init_common(this)
124
125 end subroutine case_init_from_file
126
128 subroutine case_init_from_json(this, case_json)
129 type(case_t), target, intent(inout) :: this
130 type(json_file), intent(in) :: case_json
131
132 call neko_log%section('Case')
133 call neko_log%message('Creating case from JSON object', neko_log_quiet)
134
135 this%params = case_json
136
137 call case_init_common(this)
138
139 end subroutine case_init_from_json
140
142 subroutine case_init_common(this)
143 type(case_t), target, intent(inout) :: this
144 integer :: lx = 0
145 logical :: scalar = .false.
146 type(file_t) :: msh_file, bdry_file, part_file
147 type(mesh_fld_t) :: msh_part, parts
148 logical :: found, logical_val
149 integer :: integer_val
150 real(kind=rp) :: real_val
151 character(len = :), allocatable :: string_val, name, file_format
152 integer :: output_dir_len
153 integer :: precision, layout
154 type(json_file) :: scalar_params, numerics_params
155 type(json_file) :: json_subdict
156 integer :: n_scalars, i
157
158 !
159 ! Setup user defined functions
160 !
161 call this%user%init()
162
163 ! Run user startup routine
164 call this%user%startup(this%params)
165
166 ! Check if default value fill-in is allowed
167 if (this%params%valid_path('case.no_defaults')) then
168 call json_get(this%params, 'case.no_defaults', json_no_defaults)
169 end if
170
171 !
172 ! Load mesh
173 !
174 call json_get_or_default(this%params, 'case.mesh_file', string_val, &
175 'no mesh')
176 if (trim(string_val) .eq. 'no mesh') then
177 call neko_error('The mesh_file keyword could not be found in the .' // &
178 'case file. Often caused by incorrectly formatted json.')
179 end if
180 call msh_file%init(string_val)
181
182 call msh_file%read(this%msh)
183
184 !
185 ! Load Balancing
186 !
187 call json_get_or_default(this%params, 'case.load_balancing', logical_val,&
188 .false.)
189
190 if (pe_size .gt. 1 .and. logical_val) then
191 call neko_log%section('Load Balancing')
192 call parmetis_partmeshkway(this%msh, parts)
193 call redist_mesh(this%msh, parts)
194
195 ! store the balanced mesh (for e.g. restarts)
196 string_val = trim(string_val(1:scan(trim(string_val), &
197 '.', back = .true.) - 1)) // '_lb.nmsh'
198 call msh_file%init(string_val)
199 call msh_file%write(this%msh)
200
201 call neko_log%end_section()
202 end if
203
204 !
205 ! Time control
206 !
207 call json_extract_object(this%params, 'case.time', json_subdict)
208 call this%time%init(json_subdict)
209
210 !
211 ! Initialize point_zones registry
212 !
213 call neko_point_zone_registry%init(this%params, this%msh)
214
215 ! Run user mesh motion routine
216 call this%user%mesh_setup(this%msh, this%time)
217
218 call json_extract_object(this%params, 'case.numerics', numerics_params)
219
220 !
221 ! Setup fluid scheme
222 !
223 call json_get(this%params, 'case.fluid.scheme', string_val)
224 call fluid_scheme_base_factory(this%fluid, trim(string_val))
225
226 call json_get(this%params, 'case.numerics.polynomial_order', lx)
227 lx = lx + 1 ! add 1 to get number of gll points
228 ! Set time lags in chkp
229 this%chkp%tlag => this%time%tlag
230 this%chkp%dtlag => this%time%dtlag
231 call this%fluid%init(this%msh, lx, this%params, this%user, this%chkp)
232
233
234 !
235 ! Setup scratch registry
236 !
237 call neko_scratch_registry%init(this%fluid%dm_Xh, 10, 10)
238
239 !
240 ! Setup scalar scheme
241 !
242 ! @todo no scalar factory for now, probably not needed
243 scalar = .false.
244 n_scalars = 0
245 if (this%params%valid_path('case.scalar')) then
246 call json_get_or_default(this%params, 'case.scalar.enabled', scalar, &
247 .true.)
248 n_scalars = 1
249 else if (this%params%valid_path('case.scalars')) then
250 call this%params%info('case.scalars', n_children = n_scalars)
251 if (n_scalars > 0) then
252 scalar = .true.
253 end if
254 end if
255
256 if (scalar) then
257 allocate(this%scalars)
258 if (this%params%valid_path('case.scalar')) then
259 ! For backward compatibility
260 call json_extract_object(this%params, 'case.scalar', scalar_params)
261 call this%scalars%init(this%msh, this%fluid%c_Xh, this%fluid%gs_Xh, &
262 scalar_params, numerics_params, this%user, this%chkp, this%fluid%ulag, &
263 this%fluid%vlag, this%fluid%wlag, this%fluid%ext_bdf, &
264 this%fluid%rho)
265 else
266 ! Multiple scalars
267 call json_extract_object(this%params, 'case.scalars', json_subdict)
268 call this%scalars%init(n_scalars, this%msh, this%fluid%c_Xh, this%fluid%gs_Xh, &
269 json_subdict, numerics_params, this%user, this%chkp, this%fluid%ulag, &
270 this%fluid%vlag, this%fluid%wlag, this%fluid%ext_bdf, &
271 this%fluid%rho)
272 end if
273 end if
274
275 !
276 ! Setup initial conditions
277 !
278 call json_get(this%params, 'case.fluid.initial_condition.type', &
279 string_val)
280 call json_extract_object(this%params, 'case.fluid.initial_condition', &
281 json_subdict)
282
283 call neko_log%section("Fluid initial condition ")
284
285 if (trim(string_val) .ne. 'user') then
286 call set_flow_ic(this%fluid%u, this%fluid%v, this%fluid%w, &
287 this%fluid%p, this%fluid%c_Xh, this%fluid%gs_Xh, string_val, &
288 json_subdict)
289 else
290 call json_get(this%params, 'case.fluid.scheme', string_val)
291 if (trim(string_val) .eq. 'compressible') then
292 call set_flow_ic(this%fluid%rho, &
293 this%fluid%u, this%fluid%v, this%fluid%w, this%fluid%p, &
294 this%fluid%c_Xh, this%fluid%gs_Xh, &
295 this%user%initial_conditions, this%fluid%name)
296 else
297 call set_flow_ic(this%fluid%u, this%fluid%v, this%fluid%w, &
298 this%fluid%p, this%fluid%c_Xh, this%fluid%gs_Xh, &
299 this%user%initial_conditions, this%fluid%name)
300 end if
301 end if
302
303 call neko_log%end_section()
304
305 if (scalar) then
306 call neko_log%section("Scalar initial condition ")
307
308 if (this%params%valid_path('case.scalar')) then
309 ! For backward compatibility with single scalar
310 call json_get(this%params, 'case.scalar.initial_condition.type', &
311 string_val)
312 call json_extract_object(this%params, &
313 'case.scalar.initial_condition', json_subdict)
314
315 if (trim(string_val) .ne. 'user') then
316 call set_scalar_ic(this%scalars%scalar_fields(1)%s, &
317 this%scalars%scalar_fields(1)%c_Xh, &
318 this%scalars%scalar_fields(1)%gs_Xh, &
319 string_val, json_subdict)
320 else
321 call set_scalar_ic(this%scalars%scalar_fields(1)%name, &
322 this%scalars%scalar_fields(1)%s, &
323 this%scalars%scalar_fields(1)%c_Xh, &
324 this%scalars%scalar_fields(1)%gs_Xh, &
325 this%user%initial_conditions)
326 end if
327
328 else
329 ! Handle multiple scalars
330 do i = 1, n_scalars
331 call json_extract_item(this%params, 'case.scalars', i, &
332 scalar_params)
333 call json_get(scalar_params, 'initial_condition.type', string_val)
334 call json_extract_object(scalar_params, 'initial_condition', &
335 json_subdict)
336
337 if (trim(string_val) .ne. 'user') then
338 call set_scalar_ic(this%scalars%scalar_fields(i)%s, &
339 this%scalars%scalar_fields(i)%c_Xh, &
340 this%scalars%scalar_fields(i)%gs_Xh, &
341 string_val, json_subdict)
342 else
343 call set_scalar_ic(this%scalars%scalar_fields(i)%name,&
344 this%scalars%scalar_fields(i)%s, &
345 this%scalars%scalar_fields(i)%c_Xh, &
346 this%scalars%scalar_fields(i)%gs_Xh, &
347 this%user%initial_conditions)
348 end if
349 end do
350 end if
351
352 call neko_log%end_section()
353 end if
354
355 ! Add initial conditions to BDF scheme (if present)
356 select type (f => this%fluid)
357 type is (fluid_pnpn_t)
358 call f%ulag%set(f%u)
359 call f%vlag%set(f%v)
360 call f%wlag%set(f%w)
361 end select
362
363 !
364 ! Validate that the case is properly setup for time-stepping
365 !
366 call this%fluid%validate
367
368 if (scalar) then
369 call this%scalars%validate()
370 end if
371
372 !
373 ! Get and process output directory
374 !
375 call json_get_or_default(this%params, 'case.output_directory',&
376 this%output_directory, '')
377
378 output_dir_len = len(trim(this%output_directory))
379 if (output_dir_len .gt. 0) then
380 if (this%output_directory(output_dir_len:output_dir_len) .ne. "/") then
381 this%output_directory = trim(this%output_directory)//"/"
382 if (pe_rank .eq. 0) then
383 call execute_command_line('mkdir -p '//this%output_directory)
384 end if
385 end if
386 end if
387
388 !
389 ! Save mesh partitions (if requested)
390 !
391 call json_get_or_default(this%params, 'case.output_partitions',&
392 logical_val, .false.)
393 if (logical_val) then
394 call mesh_field_init(msh_part, this%msh, 'MPI_Rank')
395 msh_part%data = pe_rank
396 call part_file%init(trim(this%output_directory)//'partitions.vtk')
397 call part_file%write(msh_part)
398 call mesh_field_free(msh_part)
399 end if
400
401 !
402 ! Setup output precision of the field files
403 !
404 call json_get_or_default(this%params, 'case.output_precision', string_val,&
405 'single')
406
407 if (trim(string_val) .eq. 'double') then
408 precision = dp
409 else
410 precision = sp
411 end if
412
413 !
414 ! Setup output layout of the field bp file
415 !
416 call json_get_or_default(this%params, 'case.output_layout', layout, 1)
417
418 !
419 ! Setup output_controller
420 !
421 call json_get_or_default(this%params, 'case.fluid.output_filename', &
422 name, "field")
423 call json_get_or_default(this%params, 'case.fluid.output_format', &
424 file_format, 'fld')
425 call this%output_controller%init(this%time%end_time)
426 if (scalar) then
427 call this%f_out%init(precision, this%fluid, this%scalars, name = name, &
428 path = trim(this%output_directory), &
429 fmt = trim(file_format), layout = layout)
430 else
431 call this%f_out%init(precision, this%fluid, name = name, &
432 path = trim(this%output_directory), &
433 fmt = trim(file_format), layout = layout)
434 end if
435
436 call json_get_or_default(this%params, 'case.fluid.output_control',&
437 string_val, 'org')
438
439 if (trim(string_val) .eq. 'org') then
440 ! yes, it should be real_val below for type compatibility
441 call json_get(this%params, 'case.nsamples', real_val)
442 call this%output_controller%add(this%f_out, real_val, 'nsamples')
443 else if (trim(string_val) .eq. 'never') then
444 ! Fix a dummy 0.0 output_value
445 call json_get_or_default(this%params, 'case.fluid.output_value', &
446 real_val, 0.0_rp)
447 call this%output_controller%add(this%f_out, 0.0_rp, string_val)
448 else
449 call json_get(this%params, 'case.fluid.output_value', real_val)
450 call this%output_controller%add(this%f_out, real_val, string_val)
451 end if
452
453 !
454 ! Save checkpoints (if nothing specified, default to saving at end of sim)
455 !
456 call json_get_or_default(this%params, 'case.output_checkpoints',&
457 logical_val, .true.)
458 if (logical_val) then
459 call json_get_or_default(this%params, 'case.checkpoint_filename', &
460 name, "fluid")
461 call json_get_or_default(this%params, 'case.checkpoint_format', &
462 string_val, "chkp")
463 call this%chkp_out%init(this%chkp, name = name,&
464 path = this%output_directory, fmt = trim(string_val))
465 call json_get_or_default(this%params, 'case.checkpoint_control', &
466 string_val, "simulationtime")
467 call json_get_or_default(this%params, 'case.checkpoint_value', &
468 real_val, 1e10_rp)
469 call this%output_controller%add(this%chkp_out, real_val, string_val, &
470 neko_eps)
471 end if
472
473 !
474 ! Setup joblimit
475 !
476 if (this%params%valid_path('case.job_timelimit')) then
477 call json_get(this%params, 'case.job_timelimit', string_val)
478 call jobctrl_set_time_limit(string_val)
479 end if
480
481 call neko_log%end_section()
482
483 end subroutine case_init_common
484
486 subroutine case_free(this)
487 type(case_t), intent(inout) :: this
488
489 if (allocated(this%fluid)) then
490 call this%fluid%free()
491 deallocate(this%fluid)
492 end if
493
494 if (allocated(this%scalars)) then
495 call this%scalars%free()
496 deallocate(this%scalars)
497 end if
498
499 call this%msh%free()
500
501 call this%f_out%free()
502
503 call this%output_controller%free()
504
505 end subroutine case_free
506
507end module case
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, public case_free(this)
Deallocate a case.
Definition case.f90:487
subroutine case_init_from_json(this, case_json)
Initialize a case from a JSON object describing a case.
Definition case.f90:129
subroutine case_init_common(this)
Initialize a case from its (loaded) params object.
Definition case.f90:143
Defines a checkpoint.
Defines an output for a checkpoint.
Definition comm.F90:1
integer, public pe_size
MPI size of communicator.
Definition comm.F90:58
integer, public pe_rank
MPI rank.
Definition comm.F90:55
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:42
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.
subroutine, public json_extract_object(json, name, object)
Extract object as a separate JSON dictionary.
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 logged.
Definition log.f90:72
type(log_t), public neko_log
Global log stream.
Definition log.f90:70
Definition math.f90:60
real(kind=rp), parameter, public neko_eps
Machine epsilon .
Definition math.f90:69
Defines a mesh field.
subroutine, public mesh_field_free(fld)
subroutine, public mesh_field_init(fld, msh, fld_name)
Defines a mesh.
Definition mesh.f90:34
integer, parameter, public dp
Definition num_types.f90:9
integer, parameter, public sp
Definition num_types.f90:8
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
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
Scalar initial condition.
Definition scalar_ic.f90:34
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 fields This can be used when you have a funct...
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
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Definition file.f90:55
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:63
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...