File: griddedDataReduceSampling.cpp

package info (click to toggle)
groops 0%2Bgit20250907%2Bds-1
  • links: PTS, VCS
  • area: non-free
  • in suites: forky, sid
  • size: 11,140 kB
  • sloc: cpp: 135,607; fortran: 1,603; makefile: 20
file content (173 lines) | stat: -rw-r--r-- 7,117 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/***********************************************/
/**
* @file griddedDataReduceSampling.cpp
*
* @brief Generate coarse grid by computing mean values.
*
* @author Torsten Mayer-Guerr
* @date 2013-10-24
*/
/***********************************************/

// Latex documentation
#define DOCSTRING docstring
static const char *docstring = R"(
Generate coarse grid by computing area weighted mean values.
The number of points is decimated by averaging integer multiplies of grid points
(\config{multiplierLongitude}, \config{multiplierLatitude}).

if \config{volumeConserving} is set, data are interpreted as heights above ellipsoid
and the tesseroid volume
\begin{equation}
  V=\int_r^{r+H}\int_{\varphi_1}^{\varphi_2}\int_{\lambda_1}^{\lambda_2} r^2\cos\varphi\,d\varphi\,d\lambda\,dr
\end{equation}
is conserved, where $r$ is the radius of the ellipsoid at grid center and
$(\varphi_1-\varphi_2)\times(\lambda_1-\lambda_2)$ are the grid cell boundaries.
This is meaninful for Digital Elevation Models (DEM).

The fine grid can be written, where the first coarse grid values (data0) are additionally appended.
)";

/***********************************************/

#include "programs/program.h"
#include "files/fileGriddedData.h"
#include "misc/miscGriddedData.h"

/***** CLASS ***********************************/

/** @brief Generate coarse grid by computing mean values.
* @ingroup programsGroup */
class GriddedDataReduceSampling
{
public:
  void run(Config &config, Parallel::CommunicatorPtr comm);
};

GROOPS_REGISTER_PROGRAM(GriddedDataReduceSampling, SINGLEPROCESS, "Generate coarse grid by computing mean values", Grid)

/***********************************************/

