From 893f29af6df9001c1c41aea41b60cc5c2495f319 Mon Sep 17 00:00:00 2001 From: Florian Prill <florian.prill@dwd.de> Date: Mon, 15 Apr 2019 18:07:10 +0200 Subject: [PATCH] several workarounds in mtime (division of timedelta, events). --- include/mtime_timedelta.h | 3 ++- src/libmtime.f90 | 5 ++-- src/mtime_c_bindings.f90 | 8 +++--- src/mtime_t_event.inc | 8 +++--- src/mtime_t_timedelta.inc | 55 ++++++++++++--------------------------- src/mtime_timedelta.c | 33 ++++++++++++++--------- 6 files changed, 52 insertions(+), 60 deletions(-) diff --git a/include/mtime_timedelta.h b/include/mtime_timedelta.h index 23d47466..72a90165 100644 --- a/include/mtime_timedelta.h +++ b/include/mtime_timedelta.h @@ -86,7 +86,8 @@ struct _timedelta* julianDeltaToTimeDelta(struct _juliandelta* jd, struct _datetime *dt, struct _timedelta* td_return); struct _divisionquotienttimespan* -divideTimeDeltaInSeconds(struct _timedelta* dividend, struct _timedelta* divisor, struct _divisionquotienttimespan* quo_ret); +divideTimeDeltaInSeconds(struct _timedelta* dividend, struct _timedelta* divisor, struct _datetime* base_dt, +struct _divisionquotienttimespan* quo_ret); struct _divisionquotienttimespan* divideTwoDatetimeDiffsInSeconds(struct _datetime* dt1_dividend, struct _datetime* dt2_dividend,struct _datetime* dt1_divisor, struct _datetime* dt2_divisor, int64_t * denominator_ret, struct _divisionquotienttimespan* quo_ret); diff --git a/src/libmtime.f90 b/src/libmtime.f90 index 614f774b..6e9df0ec 100644 --- a/src/libmtime.f90 +++ b/src/libmtime.f90 @@ -1741,14 +1741,15 @@ contains !! @param[out] quotient !! A pointer to type divisionquotienttimespan !! - subroutine divideTimeDeltaInSeconds(dividend, divisor, quotient, errna)!OK-UNTESTED. + SUBROUTINE divideTimeDeltaInSeconds(dividend, divisor, base_dt, quotient, errna)!OK-UNTESTED. type(timedelta), target, intent(in) :: dividend type(timedelta), target, intent(in) :: divisor + TYPE(datetime), TARGET, INTENT(in) :: base_dt type(divisionquotienttimespan), target, intent(out) :: quotient INTEGER, INTENT(out), optional :: errna type(c_ptr) :: dummy_ptr IF (PRESENT(errna)) errna = 0 ! FIXME: no_error - dummy_ptr = my_dividetimedeltainseconds(c_loc(dividend), c_loc(divisor), c_loc(quotient)) + dummy_ptr = my_dividetimedeltainseconds(c_loc(dividend), c_loc(divisor), c_loc(base_dt), c_loc(quotient)) IF (PRESENT(errna) .AND. .NOT. c_associated(dummy_ptr)) THEN errna = errna + 2 ! increment error number by 2, see below for an explanation. ENDIF diff --git a/src/mtime_c_bindings.f90 b/src/mtime_c_bindings.f90 index 420054e0..6f3da716 100644 --- a/src/mtime_c_bindings.f90 +++ b/src/mtime_c_bindings.f90 @@ -510,15 +510,17 @@ module mtime_c_bindings type(c_ptr), value :: jd end function my_timedeltatojuliandelta ! - function my_divideTimeDeltaInSeconds(dividend, divisor, quotient) result(ret_quotient) bind(c,name='divideTimeDeltaInSeconds') + FUNCTION my_divideTimeDeltaInSeconds(dividend, divisor, base_dt, quotient) & +RESULT(ret_quotient) BIND(c,name='divideTimeDeltaInSeconds') import :: c_ptr - type(c_ptr) :: ret_quotient + type(c_ptr) :: ret_quotient type(c_ptr), value :: dividend type(c_ptr), value :: divisor + type(c_ptr), value :: base_dt type(c_ptr), value :: quotient end function my_divideTimeDeltaInSeconds ! - function my_divideDatetimeDifferenceInSeconds(dt1, dt2, divisor, quotient) result(ret_quotient) & + FUNCTION my_divideDatetimeDifferenceInSeconds(dt1, dt2, divisor, quotient) RESULT(ret_quotient) & & bind(c,name='divideDatetimeDifferenceInSeconds') import :: c_ptr type(c_ptr) :: ret_quotient diff --git a/src/mtime_t_event.inc b/src/mtime_t_event.inc index 9c9fed5d..d9a99867 100644 --- a/src/mtime_t_event.inc +++ b/src/mtime_t_event.inc @@ -140,13 +140,13 @@ CLASS (t_eventGroup) :: this TYPE(t_event), TARGET :: event_to_add IF (.NOT. ASSOCIATED(this%last_event_in_group)) THEN - this%first_event_in_group => event_to_add + allocate(this%first_event_in_group, source=event_to_add) + this%last_event_in_group => this%first_event_in_group NULLIFY(this%first_event_in_group%nextEventInGroup) ELSE - this%last_event_in_group%nextEventInGroup => event_to_add - NULLIFY(event_to_add%nextEventInGroup) + allocate(this%last_event_in_group%nextEventInGroup, source=event_to_add) + this%last_event_in_group => this%last_event_in_group%nextEventInGroup ENDIF - this%last_event_in_group => event_to_add END SUBROUTINE t_eventGroup_addToGroup FUNCTION t_eventGroup_getGroupId(this) RESULT(group_id) diff --git a/src/mtime_t_timedelta.inc b/src/mtime_t_timedelta.inc index 53f0d544..7189e031 100644 --- a/src/mtime_t_timedelta.inc +++ b/src/mtime_t_timedelta.inc @@ -154,7 +154,9 @@ TYPE(timedelta), POINTER :: td_tmp TYPE(c_ptr) :: c_pointer, dummy_ptr, c_ptr_result - dummy_ptr = my_elementwisescalarmultiplytimedelta(c_loc(this%td), int(lambda, c_int64_t), c_loc(scaled_td%td)) + ! cast into real since in mtime int implementation scalar + ! multiplication can not give a value in excess of 24 hours + dummy_ptr = my_elementwisescalarmultiplytimedeltadp(c_loc(this%td), real(lambda, c_double), c_loc(scaled_td%td)) IF (.NOT. c_associated(dummy_ptr)) THEN CALL handle_errno(0*100+2, __FILE__, __LINE__) scaled_td%td%sign = '!' @@ -216,47 +218,24 @@ END FUNCTION t_timedelta_toString FUNCTION t_timedelta_divideInSecondsBy (this, divisor, referenceDateTime) RESULT(quotient) - CLASS(t_timedelta), INTENT(in) :: this - TYPE(t_timedelta), INTENT(in) :: divisor - TYPE(t_datetime), INTENT(IN), OPTIONAL :: referenceDateTime - TYPE(divisionquotienttimespan) :: quotient - TYPE(timedelta), POINTER :: tmp_dividend - TYPE(timedelta), POINTER :: tmp_divisor - TYPE(datetime), POINTER :: tmp_ref, tmp_dt - TYPE(t_datetime) :: dt_tmp - INTEGER :: errno - - tmp_dividend => newtimedelta(this%td, errno) - CALL handle_errno(errno, __FILE__, __LINE__) - tmp_divisor => newtimedelta(divisor%td, errno) - CALL handle_errno(errno, __FILE__, __LINE__) - IF (PRESENT(referenceDateTime)) THEN - tmp_ref => newDateTime(referenceDateTime%dt, errno) - CALL handle_errno(errno, __FILE__, __LINE__) - ENDIF + CLASS(t_timedelta), INTENT(in), target :: this + TYPE(t_timedelta), INTENT(in), target :: divisor + TYPE(t_datetime), INTENT(IN), target :: referenceDateTime + TYPE(divisionquotienttimespan), target :: quotient + TYPE(t_datetime), target :: dt_tmp + type(c_ptr) :: dummy_ptr - CALL divideTimeDeltaInSeconds(tmp_dividend, tmp_divisor, quotient, errno) + dummy_ptr = my_divideTimeDeltaInSeconds(c_loc(this%td), c_loc(divisor%td), & + & c_loc(referenceDateTime%dt), c_loc(quotient)) - IF (errno /= no_error) THEN - IF (.NOT. PRESENT(referenceDateTime)) THEN - CALL handle_errno(errno, __FILE__, __LINE__) - ELSE + IF (.NOT. c_associated(dummy_ptr)) THEN dt_tmp = referenceDateTime + this - tmp_dt => newDateTime(dt_tmp%dt, errno) - CALL handle_errno(errno, __FILE__, __LINE__) - CALL divideDatetimeDifferenceInSeconds(tmp_dt, tmp_ref, & - & tmp_divisor, quotient, errno) - CALL handle_errno(errno, __FILE__, __LINE__) - - CALL deallocateDatetime(tmp_dt) - ENDIF - END IF + dummy_ptr = my_dividedatetimedifferenceinseconds(c_loc(dt_tmp%dt), & + & c_loc(referenceDateTime%dt), & + & c_loc(divisor%td), c_loc(quotient)) - CALL deallocatetimedelta(tmp_dividend) - CALL deallocatetimedelta(tmp_divisor) - IF (PRESENT(referenceDateTime)) THEN - CALL deallocateDatetime(tmp_ref) - ENDIF + CALL handle_errno(.not. c_associated(dummy_ptr), general_arithmetic_error, __FILE__, __LINE__) + END IF END FUNCTION t_timedelta_divideInSecondsBy FUNCTION t_timedelta_toSeconds (this, td) RESULT(seconds) diff --git a/src/mtime_timedelta.c b/src/mtime_timedelta.c index 9448228b..558bcd8f 100644 --- a/src/mtime_timedelta.c +++ b/src/mtime_timedelta.c @@ -1172,26 +1172,35 @@ else /*! \endcond */ +// WE REALLY NEED SOMETHING BETTER HERE! struct _divisionquotienttimespan* -divideTimeDeltaInSeconds(struct _timedelta* dividend, struct _timedelta* divisor, struct _divisionquotienttimespan* quo_ret) +divideTimeDeltaInSeconds(struct _timedelta* dividend, struct _timedelta* divisor, struct _datetime* base_dt, struct _divisionquotienttimespan* quo_ret) { if ((dividend != NULL) && (divisor != NULL) && (quo_ret != NULL)) { - if ((dividend->year == 0) && (dividend->month == 0) && (divisor->year == 0) && (divisor->month == 0)) + if ((dividend->year == 0) && (divisor->year == 0) && (divisor->month == 0)) { - intmax_t numerator = (intmax_t) (((int64_t) dividend->day * 86400 + - dividend->hour * 3600 + - dividend->minute * 60 + - dividend->second) * 1000 + - dividend->ms); + + struct _juliandelta* jd = newJulianDelta('+', 0, 0); + if ( jd == NULL ) + return 0; + jd = timeDeltaToJulianDelta(dividend, base_dt, jd); + if ( jd == NULL ) + { + deallocateJulianDelta(jd); + return 0; + } + + intmax_t numerator = (intmax_t) (((int64_t) jd->day * NO_OF_MS_IN_A_DAY + jd->ms)); intmax_t denominator = (intmax_t) (((int64_t) divisor->day * 86400 + - divisor->hour * 3600 + - divisor->minute * 60 + - divisor->second ) * 1000 + - divisor->ms); + divisor->hour * 3600 + + divisor->minute * 60 + + divisor->second ) * 1000 + + divisor->ms); + deallocateJulianDelta(jd); if (denominator == 0) /* Division by zero is illegal. */ - return NULL; + return NULL; imaxdiv_t div = imaxdiv(numerator, denominator); -- GitLab