MODFLOW 6  version 6.9.0.dev0
USGS Modular Hydrologic Model
obsmodule Module Reference

This module contains the derived type ObsType. More...

Data Types

type  obstype
 

Functions/Subroutines

subroutine, public obs_cr (obs, inobs)
 @ brief Create a new ObsType object More...
 
subroutine, public defaultobsidprocessor (obsrv, dis, inunitobs, iout)
 @ brief Process IDstring provided for each observation More...
 
subroutine obs_df (this, iout, pkgname, filtyp, dis)
 @ brief Define some members of an ObsType object More...
 
subroutine obs_ar (this)
 @ brief Allocate and read package observations More...
 
subroutine obs_ad (this)
 @ brief Advance package observations More...
 
subroutine obs_bd_clear (this)
 @ brief Clear observation output lines More...
 
subroutine obs_ot (this)
 @ brief Output observation data More...
 
subroutine obs_da (this)
 @ brief Deallocate observation data More...
 
subroutine saveonesimval (this, obsrv, simval)
 @ brief Save a simulated value More...
 
subroutine storeobstype (this, obsrvType, cumulative, indx)
 @ brief Store observation type More...
 
subroutine allocate_scalars (this)
 @ brief Allocate observation scalars More...
 
subroutine obs_ar1 (this, pkgname)
 @ brief Read observation options and output formats More...
 
subroutine obs_ar2 (this, dis)
 @ brief Call procedure provided by package More...
 
subroutine read_obs_options (this)
 @ brief Read observation options block More...
 
subroutine define_fmts (this)
 @ brief Define observation output formats More...
 
subroutine read_observations (this)
 @ brief Read observations More...
 
integer(i4b) function get_num (this)
 @ brief Get the number of observations More...
 
subroutine build_headers (this)
 @ brief Build observation headers More...
 
subroutine get_obs_array (this, nObs, obsArray)
 @ brief Get an array of observations More...
 
type(obsdatatype) function, pointer get_obs_datum (this, obsTypeID)
 @ brief Get an ObsDataType object More...
 
subroutine set_obs_array (this, nObs, obsArray)
 @ brief Set observation array values More...
 
class(observetype) function, pointer get_obs (this, indx)
 @ brief Get an ObserveType object More...
 
subroutine read_obs_blocks (this, fname)
 @ brief Read observation blocks More...
 
subroutine write_obs_simvals (this)
 @ brief Write observation data More...
 

Detailed Description

This module defines type ObsType, which is the highest-level derived type for implementing observations. All objects derived from NumericalModelType or BndType already contain an ObsType member.

Examples: NumericalModelType.obs BndType.obs

Similarly, an ObsType member could be added to, say, NumericalExchangeType or any other type that has DF, AR, RP, AD, BD, and OT routines.

IMPLEMENTATION OF OBSERVATIONS IN A MODEL OR PACKAGE

For simple boundary packages like RIV and DRN, only steps 1-6 are needed. For models and advanced packages like MAW and SFR, additional steps are needed.

  1. (package only) Override BndType.bnd_obs_supported to return true. bnd_obs_supported is called from various places in code.
  2. (optional) Write a subroutine that implements abstract interface ObserveModule.ProcessIdSub. (Not needed if IDstring, which identifies location in model to be observed, is either a single node number or a single {lay, row, col} set of indices).

    Examples: gwf_process_head_drawdown_obs_id, gwf_process_intercell_obs_id

    A package can allow IDstring to be a boundary name. Example: ObsModule.DefaultObsIdProcessor

  3. Override BndType.bnd_df_obs() to define string(s) to be recognized as observation type(s) and (optional) assign ProcessIdPtr (not needed if IDstring is either a node number or a {lay, row, col} set of indices).

    Examples: gwf_df_obs, drn_df_obs

    When boundary names are allowed and developer wants simulated value to be cumulative (flow, for example) if user specifies multiple boundaries with the same BOUNDNAME, in bnd_df_obs call to ObsPackage.StoreObsType, provide cumulative argument as true. Otherwise, simulated values are not cumulative.

  4. In DF routine: Call bnd_df_obs
  5. In AR routine: Call ObsType.obs_ar. This reads the OBS input file. Example (gwf_ar): call thisobsobs_ar() Example (lak_ar): call thisobsobs_ar()
  6. Override BndType.bnd_rp_obs for any package that needs to check user input or process observation input in any special way. If no special processing is needed, BndType.bnd_rp_obs can be used. This routine also expands the ObserveTypeindxbnds array for each observation in a package. ObserveTypeindxbnds is used to sum simulated values from multiple boundaries when BOUNDNAMES is used. Equivalent routine may or may not be needed for model observations. If needed, call it from bottom of RP routine.

    Examples: BndType.bnd_rp_obs, which is called from gwf_rp

  7. In AD routine: Call ObsType.obs_ad Example: gwf_ad
  8. Write a *_bd_obs routine. This is the routine that actually calculates the simulated value for each observation type supported by the model/package. Call *_bd_obs from the bottom of the _bd routine. *_bd_obs needs to: Call ObsType.obs_bd_clear For each observation: Calculate the simulated value Call ObsType.SaveOneSimval Examples: gwf_bd_obs, maw_bd_obs, lak_bd_obs
  9. In BD routine: Call BndType.bnd_bd_obs Examples: BndType.bnd_bd calls bnd_bd_obs GwfModelType.gwf_bd calls gwf_bd_obs MawType.maw_bd calls maw_bd_obs LakType.lak_bd calls lak_bd_obs
  10. Ensure that ObsType.obs_ot is called. For packages, obs_ot is called from the model _ot procedure. The model _ot procedure should also call obs_ot for its own observations. Do not call obs_ot from a package _ot procedure because the package _ot procedure may not be called, depending on Output Control settings (ibudfl).

    Note: BndType.bnd_ot_obs calls: ObsType.obs_ot

    Note: ObsType.obs_ot calls: store_all_simvals write_continuous_simvals obsOutputList.WriteOutputLines

