MODFLOW 6  version 6.5.0.dev2
MODFLOW 6 Code Documentation
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 542 of file Obs.f90.

543  ! -- dummy
544  class(ObsType) :: this
545  !
546  allocate (this%active)
547  allocate (this%inputFilename)
548  allocate (this%obsOutputList)
549  allocate (this%obsData(maxobstypes))
550  !
551  ! -- Initialize
552  this%active = .false.
553  this%inputFilename = ''
554  !
555  ! -- return
556  return

◆ 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 810 of file Obs.f90.

811  ! -- module
812  use iso_fortran_env, only: int32
813  ! -- dummy
814  class(ObsType), target :: this
815  ! -- local
816  integer(I4B) :: i
817  integer(I4B) :: ii
818  integer(I4B) :: idx
819  integer(I4B) :: iu
820  integer(I4B) :: num
821  integer(int32) :: nobs
822  character(len=4) :: clenobsname
823  type(ObserveType), pointer :: obsrv => null()
824  type(ObsOutputType), pointer :: obsOutput => null()
825  !
826  ! -- Cycle through ObsOutputList to write headers
827  ! to formatted and unformatted file(s).
828  idx = 1
829  num = this%obsOutputList%Count()
830  all_obsfiles: do i = 1, num
831  obsoutput => this%obsOutputList%Get(i)
832  nobs = obsoutput%nobs
833  iu = obsoutput%nunit
834  !
835  ! -- write header information to the formatted file
836  if (obsoutput%FormattedOutput) then
837  write (iu, '(a)', advance='NO') 'time'
838  else
839  ! -- write header to unformatted file
840  ! First 11 bytes are obs type and precision
841  if (this%iprecision == 1) then
842  ! -- single precision output
843  write (iu) 'cont single'
844  else if (this%iprecision == 2) then
845  ! -- double precision output
846  write (iu) 'cont double'
847  end if
848  ! -- write LENOBSNAME to bytes 12-15
849  write (clenobsname, '(i4)') lenobsname
850  write (iu) clenobsname
851  ! -- write blanks to complete 100-byte header
852  do ii = 16, 100
853  write (iu) ' '
854  end do
855  ! -- write NOBS
856  write (iu) nobs
857  end if
858  !
859  ! -- write observation name
860  obsfile: do ii = 1, nobs
861  obsrv => this%get_obs(idx)
862  if (obsoutput%FormattedOutput) then
863  write (iu, '(a,a)', advance='NO') ',', trim(obsrv%Name)
864  !
865  ! -- terminate the line on the last observation in file
866  if (ii == nobs) then
867  write (iu, '(a)', advance='YES') ''
868  end if
869  else
870  write (iu) obsrv%Name
871  end if
872  idx = idx + 1
873  end do obsfile
874  end do all_obsfiles
875  !
876  ! -- return
877  return

◆ 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 248 of file Obs.f90.

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

749  ! -- dummy
750  class(ObsType) :: this
751  ! formats
752 50 format('(g', i2.2, '.', i2.2, ')')
753  !
754  if (this%idigits == 0) then
755  this%obsfmtcont = '(G0)'
756  else
757  write (this%obsfmtcont, 50) this%idigits + 7, this%idigits
758  end if
759  !
760  ! -- return
761  return

◆ 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 790 of file Obs.f90.

791  ! -- return
792  integer(I4B) :: get_num !< number of observations
793  ! -- dummy
794  class(ObsType) :: this
795  !
796  get_num = this%obsList%Count()
797  !
798  ! -- return
799  return

◆ 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 969 of file Obs.f90.

970  ! -- dummy
971  class(ObsType) :: this
972  integer(I4B), intent(in) :: indx !< observation list index
973  class(ObserveType), pointer :: obsrv !< observation ObserveType
974  !
975  obsrv => getobsfromlist(this%obsList, indx)
976  !
977  ! -- return
978  return
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 886 of file Obs.f90.

