Neko  0.8.99
A portable framework for high-order spectral element flow simulations
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 !
34 module case
35  use num_types, only : rp, sp, dp
36  use fluid_pnpn, only : fluid_pnpn_t
37  use fluid_scheme, only : fluid_scheme_t, fluid_scheme_factory
38  use fluid_output, only : fluid_output_t
39  use chkp_output, only : chkp_output_t
45  use redist, only : redist_mesh
46  use sampler, only : sampler_t
47  use flow_ic, only : set_flow_ic
48  use scalar_ic, only : set_scalar_ic
49  use stats, only : stats_t
50  use file, only : file_t
51  use utils, only : neko_error
52  use mesh, only : mesh_t
53  use comm
57  use user_intf, only : user_t
58  use scalar_pnpn, only : scalar_pnpn_t
59  use json_module, only : json_file, json_core, json_value
64  implicit none
65  private
66 
67  type, public :: case_t
68  type(mesh_t) :: msh
69  type(json_file) :: params
70  type(time_scheme_controller_t) :: ext_bdf
71  real(kind=rp), dimension(10) :: tlag
72  real(kind=rp), dimension(10) :: dtlag
73  real(kind=rp) :: dt
74  real(kind=rp) :: end_time
75  type(sampler_t) :: s
76  type(fluid_output_t) :: f_out
77  type(fluid_stats_output_t) :: f_stats_output
78  type(chkp_output_t) :: f_chkp
79  type(mean_flow_output_t) :: f_mf
80  type(mean_sqr_flow_output_t) :: f_msqrf
81  type(stats_t) :: q
82  type(user_t) :: usr
83  class(fluid_scheme_t), allocatable :: fluid
84  type(scalar_pnpn_t), allocatable :: scalar
86  end type case_t
87 
88  interface case_init
90  end interface case_init
91 
92  public :: case_init, case_free
93 
94 contains
95 
97  subroutine case_init_from_file(C, case_file)
98  type(case_t), target, intent(inout) :: C
99  character(len=*), intent(in) :: case_file
100  integer :: ierr, integer_val
101  character(len=:), allocatable :: json_buffer
102 
103  call neko_log%section('Case')
104  call neko_log%message('Reading case file ' // trim(case_file), &
106 
107  if (pe_rank .eq. 0) then
108  call c%params%load_file(filename = trim(case_file))
109  call c%params%print_to_string(json_buffer)
110  integer_val = len(json_buffer)
111  end if
112 
113  call mpi_bcast(integer_val, 1, mpi_integer, 0, neko_comm, ierr)
114  if (pe_rank .ne. 0) allocate(character(len=integer_val)::json_buffer)
115  call mpi_bcast(json_buffer, integer_val, mpi_character, 0, neko_comm, ierr)
116  call c%params%load_from_string(json_buffer)
117 
118  deallocate(json_buffer)
119 
120  call case_init_common(c)
121 
122  end subroutine case_init_from_file
123 
125  subroutine case_init_from_json(C, case_json)
126  type(case_t), target, intent(inout) :: C
127  type(json_file), intent(in) :: case_json
128 
129  call neko_log%section('Case')
130  call neko_log%message('Creating case from JSON object', neko_log_quiet)
131 
132  c%params = case_json
133 
134  call case_init_common(c)
135 
136  end subroutine case_init_from_json
137 
139  subroutine case_init_common(C)
140  type(case_t), target, intent(inout) :: C
141  character(len=:), allocatable :: output_directory
142  integer :: lx = 0
143  logical :: scalar = .false.
144  type(file_t) :: msh_file, bdry_file, part_file
145  type(mesh_fld_t) :: msh_part, parts
146  logical :: found, logical_val
147  integer :: integer_val
148  real(kind=rp) :: real_val
149  character(len=:), allocatable :: string_val
150  real(kind=rp) :: stats_start_time, stats_output_val
151  integer :: stats_sampling_interval
152  integer :: output_dir_len
153  integer :: precision
154 
155  !
156  ! Load mesh
157  !
158  call json_get_or_default(c%params, 'case.mesh_file', string_val, 'no mesh')
159  if (trim(string_val) .eq. 'no mesh') then
160  call neko_error('The mesh_file keyword could not be found in the .' // &
161  'case file. Often caused by incorrectly formatted json.')
162  end if
163  msh_file = file_t(string_val)
164 
165  call msh_file%read(c%msh)
166 
167  !
168  ! Load Balancing
169  !
170  call json_get_or_default(c%params, 'case.load_balancing', logical_val,&
171  .false.)
172 
173  if (pe_size .gt. 1 .and. logical_val) then
174  call neko_log%section('Load Balancing')
175  call parmetis_partmeshkway(c%msh, parts)
176  call redist_mesh(c%msh, parts)
177  call neko_log%end_section()
178  end if
179 
180  !
181  ! Time step
182  !
183  call c%params%get('case.variable_timestep', logical_val, found)
184  if (.not. logical_val) then
185  call json_get(c%params, 'case.timestep', c%dt)
186  else
187  ! randomly set an initial dt to get cfl when dt is variable
188  c%dt = 1.0_rp
189  end if
190 
191  !
192  ! End time
193  !
194  call json_get(c%params, 'case.end_time', c%end_time)
195 
196  !
197  ! Initialize point_zones registry
198  !
199  call neko_point_zone_registry%init(c%params, c%msh)
200 
201  !
202  ! Setup user defined functions
203  !
204  call c%usr%init()
205  call c%usr%user_mesh_setup(c%msh)
206 
207  !
208  ! Set order of timestepper
209  !
210  call json_get(c%params, 'case.numerics.time_order', integer_val)
211  call c%ext_bdf%init(integer_val)
212 
213 
214  !
215  ! Material properties
216  !
217  call c%material_properties%init(c%params, c%usr)
218 
219  !
220  ! Setup fluid scheme
221  !
222  call json_get(c%params, 'case.fluid.scheme', string_val)
223  call fluid_scheme_factory(c%fluid, trim(string_val))
224 
225  call json_get(c%params, 'case.numerics.polynomial_order', lx)
226  lx = lx + 1 ! add 1 to get number of gll points
227  c%fluid%chkp%tlag => c%tlag
228  c%fluid%chkp%dtlag => c%dtlag
229  call c%fluid%init(c%msh, lx, c%params, c%usr, c%material_properties, &
230  c%ext_bdf)
231  select type (f => c%fluid)
232  type is (fluid_pnpn_t)
233  f%chkp%abx1 => f%abx1
234  f%chkp%abx2 => f%abx2
235  f%chkp%aby1 => f%aby1
236  f%chkp%aby2 => f%aby2
237  f%chkp%abz1 => f%abz1
238  f%chkp%abz2 => f%abz2
239  end select
240 
241 
242  !
243  ! Setup scratch registry
244  !
245  neko_scratch_registry = scratch_registry_t(c%fluid%dm_Xh, 10, 10)
246 
247  !
248  ! Setup scalar scheme
249  !
250  ! @todo no scalar factory for now, probably not needed
251  if (c%params%valid_path('case.scalar')) then
252  call json_get_or_default(c%params, 'case.scalar.enabled', scalar,&
253  .true.)
254  end if
255 
256  if (scalar) then
257  allocate(c%scalar)
258  c%scalar%chkp%tlag => c%tlag
259  c%scalar%chkp%dtlag => c%dtlag
260  call c%scalar%init(c%msh, c%fluid%c_Xh, c%fluid%gs_Xh, c%params, c%usr,&
261  c%material_properties, c%fluid%ulag, c%fluid%vlag, &
262  c%fluid%wlag, c%ext_bdf)
263  call c%fluid%chkp%add_scalar(c%scalar%s)
264  c%fluid%chkp%abs1 => c%scalar%abx1
265  c%fluid%chkp%abs2 => c%scalar%abx2
266  c%fluid%chkp%slag => c%scalar%slag
267  end if
268 
269  !
270  ! Setup user defined conditions
271  !
272  if (c%params%valid_path('case.fluid.inflow_condition')) then
273  call json_get(c%params, 'case.fluid.inflow_condition.type',&
274  string_val)
275  if (trim(string_val) .eq. 'user') then
276  call c%fluid%set_usr_inflow(c%usr%fluid_user_if)
277  end if
278  end if
279 
280  ! Setup user boundary conditions for the scalar.
281  if (scalar) then
282  call c%scalar%set_user_bc(c%usr%scalar_user_bc)
283  end if
284 
285  !
286  ! Setup initial conditions
287  !
288  call json_get(c%params, 'case.fluid.initial_condition.type',&
289  string_val)
290  if (trim(string_val) .ne. 'user') then
291  call set_flow_ic(c%fluid%u, c%fluid%v, c%fluid%w, c%fluid%p, &
292  c%fluid%c_Xh, c%fluid%gs_Xh, string_val, c%params)
293  else
294  call set_flow_ic(c%fluid%u, c%fluid%v, c%fluid%w, c%fluid%p, &
295  c%fluid%c_Xh, c%fluid%gs_Xh, c%usr%fluid_user_ic, c%params)
296  end if
297 
298  if (scalar) then
299  call json_get(c%params, 'case.scalar.initial_condition.type', string_val)
300  if (trim(string_val) .ne. 'user') then
301  call set_scalar_ic(c%scalar%s, &
302  c%scalar%c_Xh, c%scalar%gs_Xh, string_val, c%params)
303  else
304  call set_scalar_ic(c%scalar%s, &
305  c%scalar%c_Xh, c%scalar%gs_Xh, c%usr%scalar_user_ic, c%params)
306  end if
307  end if
308 
309  ! Add initial conditions to BDF scheme (if present)
310  select type (f => c%fluid)
311  type is (fluid_pnpn_t)
312  call f%ulag%set(f%u)
313  call f%vlag%set(f%v)
314  call f%wlag%set(f%w)
315  end select
316 
317  !
318  ! Validate that the case is properly setup for time-stepping
319  !
320  call c%fluid%validate
321 
322  if (scalar) then
323  call c%scalar%slag%set(c%scalar%s)
324  call c%scalar%validate
325  end if
326 
327  !
328  ! Get and process output directory
329  !
330  call json_get_or_default(c%params, 'case.output_directory',&
331  output_directory, '')
332 
333  output_dir_len = len(trim(output_directory))
334  if (output_dir_len .gt. 0) then
335  if (output_directory(output_dir_len:output_dir_len) .ne. "/") then
336  output_directory = trim(output_directory)//"/"
337  if (pe_rank .eq. 0) then
338  call execute_command_line('mkdir -p '//output_directory)
339  end if
340  end if
341  end if
342 
343  !
344  ! Save boundary markings for fluid (if requested)
345  !
346  call json_get_or_default(c%params, 'case.output_boundary',&
347  logical_val, .false.)
348  if (logical_val) then
349  bdry_file = file_t(trim(output_directory)//'bdry.fld')
350  call bdry_file%write(c%fluid%bdry)
351  end if
352 
353  !
354  ! Save mesh partitions (if requested)
355  !
356  call json_get_or_default(c%params, 'case.output_partitions',&
357  logical_val, .false.)
358  if (logical_val) then
359  call mesh_field_init(msh_part, c%msh, 'MPI_Rank')
360  msh_part%data = pe_rank
361  part_file = file_t(trim(output_directory)//'partitions.vtk')
362  call part_file%write(msh_part)
363  call mesh_field_free(msh_part)
364  end if
365 
366  !
367  ! Setup output precision of the field files
368  !
369  call json_get_or_default(c%params, 'case.output_precision', string_val,&
370  'single')
371 
372  if (trim(string_val) .eq. 'double') then
373  precision = dp
374  else
375  precision = sp
376  end if
377 
378  !
379  ! Setup sampler
380  !
381  call c%s%init(c%end_time)
382  if (scalar) then
383  c%f_out = fluid_output_t(precision, c%fluid, c%scalar, &
384  path = trim(output_directory))
385  else
386  c%f_out = fluid_output_t(precision, c%fluid, &
387  path = trim(output_directory))
388  end if
389 
390  call json_get_or_default(c%params, 'case.fluid.output_control',&
391  string_val, 'org')
392 
393  if (trim(string_val) .eq. 'org') then
394  ! yes, it should be real_val below for type compatibility
395  call json_get(c%params, 'case.nsamples', real_val)
396  call c%s%add(c%f_out, real_val, 'nsamples')
397  else if (trim(string_val) .eq. 'never') then
398  ! Fix a dummy 0.0 output_value
399  call json_get_or_default(c%params, 'case.fluid.output_value', real_val, &
400  0.0_rp)
401  call c%s%add(c%f_out, 0.0_rp, string_val)
402  else
403  call json_get(c%params, 'case.fluid.output_value', real_val)
404  call c%s%add(c%f_out, real_val, string_val)
405  end if
406 
407  !
408  ! Save checkpoints (if nothing specified, default to saving at end of sim)
409  !
410  call json_get_or_default(c%params, 'case.output_checkpoints',&
411  logical_val, .true.)
412  if (logical_val) then
413  call json_get_or_default(c%params, 'case.checkpoint_format', &
414  string_val, "chkp")
415  c%f_chkp = chkp_output_t(c%fluid%chkp, path = output_directory, &
416  fmt = trim(string_val))
417  call json_get_or_default(c%params, 'case.checkpoint_control', &
418  string_val, "simulationtime")
419  call json_get_or_default(c%params, 'case.checkpoint_value', real_val,&
420  1e10_rp)
421  call c%s%add(c%f_chkp, real_val, string_val)
422  end if
423 
424  !
425  ! Setup statistics
426  !
427 
428  ! Always init, so that we can call eval in simulation.f90 with no if.
429  ! Note, don't use json_get_or_default here, because that will break the
430  ! valid_path if statement below (the path will become valid always).
431  call c%params%get('case.statistics.start_time', stats_start_time,&
432  found)
433  if (.not. found) stats_start_time = 0.0_rp
434 
435  call c%params%get('case.statistics.sampling_interval', &
436  stats_sampling_interval, found)
437  if (.not. found) stats_sampling_interval = 10
438 
439  call c%q%init(stats_start_time, stats_sampling_interval)
440 
441  found = c%params%valid_path('case.statistics')
442  if (found) then
443  call json_get_or_default(c%params, 'case.statistics.enabled',&
444  logical_val, .true.)
445  if (logical_val) then
446  call c%q%add(c%fluid%mean%u)
447  call c%q%add(c%fluid%mean%v)
448  call c%q%add(c%fluid%mean%w)
449  call c%q%add(c%fluid%mean%p)
450 
451  c%f_mf = mean_flow_output_t(c%fluid%mean, stats_start_time, &
452  path = output_directory)
453 
454  call json_get(c%params, 'case.statistics.output_control', &
455  string_val)
456  call json_get(c%params, 'case.statistics.output_value', &
457  stats_output_val)
458 
459  call c%s%add(c%f_mf, stats_output_val, string_val)
460  call c%q%add(c%fluid%stats)
461 
462  c%f_stats_output = fluid_stats_output_t(c%fluid%stats, &
463  stats_start_time, path = output_directory)
464  call c%s%add(c%f_stats_output, stats_output_val, string_val)
465  end if
466  end if
467 
468  !
469  ! Setup joblimit
470  !
471  if (c%params%valid_path('case.job_timelimit')) then
472  call json_get(c%params, 'case.job_timelimit', string_val)
473  call jobctrl_set_time_limit(string_val)
474  end if
475 
476  call neko_log%end_section()
477 
478  end subroutine case_init_common
479 
481  subroutine case_free(C)
482  type(case_t), intent(inout) :: c
483 
484  if (allocated(c%fluid)) then
485  call c%fluid%free()
486  deallocate(c%fluid)
487  end if
488 
489  if (allocated(c%scalar)) then
490  call c%scalar%free()
491  deallocate(c%scalar)
492  end if
493 
494  call c%msh%free()
495 
496  call c%s%free()
497 
498  call c%q%free()
499 
500  end subroutine case_free
501 
502 end module case
Retrieves a parameter by name or assigns a provided default value. In the latter case also adds the m...
Definition: json_utils.f90:53
Retrieves a parameter by name or throws an error.
Definition: json_utils.f90:44
Defines a simulation case.
Definition: case.f90:34
subroutine case_init_common(C)
Initialize a case from its (loaded) params object.
Definition: case.f90:140
subroutine, public case_free(C)
Deallocate a case.
Definition: case.f90:482
subroutine case_init_from_json(C, case_json)
Initialize a case from a JSON object describing a case.
Definition: case.f90:126
subroutine case_init_from_file(C, case_file)
Initialize a case from an input file case_file.
Definition: case.f90:98
Defines an output for a checkpoint.
Definition: chkp_output.f90:34
Definition: comm.F90:1
integer pe_rank
MPI rank.
Definition: comm.F90:26
type(mpi_comm) neko_comm
MPI communicator.
Definition: comm.F90:16
integer pe_size
MPI size of communicator.
Definition: comm.F90:29
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.
Definition: fluid_pnpn.f90:34
Fluid formulations.
Defines an output for a mean flow field.
Job control.
Definition: jobctrl.f90:34
Utilities for retrieving parameters from the case files.
Definition: json_utils.f90:34
Logging routines.
Definition: log.f90:34
integer, parameter, public neko_log_quiet
Always logged.
Definition: log.f90:63
type(log_t), public neko_log
Global log stream.
Definition: log.f90:61
integer, parameter, public log_size
Definition: log.f90:40
Implements material_properties_t type.
Defines an output for a mean flow field.
Defines an output for a mean squared flow field.
Defines a mesh field.
Definition: mesh_field.f90:35
subroutine, public mesh_field_free(fld)
Definition: mesh_field.f90:73
subroutine, public mesh_field_init(fld, msh, fld_name)
Definition: mesh_field.f90:52
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
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:111
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:56
Defines a sampler.
Definition: sampler.f90:34
Scalar initial condition.
Definition: scalar_ic.f90:34
Containts the scalar_pnpn_t type.
Definition: scalar_pnpn.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.
Defines a container for all statistics.
Definition: statistics.f90:34
Compound scheme for the advection and diffusion operators in a transport equation.
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:54
Base type of all fluid formulations.
Contains all the material properties necessary in the simulation.
Statistics backend.
Definition: statistics.f90:48
Implements the logic to compute the time coefficients for the advection and diffusion operators in a ...