BINARY OUTPUT:

When observation-output files are written, the user has the option to have output written to a binary file. Binary obs output files start with a 100-byte header structured as follows:

bytes 1-4 (ascii): Observation type contained in file; options are: "cont" – Continuous observations byte 5: blank bytes 6-11 (ascii): Precision of all floating-point values; options are: "single" – Single precision "double" – Double precision bytes 12-15 (ascii): LENOBSNAME (integer; length of observation names, in bytes) bytes 16-100: blank

IN A FILE OF CONTINUOUS OBSERVATIONS:

The 100-byte header is followed by: NOBS (4-byte integer) – Number of observations. NOBS repetitions of OBSNAME (ascii, LENOBSNAME bytes each). Any number of repetitions of: TIME SIMVAL-1 SIMVAL-2 ... SIMVAL-NOBS (floating point)

Function/Subroutine Documentation

◆ allocate_scalars()

subroutine obsmodule::allocate_scalars ( class(obstype)  this)
private

Subroutine to allocate and initialize memory for non-allocatable

Definition at line 512 of file Obs.f90.

513  ! -- dummy
514  class(ObsType) :: this
515  !
516  allocate (this%active)
517  allocate (this%inputFilename)
518  allocate (this%obsOutputList)
519  allocate (this%obsData(maxobstypes))
520  !
521  ! -- Initialize
522  this%active = .false.
523  this%inputFilename = ''

◆ build_headers()

subroutine obsmodule::build_headers ( class(obstype), target  this)
private

Subroutine to build headers for CSV-formatted and unformatted continuous-observation output files and write them to those files.

Each formatted header will have the form: "time,obsname-1,obsname-2, ..."

Definition at line 761 of file Obs.f90.

762  ! -- module
763  use iso_fortran_env, only: int32
764  ! -- dummy
765  class(ObsType), target :: this
766  ! -- local
767  integer(I4B) :: i
768  integer(I4B) :: ii
769  integer(I4B) :: idx
770  integer(I4B) :: iu
771  integer(I4B) :: num
772  integer(int32) :: nobs
773  character(len=4) :: clenobsname
774  type(ObserveType), pointer :: obsrv => null()
775  type(ObsOutputType), pointer :: obsOutput => null()
776  !
777  ! -- Cycle through ObsOutputList to write headers
778  ! to formatted and unformatted file(s).
779  idx = 1
780  num = this%obsOutputList%Count()
781  all_obsfiles: do i = 1, num
782  obsoutput => this%obsOutputList%Get(i)
783  nobs = obsoutput%nobs
784  iu = obsoutput%nunit
785  !
786  ! -- write header information to the formatted file
787  if (obsoutput%FormattedOutput) then
788  write (iu, '(a)', advance='NO') 'time'
789  else
790  ! -- write header to unformatted file
791  ! First 11 bytes are obs type and precision
792  if (this%iprecision == 1) then
793  ! -- single precision output
794  write (iu) 'cont single'
795  else if (this%iprecision == 2) then
796  ! -- double precision output
797  write (iu) 'cont double'
798  end if
799  ! -- write LENOBSNAME to bytes 12-15
800  write (clenobsname, '(i4)') lenobsname
801  write (iu) clenobsname
802  ! -- write blanks to complete 100-byte header
803  do ii = 16, 100
804  write (iu) ' '
805  end do
806  ! -- write NOBS
807  write (iu) nobs
808  end if
809  !
810  ! -- write observation name
811  obsfile: do ii = 1, nobs
812  obsrv => this%get_obs(idx)
813  if (obsoutput%FormattedOutput) then
814  write (iu, '(a,a)', advance='NO') ',', trim(obsrv%Name)
815  !
816  ! -- terminate the line on the last observation in file
817  if (ii == nobs) then
818  write (iu, '(a)', advance='YES') ''
819  end if
820  else
821  write (iu) obsrv%Name
822  end if
823  idx = idx + 1
824  end do obsfile
825  end do all_obsfiles