887  ! -- dummy
888  class(ObsType), intent(inout) :: this
889  integer(I4B), intent(out) :: nObs !< number of observations
890  type(ObsContainerType), dimension(:), pointer, intent(inout) :: obsArray !< observation array
891  !
892  nobs = this%get_num()
893  if (associated(obsarray)) deallocate (obsarray)
894  allocate (obsarray(nobs))
895  !
896  ! set observations in obsArray
897  if (nobs > 0) then
898  call this%set_obs_array(nobs, obsarray)
899  end if
900  !
901  ! -- return
902  return

◆ 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 910 of file Obs.f90.

911  ! -- dummy
912  class(ObsType) :: this
913  character(len=*), intent(in) :: obsTypeID !< observation type
914  ! -- return
915  type(ObsDataType), pointer :: obsDatum !< observation ObsDataType
916  ! -- local
917  integer(I4B) :: i
918  !
919  obsdatum => null()
920  do i = 1, maxobstypes
921  if (this%obsData(i)%ObsTypeID == obstypeid) then
922  obsdatum => this%obsData(i)
923  exit
924  end if
925  end do
926  !
927  if (.not. associated(obsdatum)) then
928  errmsg = 'Observation type not found: '//trim(obstypeid)
929  call store_error(errmsg)
930  call store_error_unit(this%inUnitObs)
931  end if
932  !
933  ! -- return
934  return
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 342 of file Obs.f90.

343  ! -- dummy
344  class(ObsType) :: this
345  ! -- local
346  integer(I4B) :: i, n
347  class(ObserveType), pointer :: obsrv => null()
348  !
349  n = this%get_num()
350  do i = 1, n
351  obsrv => this%get_obs(i)
352  call obsrv%ResetCurrentValue()
353  end do
354  !
355  ! -- return
356  return

◆ 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 323 of file Obs.f90.

324  ! -- dummy
325  class(ObsType) :: this
326  !
327  call this%obs_ar1(this%pkgName)
328  if (this%active) then
329  call this%obs_ar2(this%dis)
330  end if
331  !
332  ! -- return
333  return

◆ 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 565 of file Obs.f90.

566  ! -- dummy
567  class(ObsType), intent(inout) :: this
568  character(len=*), intent(in) :: pkgname !< package name
569  ! -- formats
570 10 format(/, 'The observation utility is active for "', a, '"')
571  !
572  if (this%inUnitObs > 0) then
573  this%active = .true.
574  !
575  ! -- Indicate that OBS is active
576  write (this%iout, 10) trim(pkgname)
577  !
578  ! -- Read Options block
579  call this%read_obs_options()
580  !
581  ! -- define output formats
582  call this%define_fmts()
583  end if
584  !
585  ! -- return
586  return

◆ 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 595 of file Obs.f90.

596  ! -- dummy
597  class(ObsType), intent(inout) :: this
598  class(DisBaseType) :: dis !< discretization object
599  ! -- local
600  integer(I4B) :: i
601  type(ObsDataType), pointer :: obsDat => null()
602  character(len=LENOBSTYPE) :: obsTypeID
603  class(ObserveType), pointer :: obsrv => null()
604  !
605  call this%read_observations()
606  ! -- allocate and set observation array
607  call this%get_obs_array(this%npakobs, this%pakobs)
608  !
609  do i = 1, this%npakobs
610  obsrv => this%pakobs(i)%obsrv
611  ! -- Call IDstring processor procedure provided by package
612  obstypeid = obsrv%ObsTypeId
613  obsdat => this%get_obs_datum(obstypeid)
614  if (associated(obsdat%ProcessIdPtr)) then
615  call obsdat%ProcessIdPtr(obsrv, dis, &
616  this%inUnitObs, this%iout)
617  else
618  call defaultobsidprocessor(obsrv, dis, &
619  this%inUnitObs, this%iout)
620  end if
621  end do
622  !
623  if (count_errors() > 0) then
624  call store_error_unit(this%inunitobs)
625  end if
626  !
627  ! -- return
628  return
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 365 of file Obs.f90.

366  ! -- dummy
367  class(ObsType), target :: this
368  !
369  call this%obsOutputList%ResetAllObsEmptyLines()
370  !
371  ! -- return
372  return

◆ 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
232  !
233  ! -- return
234  return
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 405 of file Obs.f90.

