MUQ  0.4.3
FlowModelComponents.cpp
Go to the documentation of this file.
1 #include "FlowModelComponents.h"
2 
4 
8 
13 
14 using namespace muq::Utilities;
15 using namespace muq::Modeling;
16 using namespace muq::Approximation;
17 using namespace muq::SamplingAlgorithms;
18 
19 Discretization::Discretization(std::size_t const numCells) :
20 numCells(numCells),
21 numNodes(numCells+1),
22 nodeLocs(Eigen::VectorXd::LinSpaced(numCells+1, -1.0, 1.0)),
23 cellLocs(0.5*(nodeLocs.tail(numCells) + nodeLocs.head(numCells)))
24 {}
25 
26 Data::Data(Eigen::VectorXd const& x, Eigen::VectorXd const& soln, Eigen::VectorXd const& obsLoc, Eigen::VectorXd const& obs) :
27 x(x),
28 soln(soln),
29 obsLoc(obsLoc),
30 obs(obs)
31 {}
32 
33 Eigen::VectorXd GetTrueLogConductivity(Discretization const& mesh) {
34  return (M_PI*mesh.cellLocs).array().cos() + (3.0*M_PI*mesh.cellLocs).array().sin();
35 }
36 
37 Eigen::VectorXd GetRecharge(Discretization const& mesh) {
38  return Eigen::VectorXd::Ones(mesh.cellLocs.size());
39 }
40 
41 std::shared_ptr<LinearOperator> InterpolateOntoObs(Discretization const& mesh, Eigen::VectorXd const& obsLoc) {
42  Eigen::MatrixXd A = Eigen::MatrixXd::Zero(obsLoc.size(), mesh.numNodes);
43  std::size_t j = 0;
44  for( std::size_t i=0; i<obsLoc.size(); ++i ) {
45  while( mesh.nodeLocs(j+1)<obsLoc(i) ) { ++j; }
46  assert(j<mesh.numNodes-1);
47  assert(obsLoc(i)>mesh.nodeLocs(j)-1.0e-14);
48  assert(obsLoc(i)<mesh.nodeLocs(j+1)+1.0e-14);
49 
50  A(i, j) = (mesh.nodeLocs(j+1)-obsLoc(i))/(mesh.nodeLocs(j+1)-mesh.nodeLocs(j));
51  assert(A(i, j)>-1.0e-14); assert(A(i, j)<1.0+1.0e-14);
52  A(i, j+1) = 1.0-A(i, j);
53  }
54 
55  return LinearOperator::Create(A);
56 }
57 
58 Data GenerateData(std::size_t const numCells, std::size_t const numObs, double const obsVar) {
59  const Discretization mesh(numCells);
60 
61  const Eigen::VectorXd trueCond = GetTrueLogConductivity(mesh).array().exp();
62  const Eigen::VectorXd recharge = GetRecharge(mesh);
63 
64  auto mod = std::make_shared<FlowEquation>(recharge);
65  const Eigen::VectorXd obsLoc = Eigen::VectorXd::LinSpaced(numObs, -1.0, 1.0);
66  auto interp = InterpolateOntoObs(mesh, obsLoc);
67 
68  // solve the forward problem with the true conductivity
69  const Eigen::VectorXd trueSol = mod->Evaluate(trueCond).at(0);
70  return Data(mesh.nodeLocs, trueSol, obsLoc, interp->Evaluate(trueSol).at(0) + std::sqrt(obsVar)*RandomGenerator::GetNormal(interp->outputSizes(0)));
71 }
72 
73 std::shared_ptr<ModPiece> ConstructDensity(std::size_t const numCells, Data const& data, double const likelihoodVar) {
74  const Discretization mesh(numCells);
75 
76  const double sigma2 = 1.0;
77  const double length = 0.1;
78  auto kernel = std::make_shared<SquaredExpKernel>(1, sigma2, length);
79 
80  GaussQuadrature quad(std::make_shared<Legendre>());
81  const std::size_t order = 15;
82  quad.Compute(order);
83  const Eigen::RowVectorXd points = quad.Points();
84  const Eigen::VectorXd weights = quad.Weights();
85 
86  KarhunenLoeveExpansion klexpansion(kernel, points, weights);
87  const Eigen::Matrix modes = klexpansion.GetModes(mesh.cellLocs.transpose());
88  auto logConductivity = LinearOperator::Create(modes);
89 
90  auto prior = std::make_shared<Gaussian>(modes.cols());
91 
92  const std::size_t numSamps = 15;
93  Eigen::MatrixXd priorSamples(numSamps, mesh.numCells);
94  for( std::size_t i=0; i<numSamps; ++i ) {
95  priorSamples.row(i) = logConductivity->Evaluate(prior->Sample()).at(0);
96  }
97 
98  const std::string filename = "output.h5";
99  auto file = std::make_shared<HDF5File>(filename);
100  file->WriteMatrix("/prior information/x", mesh.cellLocs);
101  file->WriteMatrix("/prior information/samples", priorSamples);
102  file->Close();
103 
104  auto graph = std::make_shared<WorkGraph>();
105  graph->AddNode(std::make_shared<IdentityOperator>(logConductivity->inputSizes(0)), "theta");
106  graph->AddNode(logConductivity, "log conductivity");
107  graph->AddEdge("theta", 0, "log conductivity", 0);
108 
109  graph->AddNode(std::make_shared<ExpOperator>(mesh.numCells), "conductivity");
110  graph->AddEdge("log conductivity", 0, "conductivity", 0);
111 
112  // define the forward model
113  Eigen::VectorXd recharge = GetRecharge(mesh);
114  auto forwardMod = std::make_shared<FlowEquation>(recharge);
115 
116  graph->AddNode(forwardMod, "forward model");
117  graph->AddEdge("conductivity", 0, "forward model", 0);
118 
119  graph->AddNode(InterpolateOntoObs(mesh, data.obsLoc), "observations");
120  graph->AddEdge("forward model", 0, "observations", 0);
121 
122  auto likelihood = std::make_shared<Gaussian>(data.obs, likelihoodVar*Eigen::VectorXd::Ones(data.obs.size()));
123  graph->AddNode(likelihood->AsDensity(), "likelihood");
124  graph->AddEdge("observations", 0, "likelihood", 0);
125 
126  graph->AddNode(prior->AsDensity(), "prior");
127  graph->AddEdge("theta", 0, "prior", 0);
128 
129  graph->AddNode(std::make_shared<DensityProduct>(2), "posterior");
130  graph->AddEdge("prior", 0, "posterior", 0);
131  graph->AddEdge("likelihood", 0, "posterior", 1);
132 
133  graph->Visualize("WorkGraph.pdf");
134 
135  return graph->CreateModPiece("posterior");
136 }
137 
138 std::vector<std::shared_ptr<ModPiece> > ConstructDensities(std::size_t const numLevels, std::size_t const baseRefinement) {
139  // generate the data
140  const std::size_t numObs = 25;
141  const double obsVar = 1.0e-4;
142  const Data data = GenerateData(baseRefinement*(numLevels+1), numObs, obsVar);
143 
144  const std::string filename = "output.h5";
145  auto file = std::make_shared<HDF5File>(filename);
146  file->WriteMatrix("/truth/x", data.x);
147  file->WriteMatrix("/truth/solution", data.soln);
148  file->WriteMatrix("/data/locations", data.obsLoc);
149  file->WriteMatrix("/data/observations", data.obs);
150  file->Close();
151 
152  std::vector<std::shared_ptr<ModPiece> > logDensities(numLevels);
153 
154  for( std::size_t i=0; i<numLevels; ++i ) {
155  logDensities[i] = ConstructDensity(baseRefinement*(i+1), data, obsVar);
156  }
157 
158  return logDensities;
159 }
Data GenerateData(std::size_t const numCells, std::size_t const numObs, double const obsVar)
std::shared_ptr< LinearOperator > InterpolateOntoObs(Discretization const &mesh, Eigen::VectorXd const &obsLoc)
Interpolate the model solution onto the observation points.
std::vector< std::shared_ptr< ModPiece > > ConstructDensities(std::size_t const numLevels, std::size_t const baseRefinement)
Eigen::VectorXd GetTrueLogConductivity(Discretization const &mesh)
std::shared_ptr< ModPiece > ConstructDensity(std::size_t const numCells, Data const &data, double const likelihoodVar)
Eigen::VectorXd GetRecharge(Discretization const &mesh)
Class for computing Gauss Quadrature rules from an orthogonal polynomial family.
virtual void Compute(unsigned int quadOrder) override
Used to compute and evaluate the Karhunen-Loeve decomposition of a zero mean Gaussian process....
virtual Eigen::MatrixXd GetModes(Eigen::Ref< const Eigen::MatrixXd > const &pts) const override
virtual Eigen::MatrixXd const & Points() const
Definition: Quadrature.h:161
virtual Eigen::VectorXd const & Weights() const
Definition: Quadrature.h:165
Data(Eigen::VectorXd const &x, Eigen::VectorXd const &soln, Eigen::VectorXd const &obsLoc, Eigen::VectorXd const &obs)
const Eigen::VectorXd soln
The true solution.
const Eigen::VectorXd obs
The observations.
const Eigen::VectorXd x
The locations where we have computed the true solution.
const Eigen::VectorXd obsLoc
The locations where we have made observations.