◆ defaultobsidprocessor()

subroutine, public obsmodule::defaultobsidprocessor ( type(observetype), intent(inout)  obsrv,
class(disbasetype), intent(in)  dis,
integer(i4b), intent(in)  inunitobs,
integer(i4b), intent(in)  iout 
)

Subroutine to process the IDstring provided for each observation. The IDstring identifies the location in the model of the node(s) or feature(s) where the simulated value is to be extracted and recorded. Subroutine

  • interprets the IDstring
  • stores the location of interest in the ObserveType object that contains information about the observation
    Parameters
    [in,out]obsrvobservation ObserveType
    [in]disdiscretization object
    [in]inunitobsobservation input file unit
    [in]ioutmodel list file

Definition at line 245 of file Obs.f90.

246  ! -- dummy
247  type(ObserveType), intent(inout) :: obsrv !< observation ObserveType
248  class(DisBaseType), intent(in) :: dis !< discretization object
249  integer(I4B), intent(in) :: inunitobs !< observation input file unit
250  integer(I4B), intent(in) :: iout !< model list file
251  ! -- local
252  integer(I4B) :: n
253  integer(I4B) :: icol, istart, istop
254  character(len=LINELENGTH) :: string
255  logical :: flag_string
256  !
257  ! -- Initialize variables
258  string = obsrv%IDstring
259  icol = 1
260  flag_string = .true. ! Allow string to contain a boundary name
261  !
262  n = dis%noder_from_string(icol, istart, istop, inunitobs, &
263  iout, string, flag_string)
264  !
265  if (n > 0) then
266  obsrv%NodeNumber = n
267  elseif (n == -2) then
268  ! Integer can't be read from string; it's presumed to be a boundary
269  ! name (already converted to uppercase)
270  obsrv%FeatureName = string(istart:istop)
271  ! -- Observation may require summing rates from multiple boundaries,
272  ! so assign NodeNumber as a value that indicates observation
273  ! is for a named boundary or group of boundaries.
274  obsrv%NodeNumber = namedboundflag
275  else
276  errmsg = 'Error reading data from ID string'
277  call store_error(errmsg)
278  call store_error_unit(inunitobs)
279  end if
Here is the call graph for this function:
Here is the caller graph for this function:

◆ define_fmts()

subroutine obsmodule::define_fmts ( class(obstype)  this)
private

Subroutine to define observation output formats.

Definition at line 706 of file Obs.f90.

707  ! -- dummy
708  class(ObsType) :: this
709  ! formats
710 50 format('(g', i2.2, '.', i2.2, 'e3)')
711  !
712  ! -- E3 keeps the E for any exponent; the width DIGITS + 8 holds the
713  ! longest value, a sign, "0.", the digits, and an exponent such as E-119
714  if (this%idigits == 0) then
715  this%obsfmtcont = '(G0)'
716  else
717  write (this%obsfmtcont, 50) this%idigits + 8, this%idigits
718  end if

◆ get_num()

integer(i4b) function obsmodule::get_num ( class(obstype)  this)
private

Function to get the number of observationns in this ObsType object.

Returns
number of observations

Definition at line 744 of file Obs.f90.

745  ! -- return
746  integer(I4B) :: get_num !< number of observations
747  ! -- dummy
748  class(ObsType) :: this
749  !
750  get_num = this%obsList%Count()

◆ get_obs()

class(observetype) function, pointer obsmodule::get_obs ( class(obstype)  this,
integer(i4b), intent(in)  indx 
)
private

Subroutine to get an ObserveType object from the list of observations using an list index.

Parameters
[in]indxobservation list index
Returns
observation ObserveType

Definition at line 908 of file Obs.f90.

909  ! -- dummy
910  class(ObsType) :: this
911  integer(I4B), intent(in) :: indx !< observation list index
912  class(ObserveType), pointer :: obsrv !< observation ObserveType
913  !
914  obsrv => getobsfromlist(this%obsList, indx)
Here is the call graph for this function:

◆ get_obs_array()

subroutine obsmodule::get_obs_array ( class(obstype), intent(inout)  this,
integer(i4b), intent(out)  nObs,
type(obscontainertype), dimension(:), intent(inout), pointer  obsArray 
)

Subroutine to get an array containing all observations in this ObsType object.

Parameters
[out]nobsnumber of observations
[in,out]obsarrayobservation array

Definition at line 834 of file Obs.f90.

835  ! -- dummy
836  class(ObsType), intent(inout) :: this
837  integer(I4B), intent(out) :: nObs !< number of observations
838  type(ObsContainerType), dimension(:), pointer, intent(inout) :: obsArray !< observation array
839  !
840  nobs = this%get_num()
841  if (associated(obsarray)) deallocate (obsarray)
842  allocate (obsarray(nobs))
843  !
844  ! set observations in obsArray
845  if (nobs > 0) then
846  call this%set_obs_array(nobs, obsarray)
847  end if

