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
67 10
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, &
428 10
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
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
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()
517 10
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.
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.
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
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 constructtimearray(newTa, modelname)
Construct time array.
subroutine, public addtimearraytolist(list, timearray)
Add a time array to a to list.
subroutine, public constructtimearrayseries(newTas, filename)
Allocate a new TimeArraySeriesType object.
subroutine tas_init(this, fname, modelname, iout, tasname, autoDeallocate)
Initialize the time array series.
subroutine get_latest_preceding_node(this, time, tslNode)
Return pointer to ListNodeType object for the node representing the latest preceding time in the time...
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 deallocatebackward(this, fromNode)
Deallocate fromNode and all previous nodes in list; reassign firstNode.
subroutine get_surrounding_records(this, time, taEarlier, taLater)
Get surrounding records.
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.
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.