UFO
LAMDomainCheck.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 2020 NOAA NWS NCEP EMC
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  */
7 
9 
10 #include "eckit/exception/Exceptions.h"
11 
12 #include "oops/util/missingValues.h"
13 
14 #include "ufo/filters/Variable.h"
15 
16 namespace ufo {
17 
19 
20 // -----------------------------------------------------------------------------
21 
22 LAMDomainCheck::LAMDomainCheck(const eckit::LocalConfiguration & conf)
23  : invars_() {
24  oops::Log::debug() << "LAMDomainCheck: config = " << conf << std::endl;
25  // Initialize options
26  options_.deserialize(conf);
27 
28  // We must know the latitude of each observation
29  invars_ += Variable("latitude@MetaData");
30  // We must know the longitude of each observation
31  invars_ += Variable("longitude@MetaData");
32 }
33 
34 // -----------------------------------------------------------------------------
35 
37 
38 // -----------------------------------------------------------------------------
39 /*! \brief LAMDomainCheck::compute
40 *
41 * \details The LAMDomainCheck is an obsfunction to compute if an observation is
42 * located inside a specified limited area model domain.
43 * The LAMDomainCheck obsfunction returns a value of 1 if the observation is determined
44 * to be located inside the specified domain and a value of 0 if it lies outside.
45 *
46 * In the UFO obs functions YAML, first one must define the map_projection.
47 * The following values of map_projection are currently supported:
48 * * "gnomonic_ed" - the ESG grid used by FV3-LAM
49 *
50 * The option 'save: true' will save the computed value to the output IODA file as
51 * 'LAMDomainCheck@DerivedValue' (default is false).
52 *
53 * The additional parameters to be defined in the options section
54 * of the obs function YAML will depend on the choice of map_projection used.
55 * For gnomonic_ed:
56 * * a - ESG alpha parameter (default 0)
57 * * k - ESG kappa parameter (default 0)
58 * * plat - ESG center point latitude (degrees; default 0)
59 * * plon - ESG center point longitude (degrees; default 0)
60 * * pazi - ESG azimuthal angle (radians; default 0)
61 * * dx - grid spacing in x (degrees; default 1)
62 * * dy - grid spacing in y (degrees, default 1)
63 * * npx - number of gridpoints in x (default 2)
64 * * npy - number of gridpoints in y (default 2)
65 * If using FV3-LAM, the above values are provided in the netCDF grid file attributes,
66 * but this option will work for any regional model that utilizes the
67 * Extended Schmidt Gnomonic grid developed by R. Jim Purser:
68 * https://dtcenter.org/sites/default/files/events/2020/2-purser-james.pdf
69 * "The Extended Schmidt Gnomonic grid for regional applications"
70 * by R. J. Purser, D. Jovic, G. Ketefian, T. Black, J. Beck, J. Dong, J. Carley.
71 * UFS Users' Workshop, July 27--29, 2020.
72 *
73 */
74 
76  ioda::ObsDataVector<float> & out) const {
77  const size_t nlocs = in.nlocs();
78  const float missing = util::missingValue(missing);
79 
80  // Ensure that only one output variable is expected.
81  ASSERT(out.nvars() == 1);
82 
83  std::vector<int> iidx(nlocs);
84 
85  // Retrieve the latitude and longitude.
86  std::vector<float> latitude;
87  std::vector<float> longitude;
88  in.get(Variable("latitude@MetaData"), latitude);
89  in.get(Variable("longitude@MetaData"), longitude);
90 
91  // get options based off the name of the map projection
92  if (options_.mapproj.value() == "gnomonic_ed") {
93  // ESG used in FV3-LAM
94  const float a = options_.esg_a.value();
95  const float k = options_.esg_k.value();
96  const float plat = options_.esg_plat.value();
97  const float plon = options_.esg_plon.value();
98  const float pazi = options_.esg_pazi.value();
99  const float dx = options_.esg_dx.value();
100  const float dy = options_.esg_dy.value();
101  const int npx = options_.esg_npx.value();
102  const int npy = options_.esg_npy.value();
103  for (size_t jj = 0; jj < nlocs; ++jj) {
104  lam_domaincheck_esg_f90(a, k, plat, plon, pazi, npx, npy,
105  dx, dy, latitude[jj], longitude[jj], iidx[jj]);
106  out[0][jj] = static_cast<float>(iidx[jj]);
107  }
108  } else if (options_.mapproj.value() == "circle") {
109  const float cenlat = options_.cenlat.value();
110  const float cenlon = options_.cenlon.value();
111  const float radius = options_.radius.value();
112  for (size_t jj = 0; jj < nlocs; ++jj) {
113  // calculate great-circle distance on sphere
114  lam_domaincheck_circle_f90(cenlat, cenlon, radius,
115  latitude[jj], longitude[jj], iidx[jj]);
116  out[0][jj] = static_cast<float>(iidx[jj]);
117  }
118  } else {
119  // throw exception for unsupported projection
120  std::string errString = " is not a supported map projection. Fatal error!!!";
121  oops::Log::error() << options_.mapproj.value() << errString;
122  throw eckit::BadValue(errString);
123  }
124 
125  if (options_.save) {
126  out.save("DerivedValue");
127  }
128 }
129 
130 // -----------------------------------------------------------------------------
131 
133  return invars_;
134 }
135 
136 // -----------------------------------------------------------------------------
137 
138 } // namespace ufo
void compute(const ObsFilterData &, ioda::ObsDataVector< float > &) const
LAMDomainCheck::compute.
const ufo::Variables & requiredVariables() const
geovals required to compute the function
ufo::Variables invars_
LAMDomainCheck(const eckit::LocalConfiguration &=eckit::LocalConfiguration())
LAMDomainCheckParameters options_
oops::Parameter< float > cenlon
oops::Parameter< bool > save
oops::Parameter< float > esg_k
oops::RequiredParameter< std::string > mapproj
oops::Parameter< float > esg_a
oops::Parameter< int > esg_npy
oops::Parameter< float > esg_dx
oops::Parameter< float > esg_plat
oops::Parameter< float > esg_dy
oops::Parameter< int > esg_npx
oops::Parameter< float > radius
oops::Parameter< float > cenlat
oops::Parameter< float > esg_pazi
oops::Parameter< float > esg_plon
ObsFilterData provides access to all data related to an ObsFilter.
size_t nlocs() const
Returns the number of locations in the associated ObsSpace.
void get(const Variable &varname, std::vector< float > &values) const
Fills a std::vector with values of the specified variable.
constexpr int missing
Definition: QCflags.h:20
integer function nlocs(this)
Return the number of observational locations in this Locations object.
Definition: RunCRTM.h:27
void lam_domaincheck_circle_f90(const float &, const float &, const float &, const float &, const float &, int &)
void lam_domaincheck_esg_f90(const float &, const float &, const float &, const float &, const float &, const int &, const int &, const float &, const float &, const float &, const float &, int &)
static ObsFunctionMaker< LAMDomainCheck > makerObsFuncLAMDomainCheck_("LAMDomainCheck")