Octopus
clock.F90
Go to the documentation of this file.
1!! Copyright (C) 2020 Heiko Appel, M. Oliveira
2!! Copyright (C) 2021 I-Te Lu
3!!
4!! This program is free software; you can redistribute it and/or modify
5!! it under the terms of the GNU General Public License as published by
6!! the Free Software Foundation; either version 2, or (at your option)
7!! any later version.
8!!
9!! This program is distributed in the hope that it will be useful,
10!! but WITHOUT ANY WARRANTY; without even the implied warranty of
11!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12!! GNU General Public License for more details.
13!!
14!! You should have received a copy of the GNU General Public License
15!! along with this program; if not, write to the Free Software
16!! Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17!! 02110-1301, USA.
18!!
19
20#include "global.h"
21
22module clock_oct_m
23 use debug_oct_m
24 use global_oct_m
25 use io_oct_m
26 use loct_oct_m
30
31 implicit none
32
33 private
34
35 integer, parameter :: CLOCK_TICK = 1
36
37 float, parameter :: time_relative_tolerance = cnst(1.e-8)
38
39 public :: &
40 clock_t, &
41 clock_tick
42
43 type clock_t
44 private
45 integer :: tick
46 float :: time_step
47 float :: time_
48 contains
49 procedure :: print => clock_print
50 procedure :: print_str => clock_print_str
51 procedure :: set_time => clock_set_time
52 procedure :: copy => clock_copy
53 procedure :: get_tick => clock_get_tick
54 procedure :: get_dt => clock_get_dt
55 procedure :: time => clock_time
56 procedure :: reset => clock_reset
57 procedure :: clock_is_equal
58 generic :: operator(.eq.) => clock_is_equal
59 procedure :: clock_is_different
60 generic :: operator(/=) => clock_is_different
61 procedure :: clock_is_earlier
62 generic :: operator(.lt.) => clock_is_earlier
63 procedure :: clock_is_later
64 generic :: operator(.gt.) => clock_is_later
65 procedure :: clock_is_equal_or_earlier
66 generic :: operator(.le.) => clock_is_equal_or_earlier
67 procedure :: clock_is_equal_or_later
68 generic :: operator(.ge.) => clock_is_equal_or_later
69 procedure :: clock_copy
70 generic :: assignment(=) => clock_copy
71 procedure :: clock_add_tick
72 generic :: operator(+) => clock_add_tick
73 procedure :: clock_subtract_tick
74 generic :: operator(-) => clock_subtract_tick
75 procedure :: restart_write => clock_restart_write
76 procedure :: restart_read => clock_restart_read
77 end type clock_t
78
79 interface clock_t
80 module procedure clock_init
81 end interface clock_t
82
83contains
84
85 ! ---------------------------------------------------------
89 type(clock_t) function clock_init(time_step, initial_tick) result(this)
90 float, optional, intent(in) :: time_step
91 integer, optional, intent(in) :: initial_tick
92
93 push_sub(clock_init)
94
95 this%tick = optional_default(initial_tick, 0)
96 this%time_step = optional_default(time_step, m_zero)
97 if (this%time_step <= m_zero) then
98 this%time_ = m_zero
99 else
100 this%time_ = this%tick*this%time_step
101 end if
102
103 pop_sub(clock_init)
104 end function clock_init
105
106 ! ---------------------------------------------------------
107 function clock_print_str(this) result(clock_string)
108 class(clock_t), intent(in) :: this
109 character(len=65) :: clock_string
110
111 push_sub(clock_print_str)
112
113 write(clock_string,'(A7,F16.6,A,I8.8,A)') &
114 '[Clock:', &
115 this%time_, &
116 '|', &
117 this%tick, &
118 ']'
119
121 end function clock_print_str
123 ! ---------------------------------------------------------
124 subroutine clock_print(this)
125 class(clock_t), intent(in) :: this
126
127 push_sub(clock_print)
129 message(1) = this%print_str()
130 call messages_info(1)
132 pop_sub(clock_print)
133 end subroutine clock_print
135 ! ---------------------------------------------------------
136 subroutine clock_set_time(this, new)
137 class(clock_t), intent(inout) :: this
138 class(clock_t), intent(in) :: new
140 logical :: commensurable
141 integer :: this_granularity, new_granularity
145 if (this%time_step > m_zero .and. new%time_step > m_zero) then
146 if (this%time_step >= new%time_step) then
147 commensurable = ceiling(this%time_step/new%time_step) == floor(this%time_step/new%time_step)
148 this_granularity = ceiling(this%time_step/new%time_step)
149 new_granularity = 1
150 else
151 commensurable = ceiling(new%time_step/this%time_step) == floor(new%time_step/this%time_step)
152 this_granularity = 1
153 new_granularity = ceiling(new%time_step/this%time_step)
154 end if
156 if (.not. commensurable) then
157 message(1) = 'Cannot set clock new time, as it is not commensurable with clock time-step.'
158 call messages_fatal(1)
159 end if
161 this%tick = (new%tick * new_granularity) / this_granularity
162 this%time_ = this%tick*this%time_step
163 else
164 this%time_ = new%time_
165 end if
166
167 pop_sub(clock_set_time)
168 end subroutine clock_set_time
169
170 ! ---------------------------------------------------------
171 subroutine clock_copy(this, clock_in)
172 class(clock_t), intent(in) :: clock_in
173 class(clock_t), intent(inout) :: this
175 push_sub(clock_copy)
176
177 this%tick = clock_in%tick
178 this%time_step = clock_in%time_step
179 this%time_ = clock_in%time_
180
181 pop_sub(clock_copy)
182 end subroutine clock_copy
183
184 ! ---------------------------------------------------------
185 type(clock_t) function clock_add_tick(clock, tick) result(new_clock)
186 class(clock_t), intent(in) :: clock
187 integer, intent(in) :: tick
188
189 push_sub(clock_add_tick)
190
191 new_clock = clock
192 new_clock%tick = new_clock%tick + tick
193 new_clock%time_ = new_clock%tick*new_clock%time_step
194
195 pop_sub(clock_add_tick)
196 end function clock_add_tick
197
198 ! ---------------------------------------------------------
199 type(clock_t) function clock_subtract_tick(clock, tick) result(new_clock)
200 class(clock_t), intent(in) :: clock
201 integer, intent(in) :: tick
202
203 push_sub(clock_subtract_tick)
204
205 new_clock = clock
206 new_clock%tick = new_clock%tick - tick
207 new_clock%time_ = new_clock%tick*new_clock%time_step
208
210 end function clock_subtract_tick
211
212 ! ---------------------------------------------------------
213 integer function clock_get_tick(this) result(tick)
214 class(clock_t), intent(in) :: this
215
216 push_sub(clock_get_tick)
217
218 tick = this%tick
219
220 pop_sub(clock_get_tick)
221 end function clock_get_tick
222
223 ! ---------------------------------------------------------
224 float function clock_get_dt(this) result(dt)
225 class(clock_t), intent(in) :: this
226
227 push_sub(clock_get_dt)
228
229 dt = this%time_step
230
231 pop_sub(clock_get_dt)
232 end function clock_get_dt
233
234
235 ! ---------------------------------------------------------
236 float function clock_time(this)
237 class(clock_t), intent(in) :: this
238
239 push_sub(clock_time)
240
241 clock_time = this%time_
242
243 pop_sub(clock_time)
244 end function clock_time
245
246 ! ---------------------------------------------------------
247 subroutine clock_reset(this)
248 class(clock_t), intent(inout) :: this
249
250 push_sub(clock_reset)
251
252 this%tick = 0
253 this%time_ = m_zero
254
255 pop_sub(clock_reset)
256 end subroutine clock_reset
257
258 ! ---------------------------------------------------------
259 logical function clock_is_earlier(clock_a, clock_b) result(is_earlier)
260 class(clock_t), intent(in) :: clock_a, clock_b
261
262 push_sub(clock_is_earlier)
263
264 ! take into account the finite precision of the clocks
265 if (clock_is_equal(clock_a, clock_b)) then
266 is_earlier = .false.
267 else
268 is_earlier = clock_a%time_ < clock_b%time_
269 end if
271 pop_sub(clock_is_earlier)
272 end function clock_is_earlier
273
274 ! ---------------------------------------------------------
275 logical function clock_is_later(clock_a, clock_b) result(is_later)
276 class(clock_t), intent(in) :: clock_a, clock_b
277
278 push_sub(clock_is_later)
279
280 ! take into account the finite precision of the clocks
281 if (clock_is_equal(clock_a, clock_b)) then
282 is_later = .false.
283 else
284 is_later = clock_a%time_ > clock_b%time_
285 end if
286
287 pop_sub(clock_is_later)
288 end function clock_is_later
289
290 ! ---------------------------------------------------------
291 logical function clock_is_equal_or_earlier(clock_a, clock_b) result(is_earlier)
292 class(clock_t), intent(in) :: clock_a, clock_b
293
295
296 is_earlier = .not. clock_is_later(clock_a, clock_b)
297
299 end function clock_is_equal_or_earlier
300
301 ! ---------------------------------------------------------
302 logical function clock_is_equal_or_later(clock_a, clock_b) result(is_later)
303 class(clock_t), intent(in) :: clock_a, clock_b
304
306
307 is_later = .not. clock_is_earlier(clock_a, clock_b)
308
310 end function clock_is_equal_or_later
311
312 ! ---------------------------------------------------------
313 logical function clock_is_equal(clock_a, clock_b) result(are_equal)
314 class(clock_t), intent(in) :: clock_a, clock_b
315
316 push_sub(clock_is_equal)
317
318 ! we need to take into account the finite precision of floating point numbers
319 if (abs(clock_b%time_) <= m_epsilon) then
320 ! if the times are exactly 0, we cannot do a relative comparison, so we require
321 ! both clocks to be exactly 0
322 are_equal = clock_a%time_ == m_zero
323 else if (abs(clock_a%time_) <= m_epsilon) then
324 ! if the times are exactly 0, we cannot do a relative comparison, so we require
325 ! both clocks to be exactly 0
326 are_equal = clock_b%time_ == m_zero
327 else
328 ! otherwise we allow for a certain relative difference between the two values
329 are_equal = abs((clock_a%time_-clock_b%time_)/clock_b%time_) <= time_relative_tolerance
330 end if
331
333 end function clock_is_equal
334
335 ! ---------------------------------------------------------
336 logical function clock_is_different(clock_a, clock_b) result(are_diff)
337 class(clock_t), intent(in) :: clock_a, clock_b
338
339 push_sub(clock_is_different)
340
341 are_diff = .not. clock_is_equal(clock_a, clock_b)
342
343 pop_sub(clock_is_different)
345
346 ! ---------------------------------------------------------
347 subroutine clock_restart_write(this, filename, namespace)
348 class(clock_t), intent(in) :: this
349 character(len=*), intent(in) :: filename
350 type(namespace_t), intent(in) :: namespace
351
352 integer :: restart_file_unit
353
354 push_sub(clock_restart_write)
355
356 call io_mkdir("restart", namespace, parents=.true.)
357 restart_file_unit = io_open("restart/"//filename, namespace, form="unformatted", action='write')
358 write(restart_file_unit) this%tick, this%time_step
359 call io_close(restart_file_unit)
361 pop_sub(clock_restart_write)
362 end subroutine clock_restart_write
363
364 ! ---------------------------------------------------------
365 logical function clock_restart_read(this, filename, namespace)
366 class(clock_t), intent(inout) :: this
367 character(len=*), intent(in) :: filename
368 type(namespace_t), intent(in) :: namespace
369
370 integer :: restart_file_unit
371
372 push_sub(clock_restart_read)
373
374 restart_file_unit = io_open("restart/"//filename, namespace, form="unformatted", action='read', die=.false.)
375 if (restart_file_unit > 0) then
376 read(restart_file_unit) this%tick, this%time_step
377 call io_close(restart_file_unit)
378
379 this = clock_t(this%time_step, this%tick)
381 else
382 ! could not open file
383 clock_restart_read = .false.
384 end if
385
386 pop_sub(clock_restart_read)
388
389end module clock_oct_m
390
391!! Local Variables:
392!! mode: f90
393!! coding: utf-8
394!! End:
double floor(double __x) __attribute__((__nothrow__
type(clock_t) function clock_init(time_step, initial_tick)
Initialize the clock with a given label and associated physical time step. The internal clock counter...
Definition: clock.F90:175
real(8) function clock_get_dt(this)
Definition: clock.F90:310
type(clock_t) function clock_add_tick(clock, tick)
Definition: clock.F90:271
logical function clock_is_equal_or_later(clock_a, clock_b)
Definition: clock.F90:388
subroutine clock_restart_write(this, filename, namespace)
Definition: clock.F90:433
integer function clock_get_tick(this)
Definition: clock.F90:299
subroutine clock_print(this)
Definition: clock.F90:210
subroutine clock_set_time(this, new)
Definition: clock.F90:222
real(8) function clock_time(this)
Definition: clock.F90:322
type(clock_t) function clock_subtract_tick(clock, tick)
Definition: clock.F90:285
logical function clock_is_later(clock_a, clock_b)
Definition: clock.F90:361
logical function clock_is_equal_or_earlier(clock_a, clock_b)
Definition: clock.F90:377
real(8), parameter time_relative_tolerance
Definition: clock.F90:122
character(len=65) function clock_print_str(this)
Definition: clock.F90:193
logical function clock_is_equal(clock_a, clock_b)
Definition: clock.F90:399
subroutine clock_reset(this)
Definition: clock.F90:333
subroutine clock_copy(this, clock_in)
Definition: clock.F90:257
logical function clock_is_earlier(clock_a, clock_b)
Definition: clock.F90:345
logical function clock_restart_read(this, filename, namespace)
Definition: clock.F90:451
logical function clock_is_different(clock_a, clock_b)
Definition: clock.F90:422
real(8), parameter, public m_zero
Definition: global.F90:170
Definition: io.F90:106
subroutine, public push_sub(sub_name)
Definition: messages.F90:1046
subroutine, public pop_sub(sub_name)
Definition: messages.F90:1101
clock_t clock(void)
Definition: oct_f.c:3427
int true(void)