File: instrumentArcCalculate.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 (227 lines) | stat: -rw-r--r-- 10,286 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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
/***********************************************/
/**
* @file instrumentArcCalculate.cpp
*
* @brief Instrument data calculation arc wise.
*
* @author Torsten Mayer-Guerr
* @date 2018-05-01
*
*/
/***********************************************/

// Latex documentation
#define DOCSTRING docstring
static const char *docstring = R"(
This program manipulates the data columns every arc of an \file{instrument file}{instrument} similar to
\program{FunctionsCalculate}, see there for more details.
If several \configFile{inputfileInstrument}{instrument}s are given the data columns are copied side by side.
For this the instrument files must be synchronized (see \program{InstrumentSynchronize}). For the data
columns the standard data variables are available, see~\reference{dataVariables}{general.parser:dataVariables}.
For the time column (MJD) a variable \verb|epoch| (together with \verb|epochmean|, \verb|epochmin|, \ldots)
is defined additionally.

The content of \configFile{outputfileInstrument}{instrument} is controlled by \config{outColumn}.
The number of \config{outColumn} must agree with the selected \configClass{outType}{instrumentTypeType}.
The algorithm to compute the output is as follows:
The expressions in \config{outColumn} are evaluated once for each epoch of the input.
The variables \verb|data0|,~\verb|data1|,~\ldots are replaced by the according values from the input columns before.
If no \config{outColumn} are specified all input columns are used instead directly.
The \configClass{instrument type}{instrumentTypeType} can be specified with \config{outType} and must be agree with the number of columns.

An extra \config{statistics} file can be generated with one mid epoch per arc. For the computation of the \config{outColumn} values
all~\reference{dataVariables}{general.parser:dataVariables} are available (e.g. \verb|epochmin|, \verb|data0mean|, \verb|data1std|, \ldots)
inclusively the \config{constant}s and estimated \config{parameter}s but without the \verb|data0|,~\verb|data1|,~\ldots itself.
The variables and the numbering of the columns refers to the \configFile{outputfileInstrument}{instrument}.

See also \program{FunctionsCalculate}, \program{MatrixCalculate}.
)";

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

#include "programs/program.h"
#include "parser/dataVariables.h"
#include "files/fileMatrix.h"
#include "files/fileInstrument.h"

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

/** @brief Instrument data calculation arc wise.
* @ingroup programsGroup */
class InstrumentArcCalculate
{
public:
  void run(Config &config, Parallel::CommunicatorPtr comm);
};

GROOPS_REGISTER_PROGRAM(InstrumentArcCalculate, PARALLEL, "Instrument data calculation arc wise.", Instrument)

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