void GriddedDataReduceSampling::run(Config &config, Parallel::CommunicatorPtr /*comm*/)
{
  try
  {
    FileName fileNameOutCoarseGrid, fileNameOutFineGrid;
    FileName fileNameInFineGrid;
    UInt     numberRows, numberCols;
    Bool     volumeConserving;

    readConfig(config, "outputfileCoarseGridRectangular", fileNameOutCoarseGrid, Config::OPTIONAL, "", "coarse grid");
    readConfig(config, "outputfileFineGridRectangular",   fileNameOutFineGrid,   Config::OPTIONAL, "", "fine grid with additional coarse grid values");
    readConfig(config, "inputfileFineGridRectangular",    fileNameInFineGrid,    Config::MUSTSET,  "", "Digital Terrain Model");
    readConfig(config, "multiplierLongitude",             numberCols,            Config::MUSTSET,  "8", "Generalizing factor");
    readConfig(config, "multiplierLatitude",              numberRows,            Config::MUSTSET,  "8", "Generalizing factor");
    readConfig(config, "volumeConserving",                volumeConserving,      Config::DEFAULT,  "0", "data are interpreted as heights above ellipsoid");
    if(isCreateSchema(config)) return;

    // read grid
    // ---------
    logStatus<<"read grid from file <"<<fileNameInFineGrid<<">"<<Log::endl;
    GriddedDataRectangular gridFine;
    readFileGriddedData(fileNameInFineGrid, gridFine);

    std::vector<Angle>  tmp;
    std::vector<Double> radiusFine, longitude, latitude, dLambda, dPhi;
    gridFine.geocentric(tmp, tmp, radiusFine);
    gridFine.cellBorders(longitude, latitude);
    gridFine.areaElements(dLambda, dPhi);

    // Generate coarse grid
    // --------------------
    logStatus<<"generate coarse grid"<<Log::endl;
    GriddedDataRectangular gridCoarse;
    gridCoarse.ellipsoid = gridFine.ellipsoid;

    gridCoarse.latitudes.resize(gridFine.latitudes.size()/numberRows);
    for(UInt i=0; i<gridCoarse.latitudes.size(); i++)
      gridCoarse.latitudes.at(i) = 0.5*(latitude.at(i*numberRows) + latitude.at((i+1)*numberRows));

    gridCoarse.longitudes.resize(gridFine.longitudes.size()/numberCols);
    for(UInt k=0; k<gridCoarse.longitudes.size(); k++)
      gridCoarse.longitudes.at(k) = std::remainder(longitude.at(k*numberCols) + 0.5*std::remainder(longitude.at((k+1)*numberCols)-longitude.at(k*numberCols), 2*PI), 2*PI);

    gridCoarse.heights.resize(gridCoarse.latitudes.size()); // Compute mean height
    for(UInt i=0; i<gridCoarse.heights.size(); i++)
    {
      Double height = 0, weight = 0;
      for(UInt ii=0; ii<numberRows; ii++)
      {
        height += dPhi.at(i) * gridFine.heights.at(i*numberRows+ii);
        weight += dPhi.at(i);
      }
      gridCoarse.heights.at(i) = height/weight;
    }

    gridCoarse.values.resize(gridFine.values.size(), Matrix(gridCoarse.latitudes.size(), gridCoarse.longitudes.size()));

    std::vector<Double> radiusCoarse, dLambdaCoarse, dPhiCoarse;
    gridCoarse.geocentric(tmp, tmp, radiusCoarse);
    gridCoarse.areaElements(dLambdaCoarse, dPhiCoarse);

    // Compute mean values
    // -------------------
    logStatus<<"compute mean values"<<Log::endl;
    if(!fileNameOutFineGrid.empty())
      gridFine.values.push_back(Matrix(gridFine.latitudes.size(), gridFine.longitudes.size()));
    Single::forEach(gridCoarse.latitudes.size(), [&](UInt i)
    {
      for(UInt k=0; k<gridCoarse.longitudes.size(); k++)
      {
        // compute volume of tesseroid V = (r2^3-r1^3)/3 * area with r2=r1+h
        Vector volumes(gridCoarse.values.size());
        for(UInt ii=0; ii<numberRows; ii++)
          for(UInt kk=0; kk<numberCols; kk++)
          {
            const Double area = dPhi.at(i*numberRows+ii) * dLambda.at(k*numberCols+kk);
            const Double r1   = radiusFine.at(i*numberRows+ii);
            for(UInt idx=0; idx<gridCoarse.values.size(); idx++)
              if(volumeConserving)
                volumes(idx) += area * (std::pow(r1+gridFine.values.at(idx)(i*numberRows+ii, k*numberCols+kk), 3) - std::pow(r1, 3))/3.;
            else
              volumes(idx) += area * gridFine.values.at(idx)(i*numberRows+ii, k*numberCols+kk);
          }

        // height of tesseroid = (V*3/area - r1^3)^(1/3) - r1
        const Double area = dPhiCoarse.at(i) * dLambdaCoarse.at(k);
        const Double r1   = radiusCoarse.at(i);
        for(UInt idx=0; idx<gridCoarse.values.size(); idx++)
          if(volumeConserving)
            gridCoarse.values.at(idx)(i, k) = std::pow(volumes(idx)*3/area + std::pow(r1, 3), 1./3.) - r1;
          else
            gridCoarse.values.at(idx)(i, k) = volumes(idx)/area;

        if(!fileNameOutFineGrid.empty())
          for(UInt ii=0; ii<numberRows; ii++)
            for(UInt kk=0; kk<numberCols; kk++)
              gridFine.values.back()(i*numberRows+ii, k*numberCols+kk) = gridCoarse.values.at(0)(i, k);
      }
    });

    // write new grid
    // --------------
    if(!fileNameOutCoarseGrid.empty())
    {
      logStatus<<"write coarse grid to file <"<<fileNameOutCoarseGrid<<">"<<Log::endl;
      writeFileGriddedData(fileNameOutCoarseGrid, gridCoarse);
      MiscGriddedData::printStatistics(gridCoarse);
    }

    if(!fileNameOutFineGrid.empty())
    {
      logStatus<<"write fine grid to file <"<<fileNameOutFineGrid<<">"<<Log::endl;
      writeFileGriddedData(fileNameOutFineGrid, gridFine);
      MiscGriddedData::printStatistics(gridFine);
    }
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

/***********************************************/