406  ! -- dummy
407  class(ObsType), intent(inout) :: this
408  ! -- local
409  integer(I4B) :: i
410  class(ObserveType), pointer :: obsrv => null()
411  !
412  deallocate (this%active)
413  deallocate (this%inputFilename)
414  deallocate (this%obsData)
415  !
416  ! -- observation table object
417  if (associated(this%obstab)) then
418  call this%obstab%table_da()
419  deallocate (this%obstab)
420  nullify (this%obstab)
421  end if
422  !
423  ! -- deallocate pakobs components and pakobs
424  if (associated(this%pakobs)) then
425  do i = 1, this%npakobs
426  obsrv => this%pakobs(i)%obsrv
427  call obsrv%da()
428  deallocate (obsrv)
429  nullify (this%pakobs(i)%obsrv)
430  end do
431  deallocate (this%pakobs)
432  end if
433  !
434  ! -- deallocate obsOutputList
435  call this%obsOutputList%DeallocObsOutputList()
436  deallocate (this%obsOutputList)
437  !
438  ! -- deallocate obslist
439  call this%obslist%Clear()
440  !
441  ! -- nullify
442  nullify (this%inUnitObs)
443  !
444  ! -- return
445  return

◆ 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 295 of file Obs.f90.

296  ! -- dummy
297  class(ObsType), intent(inout) :: this
298  integer(I4B), intent(in) :: iout !< model list file unit
299  character(len=*), intent(in) :: pkgname !< package name
300  character(len=*), intent(in) :: filtyp !< package file type
301  class(DisBaseType), pointer :: dis !< discretization object
302  !
303  this%iout = iout
304  this%pkgName = pkgname
305  this%filtyp = filtyp
306  this%dis => dis
307  !
308  ! -- Initialize block parser
309  call this%parser%Initialize(this%inUnitObs, this%iout)
310  !
311  ! -- return
312  return

◆ 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 387 of file Obs.f90.

388  ! -- dummy
389  class(ObsType), intent(inout) :: this
390  !
391  if (this%npakobs > 0) then
392  call this%write_obs_simvals()
393  call this%obsOutputList%WriteAllObsLineReturns()
394  end if
395  !
396  ! -- return
397  return

◆ 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 986 of file Obs.f90.