◆ get_obs_datum()

type(obsdatatype) function, pointer obsmodule::get_obs_datum ( class(obstype)  this,
character(len=*), intent(in)  obsTypeID 
)
private

Function to get an ObsDataType object for the specified observation type.

Parameters
[in]obstypeidobservation type
Returns
observation ObsDataType

Definition at line 855 of file Obs.f90.

856  ! -- dummy
857  class(ObsType) :: this
858  character(len=*), intent(in) :: obsTypeID !< observation type
859  ! -- return
860  type(ObsDataType), pointer :: obsDatum !< observation ObsDataType
861  ! -- local
862  integer(I4B) :: i
863  !
864  obsdatum => null()
865  do i = 1, maxobstypes
866  if (this%obsData(i)%ObsTypeID == obstypeid) then
867  obsdatum => this%obsData(i)
868  exit
869  end if
870  end do
871  !
872  if (.not. associated(obsdatum)) then
873  errmsg = 'Observation type not found: '//trim(obstypeid)
874  call store_error(errmsg)
875  call store_error_unit(this%inUnitObs)
876  end if
Here is the call graph for this function:

◆ obs_ad()

subroutine obsmodule::obs_ad ( class(obstype)  this)
private

Subroutine to advance each package observations by resetting the "current" value.

Definition at line 330 of file Obs.f90.

331  ! -- dummy
332  class(ObsType) :: this
333  ! -- local
334  integer(I4B) :: i, n
335  class(ObserveType), pointer :: obsrv => null()
336  !
337  n = this%get_num()
338  do i = 1, n
339  obsrv => this%get_obs(i)
340  call obsrv%ResetCurrentValue()
341  end do

◆ obs_ar()

subroutine obsmodule::obs_ar ( class(obstype)  this)
private

Subroutine to allocate and read observations for a package. Subroutine

  • reads OPTIONS block of OBS input file
  • reads CONTINUOUS blocks of OBS input file

Definition at line 314 of file Obs.f90.

315  ! -- dummy
316  class(ObsType) :: this
317  !
318  call this%obs_ar1(this%pkgName)
319  if (this%active) then
320  call this%obs_ar2(this%dis)
321  end if

◆ obs_ar1()

subroutine obsmodule::obs_ar1 ( class(obstype), intent(inout)  this,
character(len=*), intent(in)  pkgname 
)
private

Subroutine to read the options block in the observation input file and define output formats.

Parameters
[in]pkgnamepackage name

Definition at line 532 of file Obs.f90.

533  ! -- dummy
534  class(ObsType), intent(inout) :: this
535  character(len=*), intent(in) :: pkgname !< package name
536  ! -- formats
537 10 format(/, 'The observation utility is active for "', a, '"')
538  !
539  if (this%inUnitObs > 0) then
540  this%active = .true.
541  !
542  ! -- Indicate that OBS is active
543  write (this%iout, 10) trim(pkgname)
544  !
545  ! -- Read Options block
546  call this%read_obs_options()
547  !
548  ! -- define output formats
549  call this%define_fmts()
550  end if

◆ obs_ar2()

subroutine obsmodule::obs_ar2 ( class(obstype), intent(inout)  this,
class(disbasetype)  dis 
)
private

Subroutine to call procedure provided by package to interpret IDstring and store required data.

Parameters
disdiscretization object

Definition at line 559 of file Obs.f90.

560  ! -- dummy
561  class(ObsType), intent(inout) :: this
562  class(DisBaseType) :: dis !< discretization object
563  ! -- local
564  integer(I4B) :: i
565  type(ObsDataType), pointer :: obsDat => null()
566  character(len=LENOBSTYPE) :: obsTypeID
567  class(ObserveType), pointer :: obsrv => null()
568  !
569  call this%read_observations()
570  ! -- allocate and set observation array
571  call this%get_obs_array(this%npakobs, this%pakobs)
572  !
573  do i = 1, this%npakobs
574  obsrv => this%pakobs(i)%obsrv
575  ! -- Call IDstring processor procedure provided by package
576  obstypeid = obsrv%ObsTypeId
577  obsdat => this%get_obs_datum(obstypeid)
578  if (associated(obsdat%ProcessIdPtr)) then
579  call obsdat%ProcessIdPtr(obsrv, dis, &
580  this%inUnitObs, this%iout)
581  else
582  call defaultobsidprocessor(obsrv, dis, &
583  this%inUnitObs, this%iout)
584  end if
585  end do
586  !
587  if (count_errors() > 0) then
588  call store_error_unit(this%inunitobs)
589  end if
Here is the call graph for this function:

◆ obs_bd_clear()

subroutine obsmodule::obs_bd_clear ( class(obstype), target  this)
private

Subroutine to clear output lines in preparation for new rows of continuous observations.

Definition at line 350 of file Obs.f90.

351  ! -- dummy
352  class(ObsType), target :: this
353  !
354  call this%obsOutputList%ResetAllObsEmptyLines()

