17 use,
intrinsic :: iso_fortran_env, only: iostat_end
26 character(len=LENTIMESERIESNAME),
public :: name =
''
28 integer(I4B),
private :: inunit = 0
29 integer(I4B),
private ::
iout = 0
31 real(dp),
private :: sfac =
done
32 character(len=LINELENGTH),
private :: datafile =
''
33 logical,
private :: autodeallocate = .true.
34 type(
listtype),
pointer,
private :: list => null()
35 character(len=LENMODELNAME) :: modelname
63 character(len=*),
intent(in) :: filename
6710
format(
'Error: Time-array-series file "', a,
'" does not exist.')
71 allocate (newtas%list)
74 inquire (file=filename, exist=lex)
76 write (
errmsg, 10) trim(filename)
79 newtas%datafile = filename
86 subroutine tas_init(this, fname, modelname, iout, tasname, autoDeallocate)
89 character(len=*),
intent(in) :: fname
90 character(len=*),
intent(in) :: modelname
91 integer(I4B),
intent(in) :: iout
92 character(len=*),
intent(inout) :: tasname
93 logical,
optional,
intent(in) :: autoDeallocate
95 integer(I4B) :: istatus
97 integer(I4B) :: inunit
98 character(len=40) :: keyword, keyvalue
99 logical :: found, continueread, endOfBlock
102 if (
present(autodeallocate)) this%autoDeallocate = autodeallocate
103 this%dataFile = fname
107 this%modelname = modelname
113 call openfile(inunit, 0, fname,
'TAS6')
116 call this%parser%Initialize(this%inunit, this%iout)
119 continueread = .false.
123 call this%parser%GetBlock(
'ATTRIBUTES', found, ierr, &
124 supportopenclose=.true.)
125 if (.not. found)
then
126 errmsg =
'Error: Attributes block not found in file: '// &
129 call this%parser%StoreErrorUnit()
135 call this%parser%GetNextLine(endofblock)
139 call this%parser%GetStringCaps(keyword)
142 call this%parser%GetStringCaps(keyvalue)
143 select case (keyword)
148 select case (keyvalue)
154 errmsg =
'Unknown interpolation method: "'//trim(keyvalue)//
'"'
156 call this%parser%StoreErrorUnit()
158 case (
'AUTODEALLOCATE')
159 this%autoDeallocate = (keyvalue ==
'TRUE')
161 read (keyvalue, *, iostat=istatus) this%sfac
162 if (istatus /= 0)
then
163 errmsg =
'Error reading numeric SFAC value from "'//trim(keyvalue) &
166 call this%parser%StoreErrorUnit()
169 errmsg =
'Unknown option found in ATTRIBUTES block: "'// &
172 call this%parser%StoreErrorUnit()
177 if (this%Name ==
'')
then
178 errmsg =
'Name not specified for time array series in file: '// &
181 call this%parser%StoreErrorUnit()
184 errmsg =
'Interpolation method not specified for time'// &
185 ' array series in file: '//trim(this%dataFile)
187 call this%parser%StoreErrorUnit()
192 errmsg =
'Error(s) encountered initializing time array series from file: ' &
193 //trim(this%dataFile)
195 call this%parser%StoreErrorUnit()
199 if (.not. this%read_next_array())
then
200 errmsg =
'Error encountered reading time-array data from file: '// &
203 call this%parser%StoreErrorUnit()
213 integer(I4B),
intent(in) :: nvals
214 real(DP),
dimension(nvals),
intent(inout) :: values
215 real(DP),
intent(in) :: time0
216 real(DP),
intent(in) :: time1
221 timediff = time1 - time0
222 if (timediff > 0)
then
223 call this%get_integrated_values(nvals, values, time0, time1)
225 values(i) = values(i) / timediff
229 call this%get_values_at_time(nvals, values, time0)
251 real(DP),
intent(in) :: time
255 real(DP) :: time0, time1
259 type(
timearraytype),
pointer :: ta => null(), ta0 => null(), ta1 => null()
260 class(*),
pointer :: obj
265 if (
associated(this%list%firstNode))
then
266 currnode => this%list%firstNode
272 if (
associated(currnode))
then
273 if (
associated(currnode%nextNode))
then
274 obj => currnode%nextNode%GetItem()
276 if (ta%taTime <= time)
then
277 currnode => currnode%nextNode
283 if (.not. this%read_next_array())
exit
290 if (
associated(currnode))
then
294 obj => node0%GetItem()
297 do while (time0 > time)
298 if (
associated(node0%prevNode))
then
299 node0 => node0%prevNode
300 obj => node0%GetItem()
310 obj => node1%GetItem()
313 do while (time1 < time)
314 if (
associated(node1%nextNode))
then
315 node1 => node1%nextNode
316 obj => node1%GetItem()
321 if (.not. this%read_next_array())
then
330 if (time0 <= time) taearlier => ta0
331 if (time1 >= time) talater => ta1
345 integer(I4B) :: i, ierr, istart, istat, istop, lloc, nrow, ncol, &
347 logical :: lopen, isfound
349 character(len=LENMEMPATH) :: mempath
350 integer(I4B),
dimension(:),
contiguous,
pointer :: mshape
364 call mem_setptr(mshape,
'MODEL_SHAPE', mempath)
367 if (
size(mshape) == 2)
then
368 nodesperlayer = mshape(2)
371 else if (
size(mshape) == 3)
then
372 nodesperlayer = mshape(2) * mshape(3)
376 errmsg =
'Time array series is not supported for selected &
377 &discretization type.'
379 call this%parser%StoreErrorUnit()
383 inquire (unit=this%inunit, opened=lopen)
388 call this%parser%GetBlock(
'TIME', isfound, ierr, &
389 supportopenclose=.false.)
391 ta%taTime = this%parser%GetDouble()
393 call readarray(this%parser%iuactive, ta%taArray, this%Name, &
394 size(mshape), ncol, nrow, 1, nodesperlayer, &
398 do i = 1, nodesperlayer
399 ta%taArray(i) = ta%taArray(i) * this%sfac
407 call this%parser%terminateblock()
418 integer(I4B),
intent(in) :: nvals
419 real(DP),
dimension(nvals),
intent(inout) :: values
420 real(DP),
intent(in) :: time
422 integer(I4B) :: i, ierr
423 real(DP) :: ratio, time0, time1, timediff, timediffi, val0, val1, &
42810
format(
'Error getting array at time ', g10.3, &
429 ' for time-array series "', a,
'"')
432 call this%get_surrounding_records(time, taearlier, talater)
433 if (
associated(taearlier))
then
434 if (
associated(talater))
then
436 if (this%iMethod == stepwise)
then
438 values = taearlier%taArray
439 elseif (this%iMethod == linear)
then
441 time0 = taearlier%taTime
442 time1 = talater%tatime
443 timediff = time1 - time0
444 timediffi = time - time0
445 if (timediff > 0)
then
446 ratio = timediffi / timediff
453 val0 = taearlier%taArray(i)
454 val1 = talater%taArray(i)
455 valdiff = val1 - val0
456 values(i) = val0 + (ratio * valdiff)
462 if (
is_close(taearlier%taTime, time))
then
463 values = taearlier%taArray
467 if (this%iMethod == stepwise)
then
468 values = taearlier%taArray
475 if (
associated(talater))
then
476 if (
is_close(talater%taTime, time))
then
477 values = talater%taArray
490 write (errmsg, 10) time, trim(this%Name)
503 integer(I4B),
intent(in) :: nvals
504 real(DP),
dimension(nvals),
intent(inout) :: values
505 real(DP),
intent(in) :: time0
506 real(DP),
intent(in) :: time1
509 real(DP) :: area, currTime, nextTime, ratio0, ratio1, t0, &
510 t01, t1, timediff,
value, value0, value1, valuediff
513 type(
listnodetype),
pointer :: currNode => null(), nextnode => null()
514 type(
timearraytype),
pointer :: currRecord => null(), nextrecord => null()
515 class(*),
pointer :: currObj => null(), nextobj => null()
51710
format(
'Error encountered while performing integration', &
518 ' for time-array series "', a,
'" for time interval: ', &
519 g12.5,
' to ', g12.5)
525 call this%get_latest_preceding_node(time0, precnode)
526 if (
associated(precnode))
then
528 do while (.not. ldone)
529 currobj => currnode%GetItem()
531 currtime = currrecord%taTime
532 if (currtime < time1)
then
533 if (.not.
associated(currnode%nextNode))
then
535 if (.not. this%read_next_array())
then
536 write (errmsg, 10) trim(this%Name), time0, time1
541 if (
associated(currnode%nextNode))
then
542 nextnode => currnode%nextNode
543 nextobj => nextnode%GetItem()
545 nexttime = nextrecord%taTime
548 if (currtime >= time0)
then
553 if (nexttime <= time1)
then
561 select case (this%iMethod)
565 value0 = currrecord%taArray(i)
568 values(i) = values(i) + area
573 timediff = nexttime - currtime
574 ratio0 = (t0 - currtime) / timediff
575 ratio1 = (t1 - currtime) / timediff
576 valuediff = nextrecord%taArray(i) - currrecord%taArray(i)
577 value0 = currrecord%taArray(i) + ratio0 * valuediff
578 value1 = currrecord%taArray(i) + ratio1 * valuediff
579 area = 0.5d0 * t01 * (value0 + value1)
581 values(i) = values(i) + area
585 write (errmsg, 10) trim(this%Name), time0, time1
587 call store_error(
'(Probable programming error)', terminate=.true.)
595 if (t1 >= time1)
then
598 if (.not.
associated(currnode%nextNode))
then
600 if (.not. this%read_next_array())
then
601 write (errmsg, 10) trim(this%Name), time0, time1
603 call this%parser%StoreErrorUnit()
606 if (
associated(currnode%nextNode))
then
607 currnode => currnode%nextNode
609 write (errmsg, 10) trim(this%Name), time0, time1
611 call store_error(
'(Probable programming error)', terminate=.true.)
617 if (this%autoDeallocate)
then
618 if (
associated(precnode))
then
619 if (
associated(precnode%prevNode))
then
620 call this%DeallocateBackward(precnode%prevNode)
638 class(*),
pointer :: obj => null()
640 if (
associated(fromnode))
then
642 if (
associated(fromnode%nextNode))
then
643 this%list%firstNode => fromnode%nextNode
645 this%list%firstNode => null()
649 do while (
associated(current))
650 prev => current%prevNode
651 obj => current%GetItem()
656 call this%list%RemoveNode(current, .true.)
669 real(DP),
intent(in) :: time
677 class(*),
pointer :: obj => null()
680 if (
associated(this%list%firstNode))
then
681 currnode => this%list%firstNode
684 &get_latest_preceding_node', &
692 if (
associated(currnode))
then
693 if (
associated(currnode%nextNode))
then
694 obj => currnode%nextNode%GetItem()
696 if (ta%taTime < time .or.
is_close(ta%taTime, time))
then
697 currnode => currnode%nextNode
703 if (.not. this%read_next_array())
exit
710 if (
associated(currnode))
then
714 obj => node0%GetItem()
717 do while (time0 > time)
718 if (
associated(node0%prevNode))
then
719 node0 => node0%prevNode
720 obj => node0%GetItem()
729 if (time0 <= time) tslnode => node0
742 n = this%list%Count()
749 call this%list%Clear(.true.)
750 deallocate (this%list)
759 class(*),
pointer,
intent(inout) :: obj
764 if (.not.
associated(obj))
return
776 type(
listtype),
intent(inout) :: list
777 integer,
intent(in) :: indx
781 class(*),
pointer :: obj
783 obj => list%GetItem(indx)
This module contains block parser methods.
integer(i4b) function getunit(this)
@ brief Get the unit number
This module contains simulation constants.
integer(i4b), parameter linelength
maximum length of a standard line
integer(i4b), parameter lenmodelname
maximum length of the model name
integer(i4b), parameter lentimeseriesname
maximum length of a time series name
@ undefined
undefined interpolation
@ linear
linear interpolation
@ stepwise
stepwise interpolation
real(dp), parameter dzero
real constant zero
integer(i4b), parameter lenmempath
maximum length of the memory path
real(dp), parameter done
real constant 1
This module defines variable data types.
subroutine deallocatebackward(this, fromnode)
Deallocate fromNode and all previous nodes, and reassign firstNode.
pure logical function, public is_close(a, b, rtol, atol, symmetric)
Check if a real value is approximately equal to another.
character(len=lenmempath) function create_mem_path(component, subcomponent, context)
returns the path to the memory object
This module contains simulation methods.
subroutine, public store_error(msg, terminate)
Store an error message.
integer(i4b) function, public count_errors()
Return number of errors.
subroutine, public store_error_unit(iunit, terminate)
Store the file unit number.
This module contains simulation variables.
character(len=maxcharlen) errmsg
error message string
character(len=linelength) idm_context
integer(i4b) iout
file unit number for simulation output
subroutine, public constructtimearray(newta, modelname)
Construct time array.
type(timearraytype) function, pointer, public castastimearraytype(obj)
Cast an unlimited polymorphic object as TimeArrayType.
type(timearraytype) function, pointer, public gettimearrayfromlist(list, indx)
Retrieve a time array from a list.
subroutine, public addtimearraytolist(list, timearray)
Add a time array to a to list.
subroutine tas_init(this, fname, modelname, iout, tasname, autodeallocate)
Initialize the time array series.
subroutine get_surrounding_records(this, time, taearlier, talater)
Get surrounding records.
subroutine getaveragevalues(this, nvals, values, time0, time1)
Populate an array time-weighted average value for a specified time span.
subroutine tas_da(this)
Deallocate memory.
subroutine get_values_at_time(this, nvals, values, time)
Return an array of values for a specified time, same units as time-series values.
subroutine get_latest_preceding_node(this, time, tslnode)
Return pointer to ListNodeType object for the node representing the latest preceding time in the time...
type(timearrayseriestype) function, pointer, public gettimearrayseriesfromlist(list, indx)
Get time array from list.
subroutine get_integrated_values(this, nvals, values, time0, time1)
Populates an array with integrated values for a specified time span.
subroutine, public constructtimearrayseries(newtas, filename)
Allocate a new TimeArraySeriesType object.
type(timearrayseriestype) function, pointer, public castastimearrayseriestype(obj)
Cast an unlimited polymorphic object as class(TimeArraySeriesType).
integer(i4b) function getinunit(this)
Return unit number.
logical function read_next_array(this)
Read next time array from input file and append to list.
A generic heterogeneous doubly-linked list.