File: kalmanSmoother.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 (161 lines) | stat: -rw-r--r-- 7,516 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
/***********************************************/
/**
* @file kalmanSmoother.cpp
*
* @brief Computes time variable gravity fields using Kalman smoother
*
* @author Enrico Kurtenbach
* @author Andreas Kvas
* @date 2008-11-01
*/
/***********************************************/

// Latex documentation
#define DOCSTRING docstring
static const char *docstring = R"(
Apply the Rauch-Tung-Striebel smoother to a gravity field time series computed by \program{KalmanFilter}.
This is the implementation of the approach presented in

Kurtenbach, E., Eicker, A., Mayer-Gürr, T., Holschneider, M., Hayn, M., Fuhrmann, M., and Kusche, J. (2012).
Improved daily GRACE gravity field solutions using a Kalman smoother. Journal of Geodynamics, 59–60, 39–48.
\url{https://doi.org/10.1016/j.jog.2012.02.006}.

The result has zero phase and the squared magnitude response of \configFile{inputfileAutoregressiveModel}{matrix}
(see \reference{autoregressiveModel}{fundamentals.autoregressiveModel} for details).
\configFile{inputfileUpdatedState}{matrix} and \configFile{inputfileUpdatedStateCovariance}{matrix}
are the output of a \program{KalmanFilter} forward sweep.
The matrix files for\configFile{outputfileUpdatedState}{matrix}, \configFile{inputfileUpdatedState}{matrix}
and \configFile{inputfileUpdatedStateCovariance}{matrix} can also be specified using \configClass{loops}{loopType}.

See also \program{KalmanBuildNormals}, \program{KalmanFilter} and \program{KalmanSmootherLeastSquares}.
)";

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

#include "programs/program.h"
#include "parser/dataVariables.h"
#include "files/fileMatrix.h"
#include "classes/timeSeries/timeSeries.h"
#include "misc/kalmanProcessing.h"

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

/** @brief Computes time variable gravity fields using Kalman filter approach
* @ingroup programsGroup */
class KalmanSmoother
{
public:
  void run(Config &config, Parallel::CommunicatorPtr comm);
};

GROOPS_REGISTER_PROGRAM(KalmanSmoother, SINGLEPROCESS, "Computes time variable gravity fields using Kalman smoother approach", KalmanFilter, NormalEquation)

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

void KalmanSmoother::run(Config &config, Parallel::CommunicatorPtr /*comm*/)
{
  try
  {
    std::vector<FileName> fileNameSmoothedState,  fileNameSmoothedCovariance, fileNameUpdatedState, fileNameUpdatedCovariance;
    FileName fileNameArModel;

    readConfig(config, "outputfileState",                         fileNameSmoothedState,            Config::MUSTSET,   "kalman/smoothedState/x_{loopTime:%D}.txt",                    "estimated parameters (nx1-matrix)");
    readConfig(config, "outputfileStateCovarianceMatrix",         fileNameSmoothedCovariance,       Config::OPTIONAL,  "kalman/smoothedStateCovariance/covariance_{loopTime:%D}.dat", "estimated parameters' covariance matrix");
    readConfig(config, "inputfileUpdatedState",                   fileNameUpdatedState,             Config::MUSTSET,   "kalman/updatedState/x_{loopTime:%D}.txt", "");
    readConfig(config, "inputfileUpdatedStateCovarianceMatrix",   fileNameUpdatedCovariance,        Config::MUSTSET,   "kalman/updatedStateCovariance/covariance_{loopTime:%D}.dat", "");
    readConfig(config, "inputfileAutoregressiveModel",            fileNameArModel,                  Config::MUSTSET,   "", "file name of autoregressive model");
    if(isCreateSchema(config)) return;

    // check input
    // -----------
    const UInt epochCount = fileNameSmoothedState.size();

    if(fileNameUpdatedState.size() != epochCount)
      throw(Exception("Number of update state file names and state vectors does not match (" + fileNameUpdatedState.size()%"%i"s + " vs. " + epochCount%"%i"s + ")."));

    if(fileNameUpdatedCovariance.size() != epochCount)
      throw(Exception("Number of update state covariance file names and state vectors does not match (" + fileNameUpdatedCovariance.size()%"%i"s + " vs. " + epochCount%"%i"s + ")."));

    if( (fileNameSmoothedCovariance.size() > 0) && (fileNameSmoothedCovariance.size() != epochCount))
      throw(Exception("Number of smoothed state covariance file names and state vectors does not match (" + fileNameSmoothedCovariance.size()%"%i"s + " vs. " + epochCount%"%i"s + ")."));

    // compute AR model
    // ----------------
    logStatus<<"read autoregressive model from <"<<fileNameArModel<<">"<<Log::endl;
    Matrix tmp;
    readFileMatrix(fileNameArModel, tmp);
    AutoregressiveModel arModel(tmp);

    Matrix B, Q;
    arModel.orderOneRepresentation(B, Q);

    // Initialize backward smoother:
    Matrix smoothedState, smoothedStateCovariance;
    Matrix updatedState, updatedStateCovariance;
    Matrix predictedState, predictedStateCovariance;

    logStatus <<"initialize state with <"<<fileNameUpdatedState.back()<<"> and <"<<fileNameUpdatedCovariance.back()<<">"<<Log::endl;
    readFileMatrix(fileNameUpdatedState.back(), updatedState);
    readFileMatrix(fileNameUpdatedCovariance.back(), updatedStateCovariance);

    smoothedState = updatedState;
    smoothedStateCovariance = updatedStateCovariance;
    logStatus <<"write smoothed state to <"<<fileNameSmoothedState.back()<<">"<<Log::endl;
    writeFileMatrix(fileNameSmoothedState.back(), smoothedState);
    if(fileNameSmoothedCovariance.size() > 0)
    {
      logStatus <<"write smoothed state to <"<<fileNameSmoothedCovariance.back()<<">"<<Log::endl;
      writeFileMatrix(fileNameSmoothedCovariance.back(), smoothedStateCovariance);
    }

    for(UInt k=epochCount-1; k>0; k--)
    {
      readFileMatrix(fileNameUpdatedState.at(k-1), updatedState);
      readFileMatrix(fileNameUpdatedCovariance.at(k-1), updatedStateCovariance);

      predictedState = B*updatedState;

      // predicted state covariance
      cholesky(updatedStateCovariance);
      Matrix smootherGain = B;
      triangularMult(1.0, updatedStateCovariance, smootherGain.trans());

      predictedStateCovariance = Q;
      rankKUpdate(1.0, smootherGain.trans(), predictedStateCovariance);

      // transposed gain matrix K
      triangularMult(1.0, updatedStateCovariance.trans(), smootherGain.trans());
      solveInPlace(predictedStateCovariance, smootherGain);

      // smoothed state
      smoothedState = updatedState + smootherGain.trans()*(smoothedState-predictedState);

      // smoothed state covariance
      zeroUnusedTriangle(predictedStateCovariance);
      predictedStateCovariance.setType(Matrix::GENERAL);
      rankKUpdate(-1.0, predictedStateCovariance, smoothedStateCovariance);
      fillSymmetric(smoothedStateCovariance);
      smoothedStateCovariance.setType(Matrix::GENERAL);

      smoothedStateCovariance = smootherGain.trans()*smoothedStateCovariance*smootherGain;
      smoothedStateCovariance.setType(Matrix::SYMMETRIC);
      zeroUnusedTriangle(updatedStateCovariance);
      updatedStateCovariance.setType(Matrix::GENERAL);
      rankKUpdate(1.0, updatedStateCovariance, smoothedStateCovariance);

      logStatus <<"write smoothed state to <"<<fileNameSmoothedState.at(k-1)<<">"<<Log::endl;
      writeFileMatrix(fileNameSmoothedState.at(k-1), smoothedState);
      if(!fileNameSmoothedCovariance.empty())
      {
        logStatus <<"write smoothed state covariance to <"<<fileNameSmoothedCovariance.at(k-1)<<">"<<Log::endl;
        writeFileMatrix(fileNameSmoothedCovariance.at(k-1), smoothedStateCovariance);
      }
    }
  }
  catch(std::exception &e)
  {
    GROOPS_RETHROW(e)
  }
}

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