987  ! -- dummy
988  class(ObsType), intent(inout) :: this
989  character(len=*), intent(inout) :: fname
990  ! -- local
991  integer(I4B) :: ierr, indexobsout, numspec
992  logical :: fmtd, found, endOfBlock
993  character(len=LENBIGLINE) :: pnamein, fnamein
994  character(len=LENHUGELINE) :: line
995  character(len=LINELENGTH) :: btagfound, message, word
996  character(len=LINELENGTH) :: title
997  character(len=LINELENGTH) :: tag
998  character(len=20) :: accarg, bin, fmtarg
999  type(ObserveType), pointer :: obsrv => null()
1000  type(ObsOutputType), pointer :: obsOutput => null()
1001  integer(I4B) :: ntabrows
1002  integer(I4B) :: ntabcols
1003  !
1004  ! -- initialize local variables
1005  numspec = -1
1006  errmsg = ''
1007  !
1008  inquire (unit=this%parser%iuactive, name=pnamein)
1009  call getfilefrompath(pnamein, fnamein)
1010  !
1011  if (this%echo) then
1012  !
1013  ! -- create the observation table
1014  ! -- table dimensions
1015  ntabrows = 1
1016  ntabcols = 5
1017  !
1018  ! -- initialize table and define columns
1019  title = 'OBSERVATIONS READ FROM FILE "'//trim(fnamein)//'"'
1020  call table_cr(this%obstab, fnamein, title)
1021  call this%obstab%table_df(ntabrows, ntabcols, this%iout, &
1022  finalize=.false.)
1023  tag = 'NAME'
1024  call this%obstab%initialize_column(tag, lenobsname, alignment=tableft)
1025  tag = 'TYPE'
1026  call this%obstab%initialize_column(tag, lenobstype + 12, alignment=tableft)
1027  tag = 'TIME'
1028  call this%obstab%initialize_column(tag, 12, alignment=tableft)
1029  tag = 'LOCATION DATA'
1030  call this%obstab%initialize_column(tag, lenboundname + 2, alignment=tableft)
1031  tag = 'OUTPUT FILENAME'
1032  call this%obstab%initialize_column(tag, 80, alignment=tableft)
1033  end if
1034  !
1035  found = .true.
1036  readblocks: do
1037  if (.not. found) exit
1038  !
1039  call this%parser%GetBlock('*', found, ierr, .true., .false., btagfound)
1040  if (.not. found) then
1041  exit readblocks
1042  end if
1043  this%blockTypeFound = btagfound
1044  !
1045  ! Get keyword, which should be FILEOUT
1046  call this%parser%GetStringCaps(word)
1047  if (word /= 'FILEOUT') then
1048  call store_error('CONTINUOUS keyword must be followed by '// &
1049  '"FILEOUT" then by filename.')
1050  cycle
1051  end if
1052  !
1053  ! -- get name of output file
1054  call this%parser%GetString(fname)
1055  ! Fname is the output file name defined in the BEGIN line of the block.
1056  if (fname == '') then
1057  message = 'Error reading OBS input file, likely due to bad'// &
1058  ' block or missing file name.'
1059  call store_error(message)
1060  cycle
1061  else if (this%obsOutputList%ContainsFile(fname)) then
1062  errmsg = 'OBS outfile "'//trim(fname)// &
1063  '" is provided more than once.'
1064  call store_error(errmsg)
1065  cycle
1066  end if
1067  !
1068  ! -- look for BINARY option
1069  call this%parser%GetStringCaps(bin)
1070  if (bin == 'BINARY') then
1071  fmtarg = form
1072  accarg = access
1073  fmtd = .false.
1074  else
1075  fmtarg = 'FORMATTED'
1076  accarg = 'SEQUENTIAL'
1077  fmtd = .true.
1078  end if
1079  !
1080  ! -- open the output file
1081  numspec = 0
1082  call openfile(numspec, 0, fname, 'OBS OUTPUT', fmtarg, &
1083  accarg, 'REPLACE')
1084  !
1085  ! -- add output file to list of output files and assign its
1086  ! FormattedOutput member appropriately
1087  call this%obsOutputList%Add(fname, numspec)
1088  indexobsout = this%obsOutputList%Count()
1089  obsoutput => this%obsOutputList%Get(indexobsout)
1090  obsoutput%FormattedOutput = fmtd
1091  !
1092  ! -- process lines defining observations
1093  select case (btagfound)
1094  case ('CONTINUOUS')
1095  !
1096  ! -- construct a continuous observation from each line in the block
1097  readblockcontinuous: do
1098  call this%parser%GetNextLine(endofblock)
1099  if (endofblock) exit
1100  call this%parser%GetCurrentLine(line)
1101  call constructobservation(obsrv, line, numspec, fmtd, &
1102  indexobsout, this%obsData, &
1103  this%parser%iuactive)
1104  !
1105  ! -- increment number of observations
1106  ! to be written to this output file.
1107  obsoutput => this%obsOutputList%Get(indexobsout)
1108  obsoutput%nobs = obsoutput%nobs + 1
1109  call addobstolist(this%obsList, obsrv)
1110  !
1111  ! -- write line to the observation table
1112  if (this%echo) then
1113  call obsrv%WriteTo(this%obstab, btagfound, fname)
1114  end if
1115  end do readblockcontinuous
1116  case default
1117  errmsg = 'Error: Observation block type not recognized: '// &
1118  trim(btagfound)
1119  call store_error(errmsg)
1120  end select
1121  end do readblocks
1122  !
1123  ! -- finalize the observation table
1124  if (this%echo) then
1125  call this%obstab%finalize_table()
1126  end if
1127  !
1128  ! -- determine if error condition occurs
1129  if (count_errors() > 0) then
1130  call this%parser%StoreErrorUnit()
1131  end if
1132  !
1133  ! -- return
1134  return
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 636 of file Obs.f90.

