293 #include <boost/property_tree/ptree.hpp>
297 #include <Eigen/Core>
298 #include <Eigen/Sparse>
299 #include <Eigen/SparseCholesky>
331 FlowEquation(Eigen::VectorXd
const& sourceTerm) :
muq::Modeling::
ModPiece({int(sourceTerm.size())},
332 {int(sourceTerm.size()+1)})
334 numCells = sourceTerm.size();
335 numNodes = sourceTerm.size()+1;
337 xs = Eigen::VectorXd::LinSpaced(numNodes,0,1);
340 rhs = BuildRhs(sourceTerm);
356 auto& cond = inputs.at(0).get();
359 auto K = BuildStiffness(cond);
362 Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver;
366 outputs.at(0) = solver.solve(rhs);
400 Eigen::VectorXd
const& sens)
override
403 auto& cond = inputs.at(0).get();
406 auto A = BuildStiffness(cond);
409 Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver;
413 Eigen::VectorXd sol = solver.solve(rhs);
416 Eigen::VectorXd adjRhs = BuildAdjointRHS(sens);
417 Eigen::VectorXd adjSol = solver.solve(adjRhs);
420 gradient = (1.0/dx)*(sol.tail(numCells)-sol.head(numCells)).
array() * (adjSol.tail(numCells) - adjSol.head(numCells)).
array();
454 Eigen::VectorXd
const& vec)
override
457 auto& cond = inputs.at(0).get();
460 auto A = BuildStiffness(cond);
463 Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver;
467 Eigen::VectorXd sol = solver.solve(rhs);
470 Eigen::VectorXd incrRhs = Eigen::VectorXd::Zero(numNodes);
472 Eigen::VectorXd dh_dx = (sol.tail(numCells)-sol.head(numCells))/dx;
474 incrRhs.head(numCells) += ( vec.array()*dh_dx.array() ).matrix();
475 incrRhs.tail(numCells) -= ( vec.array()*dh_dx.array() ).matrix();
523 Eigen::VectorXd
const& sens,
524 Eigen::VectorXd
const& vec)
override
527 auto& cond = inputs.at(0).get();
530 auto K = BuildStiffness(cond);
533 Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver;
537 Eigen::VectorXd sol = solver.solve(rhs);
540 if((inWrt1==0)&&(inWrt2==0)){
543 Eigen::VectorXd adjRhs = BuildAdjointRHS(sens);
544 Eigen::VectorXd adjSol = solver.solve(adjRhs);
547 Eigen::VectorXd incrForRhs = BuildIncrementalRhs(sol, vec);
548 Eigen::VectorXd incrForSol = solver.solve(incrForRhs);
551 Eigen::VectorXd incrAdjRhs = BuildIncrementalRhs(adjSol, vec);
552 Eigen::VectorXd incrAdjSol = solver.solve(incrAdjRhs);
555 auto solDeriv = (sol.tail(numCells)-sol.head(numCells))/dx;
556 auto adjDeriv = (adjSol.tail(numCells)-adjSol.head(numCells))/dx;
557 auto incrForDeriv = (incrForSol.tail(numCells) - incrForSol.head(numCells))/dx;
558 auto incrAdjDeriv = (incrAdjSol.tail(numCells) - incrAdjSol.head(numCells))/dx;
560 hessAction = -(incrAdjDeriv.array() * solDeriv.array() + incrForDeriv.array() * adjDeriv.array());
563 }
else if((inWrt1==0)&&(inWrt2==1)){
565 Eigen::VectorXd temp = solver.solve(vec);
566 auto solDeriv = (sol.tail(numCells) - sol.head(numCells))/dx;
567 auto tempDeriv = (temp.tail(numCells)-temp.head(numCells))/dx;
569 hessAction = -dx * solDeriv.array() * tempDeriv.array();
578 Eigen::VectorXd BuildRhs(Eigen::VectorXd
const& sourceTerm)
const
580 Eigen::VectorXd rhs = Eigen::VectorXd::Zero(numNodes);
582 rhs.segment(1,numNodes-2) = 0.5*dx*(sourceTerm.tail(numNodes-2) + sourceTerm.head(numNodes-2));
583 rhs(numNodes-1) = 0.5*dx*sourceTerm(numNodes-2);
589 Eigen::VectorXd BuildAdjointRHS(Eigen::VectorXd
const& sensitivity)
const
591 Eigen::VectorXd rhs = -1.0*sensitivity;
597 Eigen::VectorXd BuildIncrementalRhs(Eigen::VectorXd
const& sol, Eigen::VectorXd
const& khat)
600 Eigen::VectorXd solGrad = (sol.tail(numCells)-sol.head(numCells))/dx;
601 Eigen::VectorXd rhs = Eigen::VectorXd::Zero(numNodes);
603 unsigned int leftNode, rightNode;
604 for(
unsigned int cellInd=0; cellInd<numCells; ++cellInd)
607 rightNode = cellInd + 1;
609 rhs(leftNode) -= dx*khat(cellInd)*solGrad(cellInd);
610 rhs(rightNode) += dx*khat(cellInd)*solGrad(cellInd);
618 Eigen::SparseMatrix<double> BuildStiffness(Eigen::VectorXd
const& condVals)
const{
620 typedef Eigen::Triplet<double> T;
621 std::vector<T> nzVals;
624 nzVals.push_back( T(0,0,1e10) );
626 unsigned int leftNode, rightNode;
627 for(
unsigned int cellInd=0; cellInd<numCells; ++cellInd)
630 rightNode = cellInd+1;
632 nzVals.push_back( T(leftNode, rightNode, -condVals(cellInd)/dx) );
633 nzVals.push_back( T(rightNode, leftNode, -condVals(cellInd)/dx) );
634 nzVals.push_back( T(rightNode, rightNode, condVals(cellInd)/dx) );
635 nzVals.push_back( T(leftNode, leftNode, condVals(cellInd)/dx) );
638 Eigen::SparseMatrix<double> stiffMat(numNodes,numNodes);
639 stiffMat.setFromTriplets(nzVals.begin(), nzVals.end());
650 unsigned int numCells;
651 unsigned int numNodes;
669 unsigned int numCells = 200;
672 Eigen::VectorXd nodeLocs = Eigen::VectorXd::LinSpaced(numCells+1,0,1);
675 Eigen::VectorXd cellLocs = 0.5*(nodeLocs.head(numCells) + nodeLocs.tail(numCells));
678 Eigen::VectorXd recharge = Eigen::VectorXd::Ones(numCells);
681 auto mod = std::make_shared<FlowEquation>(recharge);
692 Eigen::VectorXd cond = (20.0*cellLocs.array()).cos().exp();
694 Eigen::VectorXd h = mod->Evaluate(cond).at(0);
696 std::cout <<
"Solution: \n" << h.transpose() << std::endl << std::endl;
711 auto objective = std::make_shared<Gaussian>(numCells+1)->AsDensity();
723 Eigen::VectorXd objSens = Eigen::VectorXd::Ones(1);
724 Eigen::VectorXd sens = objective->Gradient(0,0,h,objSens);
725 Eigen::VectorXd grad = mod->Gradient(0,0,cond,sens);
727 std::cout <<
"Gradient: \n" << grad.transpose() << std::endl << std::endl;
734 Eigen::VectorXd gradFD = mod->GradientByFD(0,0,std::vector<Eigen::VectorXd>{cond},sens);
735 std::cout <<
"Finite Difference Gradient:\n" << gradFD.transpose() << std::endl << std::endl;
741 Eigen::VectorXd jacDir = RandomGenerator::GetUniform(numCells);
743 Eigen::VectorXd jacAct = mod->ApplyJacobian(0,0, cond, jacDir);
744 std::cout <<
"Jacobian Action: \n" << jacAct.transpose() << std::endl << std::endl;
746 Eigen::VectorXd jacActFD = mod->ApplyJacobianByFD(0,0, std::vector<Eigen::VectorXd>{cond}, jacDir);
747 std::cout <<
"Finite Difference Jacobian Action \n" << jacActFD.transpose() << std::endl << std::endl;
754 Eigen::VectorXd hessDir = RandomGenerator::GetUniform(numCells);
756 Eigen::VectorXd hessAct = mod->ApplyHessian(0,0,0,cond,sens,hessDir);
757 std::cout <<
"Hessian Action: \n" << hessAct.transpose() << std::endl << std::endl;
759 Eigen::VectorXd hessActFD = mod->ApplyHessianByFD(0,0,0,std::vector<Eigen::VectorXd>{cond},sens,hessDir);
760 std::cout <<
"Finite Difference Hessian Action \n" << hessActFD.transpose() << std::endl << std::endl;
773 graph.
AddNode(objective,
"Objective");
774 graph.
AddEdge(
"Model",0,
"Objective",0);
785 hessAct = fullMod->ApplyHessian(0,0,0,cond,objSens,hessDir);
786 hessActFD = fullMod->ApplyHessianByFD(0,0,0,std::vector<Eigen::VectorXd>{cond},objSens,hessDir);
788 std::cout <<
"Hessian Action: \n" << hessAct.transpose() << std::endl << std::endl;
789 std::cout <<
"Finite Difference Hessian Action \n" << hessActFD.transpose() << std::endl << std::endl;
808 unsigned int outWrt = 0;
809 unsigned int inWrt1 = 0;
810 unsigned int inWrt2 = 0;
812 double scaling = -1.0;
813 std::vector<Eigen::VectorXd> inputs(1);
815 auto hessOp = std::make_shared<HessianOperator>(fullMod, inputs, outWrt, inWrt1, inWrt2, objSens, scaling);
822 boost::property_tree::ptree opts;
823 opts.put(
"NumEigs", numCells);
824 opts.put(
"Verbosity", 3);
841 std::cout <<
"Eigenvalues:\n" << vals.transpose() << std::endl << std::endl;
Eigen::VectorXd const & eigenvalues() const
Eigen::MatrixXd const & eigenvectors() const
Provides an abstract interface for defining vector-valued model components.
virtual void GradientImpl(unsigned int const outputDimWrt, unsigned int const inputDimWrt, ref_vector< Eigen::VectorXd > const &input, Eigen::VectorXd const &sensitivity)
virtual void ApplyJacobianImpl(unsigned int const outputDimWrt, unsigned int const inputDimWrt, ref_vector< Eigen::VectorXd > const &input, Eigen::VectorXd const &vec)
std::vector< Eigen::VectorXd > outputs
ModPiece(std::vector< int > const &inputSizes, std::vector< int > const &outputSizes)
virtual void EvaluateImpl(ref_vector< boost::any > const &inputs) override
User-implemented function that determines the behavior of this muq::Modeling::WorkPiece.
Eigen::VectorXd hessAction
Eigen::VectorXd jacobianAction
virtual void ApplyHessianImpl(unsigned int const outWrt, unsigned int const inWrt1, unsigned int const inWrt2, ref_vector< Eigen::VectorXd > const &input, Eigen::VectorXd const &sens, Eigen::VectorXd const &vec)
Two-pass stochastic algorithm for computing generalized eigenvalues from matrix products.
virtual StochasticEigenSolver & compute(std::shared_ptr< LinearOperator > const &A, std::shared_ptr< LinearOperator > B=nullptr, std::shared_ptr< LinearOperator > Binv=nullptr)
A graph of connected muq::Modeling::WorkPiece's.
void AddNode(std::shared_ptr< WorkPiece > input, std::string const &name)
Add a new node to the graph.
void AddEdge(std::string const &nameFrom, unsigned int const outputDim, std::string const &nameTo, unsigned int const inputDim)
Add a new edge to the graph.
std::shared_ptr< ModGraphPiece > CreateModPiece(std::string const &node, std::vector< std::string > const &inNames=std::vector< std::string >()) const
Create a muq::Modeling::ModPiece whose output matches a given node.
std::vector< std::reference_wrapper< const T > > ref_vector
A vector of references to something ...
@ array
array (ordered collection of values)