◆ obs_cr()

subroutine, public obsmodule::obs_cr ( type(obstype), intent(out), pointer  obs,
integer(i4b), intent(in), pointer  inobs 
)

Subroutine to create a new ObsType object. Soubroutine

  • creates object
  • allocates pointer
  • initializes values
    Parameters
    [out]obsobservation ObsType
    [in]inobsobservation input file unit

Definition at line 224 of file Obs.f90.

225  ! -- dummy
226  type(ObsType), pointer, intent(out) :: obs !< observation ObsType
227  integer(I4B), pointer, intent(in) :: inobs !< observation input file unit
228  !
229  allocate (obs)
230  call obs%allocate_scalars()
231  obs%inUnitObs => inobs
Here is the caller graph for this function:

◆ obs_da()

subroutine obsmodule::obs_da ( class(obstype), intent(inout)  this)
private

Subroutine to deallocate observation data.

Definition at line 384 of file Obs.f90.

385  ! -- dummy
386  class(ObsType), intent(inout) :: this
387  ! -- local
388  integer(I4B) :: i
389  class(ObserveType), pointer :: obsrv => null()
390  !
391  deallocate (this%active)
392  deallocate (this%inputFilename)
393  deallocate (this%obsData)
394  !
395  ! -- observation table object
396  if (associated(this%obstab)) then
397  call this%obstab%table_da()
398  deallocate (this%obstab)
399  nullify (this%obstab)
400  end if
401  !
402  ! -- deallocate pakobs components and pakobs
403  if (associated(this%pakobs)) then
404  do i = 1, this%npakobs
405  obsrv => this%pakobs(i)%obsrv
406  call obsrv%da()
407  deallocate (obsrv)
408  nullify (this%pakobs(i)%obsrv)
409  end do
410  deallocate (this%pakobs)
411  end if
412  !
413  ! -- deallocate obsOutputList
414  call this%obsOutputList%DeallocObsOutputList()
415  deallocate (this%obsOutputList)
416  !
417  ! -- deallocate obslist
418  call this%obslist%Clear()
419  !
420  ! -- nullify
421  nullify (this%inUnitObs)

◆ obs_df()

subroutine obsmodule::obs_df ( class(obstype), intent(inout)  this,
integer(i4b), intent(in)  iout,
character(len=*), intent(in)  pkgname,
character(len=*), intent(in)  filtyp,
class(disbasetype), pointer  dis 
)
private

Subroutine to define some members of an ObsType object.

Parameters
[in]ioutmodel list file unit
[in]pkgnamepackage name
[in]filtyppackage file type
disdiscretization object

Definition at line 289 of file Obs.f90.

290  ! -- dummy
291  class(ObsType), intent(inout) :: this
292  integer(I4B), intent(in) :: iout !< model list file unit
293  character(len=*), intent(in) :: pkgname !< package name
294  character(len=*), intent(in) :: filtyp !< package file type
295  class(DisBaseType), pointer :: dis !< discretization object
296  !
297  this%iout = iout
298  this%pkgName = pkgname
299  this%filtyp = filtyp
300  this%dis => dis
301  !
302  ! -- Initialize block parser
303  call this%parser%Initialize(this%inUnitObs, this%iout)

◆ obs_ot()

subroutine obsmodule::obs_ot ( class(obstype), intent(inout)  this)
private

Subroutine to output observation data. Subroutine

  • stores each simulated value into its ObserveType object
  • writes each simulated value to it ObsOutputList object _ writes contents of ObsOutputList to output file

This procedure should NOT be called from a package's _ot procedure because the package _ot procedure may not be called every time step.

Definition at line 369 of file Obs.f90.

370  ! -- dummy
371  class(ObsType), intent(inout) :: this
372  !
373  if (this%npakobs > 0) then
374  call this%write_obs_simvals()
375  call this%obsOutputList%WriteAllObsLineReturns()
376  end if

◆ read_obs_blocks()

subroutine obsmodule::read_obs_blocks ( class(obstype), intent(inout)  this,
character(len=*), intent(inout)  fname 
)
private

Subroutine to read CONTIGUOUS block from the observation input file.

Definition at line 922 of file Obs.f90.

