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, pass(this) :: time_to_next => &
97 procedure(simulation_component_init), pass(this), deferred :: init
99 procedure(simulation_component_free), pass(this), deferred :: free
101 procedure, pass(this) :: preprocess_
103 procedure, pass(this) :: compute_
105 procedure, pass(this) :: restart_
107 procedure, pass(this) :: parse_json => simulation_component_parse_json
109
112 class(simulation_component_t), allocatable :: simcomp
113 contains
115 procedure, pass(this) :: init => simulation_component_wrapper_init
117 procedure, pass(this) :: free => simulation_component_wrapper_free
120 procedure, pass(this) :: move_from => &
123 procedure, pass(this) :: is_allocated => &
126
127 abstract interface
128
131 subroutine simulation_component_init(this, json, case)
132 import simulation_component_t, json_file, case_t
133 class(simulation_component_t), intent(inout), target :: this
134 type(json_file), intent(inout) :: json
135 class(case_t), intent(inout), target :: case
136 end subroutine simulation_component_init
137 end interface
138
139 abstract interface
140
143 class(simulation_component_t), intent(inout) :: this
144 end subroutine simulation_component_free
145 end interface
146
147 interface
148
153 module subroutine simulation_component_factory(object, json, case)
154 class(simulation_component_t), allocatable, intent(inout) :: object
155 type(json_file), intent(inout) :: json
156 class(case_t), intent(inout), target :: case
157 end subroutine simulation_component_factory
158 end interface
159
160 interface
161
164 module subroutine simulation_component_allocator(object, type_name)
165 class(simulation_component_t), allocatable, intent(inout) :: object
166 character(len=*), intent(in):: type_name
167 end subroutine simulation_component_allocator
168 end interface
169
170 !
171 ! Machinery for injecting user-defined types
172 !
173
177 abstract interface
178 subroutine simulation_component_allocate(obj)
179 import simulation_component_t
180 class(simulation_component_t), allocatable, intent(inout) :: obj
181 end subroutine simulation_component_allocate
182 end interface
183
184 interface
185
186 module subroutine register_simulation_component(type_name, allocator)
187 character(len=*), intent(in) :: type_name
188 procedure(simulation_component_allocate), pointer, intent(in) :: &
189 allocator
190 end subroutine register_simulation_component
191 end interface
192
193 ! A name-allocator pair for user-defined types. A helper type to define a
194 ! registry of custom allocators.
195 type allocator_entry
196 character(len=NEKO_TYPENAME_LEN) :: type_name
197 procedure(simulation_component_allocate), pointer, nopass :: allocator
198 end type allocator_entry
199
201 type(allocator_entry), allocatable :: simcomp_registry(:)
202
204 integer :: simcomp_registry_size = 0
205
206 public :: simulation_component_factory, simulation_component_allocator, &
207 register_simulation_component, simulation_component_allocate
208
209
210contains
212 subroutine simulation_component_init_base(this, json, case)
213 class(simulation_component_t), intent(inout) :: this
214 type(json_file), intent(inout) :: json
215 class(case_t), intent(inout), target :: case
216 character(len=:), allocatable :: preprocess_control, compute_control, &
217 output_control
218 real(kind=dp) :: preprocess_value, compute_value, output_value
219 integer :: order
220
221 call this%parse_json(json, case%params, preprocess_control, &
222 preprocess_value, compute_control, compute_value, output_control, &
223 output_value)
224
225 call json_get_or_default(json, "order", order, -1)
226
227 call this%init_base_from_components(case, order, &
228 preprocess_control, preprocess_value, compute_control, compute_value, &
229 output_control, output_value)
230
231 end subroutine simulation_component_init_base
232
243 subroutine simulation_component_init_base_from_controllers_properties(this, &
244 case, order, preprocess_control, preprocess_value, compute_control, &
245 compute_value, output_control, output_value)
246 class(simulation_component_t), intent(inout) :: this
247 class(case_t), intent(inout), target :: case
248 integer :: order
249 character(len=*), intent(in) :: preprocess_control
250 real(kind=dp), intent(in) :: preprocess_value
251 character(len=*), intent(in) :: compute_control
252 real(kind=dp), intent(in) :: compute_value
253 character(len=*), intent(in) :: output_control
254 real(kind=dp), intent(in) :: output_value
255
256 this%case => case
257 this%order = order
258
259 call this%preprocess_controller%init(case%time%start_time, &
260 case%time%end_time, preprocess_control, preprocess_value)
261 call this%compute_controller%init(case%time%start_time, case%time%end_time,&
262 compute_control, compute_value)
263 call this%output_controller%init(case%time%start_time, case%time%end_time, &
264 output_control, output_value)
265
266 end subroutine simulation_component_init_base_from_controllers_properties
267
274 subroutine simulation_component_init_base_from_controllers(this, case, order,&
275 preprocess_controller, compute_controller, output_controller)
276 class(simulation_component_t), intent(inout) :: this
277 class(case_t), intent(inout), target :: case
278 integer :: order
279 type(time_based_controller_t), intent(in) :: preprocess_controller
280 type(time_based_controller_t), intent(in) :: compute_controller
281 type(time_based_controller_t), intent(in) :: output_controller
282
283 this%case => case
284 this%order = order
285 this%preprocess_controller = preprocess_controller
286 this%compute_controller = compute_controller
287 this%output_controller = output_controller
288 end subroutine simulation_component_init_base_from_controllers
289
299 subroutine simulation_component_parse_json(this, json, case_params, &
300 preprocess_control, preprocess_value, compute_control, compute_value, &
301 output_control, output_value)
302 class(simulation_component_t), intent(inout) :: this
303 type(json_file), intent(inout) :: json
304 type(json_file), intent(inout) :: case_params
305 character(len=:), allocatable, intent(inout) :: preprocess_control
306 real(kind=dp), intent(out) :: preprocess_value
307 character(len=:), allocatable, intent(inout) :: compute_control
308 real(kind=dp), intent(out) :: compute_value
309 character(len=:), allocatable, intent(inout) :: output_control
310 real(kind=dp), intent(out) :: output_value
311 integer :: preprocess_value_int, compute_value_int, output_value_int
312 character(len=:), allocatable :: json_path
313 type(json_file) :: json_object
314
315 !
316 ! Preprocess
317 !
318
319 ! Get the preprocess control, defaulting to tsteps, pin to fluid if
320 ! requested
321 call json_get_or_default(json, "preprocess_control", preprocess_control, &
322 "tsteps")
323
324 json_path = "preprocess_value"
325 json_object = json
326 if (preprocess_control .eq. "fluid_output") then
327 call json_get(case_params, 'case.fluid.output_control', &
328 preprocess_control)
329 json_path = "case.fluid.output_value"
330 json_object = case_params
331 end if
332
333 ! Read preprocess value based on control type
334 if ((preprocess_control .eq. "tsteps") .or. &
335 (preprocess_control .eq. "nsamples")) then
336 ! Read it is an interger, and convert to real
337 call json_get_or_lookup_or_default(json_object, json_path, &
338 preprocess_value_int, 1)
339 preprocess_value = real(preprocess_value_int, kind=dp)
340 else if (preprocess_control .eq. "simulationtime") then
341 ! Read as real
342 call json_get_or_lookup_or_default(json_object, json_path, &
343 preprocess_value, 1.0_dp)
344 else if (preprocess_control .eq. "never") then
345 ! Dummy value
346 preprocess_value = 0.0_dp
347 end if
348
349 !
350 ! Compute
351 !
352
353 ! Get the compute control, defaulting to tsteps, pin to fluid if
354 ! requested
355 call json_get_or_default(json, "compute_control", compute_control, &
356 "tsteps")
357
358 json_path = "compute_value"
359 json_object = json
360 if (compute_control .eq. "fluid_output") then
361 call json_get(case_params, 'case.fluid.output_control', &
362 compute_control)
363 json_path = "case.fluid.output_value"
364 json_object = case_params
365 end if
366
367 ! Read compute value based on control type
368 if ((compute_control .eq. "tsteps") .or. &
369 (compute_control .eq. "nsamples")) then
370 ! Read it is an interger, and convert to real
371 call json_get_or_lookup_or_default(json_object, json_path, &
372 compute_value_int, 1)
373 compute_value = real(compute_value_int, kind=dp)
374 else if (compute_control .eq. "simulationtime") then
375 ! Read as real
376 call json_get_or_lookup_or_default(json_object, json_path, &
377 compute_value, 1.0_dp)
378 compute_value_int = int(compute_value)
379 else if (compute_control .eq. "never") then
380 ! Dummy value
381 compute_value = 0.0_dp
382 compute_value_int = 0
383 end if
384
385 !
386 ! Output
387 !
388
389 ! We default to output whenever we execute, pin to fluid if requested
390 call json_get_or_default(json, "output_control", output_control, &
391 compute_control)
392
393 json_path = "output_value"
394 json_object = json
395 if (output_control .eq. "global") then
396 call json_get(case_params, 'case.fluid.output_control', &
397 output_control)
398 json_path = "case.fluid.output_value"
399 json_object = case_params
400 end if
401
402
403 ! Read output value based on control type. We default to compute_value
404 if ((output_control .eq. "tsteps") .or. &
405 (output_control .eq. "nsamples")) then
406 ! Read it is an interger, and convert to real
407 call json_get_or_lookup_or_default(json_object, json_path, &
408 output_value_int, compute_value_int)
409 output_value = real(output_value_int, kind=dp)
410 else if (output_control .eq. "simulationtime") then
411 ! Read as real
412 call json_get_or_lookup_or_default(json_object, json_path, &
413 output_value, compute_value)
414 else if (output_control .eq. "never") then
415 ! Dummy value
416 output_value = 0.0_dp
417 end if
418
419 deallocate(json_path)
420 end subroutine simulation_component_parse_json
421
423 subroutine simulation_component_free_base(this)
424 class(simulation_component_t), intent(inout) :: this
425
426 nullify(this%case)
427
428 if (allocated(this%name)) then
429 deallocate(this%name)
430 end if
431
432 call this%preprocess_controller%free()
433 call this%compute_controller%free()
434 call this%output_controller%free()
435 end subroutine simulation_component_free_base
436
440 subroutine simulation_component_preprocess_wrapper(this, time)
441 class(simulation_component_t), intent(inout) :: this
442 type(time_state_t), intent(in) :: time
443
444 if (this%preprocess_controller%check(time)) then
445 call this%preprocess_(time)
446 call this%preprocess_controller%register_execution(time)
447 end if
448 end subroutine simulation_component_preprocess_wrapper
449
453 subroutine simulation_component_compute_wrapper(this, time)
454 class(simulation_component_t), intent(inout) :: this
455 type(time_state_t), intent(in) :: time
456
457 if (this%compute_controller%check(time)) then
458 call this%compute_(time)
459 call this%compute_controller%register_execution(time)
460 end if
461 end subroutine simulation_component_compute_wrapper
462
469 function simulation_component_time_to_next(this, time) &
470 result(t)
471 class(simulation_component_t), intent(in) :: this
472 type(time_state_t), intent(in) :: time
473 real(kind=dp) :: t
474
475 t = min(this%preprocess_controller%time_to_next(time), &
476 this%compute_controller%time_to_next(time), &
477 this%output_controller%time_to_next(time))
478
479 end function simulation_component_time_to_next
480
483 subroutine simulation_component_restart_wrapper(this, time)
484 class(simulation_component_t), intent(inout) :: this
485 type(time_state_t), intent(in) :: time
486
487 call this%preprocess_controller%set_counter(time)
488 call this%compute_controller%set_counter(time)
489 call this%output_controller%set_counter(time)
490 call this%restart_(time)
491
492 end subroutine simulation_component_restart_wrapper
493
496 subroutine restart_(this, time)
497 class(simulation_component_t), intent(inout) :: this
498 type(time_state_t), intent(in) :: time
499
500 ! Do nothing
501 end subroutine restart_
502
505 subroutine preprocess_(this, time)
506 class(simulation_component_t), intent(inout) :: this
507 type(time_state_t), intent(in) :: time
508
509 ! Do nothing
510 end subroutine preprocess_
511
514 subroutine compute_(this, time)
515 class(simulation_component_t), intent(inout) :: this
516 type(time_state_t), intent(in) :: time
517
518 ! Do nothing
519 end subroutine compute_
520
521 ! ========================================================================== !
522 ! Simulation component wrapper type methods
523
525 subroutine simulation_component_wrapper_init(this, json, case)
526 class(simulation_component_wrapper_t), intent(inout) :: this
527 type(json_file), intent(inout) :: json
528 class(case_t), intent(inout), target :: case
529
530 call this%free()
531 call simulation_component_factory(this%simcomp, json, case)
532
533 end subroutine simulation_component_wrapper_init
534
536 subroutine simulation_component_wrapper_free(this)
537 class(simulation_component_wrapper_t), intent(inout) :: this
538
539 if (allocated(this%simcomp)) then
540 call this%simcomp%free()
541 deallocate(this%simcomp)
542 end if
543
544 end subroutine simulation_component_wrapper_free
545
550 subroutine simulation_component_wrapper_move_from(this, other)
551 class(simulation_component_wrapper_t), intent(inout) :: this
552 class(simulation_component_wrapper_t), intent(inout) :: other
553
554 ! Move the pointer
555 call move_alloc(other%simcomp, this%simcomp)
556
557 end subroutine simulation_component_wrapper_move_from
558
561 function simulation_component_wrapper_is_allocated(this) result(is_alloc)
562 class(simulation_component_wrapper_t), intent(in) :: this
563 logical :: is_alloc
564 is_alloc = allocated(this%simcomp)
565 end function simulation_component_wrapper_is_allocated
566
567end 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.
real(kind=dp) function simulation_component_time_to_next(this, time)
The time until the next scheduled execution of preprocess, compute or the output, whichever comes fir...
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.