Loading...
Searching...
No Matches
Fang2017filter.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ██╗████████╗██╗ ██╗ █████╗ ██████╗ █████╗ ███████╗██╗ ██╗
3 ██║╚══██╔══╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ██╔════╝██║ ██║
4 ██║ ██║ ███████║███████║██║ ███████║█████╗█████╗ ██║ ██║
5 ██║ ██║ ██╔══██║██╔══██║██║ ██╔══██║╚════╝██╔══╝ ╚██╗ ██╔╝
6 ██║ ██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ╚████╔╝
7 ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═══╝
8
9 * In real Time Highly Advanced Computational Applications for Finite Volumes
10 * Copyright (C) 2017 by the ITHACA-FV authors
11-------------------------------------------------------------------------------
12
13 License
14 This file is part of ITHACA-FV
15
16 ITHACA-FV is free software: you can redistribute it and/or modify
17 it under the terms of the GNU Lesser General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
20
21 ITHACA-FV is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU Lesser General Public License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with ITHACA-FV. If not, see <http://www.gnu.org/licenses/>.
28
29\*---------------------------------------------------------------------------*/
30
31
34
35#include "Fang2017filter.H"
36
37namespace ITHACAmuq
38{
39// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * //
40// Constructor
41Fang2017filter::Fang2017filter() {}
42Fang2017filter::Fang2017filter(int _Nsamples)
43{
44 Nsamples = _Nsamples;
45}
46
47// * * * * * * * * * * * * * * Filter Methods * * * * * * * * * * * * * * //
48
49// Return number of samples per ensamble
51{
52 return Nsamples;
53}
54
55// Return time
57{
58 return timeVector(timeStepI);
59}
60
61//--------------------------------------------------------------------------
63double Fang2017filter::getTime(int _timeStepI)
64{
65 return timeVector(_timeStepI);
66}
67
68//--------------------------------------------------------------------------
71{
72 return timeStepI;
73}
74
75//--------------------------------------------------------------------------
78{
79 return timeVector;
80}
81
82//--------------------------------------------------------------------------
85{
86 return stateMean;
87}
88
89//--------------------------------------------------------------------------
91void Fang2017filter::setObservations(Eigen::MatrixXd _observations)
92{
93 observations = _observations;
94}
95
96//--------------------------------------------------------------------------
98void Fang2017filter::setTime(double _startTime, double _deltaTime,
99 double _endTime)
100{
101 M_Assert(_endTime > _startTime, "endTime must be bigger than startTime");
102 startTime = _startTime;
103 deltaTime = _deltaTime;
104 endTime = _endTime;
105 Ntimes = (endTime - startTime) / deltaTime;
106 Foam::Info << "startTime = " << startTime << endl;
107 Foam::Info << "endTime = " << endTime << endl;
108 Foam::Info << "deltaTime = " << deltaTime << endl;
109 Foam::Info << "Ntimes = " << Ntimes << endl;
110 timeVector = Eigen::VectorXd::LinSpaced(Ntimes + 1, startTime, endTime);
111}
112
113//--------------------------------------------------------------------------
115void Fang2017filter::setObservationTime(int _observationStart,
116 int _observationDelta)
117{
118 M_Assert(timeVector.size() > 0,
119 "Setup the timeVector before setting up the observations vector");
120 M_Assert(_observationStart > 0, "First observation timestep can't be 0");
121 observationStart = _observationStart;
122 observationDelta = _observationDelta;
123 Foam::Info << "First observation at time = " << timeVector(observationStart) << " s"
124 << endl;
125 Foam::Info << "Observations taken every " << observationDelta << " timesteps" << endl;
126 observationBoolVec = Eigen::VectorXi::Zero(timeVector.size() - 1);
127
128 for (int i = observationStart - 1; i < Ntimes; i += observationDelta)
129 {
130 observationBoolVec(i) = 1;
131 }
132}
133
134//--------------------------------------------------------------------------
136void Fang2017filter::setModelError(double cov, bool univariate)
137{
138 M_Assert(stateSize > 0, "Set the stateSize before setting up the model error");
139 Eigen::VectorXd modelError_mu;
140 Eigen::MatrixXd modelError_cov;
141
142 if (univariate)
143 {
144 modelError_mu = Eigen::VectorXd::Zero(1);
145 modelError_cov = Eigen::MatrixXd::Identity(1,
146 1) * cov;
147 }
148 else
149 {
150 modelError_mu = Eigen::VectorXd::Zero(stateSize);
151 modelError_cov = Eigen::MatrixXd::Identity(stateSize,
152 stateSize) * cov;
153 }
154
155 modelErrorDensity = std::make_shared<muq::Modeling::Gaussian>(modelError_mu,
156 modelError_cov);
157 modelErrorFlag = 1;
158}
159
160//--------------------------------------------------------------------------
163{
164 M_Assert(observationSize > 0,
165 "Read measurements before setting up the measurement noise");
166 Eigen::VectorXd measNoise_mu = Eigen::VectorXd::Zero(observationSize);
167 Eigen::MatrixXd measNoise_cov = Eigen::MatrixXd::Identity(observationSize,
168 observationSize) * cov;
169 measNoiseDensity = std::make_shared<muq::Modeling::Gaussian>(measNoise_mu,
170 measNoise_cov);
171 measurementNoiseFlag = 1;
172}
173
174//--------------------------------------------------------------------------
176void Fang2017filter::setInitialStateDensity(Eigen::VectorXd _mean,
177 Eigen::MatrixXd _cov)
178{
179 if (stateSize == 0)
180 {
181 stateSize = _mean.size();
182 }
183 else
184 {
185 std::string message = "State has size = " + std::to_string(stateSize)
186 + " while input mean vector has size = "
187 + std::to_string(_mean.size());
188 M_Assert(stateSize == _mean.size(), message.c_str());
189 }
190
191 M_Assert(_cov.rows() == stateSize
192 && _cov.cols() == stateSize,
193 "To initialize the state ensemble use mean and cov with same dimentions");
194 initialStateDensity = std::make_shared<muq::Modeling::Gaussian>(_mean, _cov);
195 initialStateFlag = 1;
196}
197
198//--------------------------------------------------------------------------
201{
202 M_Assert(initialStateFlag == 1,
203 "Initialize the initial state density before sampling it");
204 stateEns.assignSamples(ensembleFromDensity(initialStateDensity));
205}
206
207//--------------------------------------------------------------------------
210 Eigen::MatrixXd _cov)
211{
212 if (parameterSize == 0)
213 {
214 parameterSize = _mean.size();
215 }
216 else
217 {
218 std::string message = "The input mean has size = " + std::to_string(
219 _mean.size())
220 + " but the parameterSize is "
221 + std::to_string(parameterSize);
222 M_Assert(parameterSize == _mean.size(), message.c_str());
223 }
224
225 M_Assert(_cov.rows() == parameterSize
226 && _cov.cols() == parameterSize, "Use mean and cov with same dimentions");
227 parameterPriorMean = _mean;
228 parameterPriorCov = _cov;
229 parameterPriorDensity = std::make_shared<muq::Modeling::Gaussian>(_mean, _cov);
230 parameterPriorFlag = 1;
231}
232
233//--------------------------------------------------------------------------
236{
237 M_Assert(parameterPriorFlag == 1, "Set up the parameter prior density");
238 parameterEns.assignSamples(ensembleFromDensity(parameterPriorDensity));
239 parameterMean.col(timeStepI) = parameterEns.mean();
240}
241
242//--------------------------------------------------------------------------
245 std::shared_ptr<muq::Modeling::Gaussian> _density)
246{
247 M_Assert(Nsamples > 0, "Number of samples not set up correctly");
248 Eigen::MatrixXd output(_density->Sample().size(), Nsamples);
249
250 for (int i = 0; i < Nsamples; i++)
251 {
252 output.col(i) = _density->Sample();
253 }
254
255 return output;
256}
257
258//--------------------------------------------------------------------------
261{
262 Eigen::MatrixXd stateSamps = stateEns.getSamples();
263 Eigen::MatrixXd paramSamps = parameterEns.getSamples();
264 M_Assert(stateSamps.cols() == paramSamps.cols(),
265 "State and parameter ensambles must have same number of samples");
266 Eigen::MatrixXd temp(stateSamps.rows() + paramSamps.rows(), stateSamps.cols());
267 temp << stateSamps,
268 paramSamps;
269 jointEns.assignSamples(temp);
270}
271
272//--------------------------------------------------------------------------
274void Fang2017filter::setObservationSize(int _size)
275{
276 observationSize = _size;
277 Foam::Info << "Observation size = " << observationSize << Foam::endl;
278}
279
280//--------------------------------------------------------------------------
282void Fang2017filter::setStateSize(int _size)
283{
284 stateSize = _size;
285 Foam::Info << "State size = " << stateSize << Foam::endl;
286}
287
288//--------------------------------------------------------------------------
290int Fang2017filter::getStateSize()
291{
292 return stateSize;
293}
294
295//--------------------------------------------------------------------------
297void Fang2017filter::setParameterSize(int _size)
298{
299 parameterSize = _size;
300 Foam::Info << "Parameter size = " << parameterSize << Foam::endl;
301}
302
303//--------------------------------------------------------------------------
305int Fang2017filter::getParameterSize()
306{
307 return parameterSize;
308}
309
310//--------------------------------------------------------------------------
312void Fang2017filter::updateJointEns(Eigen::VectorXd _observation)
313{
314 M_Assert(_observation.size() == observationSize,
315 "Observation has wrong dimentions");
316 int ensSize = jointEns.getSize();
317 //Eigen::MatrixXd temp = _observation - observationEns.getSamples().colwise();
318 //TODO deal with invertibility of observationEns.cov()
319 Eigen::MatrixXd autoCovInverse = observationEns.cov().inverse();
320 //Eigen::FullPivLU<Eigen::MatrixXd> lu_decomp(observationEns.cov());
321 //auto P_rank = lu_decomp.rank();
322 //if (P_rank < P.cols() || P_rank < P.rows())
323 //{
324 // Info << "Pseudo inverse of P should be implemented in the EnKF, exiting" <<
325 // endl;
326 // Info << P << endl;
327 // exit(10);
328 //}
329 //else
330 //{
331 // P = P.inverse();
332 //}
333 Eigen::MatrixXd crossCov = jointEns.crossCov(observationEns.getSamples());
334
335 for (int i = 0; i < ensSize; i++)
336 {
337 Eigen::VectorXd newSamp = jointEns.getSample(i) + crossCov * autoCovInverse *
338 (_observation - observationEns.getSample(i));
339 jointEns.assignSample(i, newSamp);
340 }
341}
342
343//--------------------------------------------------------------------------
345void Fang2017filter::run(int innerLoopMax, word outputFolder)
346{
347 M_Assert(initialStateFlag == 1, "Set up the initial state density");
348 M_Assert(parameterPriorFlag == 1, "Set up the parameter prior density");
349 M_Assert(modelErrorFlag == 1, "Set up the model error");
350 M_Assert(measurementNoiseFlag == 1, "Set up the measurement noise");
351 M_Assert(stateSize > 0, "Set state size");
352 M_Assert(observationSize > 0, "Set observation size");
353 M_Assert(parameterSize > 0, "Set parameter size");
354 timeStepI = 0;
356 stateMean.resize(stateSize, Ntimes);
357 state_maxConf.resize(stateSize, Ntimes);
358 state_minConf.resize(stateSize, Ntimes);
359 parameter_maxConf.resize(parameterSize, Ntimes);
360 parameter_minConf.resize(parameterSize, Ntimes);
361 parameterMean.resize(parameterSize, Ntimes);
362
363 while (timeStepI < Ntimes)
364 {
365 Foam::Info << "timeStep " << timeStepI << Foam::endl;
366 innerLoopI = 0;
367 oldStateEns.assignSamples(stateEns.getSamples());
368
369 while (innerLoopI < innerLoopMax)
370 {
371 Foam::Info << "Inner loop " << innerLoopI << Foam::endl;
372
373 // Projection
374 if (innerLoopI == 0)
375 {
376 if (timeStepI == 0)
377 {
378 setParameterPriorDensity(parameterPriorMean, parameterPriorCov);
380 }
381 else
382 {
384 parameterMean.col(timeStepI - 1), parameterPriorCov);
386 }
387
388 Foam::Info << "\ndebug : parameterPriorMean = " <<
389 parameterPriorMean << Foam::endl;
390 Foam::Info << "\ndebug : parameterMean.col(" << timeStepI << ") =\n" <<
391 parameterMean.col(timeStepI) << Foam::endl;
392 }
393 else
394 {
395 Foam::Info << "\ndebug : parameterMean before loop =\n" <<
396 parameterMean.col(timeStepI) << Foam::endl;
397 setParameterPriorDensity(parameterMean.col(timeStepI), parameterPriorCov);
399 Foam::Info << "\ndebug : parameterMean after loop =\n" <<
400 parameterMean.col(timeStepI) << Foam::endl;
401 }
402
403 stateProjection();
405
406 if (observationBoolVec(timeStepI) == 1)
407 {
408 Eigen::MatrixXd measNoiseSamps = ensembleFromDensity(measNoiseDensity);
409 observeState();
410 Foam::Info << "\ndebug : observation =\n" <<
411 observations.col(observationBoolVec.head(timeStepI + 1).sum() - 1) <<
412 Foam::endl;
413 updateJointEns(
414 observations.col(
415 observationBoolVec.head(timeStepI + 1).sum() - 1));
416 }
417
418 parameterMean.col(timeStepI) = jointEns.mean().tail(parameterSize);
419 innerLoopI++;
420 }
421
422 stateEns.assignSamples(jointEns.getSamples().topRows(stateSize));
423 parameterEns.assignSamples(jointEns.getSamples().bottomRows(parameterSize));
424 stateMean.col(timeStepI) = jointEns.mean().head(stateSize);
425 state_maxConf.col(timeStepI) = muq2ithaca::quantile(stateEns.getSamples(),
426 0.95);
427 state_minConf.col(timeStepI) = muq2ithaca::quantile(stateEns.getSamples(),
428 0.05);
429 parameter_maxConf.col(timeStepI) = muq2ithaca::quantile(
430 parameterEns.getSamples(),
431 0.95);
432 parameter_minConf.col(timeStepI) = muq2ithaca::quantile(
433 parameterEns.getSamples(),
434 0.05);
435 timeStepI++;
436 }
437
438 ITHACAstream::exportMatrix(stateMean, "stateMean", "eigen", outputFolder);
439 ITHACAstream::exportMatrix(parameterMean, "parameterMean", "eigen",
440 outputFolder);
441 ITHACAstream::exportMatrix(parameter_maxConf, "parameter_maxConf", "eigen",
442 outputFolder);
443 ITHACAstream::exportMatrix(parameter_minConf, "parameter_minConf", "eigen",
444 outputFolder);
445}
446}
Header file of the Fang2017filter class.
std::shared_ptr< muq::Modeling::Gaussian > modelErrorDensity
Model noise density.
int getNumberOfSamples()
Return number of samples per ensamble.
void sampleParameterDist()
Create parameter ensemble.
ensemble observationEns
Observation ensemble.
void setMeasNoise(double cov)
Setup of the measurement noise distribution.
void sampleInitialState()
Create initial state ensemble.
Eigen::MatrixXd state_maxConf
State maximum confidence level.
Eigen::MatrixXd getStateMean()
Return state mean.
void setInitialStateDensity(Eigen::VectorXd _mean, Eigen::MatrixXd _cov)
Create initial state ensemble.
Eigen::MatrixXd state_minConf
State minimum confidence level.
void setParameterPriorDensity(Eigen::VectorXd _mean, Eigen::MatrixXd _cov)
Create parameter ensemble.
void buildJointEns()
Concatenate state and parameter ensambles to create the joint ensamble.
int getTimeStep()
Return timestep.
void setModelError(double cov, bool univariate=0)
Setup of the model error distribution.
double getTime()
Return time.
void setTime(double _startTime, double _deltaTime, double _endTime)
Setup the time vector.
Eigen::MatrixXd parameter_minConf
parameter minimum confidence level
ensemble oldStateEns
Old state ensemble.
Eigen::MatrixXd ensembleFromDensity(std::shared_ptr< muq::Modeling::Gaussian > _density)
General class to sample from an input density.
Eigen::MatrixXd parameter_maxConf
parameter maximum confidence level
ensemble jointEns
Joint state and parameter ensemble.
Eigen::VectorXd getTimeVector()
Return time vector.
void setObservationTime(int _observationStart, int _observationDelta)
Setup the observation vector.
ensemble parameterEns
Parameter ensemble.
void setObservations(Eigen::MatrixXd _observations)
Set the observations matrix.
std::shared_ptr< muq::Modeling::Gaussian > measNoiseDensity
Measurement noise density.
ensemble stateEns
State ensemble.
void run(int innerLoopMax, word outputFolder)
Run the filtering.
void exportMatrix(Eigen::Matrix< T, -1, dim > &matrix, word Name, word type, word folder)
Export the reduced matrices in numpy (type=python), matlab (type=matlab) and txt (type=eigen) format ...