637  ! -- dummy
638  class(ObsType) :: this
639  ! -- local
640  integer(I4B) :: iin
641  integer(I4B) :: ierr
642  integer(I4B) :: localprecision
643  integer(I4B) :: localdigits
644  character(len=40) :: keyword
645  character(len=LINELENGTH) :: fname
646  type(ListType), pointer :: lineList => null()
647  logical :: continueread, found, endOfBlock
648  ! -- formats
649 10 format('No options block found in OBS input. Defaults will be used.')
650 40 format('Text output number of digits of precision set to: ', i2)
651 50 format('Text output number of digits set to internal representation (G0).')
652 60 format(/, 'Processing observation options:',/)
653  !
654  localprecision = 0
655  localdigits = -1
656  linelist => null()
657  !
658  ! -- Find and store file name
659  iin = this%inUnitObs
660  inquire (unit=iin, name=fname)
661  this%inputFilename = fname
662  !
663  ! -- Read Options block
664  continueread = .false.
665  ierr = 0
666  !
667  ! -- get BEGIN line of OPTIONS block
668  call this%parser%GetBlock('OPTIONS', found, ierr, &
669  supportopenclose=.true., blockrequired=.false.)
670  if (ierr /= 0) then
671  ! end of file
672  errmsg = 'End-of-file encountered while searching for'// &
673  ' OPTIONS in OBS '// &
674  'input file "'//trim(this%inputFilename)//'"'
675  call store_error(errmsg)
676  call this%parser%StoreErrorUnit()
677  elseif (.not. found) then
678  this%blockTypeFound = ''
679  if (this%iout > 0) write (this%iout, 10)
680  end if
681  !
682  ! -- parse OPTIONS entries
683  if (found) then
684  write (this%iout, 60)
685  readblockoptions: do
686  call this%parser%GetNextLine(endofblock)
687  if (endofblock) exit
688  call this%parser%GetStringCaps(keyword)
689  select case (keyword)
690  case ('DIGITS')
691  !
692  ! -- error if digits already read
693  if (localdigits /= -1) then
694  errmsg = 'Error in OBS input: DIGITS has already been defined'
695  call store_error(errmsg)
696  exit readblockoptions
697  end if
698  !
699  ! -- Specifies number of significant digits used writing simulated
700  ! values to a text file. Default is stored digits.
701  !
702  ! -- Read integer value
703  localdigits = this%parser%GetInteger()
704  !
705  ! -- Set localdigits to valid value: 0, or 2 to 16
706  if (localdigits == 0) then
707  write (this%iout, 50)
708  else if (localdigits < 1) then
709  errmsg = 'Error in OBS input: Invalid value for DIGITS option'
710  call store_error(errmsg)
711  exit readblockoptions
712  else
713  if (localdigits < 2) localdigits = 2
714  if (localdigits > 16) localdigits = 16
715  write (this%iout, 40) localdigits
716  end if
717  case ('PRINT_INPUT')
718  this%echo = .true.
719  write (this%iout, '(a)') 'The PRINT_INPUT option has been specified.'
720  case default
721  errmsg = 'Error in OBS input: Unrecognized option: '// &
722  trim(keyword)
723  call store_error(errmsg)
724  exit readblockoptions
725  end select
726  end do readblockoptions
727  end if
728  !
729  if (count_errors() > 0) then
730  call this%parser%StoreErrorUnit()
731  end if
732  !
733  write (this%iout, '(1x)')
734  !
735  ! -- Assign type variables
736  if (localprecision > 0) this%iprecision = localprecision
737  if (localdigits >= 0) this%idigits = localdigits
738  !
739  ! -- return
740  return
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 770 of file Obs.f90.

771  ! -- dummy
772  class(ObsType) :: this
773  ! -- local
774  !
775  ! -- Read CONTINUOUS blocks and store observations
776  call this%read_obs_blocks(this%outputFilename)
777  !
778  ! -- build headers
779  call this%build_headers()
780  !
781  ! -- return
782  return

◆ 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 454 of file Obs.f90.

