MODFLOW 6  version 6.6.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 759 of file Obs.f90.

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

743  ! -- return
744  integer(I4B) :: get_num !< number of observations
745  ! -- dummy
746  class(ObsType) :: this
747  !
748  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 906 of file Obs.f90.

907  ! -- dummy
908  class(ObsType) :: this
909  integer(I4B), intent(in) :: indx !< observation list index
910  class(ObserveType), pointer :: obsrv !< observation ObserveType
911  !
912  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 832 of file Obs.f90.

833  ! -- dummy
834  class(ObsType), intent(inout) :: this
835  integer(I4B), intent(out) :: nObs !< number of observations
836  type(ObsContainerType), dimension(:), pointer, intent(inout) :: obsArray !< observation array
837  !
838  nobs = this%get_num()
839  if (associated(obsarray)) deallocate (obsarray)
840  allocate (obsarray(nobs))
841  !
842  ! set observations in obsArray
843  if (nobs > 0) then
844  call this%set_obs_array(nobs, obsarray)
845  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 853 of file Obs.f90.

854  ! -- dummy
855  class(ObsType) :: this
856  character(len=*), intent(in) :: obsTypeID !< observation type
857  ! -- return
858  type(ObsDataType), pointer :: obsDatum !< observation ObsDataType
859  ! -- local
860  integer(I4B) :: i
861  !
862  obsdatum => null()
863  do i = 1, maxobstypes
864  if (this%obsData(i)%ObsTypeID == obstypeid) then
865  obsdatum => this%obsData(i)
866  exit
867  end if
868  end do
869  !
870  if (.not. associated(obsdatum)) then
871  errmsg = 'Observation type not found: '//trim(obstypeid)
872  call store_error(errmsg)
873  call store_error_unit(this%inUnitObs)
874  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 920 of file Obs.f90.

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

726  ! -- dummy
727  class(ObsType) :: this
728  ! -- local
729  !
730  ! -- Read CONTINUOUS blocks and store observations
731  call this%read_obs_blocks(this%outputFilename)
732  !
733  ! -- build headers
734  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 882 of file Obs.f90.

883  ! -- dummy
884  class(ObsType), intent(inout) :: this
885  integer(I4B), intent(in) :: nObs !< number of observations
886  type(ObsContainerType), dimension(nObs), intent(inout) :: obsArray !< observation array
887  !
888  ! -- local
889  integer(I4B) :: i
890  integer(I4B) :: n
891  type(ObserveType), pointer :: obsrv => null()
892  !
893  n = this%get_num()
894  do i = 1, n
895  obsrv => this%get_obs(i)
896  obsarray(i)%obsrv => obsrv
897  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 1074 of file Obs.f90.

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