From a445afb5d4b7545cbae8d516f8db2efc7a9148c2 Mon Sep 17 00:00:00 2001 From: John Halley Gotway Date: Thu, 7 Jul 2022 11:11:12 -0600 Subject: [PATCH] Per #1954, adding initial unstructured grid library code. --- src/libcode/vx_grid/Makefile.am | 5 +- src/libcode/vx_grid/unstructured_grid.cc | 443 +++++++++++++++++++ src/libcode/vx_grid/unstructured_grid.h | 112 +++++ src/libcode/vx_grid/unstructured_grid_defs.h | 41 ++ 4 files changed, 600 insertions(+), 1 deletion(-) create mode 100644 src/libcode/vx_grid/unstructured_grid.cc create mode 100644 src/libcode/vx_grid/unstructured_grid.h create mode 100644 src/libcode/vx_grid/unstructured_grid_defs.h diff --git a/src/libcode/vx_grid/Makefile.am b/src/libcode/vx_grid/Makefile.am index e7d5ffc41d..9eef7c118a 100644 --- a/src/libcode/vx_grid/Makefile.am +++ b/src/libcode/vx_grid/Makefile.am @@ -28,6 +28,9 @@ libvx_grid_a_SOURCES = \ latlon_xyz.h latlon_xyz.cc \ rot_latlon_grid.cc rot_latlon_grid.h \ tcrmw_grid.cc tcrmw_grid.h \ - goes_grid_defs.h goes_grid.cc goes_grid.h \ + goes_grid_defs.h \ + goes_grid.cc goes_grid.h \ + unstructured_grid_defs.h \ + unstructured_grid.cc unstructured_grid.h \ vx_grid.h libvx_grid_a_CPPFLAGS = ${MET_CPPFLAGS} diff --git a/src/libcode/vx_grid/unstructured_grid.cc b/src/libcode/vx_grid/unstructured_grid.cc new file mode 100644 index 0000000000..6af523536b --- /dev/null +++ b/src/libcode/vx_grid/unstructured_grid.cc @@ -0,0 +1,443 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2022 +// ** University Corporation for Atmospheric Research (UCAR) +// ** National Center for Atmospheric Research (NCAR) +// ** Research Applications Lab (RAL) +// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + + +//////////////////////////////////////////////////////////////////////// + + +using namespace std; + + +#include +#include +#include +#include +#include +#include + +#include "vx_math.h" +#include "vx_util.h" +#include "vx_log.h" +#include "unstructured_grid.h" + + +//////////////////////////////////////////////////////////////////////// + + + // + // Code for class UnstructuredGrid + // + + +//////////////////////////////////////////////////////////////////////// + + +UnstructuredGrid::UnstructuredGrid() + +{ + +clear(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +UnstructuredGrid::~UnstructuredGrid() + +{ + +clear(); + +} + + +//////////////////////////////////////////////////////////////////////// + + +UnstructuredGrid::UnstructuredGrid(const UnstructuredData & data) + +{ + +clear(); + +// JHG work here + +} + + +//////////////////////////////////////////////////////////////////////// + + +void UnstructuredGrid::clear() + +{ + +Lats.clear(); +Lons.clear(); +Levels.clear(); +Times.clear(); + +Dim1 = (NumArray *) 0; +Dim2 = (NumArray *) 0; + +Nx = 0; +Ny = 0; + +Name.clear(); + +memset(&Data, 0, sizeof(Data)); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void UnstructuredGrid::latlon_to_xy(double lat, double lon, double & x, double & y) const + +{ + +if ( !Dim1 || !Dim2 ) { + mlog << Error << "\nUnstructuredGrid::latlon_to_xy() -> " + << "dimensions not defined!\n\n"; + exit ( 1 ); +} + +int i, x_int, y_int; +x_int = y_int = bad_data_int; + +// Search dimensions separately for matches +if ( Is2Dim ) { + + // Search the first dimension + for(i=0; in(); i++) { + if(is_eq(lat, Dim1->buf()[i])) { + x_int = i; + break; + } + } + + // Search the second dimension + for(i=0; in(); i++) { + if(is_eq(lat, Dim2->buf()[i])) { + y_int = i; + break; + } + } +} +else { + + // Search both dimensions + for(i=0; in(); i++) { + if(is_eq(lat, Dim1->buf()[i]) && is_eq(lon, Dim2->buf()[i])) { + x_int = y_int = i; + break; + } + } +} + +if ( is_bad_data(x_int) || is_bad_data(y_int) ) { + mlog << Error << "\nUnstructuredGrid::latlon_to_xy() -> " + << "no match found for (" << lat << ", " << lon << ").\n\n"; + exit ( 1 ); +} + +x = (double) x_int; +y = (double) y_int; + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +void UnstructuredGrid::xy_to_latlon(double x, double y, double & lat, double & lon) const + +{ + +if ( !Dim1 || !Dim2 ) { + mlog << Error << "\nUnstructuredGrid::xy_to_latlon() -> " + << "dimensions not defined!\n\n"; + exit ( 1 ); +} + +int x_int = nint(x); +int y_int = nint(y); + +if ( x_int < 0 || x_int >= Nx || + y_int < 0 || y_int >= Ny ) { + mlog << Error << "\nUnstructuredGrid::xy_to_latlon() -> " + << "(" << x_int << ", " << y_int << ") outside of the grid dimension (" + << Nx << ", " << Ny <<")!\n\n"; + exit ( 1 ); +} + +lat = Dim1->buf()[x_int]; +lon = Dim2->buf()[y_int]; + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +double UnstructuredGrid::calc_area(int x, int y) const + +{ + + // Grid cell area is not defined for unstructured grids + +return ( bad_data_double ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +int UnstructuredGrid::nx() const + +{ + +return ( Nx ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +int UnstructuredGrid::ny() const + +{ + +return ( Ny ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +ConcatString UnstructuredGrid::name() const + +{ + +return ( Name ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +void UnstructuredGrid::dump(ostream & out, int depth) const + +{ + +Indent prefix(depth); + + +out << prefix << "Name = "; + +if ( Name.length() > 0 ) out << '\"' << Name << '\"'; +else out << "(nul)\n"; + +out << '\n'; + +out << prefix << "Projection = Unstructured\n"; + +out << prefix << "Lats:\n"; +Lats.dump(out, depth+1); + +out << prefix << "Lons:\n"; +Lons.dump(out, depth+1); + +out << prefix << "Levels:\n"; +Levels.dump(out, depth+1); + +out << prefix << "Times:\n"; +Times.dump(out, depth+1); + +out << prefix << "Is2Dim = " << bool_to_string(Is2Dim) << "\n"; +out << prefix << "Nx = " << Nx << "\n"; +out << prefix << "Ny = " << Ny << "\n"; + + // + // done + // + +out.flush(); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +ConcatString UnstructuredGrid::serialize(const char *sep) const + +{ + +ConcatString a; + +a << "Projection: Unstructured" << sep; + +a << "Nx: " << Nx << sep; +a << "Ny: " << Ny << sep; + +a << "Lats: " << Lats.serialize() << sep; +a << "Lons: " << Lons.serialize() << sep; +a << "Levels: " << Levels.serialize() << sep; +a << "Times: " << Times.serialize() << sep; + + // + // done + // + +return ( a ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +GridInfo UnstructuredGrid::info() const + +{ + +GridInfo i; + +i.set(Data); + +return ( i ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +double UnstructuredGrid::rot_grid_to_earth(int x, int y) const + +{ + +// +// The rotation angle from grid relative to earth relative +// does not apply to unstructured grids +// + +return ( 0.0 ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +bool UnstructuredGrid::wrap_lon() const + +{ + +return ( false ); + +} + + +//////////////////////////////////////////////////////////////////////// + + +void UnstructuredGrid::shift_right(int N) + +{ + +mlog << Error << "\nUnstructuredGrid::shift_right(int) -> " + << "shifting is not allowed for non-global grids\n\n"; + +exit ( 1 ); + +return; + +} + + +//////////////////////////////////////////////////////////////////////// + + +GridRep * UnstructuredGrid::copy() const + +{ + +UnstructuredGrid * p = new UnstructuredGrid (Data); + +p->Name = Name; + +return ( p ); + +} + + +//////////////////////////////////////////////////////////////////////// + + + // + // Code for misc functions + // + + +//////////////////////////////////////////////////////////////////////// + + +Grid::Grid(const UnstructuredData & data) + +{ + +init_from_scratch(); + +set(data); + +} + + +//////////////////////////////////////////////////////////////////////// + + +void Grid::set(const UnstructuredData & data) + +{ + +clear(); + +rep = new UnstructuredGrid (data); + +if ( !rep ) { + + mlog << Error << "\nGrid::set(const UnstructuredData &) -> " + << "memory allocation error\n\n"; + + exit ( 1 ); + +} + +return; + +} + + +//////////////////////////////////////////////////////////////////////// diff --git a/src/libcode/vx_grid/unstructured_grid.h b/src/libcode/vx_grid/unstructured_grid.h new file mode 100644 index 0000000000..981d2af898 --- /dev/null +++ b/src/libcode/vx_grid/unstructured_grid.h @@ -0,0 +1,112 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2022 +// ** University Corporation for Atmospheric Research (UCAR) +// ** National Center for Atmospheric Research (NCAR) +// ** Research Applications Lab (RAL) +// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + + +//////////////////////////////////////////////////////////////////////// + + +#ifndef __MET_UNSTRUCTURED_GRID_H__ +#define __MET_UNSTRUCTURED_GRID_H__ + + +//////////////////////////////////////////////////////////////////////// + + +#include "grid_base.h" + + +//////////////////////////////////////////////////////////////////////// + + +class UnstructuredGrid : public GridRep { + + friend class Grid; + + private: + + UnstructuredGrid(); + ~UnstructuredGrid(); + UnstructuredGrid(const UnstructuredData &); + + // + // + // + + void clear(); + + ConcatString Name; + + // Exactly 2 have non-zero length + + NumArray Lats; + NumArray Lons; + NumArray Levels; + NumArray Times; + + NumArray * Dim1; // not allocated + NumArray * Dim2; // not allocated + + // TRUE: for lat or lon vs level or time with unique lat/lon values + // FALSE: for a 1D list of potentially non-unique lat/lon values + + bool Is2Dim; + int Nx; + int Ny; + + UnstructuredData Data; + + // + // grid interface + // + + void latlon_to_xy(double lat, double lon, double & x, double & y) const; + + void xy_to_latlon(double x, double y, double & lat, double & lon) const; + + double calc_area(int x, int y) const; + + int nx() const; + int ny() const; + + double scale_km() const; + + ConcatString name() const; + + void dump(ostream &, int = 0) const; + + ConcatString serialize(const char *sep=" ") const; + + GridInfo info() const; + + double rot_grid_to_earth(int x, int y) const; + + bool wrap_lon() const; + + void shift_right(int); + + GridRep * copy() const; + +}; + + +//////////////////////////////////////////////////////////////////////// + + +inline double UnstructuredGrid::scale_km() const { return ( -1.0 ); } + + +//////////////////////////////////////////////////////////////////////// + + +#endif /* __MET_UNSTRUCTURED_GRID_H__ */ + + +//////////////////////////////////////////////////////////////////////// + + + diff --git a/src/libcode/vx_grid/unstructured_grid_defs.h b/src/libcode/vx_grid/unstructured_grid_defs.h new file mode 100644 index 0000000000..4ba2fc7c5f --- /dev/null +++ b/src/libcode/vx_grid/unstructured_grid_defs.h @@ -0,0 +1,41 @@ +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* +// ** Copyright UCAR (c) 1992 - 2022 +// ** University Corporation for Atmospheric Research (UCAR) +// ** National Center for Atmospheric Research (NCAR) +// ** Research Applications Lab (RAL) +// ** P.O.Box 3000, Boulder, Colorado, 80307-3000, USA +// *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=* + + +//////////////////////////////////////////////////////////////////////// + + +#ifndef __UNSTRUCTURED_GRID_DEFINITIONS_H__ +#define __UNSTRUCTURED_GRID_DEFINITIONS_H__ + + +//////////////////////////////////////////////////////////////////////// + + +struct UnstructuredData { + + const char * name; + + // Exactly 2 are specified + + NumArray lats; + NumArray lons; + NumArray levels; + TimeArray times; + + void dump(); +}; + + +//////////////////////////////////////////////////////////////////////// + + +#endif /* __UNSTRUCTURED_GRID_DEFINITIONS_H__ */ + + +////////////////////////////////////////////////////////////////////////