455  ! -- dummy
456  class(ObsType) :: this
457  class(ObserveType), intent(inout) :: obsrv !< observation ObserveType
458  real(DP), intent(in) :: simval !< simulated value
459  ! -- local
460  character(len=LENOBSTYPE) :: obsTypeID
461  type(ObsDataType), pointer :: obsDatum => null()
462  !
463  ! -- initialize variables
464  obstypeid = obsrv%ObsTypeId
465  obsdatum => this%get_obs_datum(obstypeid)
466  !
467  ! -- save current simulation time
468  obsrv%CurrentTimeStepEndTime = totim
469  !
470  ! -- assign or accumulate simulated value
471  if (obsdatum%Cumulative .and. simval /= dnodata) then
472  obsrv%CurrentTimeStepEndValue = obsrv%CurrentTimeStepEndValue + simval
473  else
474  obsrv%CurrentTimeStepEndValue = simval
475  end if
476  !
477  ! -- return
478  return

◆ 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 942 of file Obs.f90.

943  ! -- dummy
944  class(ObsType), intent(inout) :: this
945  integer(I4B), intent(in) :: nObs !< number of observations
946  type(ObsContainerType), dimension(nObs), intent(inout) :: obsArray !< observation array
947  !
948  ! -- local
949  integer(I4B) :: i
950  integer(I4B) :: n
951  type(ObserveType), pointer :: obsrv => null()
952  !
953  n = this%get_num()
954  do i = 1, n
955  obsrv => this%get_obs(i)
956  obsarray(i)%obsrv => obsrv
957  end do
958  !
959  ! -- return
960  return

◆ 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 488 of file Obs.f90.

489  ! -- dummy
490  class(ObsType), intent(inout) :: this
491  character(len=*), intent(in) :: obsrvType !< observation type
492  ! cumulative: Accumulate simulated values for multiple boundaries
493  logical, intent(in) :: cumulative !< logical indicating if the observation should be accumulated
494  integer(I4B), intent(out) :: indx !< observation index
495  ! -- local
496  integer(I4B) :: i
497  character(len=LENOBSTYPE) :: obsTypeUpper
498  character(len=100) :: msg
499  !
500  ! -- Ensure that obsrvType is not blank
501  if (obsrvtype == '') then
502  msg = 'Programmer error: Invalid argument in store_obs_type.'
503  call store_error(msg, terminate=.true.)
504  end if
505  !
506  ! -- Find first unused element
507  indx = -1
508  do i = 1, maxobstypes
509  if (this%obsData(i)%ObsTypeID /= '') cycle
510  indx = i
511  exit
512  end do
513  !
514  ! -- Ensure that array size is not exceeded
515  if (indx == -1) then
516  msg = 'Size of obsData array is insufficient; ' &
517  //'need to increase MAXOBSTYPES.'
518  call store_error(msg)
519  call store_error_unit(this%inUnitObs)
520  end if
521  !
522  ! -- Convert character argument to upper case
523  obstypeupper = obsrvtype
524  call upcase(obstypeupper)
525  !
526  ! -- Assign members
527  this%obsData(indx)%ObsTypeID = obstypeupper
528  this%obsData(indx)%Cumulative = cumulative
529  !
530  ! -- return
531  return
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 1143 of file Obs.f90.

1144  ! -- dummy
1145  class(ObsType), intent(inout) :: this
1146  ! -- local
1147  integer(I4B) :: i
1148  integer(I4B) :: iprec
1149  integer(I4B) :: numobs
1150  character(len=20) :: fmtc
1151  real(DP) :: simval
1152  class(ObserveType), pointer :: obsrv => null()
1153  !
1154  ! Write simulated values for observations
1155  iprec = this%iprecision
1156  fmtc = this%obsfmtcont
1157  ! -- iterate through all observations
1158  numobs = this%obsList%Count()
1159  do i = 1, numobs
1160  obsrv => this%get_obs(i)
1161  ! -- continuous observation
1162  simval = obsrv%CurrentTimeStepEndValue
1163  if (obsrv%FormattedOutput) then
1164  call write_fmtd_obs(fmtc, obsrv, this%obsOutputList, simval)
1165  else
1166  call write_unfmtd_obs(obsrv, iprec, this%obsOutputList, simval)
1167  end if
1168  end do
1169  !
1170  ! --return
1171  return
Here is the call graph for this function: