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
344 integer(I4B) :: i, ierr, istart, istat, istop, lloc, nrow, ncol, &
346 logical :: lopen, isfound
348 character(len=LENMEMPATH) :: mempath
349 integer(I4B),
dimension(:),
contiguous,
pointer :: mshape
359 mempath =
create_mem_path(component=this%modelname, subcomponent=
'DIS')
365 if (
size(mshape) == 2)
then
366 nodesperlayer = mshape(2)
369 else if (
size(mshape) == 3)
then
370 nodesperlayer = mshape(2) * mshape(3)
374 errmsg =
'Time array series is not supported for selected &
375 &discretization type.'
377 call this%parser%StoreErrorUnit()
381 inquire (unit=this%inunit, opened=lopen)
386 call this%parser%GetBlock(
'TIME', isfound, ierr, &
387 supportopenclose=.false.)
389 ta%taTime = this%parser%GetDouble()
391 call readarray(this%parser%iuactive, ta%taArray, this%Name, &
392 size(mshape), ncol, nrow, 1, nodesperlayer, &
396 do i = 1, nodesperlayer
397 ta%taArray(i) = ta%taArray(i) * this%sfac
405 call this%parser%terminateblock()
416 integer(I4B),
intent(in) :: nvals
417 real(DP),
dimension(nvals),
intent(inout) :: values
418 real(DP),
intent(in) :: time
420 integer(I4B) :: i, ierr
421 real(DP) :: ratio, time0, time1, timediff, timediffi, val0, val1, &
426 10
format(
'Error getting array at time ', g10.3, &
427 ' for time-array series "', a,
'"')
430 call this%get_surrounding_records(time, taearlier, talater)
431 if (
associated(taearlier))
then
432 if (
associated(talater))
then
436 values = taearlier%taArray
437 elseif (this%iMethod ==
linear)
then
439 time0 = taearlier%taTime
440 time1 = talater%tatime
441 timediff = time1 - time0
442 timediffi = time - time0
443 if (timediff > 0)
then
444 ratio = timediffi / timediff
451 val0 = taearlier%taArray(i)
452 val1 = talater%taArray(i)
453 valdiff = val1 - val0
454 values(i) = val0 + (ratio * valdiff)
460 if (
is_close(taearlier%taTime, time))
then
461 values = taearlier%taArray
466 values = taearlier%taArray
473 if (
associated(talater))
then
474 if (
is_close(talater%taTime, time))
then
475 values = talater%taArray
488 write (
errmsg, 10) time, trim(this%Name)
501 integer(I4B),
intent(in) :: nvals
502 real(DP),
dimension(nvals),
intent(inout) :: values
503 real(DP),
intent(in) :: time0
504 real(DP),
intent(in) :: time1
507 real(DP) :: area, currTime, nextTime, ratio0, ratio1, t0, &
508 t01, t1, timediff,
value, value0, value1, valuediff
511 type(
listnodetype),
pointer :: currNode => null(), nextnode => null()
512 type(
timearraytype),
pointer :: currRecord => null(), nextrecord => null()
513 class(*),
pointer :: currObj => null(), nextobj => null()
515 10
format(
'Error encountered while performing integration', &
516 ' for time-array series "', a,
'" for time interval: ', &
517 g12.5,
' to ', g12.5)
523 call this%get_latest_preceding_node(time0, precnode)
524 if (
associated(precnode))
then
526 do while (.not. ldone)
527 currobj => currnode%GetItem()
529 currtime = currrecord%taTime
530 if (currtime < time1)
then
531 if (.not.
associated(currnode%nextNode))
then
533 if (.not. this%read_next_array())
then
534 write (
errmsg, 10) trim(this%Name), time0, time1
539 if (
associated(currnode%nextNode))
then
540 nextnode => currnode%nextNode
541 nextobj => nextnode%GetItem()
543 nexttime = nextrecord%taTime
546 if (currtime >= time0)
then
551 if (nexttime <= time1)
then
559 select case (this%iMethod)
563 value0 = currrecord%taArray(i)
566 values(i) = values(i) + area
571 timediff = nexttime - currtime
572 ratio0 = (t0 - currtime) / timediff
573 ratio1 = (t1 - currtime) / timediff
574 valuediff = nextrecord%taArray(i) - currrecord%taArray(i)
575 value0 = currrecord%taArray(i) + ratio0 * valuediff
576 value1 = currrecord%taArray(i) + ratio1 * valuediff
577 area = 0.5d0 * t01 * (value0 + value1)
579 values(i) = values(i) + area
583 write (
errmsg, 10) trim(this%Name), time0, time1
585 call store_error(
'(Probable programming error)', terminate=.true.)
593 if (t1 >= time1)
then
596 if (.not.
associated(currnode%nextNode))
then
598 if (.not. this%read_next_array())
then
599 write (
errmsg, 10) trim(this%Name), time0, time1
601 call this%parser%StoreErrorUnit()
604 if (
associated(currnode%nextNode))
then
605 currnode => currnode%nextNode
607 write (
errmsg, 10) trim(this%Name), time0, time1
609 call store_error(
'(Probable programming error)', terminate=.true.)
615 if (this%autoDeallocate)
then
616 if (
associated(precnode))
then
617 if (
associated(precnode%prevNode))
then
618 call this%DeallocateBackward(precnode%prevNode)
636 class(*),
pointer :: obj => null()
638 if (
associated(fromnode))
then
640 if (
associated(fromnode%nextNode))
then
641 this%list%firstNode => fromnode%nextNode
643 this%list%firstNode => null()
647 do while (
associated(current))
648 prev => current%prevNode
649 obj => current%GetItem()
654 call this%list%RemoveNode(current, .true.)
667 real(DP),
intent(in) :: time
675 class(*),
pointer :: obj => null()
678 if (
associated(this%list%firstNode))
then
679 currnode => this%list%firstNode
682 &get_latest_preceding_node', &
690 if (
associated(currnode))
then
691 if (
associated(currnode%nextNode))
then
692 obj => currnode%nextNode%GetItem()
694 if (ta%taTime < time .or.
is_close(ta%taTime, time))
then
695 currnode => currnode%nextNode
701 if (.not. this%read_next_array())
exit
708 if (
associated(currnode))
then
712 obj => node0%GetItem()
715 do while (time0 > time)
716 if (
associated(node0%prevNode))
then
717 node0 => node0%prevNode
718 obj => node0%GetItem()
727 if (time0 <= time) tslnode => node0
740 n = this%list%Count()
747 call this%list%Clear(.true.)
748 deallocate (this%list)
757 class(*),
pointer,
intent(inout) :: obj
762 if (.not.
associated(obj))
return
774 type(
listtype),
intent(inout) :: list
775 integer,
intent(in) :: indx
779 class(*),
pointer :: obj
781 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
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.