void InstrumentArcCalculate::run(Config &config, Parallel::CommunicatorPtr comm)
{
  try
  {
    FileName                           fileNameOut, fileNameStatistics;
    std::vector<FileName>              fileNamesIn;
    std::vector<ExpressionVariablePtr> constExpr, paramExpr;
    std::vector<ExpressionVariablePtr> lsaExpr, removeExpr;
    std::vector<ExpressionVariablePtr> outExpr, statisticsExpr;
    Epoch::Type                        type = Epoch::EMPTY;

    readConfig(config, "outputfileInstrument",    fileNameOut, Config::OPTIONAL, "",      "");
    readConfig(config, "inputfileInstrument",     fileNamesIn, Config::MUSTSET,  "",      "data columns are appended to the right");
    readConfig(config, "constant",                constExpr,   Config::OPTIONAL, "",      "define a constant by name=value");
    readConfig(config, "parameter",               paramExpr,   Config::OPTIONAL, "",      "define a parameter by name[=value]");
    readConfig(config, "leastSquares",            lsaExpr,     Config::OPTIONAL, "",      "try to minimize the expression by adjustment of the parameters");
    readConfig(config, "removalCriteria",         removeExpr,  Config::OPTIONAL, "",      "row is removed if one criterion evaluates true.");
    readConfig(config, "outType",                 type,        Config::OPTIONAL, "",      "");
    readConfig(config, "outColumn",               outExpr,     Config::OPTIONAL, R"(["data0"])", "expression of output columns, extra 'epoch' variable");
    if(readConfigSequence(config, "statistics", Config::OPTIONAL, "", ""))
    {
      readConfig(config, "outputfileInstrument", fileNameStatistics, Config::MUSTSET, "",         "instrument file with mid epoch per arc, data columns are user defined");
      readConfig(config, "outColumn",            statisticsExpr,     Config::MUSTSET, "data0rms", "expression to compute statistics columns, data* are from outColumn");
      endSequence(config);
    }
    if(isCreateSchema(config)) return;

    // open files
    // ----------
    std::vector<InstrumentFile> file(fileNamesIn.size());
    for(UInt i=0; i<file.size(); i++)
      file.at(i).open(fileNamesIn.at(i));
    for(UInt i=1; i<file.size(); i++)
      InstrumentFile::checkArcCount({file.at(0), file.at(i)});

    // create data variables
    // ---------------------
    VariableList varListGlobal;
    // get real variable names, otherwise all named after config element
    std::for_each(constExpr.begin(), constExpr.end(), [&](auto expr) {expr->parseVariableName();});
    std::for_each(paramExpr.begin(), paramExpr.end(), [&](auto expr) {expr->parseVariableName();});
    std::for_each(constExpr.begin(), constExpr.end(), [&](auto expr) {varListGlobal.addVariable(expr);});
    std::for_each(paramExpr.begin(), paramExpr.end(), [&](auto expr) {varListGlobal.addVariable(expr);});

    // arc wise computation
    // --------------------
    logStatus<<"computing arcs"<<Log::endl;
    std::vector<Arc> arcList(file.at(0).arcCount());
    Matrix statistics(file.at(0).arcCount(), 1+statisticsExpr.size());
    Parallel::forEach(arcList, [&](UInt arcNo)
    {
      // read data
      std::vector<Arc> arc(file.size());
      for(UInt i=0; i<arc.size(); i++)
        arc.at(i) = file.at(i).readArc(arcNo);
      for(UInt i=1; i<arc.size(); i++)
        Arc::checkSynchronized({arc.at(0), arc.at(i)});

      // copy data to one matrix + extra time vector
      std::vector<Time> times = (arc.at(0).times());
      std::vector<UInt> index(1, 0);
      for(UInt i=0; i<arc.size(); i++)
        index.push_back( arc.at(i).at(0).data().rows() + index.back() );
      Matrix data(arc.at(0).size(), index.back());
      for(UInt i=0; i<arc.size(); i++)
        copy(arc.at(i).matrix().column(1, index.at(i+1)-index.at(i)), data.column(index.at(i), index.at(i+1)-index.at(i))); // without time column

      auto varListArc       = varListGlobal;
      auto varListArcWoData = varListGlobal;
      addDataVariables("epoch", times, varListArc);
      addDataVariables(data, varListArc);

      // least squares adjustment
      if(lsaExpr.size())
      {
        Vector l(data.rows()*lsaExpr.size());
        Matrix A(data.rows()*lsaExpr.size(), paramExpr.size());
        for(UInt k=0; k<lsaExpr.size(); k++)
        {
          std::vector<ExpressionVariablePtr> designExpr(paramExpr.size());
          for(UInt s=0; s<paramExpr.size(); s++)
          {
            designExpr.at(s) = lsaExpr.at(k)->derivative(paramExpr.at(s)->name(), varListArc);
            designExpr.at(s)->simplify(varListArc);
          }

          for(UInt i=0; i<data.rows(); i++)
          {
            evaluateDataVariables(data, i, varListArc);
            varListArc.setVariable("epoch", times.at(i).mjd());
            l(i+k*data.rows()) = -lsaExpr.at(k)->evaluate(varListArc); // observations
            for(UInt s=0; s<designExpr.size(); s++)
              A(i+k*data.rows(),s) = designExpr.at(s)->evaluate(varListArc); // columns of design matrix
          }
          undefineDataVariables(data, varListArc);
          varListArc.undefineVariable("epoch");
        }

        Vector x = leastSquares(A, l);
        for(UInt s=0; s<paramExpr.size(); s++)
        {
          x(s) += paramExpr.at(s)->evaluate(varListArc);
          varListArc.setVariable(paramExpr.at(s)->name(),  x(s) );
          varListArcWoData.setVariable(paramExpr.at(s)->name(),  x(s) );
        }
      } // if(lsa)

      // create output arc
      std::vector<Time> timesOut(data.rows());
      Matrix outData(data.rows(), 1 + (outExpr.size() ? outExpr.size() : data.columns())); // first column for time
      UInt row = 0;
      for(UInt i=0; i<outData.rows(); i++)
      {
        evaluateDataVariables(data, i, varListArc);
        varListArc.setVariable("epoch", times.at(i).mjd());
        if(!std::any_of(removeExpr.begin(), removeExpr.end(), [&](auto expr) {return expr->evaluate(varListArc) != 0;}))
        {
          timesOut.at(row) = times.at(i);
          for(UInt k=0; k<outData.columns()-1; k++)
            outData(row, 1+k) = outExpr.size() ? outExpr.at(k)->evaluate(varListArc) : data(i, k);
          row++;
        }
      }
      timesOut.resize(row);
      if(row < outData.rows())
        outData = outData.row(0, row);

      // arc statistics
      if(statisticsExpr.size())
      {
        auto varList = varListArcWoData;
        addDataVariables("epoch", timesOut, varList);
        addDataVariables(outData.column(1, outData.columns()-1), varList);
        statistics(arcNo, 0) = (0.5*(timesOut.front()+timesOut.back()+medianSampling(timesOut))).mjd();
        for(UInt k=0; k<statisticsExpr.size(); k++)
          statistics(arcNo, 1+k) = statisticsExpr.at(k)->evaluate(varList);
      }

      return Arc(timesOut, outData, type);
    }, comm);

    // write results
    // -------------
    if(!fileNameOut.empty() && Parallel::isMaster(comm))
    {
      logStatus<<"write instrument data <"<<fileNameOut<<">"<<Log::endl;
      InstrumentFile::write(fileNameOut, arcList);
      Arc::printStatistics(arcList);
    }

    if(!fileNameStatistics.empty() && statistics.size())
    {
      Parallel::reduceSum(statistics, 0, comm);
      if(Parallel::isMaster(comm))
      {
        logStatus<<"write statistics file <"<<fileNameStatistics<<">"<<Log::endl;
        InstrumentFile::write(fileNameStatistics, Arc(statistics));
      }
    }
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

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