923  ! -- dummy
924  class(ObsType), intent(inout) :: this
925  character(len=*), intent(inout) :: fname
926  ! -- local
927  integer(I4B) :: ierr, indexobsout, numspec
928  logical :: fmtd, found, endOfBlock
929  character(len=LENBIGLINE) :: pnamein, fnamein
930  character(len=LENHUGELINE) :: line
931  character(len=LINELENGTH) :: btagfound, message, word
932  character(len=LINELENGTH) :: title
933  character(len=LINELENGTH) :: tag
934  character(len=20) :: accarg, bin, fmtarg
935  type(ObserveType), pointer :: obsrv => null()
936  type(ObsOutputType), pointer :: obsOutput => null()
937  integer(I4B) :: ntabrows
938  integer(I4B) :: ntabcols
939  !
940  ! -- initialize local variables
941  numspec = -1
942  errmsg = ''
943  !
944  inquire (unit=this%parser%iuactive, name=pnamein)
945  call getfilefrompath(pnamein, fnamein)
946  !
947  if (this%echo) then
948  !
949  ! -- create the observation table
950  ! -- table dimensions
951  ntabrows = 1
952  ntabcols = 5
953  !
954  ! -- initialize table and define columns
955  title = 'OBSERVATIONS READ FROM FILE "'//trim(fnamein)//'"'
956  call table_cr(this%obstab, fnamein, title)
957  call this%obstab%table_df(ntabrows, ntabcols, this%iout, &
958  finalize=.false.)
959  tag = 'NAME'
960  call this%obstab%initialize_column(tag, lenobsname, alignment=tableft)
961  tag = 'TYPE'
962  call this%obstab%initialize_column(tag, lenobstype + 12, alignment=tableft)
963  tag = 'TIME'
964  call this%obstab%initialize_column(tag, 12, alignment=tableft)
965  tag = 'LOCATION DATA'
966  call this%obstab%initialize_column(tag, lenboundname + 2, alignment=tableft)
967  tag = 'OUTPUT FILENAME'
968  call this%obstab%initialize_column(tag, 80, alignment=tableft)
969  end if
970  !
971  found = .true.
972  readblocks: do
973  if (.not. found) exit
974  !
975  call this%parser%GetBlock('*', found, ierr, .true., .false., btagfound)
976  if (.not. found) then
977  exit readblocks
978  end if
979  this%blockTypeFound = btagfound
980  !
981  ! Get keyword, which should be FILEOUT
982  call this%parser%GetStringCaps(word)
983  if (word /= 'FILEOUT') then
984  call store_error('CONTINUOUS keyword must be followed by '// &
985  '"FILEOUT" then by filename.')
986  cycle
987  end if
988  !
989  ! -- get name of output file
990  call this%parser%GetString(fname)
991  ! Fname is the output file name defined in the BEGIN line of the block.
992  if (fname == '') then
993  message = 'Error reading OBS input file, likely due to bad'// &
994  ' block or missing file name.'
995  call store_error(message)
996  cycle
997  else if (this%obsOutputList%ContainsFile(fname)) then
998  errmsg = 'OBS outfile "'//trim(fname)// &
999  '" is provided more than once.'
1000  call store_error(errmsg)
1001  cycle
1002  end if
1003  !
1004  ! -- look for BINARY option
1005  call this%parser%GetStringCaps(bin)
1006  if (bin == 'BINARY') then
1007  fmtarg = form
1008  accarg = access
1009  fmtd = .false.
1010  else
1011  fmtarg = 'FORMATTED'
1012  accarg = 'SEQUENTIAL'
1013  fmtd = .true.
1014  end if
1015  !
1016  ! -- open the output file
1017  numspec = 0
1018  call openfile(numspec, 0, fname, 'OBS OUTPUT', fmtarg, &
1019  accarg, 'REPLACE')
1020  !
1021  ! -- add output file to list of output files and assign its
1022  ! FormattedOutput member appropriately
1023  call this%obsOutputList%Add(fname, numspec)
1024  indexobsout = this%obsOutputList%Count()
1025  obsoutput => this%obsOutputList%Get(indexobsout)
1026  obsoutput%FormattedOutput = fmtd
1027  !
1028  ! -- process lines defining observations
1029  select case (btagfound)
1030  case ('CONTINUOUS')
1031  !
1032  ! -- construct a continuous observation from each line in the block
1033  readblockcontinuous: do
1034  call this%parser%GetNextLine(endofblock)
1035  if (endofblock) exit
1036  call this%parser%GetCurrentLine(line)
1037  call constructobservation(obsrv, line, numspec, fmtd, &
1038  indexobsout, this%obsData, &
1039  this%parser%iuactive)
1040  !
1041  ! -- increment number of observations
1042  ! to be written to this output file.
1043  obsoutput => this%obsOutputList%Get(indexobsout)
1044  obsoutput%nobs = obsoutput%nobs + 1
1045  call addobstolist(this%obsList, obsrv)
1046  !
1047  ! -- write line to the observation table
1048  if (this%echo) then
1049  call obsrv%WriteTo(this%obstab, btagfound, fname)
1050  end if
1051  end do readblockcontinuous
1052  case default
1053  errmsg = 'Error: Observation block type not recognized: '// &
1054  trim(btagfound)
1055  call store_error(errmsg)
1056  end select
1057  end do readblocks
1058  !
1059  ! -- finalize the observation table
1060  if (this%echo) then
1061  call this%obstab%finalize_table()
1062  end if
1063  !
1064  ! -- determine if error condition occurs
1065  if (count_errors() > 0) then
1066  call this%parser%StoreErrorUnit()
1067  end if
Here is the call graph for this function:

◆ read_obs_options()

