88 real(kind=
dp) :: frequency = 0.0_dp
90 real(kind=
dp) :: time_interval = 0.0_dp
94 real(kind=
dp) :: start_time = 0.0_dp
96 real(kind=
dp) :: end_time = 0.0_dp
98 integer :: nexecutions = 0
100 logical :: never = .false.
103 character(len=:),
allocatable :: control_mode
105 real(kind=
dp) :: control_value = 0.0_dp
108 real(kind=
dp) :: anchor_time = 0.0_dp
113 logical :: write_at_start = .true.
115 integer(kind=i8) :: first_index = 0
117 logical :: start_is_scheduled = .false.
121 logical :: start_pending = .false.
124 integer :: next_index = 0
127 real(kind=
dp) :: direction = 1.0_dp
130 integer :: tstep_offset = 0
134 integer :: last_tstep = -1
144 procedure, pass(this) :: register_execution => &
147 procedure, pass(this) :: set_counter => &
153 procedure, pass(this) :: time_to_next => &
177 control_mode, control_value, write_at_start, anchor_time, direction)
179 real(kind=
dp),
intent(in) :: start_time
180 real(kind=
dp),
intent(in) :: end_time
181 character(len=*),
intent(in) :: control_mode
182 real(kind=
dp),
intent(in) :: control_value
183 logical,
intent(in),
optional :: write_at_start
184 real(kind=
dp),
intent(in),
optional :: anchor_time
185 real(kind=
dp),
intent(in),
optional :: direction
186 real(kind=
dp) :: span, offset
190 this%start_time = start_time
191 this%end_time = end_time
192 this%control_mode = control_mode
193 this%control_value = control_value
195 if (
present(write_at_start))
then
196 this%write_at_start = write_at_start
198 this%write_at_start = .true.
201 if (
present(direction))
then
202 this%direction = sign(1.0_dp, direction)
204 this%direction = sign(1.0_dp, end_time - start_time)
207 span = this%direction * (end_time - start_time)
209 if (trim(control_mode) .eq.
'simulationtime')
then
210 if (control_value .le. 0.0_dp)
then
211 call neko_error(
"The output interval must be positive")
213 this%time_interval = control_value
214 this%frequency = 1.0_dp / this%time_interval
216 else if (trim(control_mode) .eq.
'nsamples')
then
217 if (control_value .le. 0.0_dp)
then
220 if (span .le. 0.0_dp)
then
221 call neko_error(
"nsamples requires the output to start before the &
222 &end of the simulation")
225 this%frequency = control_value / span
226 this%time_interval = 1.0_dp / this%frequency
230 this%anchor_time = start_time
231 else if (trim(control_mode) .eq.
'tsteps')
then
232 if (control_value .lt. 1.0_dp)
then
233 call neko_error(
"The output interval in time steps must be at &
236 this%nsteps = int(control_value)
238 this%frequency = 0.0_dp
239 this%time_interval = 0.0_dp
240 else if (trim(control_mode) .eq.
'never')
then
243 call neko_error(
"The control parameter must be simulationtime, nsamples&
244 & tsteps, or never, but received "//trim(control_mode))
247 if (
present(anchor_time)) this%anchor_time = anchor_time
252 this%start_is_scheduled = .true.
253 this%start_pending = .false.
255 if (this%time_interval .gt. 0.0_dp)
then
256 offset = this%direction * (start_time - this%anchor_time) / &
258 this%first_index = ceiling(offset -
span_tol *
max(1.0_dp, &
259 abs(offset)), kind =
i8)
260 this%start_is_scheduled = abs(
real(this%first_index,
dp) - offset) &
262 if (this%start_is_scheduled .and. .not. this%write_at_start)
then
263 this%first_index = this%first_index + 1_i8
265 this%start_pending = this%write_at_start .and. &
266 .not. this%start_is_scheduled
269 if (this%nsteps .gt. 0 .and. .not. this%write_at_start)
then
283 if (
allocated(this%control_mode))
then
284 deallocate(this%control_mode)
287 this%frequency = 0.0_dp
288 this%time_interval = 0.0_dp
290 this%start_time = 0.0_dp
291 this%end_time = 0.0_dp
294 this%control_value = 0.0_dp
295 this%write_at_start = .true.
296 this%anchor_time = 0.0_dp
298 this%start_is_scheduled = .false.
299 this%start_pending = .false.
301 this%direction = 1.0_dp
302 this%tstep_offset = 0
322 logical,
intent(in),
optional :: force
325 real(kind=
dp) :: progress, tol, t_next, t_start, t_end
328 if (
present(force))
then
337 if (this%last_tstep .eq. time%tstep)
return
340 if (this%never .and. .not. ifforce)
return
342 progress = this%direction * (time%t - this%anchor_time)
343 t_start = this%direction * (this%start_time - this%anchor_time)
344 tol = this%tolerance(time%dt)
347 if (progress .lt. t_start - tol)
return
351 else if (this%nsteps .gt. 0)
then
352 nstep = time%tstep - this%tstep_offset
353 check = nstep .ge. this%next_index * this%nsteps
354 else if (this%start_pending)
then
359 t_end = this%direction * (this%end_time - this%anchor_time)
360 t_next =
real(this%first_index + this%next_index,
dp) * &
365 if (t_next .gt. t_end +
span_tol *
max(abs(t_end), &
366 this%time_interval))
return
367 check = progress .ge. t_next - tol
382 real(kind=
dp) :: progress, tol
384 if (this%nsteps .gt. 0)
then
385 index = (time%tstep - this%tstep_offset) / this%nsteps + 1
386 else if (this%time_interval .gt. 0.0_dp)
then
387 progress = this%direction * (time%t - this%anchor_time)
388 tol = this%tolerance(time%dt)
389 index = int(floor((progress + tol) / this%time_interval, kind =
i8) &
390 - this%first_index) + 1
393 index = this%next_index
400 index =
max(index, 0)
427 real(kind=
dp) :: progress, tol, dt, t_start, t_first
430 if (this%never)
return
432 if (this%nsteps .gt. 0)
then
436 this%tstep_offset = time%tstep
438 this%start_pending = .false.
439 this%last_tstep = time%tstep
446 if (abs(time%dtlag(1)) .gt. 0.0_dp) dt = time%dtlag(1)
448 progress = this%direction * (time%t - this%anchor_time)
449 t_start = this%direction * (this%start_time - this%anchor_time)
450 tol = this%tolerance(dt)
452 if (progress .lt. t_start - tol)
then
457 n_passed = int(floor((progress + tol) / this%time_interval, &
458 kind =
i8) - this%first_index) + 1
459 this%next_index =
max(n_passed, 0)
460 this%nexecutions = this%next_index
461 if (this%start_pending)
then
466 t_first =
real(this%first_index,
dp) * this%time_interval
467 if (t_first .gt. t_start + tol)
then
468 this%nexecutions = this%nexecutions + 1
471 this%start_pending = .false.
476 this%last_tstep = time%tstep
525 real(kind=
dp) :: t_to_next
526 real(kind=
dp) :: progress, tol, t_next, t_end
527 integer(kind=i8) :: k
529 t_to_next = huge(0.0_dp)
533 if (this%never .or. this%nsteps .gt. 0)
return
538 progress = this%direction * (time%t - this%anchor_time)
539 tol =
span_tol *
max(abs(progress), this%time_interval)
541 if (this%start_pending)
then
545 t_next = this%direction * (this%start_time - this%anchor_time)
548 t_next =
real(this%first_index + this%next_index,
dp) * &
552 if (t_next .le. progress + tol)
then
558 k =
max(this%first_index, &
559 floor((progress + tol) / this%time_interval, kind =
i8) + 1_i8)
560 t_next =
real(k,
dp) * this%time_interval
565 t_end = this%direction * (this%end_time - this%anchor_time)
566 if (t_next .gt. t_end +
span_tol *
max(abs(t_end), this%time_interval)) &
569 t_to_next = t_next - progress
subroutine time_based_controller_init(this, start_time, end_time, control_mode, control_value, write_at_start, anchor_time, direction)
Constructor.