Neko 1.99.1
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
output_controller.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!
35 use output, only: output_t, output_ptr_t
36 use fld_file, only: fld_file_t
37 use comm
38 use time_state, only : time_state_t
39 use logger, only : neko_log, log_size
40 use utils, only : neko_error
42 use num_types, only : rp, dp
44 use mpi_f08, only : mpi_wtime
45 implicit none
46 private
47
48
53 type, public :: output_controller_t
55 type(output_ptr_t), allocatable :: output_list(:)
57 type(time_based_controller_t), allocatable :: controllers(:)
59 integer :: n
61 integer :: size
63 real(kind=rp) :: time_end
64 contains
66 procedure, pass(this) :: init => output_controller_init
68 procedure, pass(this) :: free => output_controller_free
70 procedure, pass(this) :: add => output_controller_add
72 procedure, pass(this) :: execute => output_controller_execute
74 procedure, pass(this) :: set_counter => output_controller_set_counter
75 end type output_controller_t
76
77contains
78
83 subroutine output_controller_init(this, time_end, size)
84 class(output_controller_t), intent(inout) :: this
85 integer, intent(in), optional :: size
86 real(kind=rp), intent(in) :: time_end
87 character(len=LOG_SIZE) :: log_buf
88 integer :: n, i
89
90 call this%free()
91
92 if (present(size)) then
93 n = size
94 else
95 n = 1
96 end if
97
98 allocate(this%output_list(n))
99 allocate(this%controllers(n))
100
101 do i = 1, n
102 this%output_list(i)%ptr => null()
103 end do
104
105 this%size = n
106 this%n = 0
107 this%time_end = time_end
108
109 end subroutine output_controller_init
110
112 subroutine output_controller_free(this)
113 class(output_controller_t), intent(inout) :: this
114
115 if (allocated(this%output_list)) then
116 deallocate(this%output_list)
117 end if
118 if (allocated(this%controllers)) then
119 deallocate(this%controllers)
120 end if
121
122 this%n = 0
123 this%size = 0
124
125 end subroutine output_controller_free
126
134 subroutine output_controller_add(this, out, write_par, write_control, &
135 start_time)
136 class(output_controller_t), intent(inout) :: this
137 class(output_t), intent(inout), target :: out
138 real(kind=rp), intent(in) :: write_par
139 character(len=*), intent(in) :: write_control
140 real(kind=rp), optional, intent(in) :: start_time
141 real(kind=rp) :: start_time_
142 type(output_ptr_t), allocatable :: tmp(:)
143 type(time_based_controller_t), allocatable :: tmp_ctrl(:)
144 character(len=LOG_SIZE) :: log_buf
145 integer :: n, nexecutions
146 class(*), pointer :: ft
147
148 if (present(start_time)) then
149 start_time_ = start_time
150 else
151 start_time_ = 0.0_rp
152 end if
153
154
155 if (this%n .ge. this%size) then
156 allocate(tmp(this%size * 2))
157 tmp(1:this%size) = this%output_list
158 call move_alloc(tmp, this%output_list)
159
160 allocate(tmp_ctrl(this%size * 2))
161 tmp_ctrl(1:this%size) = this%controllers
162 call move_alloc(tmp_ctrl, this%controllers)
163
164 this%size = this%size * 2
165 end if
166
167
168 this%n = this%n + 1
169 n = this%n
170 this%output_list(this%n)%ptr => out
171
172 if (trim(write_control) .eq. "org") then
173 this%controllers(n) = this%controllers(1)
174 else
175 call this%controllers(n)%init(start_time_, this%time_end, &
176 write_control, write_par)
177 end if
178
179 ! The code below only prints to console
180 call neko_log%section('Adding write output')
181 call neko_log%message('File name : '// &
182 trim(this%output_list(this%n)%ptr%file_%file_type%fname))
183 call neko_log%message('Write control : '//trim(write_control))
184
185 ! Show the output precision if we are outputting an fld file
186 select type (ft => out%file_%file_type)
187 type is (fld_file_t)
188 if (ft%dp_precision) then
189 call neko_log%message('Output precision : double')
190 else
191 call neko_log%message('Output precision : single')
192 end if
193 end select
194
195 if (trim(write_control) .eq. 'simulationtime') then
196 write(log_buf, '(A,ES13.6)') 'Writes per time unit (Freq.): ', &
197 this%controllers(n)%frequency
198 call neko_log%message(log_buf)
199 write(log_buf, '(A,ES13.6)') 'Time between writes: ', &
200 this%controllers(n)%time_interval
201 call neko_log%message(log_buf)
202 else if (trim(write_control) .eq. 'nsamples') then
203 write(log_buf, '(A,I13)') 'Total samples: ', int(write_par)
204 call neko_log%message(log_buf)
205 write(log_buf, '(A,ES13.6)') 'Writes per time unit (Freq.): ', &
206 this%controllers(n)%frequency
207 call neko_log%message(log_buf)
208 write(log_buf, '(A,ES13.6)') 'Time between writes: ', &
209 this%controllers(n)%time_interval
210 call neko_log%message(log_buf)
211 else if (trim(write_control) .eq. 'tsteps') then
212 write(log_buf, '(A,I13)') 'Time step interval: ', int(write_par)
213 call neko_log%message(log_buf)
214 else if (trim(write_control) .eq. 'org') then
215 write(log_buf, '(A)') &
216 'Write control not set, defaulting to first output settings'
217 call neko_log%message(log_buf)
218 end if
219
220 call neko_log%end_section()
221 end subroutine output_controller_add
222
228 subroutine output_controller_execute(this, time, ifforce)
229 class(output_controller_t), intent(inout) :: this
230 type(time_state_t), intent(in) :: time
231 logical, intent(in), optional :: ifforce
232 real(kind=dp) :: sample_start_time, sample_end_time
233 real(kind=dp) :: sample_time
234 character(len=LOG_SIZE) :: log_buf
235 integer :: i, ierr
236 logical :: force, write_output, write_output_test
237
238 if (present(ifforce)) then
239 force = ifforce
240 else
241 force = .false.
242 end if
243
244 call profiler_start_region('Output controller', 22)
245 !Do we need this Barrier?
246 call mpi_barrier(neko_comm, ierr)
247 sample_start_time = mpi_wtime()
248
249 write_output = .false.
250 ! Determine if at least one output needs to be written
251 ! We should not need this extra select block, and it works great
252 ! without it for GNU, Intel and NEC, but breaks horribly on Cray
253 ! (>11.0.x) when using high opt. levels.
254 select type (samp => this)
255 type is (output_controller_t)
256 do i = 1, samp%n
257 if (this%controllers(i)%check(time, force)) then
258 write_output = .true.
259 exit
260 end if
261 end do
262 end select
263
264 if (write_output) then
265 call neko_log%section('Writer output ')
266 end if
267
268 ! Loop through the outputs and write if necessary.
269 ! We should not need this extra select block, and it works great
270 ! without it for GNU, Intel and NEC, but breaks horribly on Cray
271 ! (>11.0.x) when using high opt. levels.
272 select type (samp => this)
273 type is (output_controller_t)
274 do i = 1, this%n
275 if (this%controllers(i)%check(time, force)) then
276 call neko_log%message('File name : '// &
277 trim(samp%output_list(i)%ptr%file_%file_type%fname))
278
279 write(log_buf, '(A,I6)') 'Output number :', &
280 int(this%controllers(i)%nexecutions)
281 call neko_log%message(log_buf)
282
283 call samp%output_list(i)%ptr%sample(time%t)
284
285 call this%controllers(i)%register_execution()
286 end if
287 end do
288 class default
289 call neko_error('Invalid output_controller output list')
290 end select
291
292 call mpi_barrier(neko_comm, ierr)
293 sample_end_time = mpi_wtime()
294
295 sample_time = sample_end_time - sample_start_time
296 if (write_output) then
297 write(log_buf, '(A16,1x,F12.6,A,F9.6)') 'Writing at time:', time%t, &
298 ' Output time (s): ', sample_time
299 call neko_log%message(log_buf)
300 call neko_log%end_section()
301 end if
302 call profiler_end_region('Output controller', 22)
303 end subroutine output_controller_execute
304
307 subroutine output_controller_set_counter(this, time)
308 class(output_controller_t), intent(inout) :: this
309 type(time_state_t), intent(in) :: time
310 integer :: i, nexecutions
311
312
313 do i = 1, this%n
314 if (this%controllers(i)%nsteps .eq. 0) then
315 call this%controllers(i)%set_counter(time)
316 nexecutions =this%controllers(i)%nexecutions
317 call this%output_list(i)%ptr%set_counter(nexecutions)
318 call this%output_list(i)%ptr%set_start_counter(nexecutions)
319 end if
320 end do
321
322 end subroutine output_controller_set_counter
323
326 subroutine output_controller_set_write_count(this, counter)
327 class(output_controller_t), intent(inout) :: this
328 integer, intent(in) :: counter
329 integer :: i
330
331 do i = 1, this%n
332 this%controllers(i)%nexecutions = counter
333 call this%output_list(i)%ptr%set_counter(counter)
334 call this%output_list(i)%ptr%set_start_counter(counter)
335 end do
336
338
339
340end module output_controller
Definition comm.F90:1
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:42
NEKTON fld file format.
Definition fld_file.f90:35
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:70
integer, parameter, public log_size
Definition log.f90:46
integer, parameter, public dp
Definition num_types.f90:9
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Implements output_controller_t
subroutine output_controller_execute(this, time, ifforce)
Query each of the controllers whether it is time to write, and if so, do so for the corresponding out...
subroutine output_controller_free(this)
Destructor.
subroutine output_controller_init(this, time_end, size)
Constructor.
subroutine output_controller_add(this, out, write_par, write_control, start_time)
Add an output out to the controller.
subroutine output_controller_set_counter(this, time)
Set write counter based on time (after restart)
subroutine output_controller_set_write_count(this, counter)
Set write counter (after restart) explicitly.
Defines an output.
Definition output.f90:34
Profiling interface.
Definition profiler.F90:34
subroutine, public profiler_start_region(name, region_id)
Started a named (name) profiler region.
Definition profiler.F90:78
subroutine, public profiler_end_region(name, region_id)
End the most recently started profiler region.
Definition profiler.F90:109
Contains the time_based_controller_t type.
Module with things related to the simulation time.
Utilities.
Definition utils.f90:35
Interface for NEKTON fld files.
Definition fld_file.f90:65
Wrapper around an output_t pointer.
Definition output.f90:51
Abstract type defining an output type.
Definition output.f90:41
Centralized controller for a list of outputs.
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.