subroutine obsmodule::read_obs_options ( class(obstype)  this)
private

Subroutine to read the options block in the observation input file.

Definition at line 597 of file Obs.f90.

598  ! -- dummy
599  class(ObsType) :: this
600  ! -- local
601  integer(I4B) :: iin
602  integer(I4B) :: ierr
603  integer(I4B) :: localprecision
604  integer(I4B) :: localdigits
605  character(len=40) :: keyword
606  character(len=LINELENGTH) :: fname
607  type(ListType), pointer :: lineList => null()
608  logical :: continueread, found, endOfBlock
609  ! -- formats
610 10 format('No options block found in OBS input. Defaults will be used.')
611 40 format('Text output number of digits of precision set to: ', i2)
612 50 format('Text output number of digits set to internal representation (G0).')
613 60 format(/, 'Processing observation options:',/)
614  !
615  localprecision = 0
616  localdigits = -1
617  linelist => null()
618  !
619  ! -- Find and store file name
620  iin = this%inUnitObs
621  inquire (unit=iin, name=fname)
622  this%inputFilename = fname
623  !
624  ! -- Read Options block
625  continueread = .false.
626  ierr = 0
627  !
628  ! -- get BEGIN line of OPTIONS block
629  call this%parser%GetBlock('OPTIONS', found, ierr, &
630  supportopenclose=.true., blockrequired=.false.)
631  if (ierr /= 0) then
632  ! end of file
633  errmsg = 'End-of-file encountered while searching for'// &
634  ' OPTIONS in OBS '// &
635  'input file "'//trim(this%inputFilename)//'"'
636  call store_error(errmsg)
637  call this%parser%StoreErrorUnit()
638  elseif (.not. found) then
639  this%blockTypeFound = ''
640  if (this%iout > 0) write (this%iout, 10)
641  end if
642  !
643  ! -- parse OPTIONS entries
644  if (found) then
645  write (this%iout, 60)
646  readblockoptions: do
647  call this%parser%GetNextLine(endofblock)
648  if (endofblock) exit
649  call this%parser%GetStringCaps(keyword)
650  select case (keyword)
651  case ('DIGITS')
652  !
653  ! -- error if digits already read
654  if (localdigits /= -1) then
655  errmsg = 'Error in OBS input: DIGITS has already been defined'
656  call store_error(errmsg)
657  exit readblockoptions
658  end if
659  !
660  ! -- Specifies number of significant digits used writing simulated
661  ! values to a text file. Default is stored digits.
662  !
663  ! -- Read integer value
664  localdigits = this%parser%GetInteger()
665  !
666  ! -- Set localdigits to valid value: 0, or 2 to 16
667  if (localdigits == 0) then
668  write (this%iout, 50)
669  else if (localdigits < 1) then
670  errmsg = 'Error in OBS input: Invalid value for DIGITS option'
671  call store_error(errmsg)
672  exit readblockoptions
673  else
674  if (localdigits < 2) localdigits = 2
675  if (localdigits > 16) localdigits = 16
676  write (this%iout, 40) localdigits
677  end if
678  case ('PRINT_INPUT')
679  this%echo = .true.
680  write (this%iout, '(a)') 'The PRINT_INPUT option has been specified.'
681  case default
682  errmsg = 'Error in OBS input: Unrecognized option: '// &
683  trim(keyword)
684  call store_error(errmsg)
685  exit readblockoptions
686  end select
687  end do readblockoptions
688  end if
689  !
690  if (count_errors() > 0) then
691  call this%parser%StoreErrorUnit()
692  end if
693  !
694  write (this%iout, '(1x)')
695  !
696  ! -- Assign type variables
697  if (localprecision > 0) this%iprecision = localprecision
698  if (localdigits >= 0) this%idigits = localdigits
Here is the call graph for this function:

◆ read_observations()

subroutine obsmodule::read_observations ( class(obstype)  this)
private

Subroutine to read the observations from the observation input file and build headers for the observation output files.

Definition at line 727 of file Obs.f90.

728  ! -- dummy
729  class(ObsType) :: this
730  ! -- local
731  !
732  ! -- Read CONTINUOUS blocks and store observations
733  call this%read_obs_blocks(this%outputFilename)
734  !
735  ! -- build headers
736  call this%build_headers()

◆ saveonesimval()

subroutine obsmodule::saveonesimval ( class(obstype)  this,
class(observetype), intent(inout)  obsrv,
real(dp), intent(in)  simval 
)
private

Subroutine to save or accumulate a simulated value to its ObserveType object.

Parameters
[in,out]obsrvobservation ObserveType
[in]simvalsimulated value

Definition at line 430 of file Obs.f90.

