Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
simulation_component.f90
Go to the documentation of this file.
1! Copyright (c) 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!
33!
39 use utils, only : neko_typename_len
40 use num_types, only : dp
41 use json_module, only : json_file
42 use case, only : case_t
46 use time_state, only : time_state_t
47 implicit none
48 private
49
51 type, abstract, public :: simulation_component_t
53 type(case_t), pointer :: case
55 type(time_based_controller_t) :: preprocess_controller
57 type(time_based_controller_t) :: compute_controller
61 integer :: order
63 character(:), allocatable :: name
64 contains
66 procedure, pass(this) :: init_base => simulation_component_init_base
68 generic :: init_base_from_components => &
69 init_base_from_controllers_properties, &
70 init_base_from_controllers
74 procedure, pass(this) :: init_base_from_controllers => &
79 procedure, pass(this) :: init_base_from_controllers_properties => &
82 procedure, pass(this) :: free_base => simulation_component_free_base
85 procedure, pass(this) :: restart => simulation_component_restart_wrapper
88 procedure, pass(this) :: preprocess => &
92 procedure, pass(this) :: compute => simulation_component_compute_wrapper
94 procedure(simulation_component_init), pass(this), deferred :: init
96 procedure(simulation_component_free), pass(this), deferred :: free
98 procedure, pass(this) :: preprocess_
100 procedure, pass(this) :: compute_
102 procedure, pass(this) :: restart_
104 procedure, pass(this) :: parse_json => simulation_component_parse_json
106
109 class(simulation_component_t), allocatable :: simcomp
110 contains
112 procedure, pass(this) :: init => simulation_component_wrapper_init
114 procedure, pass(this) :: free => simulation_component_wrapper_free
117 procedure, pass(this) :: move_from => &
120 procedure, pass(this) :: is_allocated => &
123
124 abstract interface
125
128 subroutine simulation_component_init(this, json, case)
129 import simulation_component_t, json_file, case_t
130 class(simulation_component_t), intent(inout), target :: this
131 type(json_file), intent(inout) :: json
132 class(case_t), intent(inout), target :: case
133 end subroutine simulation_component_init
134 end interface
135
136 abstract interface
137
140 class(simulation_component_t), intent(inout) :: this
141 end subroutine simulation_component_free
142 end interface
143
144 interface
145
150 module subroutine simulation_component_factory(object, json, case)
151 class(simulation_component_t), allocatable, intent(inout) :: object
152 type(json_file), intent(inout) :: json
153 class(case_t), intent(inout), target :: case
154 end subroutine simulation_component_factory
155 end interface
156
157 interface
158
161 module subroutine simulation_component_allocator(object, type_name)
162 class(simulation_component_t), allocatable, intent(inout) :: object
163 character(len=*), intent(in):: type_name
164 end subroutine simulation_component_allocator
165 end interface
166
167 !
168 ! Machinery for injecting user-defined types
169 !
170
174 abstract interface
175 subroutine simulation_component_allocate(obj)
176 import simulation_component_t
177 class(simulation_component_t), allocatable, intent(inout) :: obj
178 end subroutine simulation_component_allocate
179 end interface
180
181 interface
182
183 module subroutine register_simulation_component(type_name, allocator)
184 character(len=*), intent(in) :: type_name
185 procedure(simulation_component_allocate), pointer, intent(in) :: &
186 allocator
187 end subroutine register_simulation_component
188 end interface
189
190 ! A name-allocator pair for user-defined types. A helper type to define a
191 ! registry of custom allocators.
192 type allocator_entry
193 character(len=NEKO_TYPENAME_LEN) :: type_name
194 procedure(simulation_component_allocate), pointer, nopass :: allocator
195 end type allocator_entry
196
198 type(allocator_entry), allocatable :: simcomp_registry(:)
199
201 integer :: simcomp_registry_size = 0
202
203 public :: simulation_component_factory, simulation_component_allocator, &
204 register_simulation_component, simulation_component_allocate
205
206
207contains
209 subroutine simulation_component_init_base(this, json, case)
210 class(simulation_component_t), intent(inout) :: this
211 type(json_file), intent(inout) :: json
212 class(case_t), intent(inout), target :: case
213 character(len=:), allocatable :: preprocess_control, compute_control, &
214 output_control
215 real(kind=dp) :: preprocess_value, compute_value, output_value
216 integer :: order
217
218 call this%parse_json(json, case%params, preprocess_control, &
219 preprocess_value, compute_control, compute_value, output_control, &
220 output_value)
221
222 call json_get_or_default(json, "order", order, -1)
223
224 call this%init_base_from_components(case, order, &
225 preprocess_control, preprocess_value, compute_control, compute_value, &
226 output_control, output_value)
227
228 end subroutine simulation_component_init_base
229
240 subroutine simulation_component_init_base_from_controllers_properties(this, &
241 case, order, preprocess_control, preprocess_value, compute_control, &
242 compute_value, output_control, output_value)
243 class(simulation_component_t), intent(inout) :: this
244 class(case_t), intent(inout), target :: case
245 integer :: order
246 character(len=*), intent(in) :: preprocess_control
247 real(kind=dp), intent(in) :: preprocess_value
248 character(len=*), intent(in) :: compute_control
249 real(kind=dp), intent(in) :: compute_value
250 character(len=*), intent(in) :: output_control
251 real(kind=dp), intent(in) :: output_value
252
253 this%case => case
254 this%order = order
255
256 call this%preprocess_controller%init(case%time%start_time, &
257 case%time%end_time, preprocess_control, preprocess_value)
258 call this%compute_controller%init(case%time%start_time, case%time%end_time,&
259 compute_control, compute_value)
260 call this%output_controller%init(case%time%start_time, case%time%end_time, &
261 output_control, output_value)
262
263 end subroutine simulation_component_init_base_from_controllers_properties
264
271 subroutine simulation_component_init_base_from_controllers(this, case, order,&
272 preprocess_controller, compute_controller, output_controller)
273 class(simulation_component_t), intent(inout) :: this
274 class(case_t), intent(inout), target :: case
275 integer :: order
276 type(time_based_controller_t), intent(in) :: preprocess_controller
277 type(time_based_controller_t), intent(in) :: compute_controller
278 type(time_based_controller_t), intent(in) :: output_controller
279
280 this%case => case
281 this%order = order
282 this%preprocess_controller = preprocess_controller
283 this%compute_controller = compute_controller
284 this%output_controller = output_controller
285 end subroutine simulation_component_init_base_from_controllers
286
296 subroutine simulation_component_parse_json(this, json, case_params, &
297 preprocess_control, preprocess_value, compute_control, compute_value, &
298 output_control, output_value)
299 class(simulation_component_t), intent(inout) :: this
300 type(json_file), intent(inout) :: json
301 type(json_file), intent(inout) :: case_params
302 character(len=:), allocatable, intent(inout) :: preprocess_control
303 real(kind=dp), intent(out) :: preprocess_value
304 character(len=:), allocatable, intent(inout) :: compute_control
305 real(kind=dp), intent(out) :: compute_value
306 character(len=:), allocatable, intent(inout) :: output_control
307 real(kind=dp), intent(out) :: output_value
308 integer :: preprocess_value_int, compute_value_int, output_value_int
309 character(len=:), allocatable :: json_path
310 type(json_file) :: json_object
311
312 !
313 ! Preprocess
314 !
315
316 ! Get the preprocess control, defaulting to tsteps, pin to fluid if
317 ! requested
318 call json_get_or_default(json, "preprocess_control", preprocess_control, &
319 "tsteps")
320
321 json_path = "preprocess_value"
322 json_object = json
323 if (preprocess_control .eq. "fluid_output") then
324 call json_get(case_params, 'case.fluid.output_control', &
325 preprocess_control)
326 json_path = "case.fluid.output_value"
327 json_object = case_params
328 end if
329
330 ! Read preprocess value based on control type
331 if ((preprocess_control .eq. "tsteps") .or. &
332 (preprocess_control .eq. "nsamples")) then
333 ! Read it is an interger, and convert to real
334 call json_get_or_lookup_or_default(json_object, json_path, &
335 preprocess_value_int, 1)
336 preprocess_value = real(preprocess_value_int, kind=dp)
337 else if (preprocess_control .eq. "simulationtime") then
338 ! Read as real
339 call json_get_or_lookup_or_default(json_object, json_path, &
340 preprocess_value, 1.0_dp)
341 else if (preprocess_control .eq. "never") then
342 ! Dummy value
343 preprocess_value = 0.0_dp
344 end if
345
346 !
347 ! Compute
348 !
349
350 ! Get the compute control, defaulting to tsteps, pin to fluid if
351 ! requested
352 call json_get_or_default(json, "compute_control", compute_control, &
353 "tsteps")
354
355 json_path = "compute_value"
356 json_object = json
357 if (compute_control .eq. "fluid_output") then
358 call json_get(case_params, 'case.fluid.output_control', &
359 compute_control)
360 json_path = "case.fluid.output_value"
361 json_object = case_params
362 end if
363
364 ! Read compute value based on control type
365 if ((compute_control .eq. "tsteps") .or. &
366 (compute_control .eq. "nsamples")) then
367 ! Read it is an interger, and convert to real
368 call json_get_or_lookup_or_default(json_object, json_path, &
369 compute_value_int, 1)
370 compute_value = real(compute_value_int, kind=dp)
371 else if (compute_control .eq. "simulationtime") then
372 ! Read as real
373 call json_get_or_lookup_or_default(json_object, json_path, &
374 compute_value, 1.0_dp)
375 compute_value_int = int(compute_value)
376 else if (compute_control .eq. "never") then
377 ! Dummy value
378 compute_value = 0.0_dp
379 compute_value_int = 0
380 end if
381
382 !
383 ! Output
384 !
385
386 ! We default to output whenever we execute, pin to fluid if requested
387 call json_get_or_default(json, "output_control", output_control, &
388 compute_control)
389
390 json_path = "output_value"
391 json_object = json
392 if (output_control .eq. "global") then
393 call json_get(case_params, 'case.fluid.output_control', &
394 output_control)
395 json_path = "case.fluid.output_value"
396 json_object = case_params
397 end if
398
399
400 ! Read output value based on control type. We default to compute_value
401 if ((output_control .eq. "tsteps") .or. &
402 (output_control .eq. "nsamples")) then
403 ! Read it is an interger, and convert to real
404 call json_get_or_lookup_or_default(json_object, json_path, &
405 output_value_int, compute_value_int)
406 output_value = real(output_value_int, kind=dp)
407 else if (output_control .eq. "simulationtime") then
408 ! Read as real
409 call json_get_or_lookup_or_default(json_object, json_path, &
410 output_value, compute_value)
411 else if (output_control .eq. "never") then
412 ! Dummy value
413 output_value = 0.0_dp
414 end if
415
416 deallocate(json_path)
417 end subroutine simulation_component_parse_json
418
420 subroutine simulation_component_free_base(this)
421 class(simulation_component_t), intent(inout) :: this
422
423 nullify(this%case)
424
425 if (allocated(this%name)) then
426 deallocate(this%name)
427 end if
428
429 call this%preprocess_controller%free()
430 call this%compute_controller%free()
431 call this%output_controller%free()
432 end subroutine simulation_component_free_base
433
437 subroutine simulation_component_preprocess_wrapper(this, time)
438 class(simulation_component_t), intent(inout) :: this
439 type(time_state_t), intent(in) :: time
440
441 if (this%preprocess_controller%check(time)) then
442 call this%preprocess_(time)
443 call this%preprocess_controller%register_execution(time)
444 end if
445 end subroutine simulation_component_preprocess_wrapper
446
450 subroutine simulation_component_compute_wrapper(this, time)
451 class(simulation_component_t), intent(inout) :: this
452 type(time_state_t), intent(in) :: time
453
454 if (this%compute_controller%check(time)) then
455 call this%compute_(time)
456 call this%compute_controller%register_execution(time)
457 end if
458 end subroutine simulation_component_compute_wrapper
459
462 subroutine simulation_component_restart_wrapper(this, time)
463 class(simulation_component_t), intent(inout) :: this
464 type(time_state_t), intent(in) :: time
465
466 call this%preprocess_controller%set_counter(time)
467 call this%compute_controller%set_counter(time)
468 call this%output_controller%set_counter(time)
469 call this%restart_(time)
470
471 end subroutine simulation_component_restart_wrapper
472
475 subroutine restart_(this, time)
476 class(simulation_component_t), intent(inout) :: this
477 type(time_state_t), intent(in) :: time
478
479 ! Do nothing
480 end subroutine restart_
481
484 subroutine preprocess_(this, time)
485 class(simulation_component_t), intent(inout) :: this
486 type(time_state_t), intent(in) :: time
487
488 ! Do nothing
489 end subroutine preprocess_
490
493 subroutine compute_(this, time)
494 class(simulation_component_t), intent(inout) :: this
495 type(time_state_t), intent(in) :: time
496
497 ! Do nothing
498 end subroutine compute_
499
500 ! ========================================================================== !
501 ! Simulation component wrapper type methods
502
504 subroutine simulation_component_wrapper_init(this, json, case)
505 class(simulation_component_wrapper_t), intent(inout) :: this
506 type(json_file), intent(inout) :: json
507 class(case_t), intent(inout), target :: case
508
509 call this%free()
510 call simulation_component_factory(this%simcomp, json, case)
511
512 end subroutine simulation_component_wrapper_init
513
515 subroutine simulation_component_wrapper_free(this)
516 class(simulation_component_wrapper_t), intent(inout) :: this
517
518 if (allocated(this%simcomp)) then
519 call this%simcomp%free()
520 deallocate(this%simcomp)
521 end if
522
523 end subroutine simulation_component_wrapper_free
524
529 subroutine simulation_component_wrapper_move_from(this, other)
530 class(simulation_component_wrapper_t), intent(inout) :: this
531 class(simulation_component_wrapper_t), intent(inout) :: other
532
533 ! Move the pointer
534 call move_alloc(other%simcomp, this%simcomp)
535
536 end subroutine simulation_component_wrapper_move_from
537
540 function simulation_component_wrapper_is_allocated(this) result(is_alloc)
541 class(simulation_component_wrapper_t), intent(in) :: this
542 logical :: is_alloc
543 is_alloc = allocated(this%simcomp)
544 end function simulation_component_wrapper_is_allocated
545
546end module simulation_component
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.
The common constructor using a JSON dictionary.
Defines a simulation case.
Definition case.f90:34
Utilities for retrieving parameters from the case files.
integer, parameter, public dp
Definition num_types.f90:10
Implements output_controller_t
Simulation components are objects that encapsulate functionality that can be fit to a particular comp...
subroutine simulation_component_free_base(this)
Destructor for the simulation_component_t (base) class.
subroutine simulation_component_wrapper_free(this)
Destructor. Just deallocates the pointer.
subroutine restart_(this, time)
Dummy restart function.
subroutine simulation_component_restart_wrapper(this, time)
Wrapper for calling set_counter_ based for the controllers.
subroutine simulation_component_wrapper_init(this, json, case)
Constructor. Initializes the object.
subroutine simulation_component_init_base_from_controllers(this, case, order, preprocess_controller, compute_controller, output_controller)
Constructor for the simulation_component_t (base) class from components.
subroutine preprocess_(this, time)
Dummy preprocessing function.
subroutine simulation_component_wrapper_move_from(this, other)
Move assignment operator for the wrapper, needed for storing simcomps in lists and arrays.
subroutine simulation_component_init_base_from_controllers_properties(this, case, order, preprocess_control, preprocess_value, compute_control, compute_value, output_control, output_value)
Constructor for the simulation_component_t (base) class via the properties of the time_based_controll...
logical function simulation_component_wrapper_is_allocated(this)
Return allocation status.
subroutine simulation_component_init_base(this, json, case)
Constructor for the simulation_component_t (base) class.
subroutine compute_(this, time)
Dummy compute function.
subroutine simulation_component_preprocess_wrapper(this, time)
Wrapper for calling preprocess_ based on the preprocess_controller. Serves as the public interface.
subroutine simulation_component_parse_json(this, json, case_params, preprocess_control, preprocess_value, compute_control, compute_value, output_control, output_value)
Parse JSON to determine the properties of the time_based_controllers.
subroutine simulation_component_compute_wrapper(this, time)
Wrapper for calling compute_ based on the compute_controller. Serves as the public interface.
Contains the time_based_controller_t type.
Module with things related to the simulation time.
Utilities.
Definition utils.f90:35
integer, parameter, public neko_typename_len
Definition utils.f90:44
Base abstract class for simulation components.
A helper type that is needed to have an array of polymorphic objects.
A utility type for determining whether an action should be executed based on the current time value....
A struct that contains all info about the time, expand as needed.