431  ! -- dummy
432  class(ObsType) :: this
433  class(ObserveType), intent(inout) :: obsrv !< observation ObserveType
434  real(DP), intent(in) :: simval !< simulated value
435  ! -- local
436  character(len=LENOBSTYPE) :: obsTypeID
437  type(ObsDataType), pointer :: obsDatum => null()
438  !
439  ! -- initialize variables
440  obstypeid = obsrv%ObsTypeId
441  obsdatum => this%get_obs_datum(obstypeid)
442  !
443  ! -- save current simulation time
444  obsrv%CurrentTimeStepEndTime = totim
445  !
446  ! -- assign or accumulate simulated value
447  if (obsdatum%Cumulative .and. simval /= dnodata) then
448  obsrv%CurrentTimeStepEndValue = obsrv%CurrentTimeStepEndValue + simval
449  else
450  obsrv%CurrentTimeStepEndValue = simval
451  end if

◆ set_obs_array()

subroutine obsmodule::set_obs_array ( class(obstype), intent(inout)  this,
integer(i4b), intent(in)  nObs,
type(obscontainertype), dimension(nobs), intent(inout)  obsArray 
)
private

Subroutine to set values in an observation array.

Parameters
[in]nobsnumber of observations
[in,out]obsarrayobservation array

Definition at line 884 of file Obs.f90.

885  ! -- dummy
886  class(ObsType), intent(inout) :: this
887  integer(I4B), intent(in) :: nObs !< number of observations
888  type(ObsContainerType), dimension(nObs), intent(inout) :: obsArray !< observation array
889  !
890  ! -- local
891  integer(I4B) :: i
892  integer(I4B) :: n
893  type(ObserveType), pointer :: obsrv => null()
894  !
895  n = this%get_num()
896  do i = 1, n
897  obsrv => this%get_obs(i)
898  obsarray(i)%obsrv => obsrv
899  end do

◆ storeobstype()

subroutine obsmodule::storeobstype ( class(obstype), intent(inout)  this,
character(len=*), intent(in)  obsrvType,
logical, intent(in)  cumulative,
integer(i4b), intent(out)  indx 
)
private

Subroutine to store type name and related information for an observation type that belongs to a package or model in the obsData array.

Parameters
[in]obsrvtypeobservation type
[in]cumulativelogical indicating if the observation should be accumulated
[out]indxobservation index

Definition at line 461 of file Obs.f90.

462  ! -- dummy
463  class(ObsType), intent(inout) :: this
464  character(len=*), intent(in) :: obsrvType !< observation type
465  ! cumulative: Accumulate simulated values for multiple boundaries
466  logical, intent(in) :: cumulative !< logical indicating if the observation should be accumulated
467  integer(I4B), intent(out) :: indx !< observation index
468  ! -- local
469  integer(I4B) :: i
470  character(len=LENOBSTYPE) :: obsTypeUpper
471  character(len=100) :: msg
472  !
473  ! -- Ensure that obsrvType is not blank
474  if (obsrvtype == '') then
475  msg = 'Programmer error: Invalid argument in store_obs_type.'
476  call store_error(msg, terminate=.true.)
477  end if
478  !
479  ! -- Find first unused element
480  indx = -1
481  do i = 1, maxobstypes
482  if (this%obsData(i)%ObsTypeID /= '') cycle
483  indx = i
484  exit
485  end do
486  !
487  ! -- Ensure that array size is not exceeded
488  if (indx == -1) then
489  msg = 'Size of obsData array is insufficient; ' &
490  //'need to increase MAXOBSTYPES.'
491  call store_error(msg)
492  call store_error_unit(this%inUnitObs)
493  end if
494  !
495  ! -- Convert character argument to upper case
496  obstypeupper = obsrvtype
497  call upcase(obstypeupper)
498  !
499  ! -- Assign members
500  this%obsData(indx)%ObsTypeID = obstypeupper
501  this%obsData(indx)%Cumulative = cumulative
Here is the call graph for this function:

◆ write_obs_simvals()

subroutine obsmodule::write_obs_simvals ( class(obstype), intent(inout)  this)
private

Subroutine to write observation data for a time step for each observation to the observation output file.

Definition at line 1076 of file Obs.f90.

1077  ! -- dummy
1078  class(ObsType), intent(inout) :: this
1079  ! -- local
1080  integer(I4B) :: i
1081  integer(I4B) :: iprec
1082  integer(I4B) :: numobs
1083  character(len=20) :: fmtc
1084  real(DP) :: simval
1085  class(ObserveType), pointer :: obsrv => null()
1086  !
1087  ! Write simulated values for observations
1088  iprec = this%iprecision
1089  fmtc = this%obsfmtcont
1090  ! -- iterate through all observations
1091  numobs = this%obsList%Count()
1092  do i = 1, numobs
1093  obsrv => this%get_obs(i)
1094  ! -- continuous observation
1095  simval = obsrv%CurrentTimeStepEndValue
1096  if (obsrv%FormattedOutput) then
1097  call write_fmtd_obs(fmtc, obsrv, this%obsOutputList, simval)
1098  else
1099  call write_unfmtd_obs(obsrv, iprec, this%obsOutputList, simval)
1100  end if
1101  end do
Here is the call graph for this function: