#include "TSOp.hh" #include "gtest/gtest.h" #include "rnmat.hh" #include "adjtest.hh" #include "functions.hh" //#define VERBOSE #define ATOL 1.e-5 namespace { void FwdEuler(RVL::LinearOp const & A, RVL::Vector const & x0, RVL::Vector & x, float dt, float tmin, float tmax) { float t = tmin; x.copy(x0); // // cerr<<"FwdEuler initial state norm = "< t="< const & A, RVL::Vector const & x0, RVL::Vector & x, float dt, float tmin, float tmax) { float t = tmax; x.copy(x0); // cerr<<"FwdEuler initial state norm = "< tmin) { // x = (I + dt * A^T) x // cerr<<"FwdEuler t="< t="< & A; mutable RVL::RnArray z; mutable RVL::RVLLinCombObject lco; public: Aapply0(RVL::GenMat & _A, float _dt) : A(_A), z(A.getNCols()), lco(_dt,1.0) { // cerr<<"Aapply0 dt="<<_dt< Aapply0 eval factor \n"; if ((y.getSize() != 2)) { // cerr<<" error\n"; RVL::RVLException e; e<<"Error: Aapply0::operator()\n"; e<<" takes only (control, state) pairs, size=2 \n"; e<<" output vector y:\n"; RVL::Writeable const & yw = dynamic_cast(y); yw.write(e); throw e; } A.getMatVec().setAdj(false); RVL::ProductDataContainer & pdcy = dynamic_cast(y[1]); RVL::RnArray & rnout = dynamic_cast &>(pdcy[0]); // cerr<<" --> MatVec\n"; A.getMatVec()(z,rnout); lco(rnout,z); // cerr<<" exit\n"; } catch (bad_cast) { // cerr<<" Aapply0 bad cast\n"; RVL::RVLException e; e<<"Error: Aapply0::operator()\n"; e<<" TSDC y does not enclose RnArray \n"; throw e; } catch (RVL::RVLException & e) { e<<"\ncalled from Aapply0::operator()\n"; throw e; } } std::string getName() const { std::string x = "Aapply0\n"; return x; } }; class AapplyAdj0: public RVL::TSFO { private: RVL::GenMat & A; mutable RVL::RnArray z; mutable RVL::RVLLinCombObject lco; public: AapplyAdj0(RVL::GenMat & _A, float _dt) : A(_A), z(A.getNRows()), lco(_dt,1.0) {} void operator()(RVL::TSDC & y) const { try { if ((y.getSize() != 2)) { RVL::RVLException e; e<<"Error: AapplyAdj0::operator()\n"; e<<" takes only (control, state) pairs, size=2 \n"; e<<" output vector y:\n"; RVL::Writeable const & yw = dynamic_cast(y); yw.write(e); throw e; } A.getMatVec().setAdj(true); RVL::ProductDataContainer & pdcy = dynamic_cast(y[1]); RVL::RnArray & rnout = dynamic_cast &>(pdcy[0]); A.getMatVec()(z,rnout); lco(rnout,z); } catch (bad_cast) { RVL::RVLException e; e<<"Error: AapplyAdj0::operator()\n"; e<<" TSDC does not enclose RnArray\n"; throw e; } catch (RVL::RVLException & e) { e<<"\ncalled from AapplyAdj0::operator()\n"; throw e; } } std::string getName() const { std::string x = "AapplyAdj0\n"; return x; } }; // these two FOs should be set up to take tangent vectors, // i.e. pairs of (control,space) pairs class AapplyFwd1: public RVL::TSFO { public: void operator()(RVL::TSDC & y) const {} std::string getName() const { std::string x = "AapplyFwd1\n"; return x; } }; class AapplyAdj1: public RVL::TSFO { void operator()(RVL::TSDC & y) const {} std::string getName() const { std::string x = "AapplyAdj1\n"; return x; } }; class ArandAccess: public RVL::TSRAFO { void operator()(RVL::TSDC & y) const {} std::string getName() const { std::string x = "ArandAccess\n"; return x; } }; class AStep: public RVL::TSStep { private: RVL::GenMat & A; mutable Aapply0 fwd0; mutable AapplyAdj0 adj0; mutable AapplyFwd1 fwd1; mutable AapplyAdj1 adj1; mutable ArandAccess ar0; float dt; RVL::TSSpace ctrlsp; RVL::TSSpace statesp; RVL::TSSpace pdom; RVL::TSFO & applyFO() const { // cerr<<" AStep:: return applyFO\n"; return fwd0; } RVL::TSFO & applyAdjFO() const { return adj0; } RVL::TSFO & applyTangentFO() const { return fwd1; } RVL::TSFO & applyAdjTangentFO() const { return adj1; } RVL::TSRAFO & randAccessFO() const { return ar0; } protected: void stepTimeFwd() const { TSClock::stepTime(+dt); } void stepTimeBwd() const { TSClock::stepTime(-dt); } RVL::Operator * clone() const { return new AStep(*this); } public: AStep(RVL::GenMat & _A, float _t, float _dt) : A(_A), fwd0(_A,_dt), adj0(_A,_dt), dt(_dt), ctrlsp(1), statesp(1), pdom(2) { ctrlsp.set(A.getDomain(),0); statesp.set(A.getDomain(),0); // cerr<<"in AStep constructor: ctrlsp\n"; // ctrlsp.write(cerr); pdom.set(ctrlsp,0); pdom.set(statesp,1); // cerr<<"in AStep constructor: pdom\n"; // pdom.write(cerr); this->setTime(_t); } AStep(AStep const & s) : A(s.A), fwd0(A,s.dt), adj0(A,s.dt), dt(s.dt), ctrlsp(1), statesp(1), pdom(2) { ctrlsp.set(A.getDomain(),0); statesp.set(A.getDomain(),0); pdom.set(ctrlsp,0); pdom.set(statesp,1); this->setTime(s.getTime()); } RVL::TSSpace const & getTSDomain() const { return pdom; } RVL::Space const & getDomain() const { return getTSDomain(); } RVL::Space const & getRange() const { return pdom; } ostream & write(ostream & str) const { str<<"GenMat linear time step, \n"; str<<" t = "<getTime()<<" dt = "<getDomain().write(str); return str; } }; /* class ASample: public RVL::TSSample { private: RVL::GenMat & A; RVL::TSSpace statesp; protected: void apply(RVL::Vector const & x, RVL::Vector & y) const { if (start && (abs(this->getTime() - this->getMinTime()) < ATOL*(this->getMaxTime() - this->getMinTime()))) { Components cx(x); Components cy(y); A.applyOp(cx[0],cy[0]); } if (!start && (abs(this->getTime() - this->getMaxTime()) < ATOL*(this->getMaxTime() - this->getMinTime()))) { A.applyOp(cx[0],cy[0]); } } void applyAdj(RVL::Vector const & x, RVL::Vector & y) const { if (start && (abs(this->getTime() - this->getMinTime()) < ATOL*(this->getMaxTime() - this->getMinTime()))) { // cerr<<"ACopy::apply - start="<getTime() - this->getMaxTime()) < ATOL*(this->getMaxTime() - this->getMinTime()))) { // cerr<<"ACopy::apply - start="< * clone() const { return new ASample(*this); } public: ASample(RVL::GenMat & _A, float _t) : A(_A), statesp(1) { statesp.set(A.getDomain(),0); this->setTime(_t); } ASample(ASample const & s) : A(s.A), statesp(1) { statesp.set(A.getDomain(),0); this->setTime(s.getTime()); } RVL::Space const & getDomain() const { return statesp; } RVL::Space const & getRange() const { return statesp; } ostream & write(ostream & str) const { str<<"GenMat snapshot sample \n"; str<<" t = "<getTime()<<" dt = "<getProductDomain().write(str); return str; } }; */ class ACopy: public RVL::TSSample { private: RVL::Space const & dom; bool start; protected: void apply(RVL::Vector const & x, RVL::Vector & y) const { if (start && (abs(this->getTime() - this->getMinTime()) < ATOL*(this->getMaxTime() - this->getMinTime()))) { // cerr<<"ACopy::apply - start="<getTime() - this->getMaxTime()) < ATOL*(this->getMaxTime() - this->getMinTime()))) { // cerr<<"ACopy::apply - start="< const & x, RVL::Vector & y) const { if (start && (abs(this->getTime() - this->getMinTime()) < ATOL*(this->getMaxTime() - this->getMinTime()))) { // cerr<<"ACopy::apply - start="<getTime() - this->getMaxTime()) < ATOL*(this->getMaxTime() - this->getMinTime()))) { // cerr<<"ACopy::apply - start="< * clone() const { return new ACopy(*this); } public: ACopy(RVL::Space const & _dom, bool _start, float _t=RVL::ScalarFieldTraits::Zero(), float _tmin=RVL::ScalarFieldTraits::Zero(), float _tmax=RVL::ScalarFieldTraits::Zero()) : dom(_dom), start(_start) { this->setTime(_t); this->setMinTime(_tmin); this->setMaxTime(_tmax); } ACopy(ACopy const & a): dom(a.dom), start(a.start) { this->setTime(a.getTime()); this->setMinTime(a.getMinTime()); this->setMaxTime(a.getMaxTime()); } RVL::Space const & getDomain() const { return dom; } RVL::Space const & getRange() const { return dom; } void setTestTime() { if (start) this->setTime(this->getMinTime()); else this->setTime(this->getMaxTime()); } ostream & write(ostream & str) const { str<<"ACopy Time Sample Sampler\n"; str<<" time = "<getTime()<<"\n"; str<<" min time = "<getMinTime()<<"\n"; str<<" max time = "<getMaxTime()<<"\n"; if (start) str<<" copy at min time\n"; else str<<" copy at max time\n"; str<<" domain = \n"; dom.write(str); } }; /** assumes multiple components, each of which is a product itself */ template void copySubComponent(RVL::Vector const & x, RVL::Vector & v, int i, int j) { try { RVL::Components cv(v); RVL::Components ccv(cv[i]); ccv[j].copy(x); } catch (RVL::RVLException & e) { e<<"\ncalled from copySubComponent\n"; throw e; } } class TSOpTest : public ::testing::Test { protected: int n; float tmax; float tmin; float dt; RVL::RnSpace dom; RVL::GenMat A; AStep stp; RVL::Vector x0; RVL::Vector x0b; TSOpTest() :n(10), tmin(0.0), tmax(1.0), dt(0.01), dom(n), A(dom,dom), stp(A,tmin,dt), x0(dom), x0b(dom) { RVL::RVLRandomize rnd(getpid(),-1.0,1.0); A.eval(rnd); x0.eval(rnd); x0b.eval(rnd); } TSOpTest(TSOpTest const & tt) :n(tt.n), tmin(tt.tmin), tmax(tt.tmax), dt(tt.dt), A(tt.A), stp(tt.stp), x0(tt.x0), x0b(tt.x0b) {} }; /* TEST_F(TSOpTest, explicit_adjoint) { RVL::Vector x1(dom); x1.zero(); RVL::Vector x2(dom); x2.zero(); FwdEuler(A,x0,x1,dt,tmin,tmax); BwdEuler(A,x0b,x2,dt,tmin,tmax); float ipdom = (x0.inner(x2))/(x0.norm() * x0b.norm()); float iprng = (x1.inner(x0b))/(x0.norm() * x0b.norm()); EXPECT_LT(abs(ipdom-iprng),ATOL); } */ TEST_F(TSOpTest, onestep_value_test_matrix_fwd) { // cerr<<">>>> onestep_value_test_matrix_fwd\n"; // cerr<<"\n state vec construct\n"; RVL::Vector x1(dom); // cerr<<"\n state vec zero\n"; x1.zero(); // cerr<<"\n fwd euler\n"; FwdEuler(A,x0,x1,dt,0.0f,dt); // cerr<<"\n step dom vec construct\n"; RVL::Vector cs(stp.getTSDomain()); // cerr<<"\n step dom vec components\n"; copySubComponent(x0,cs,0,0); copySubComponent(x0,cs,1,0); // cerr<<"\n opeval\n"; RVL::OperatorEvaluation stpeval(stp,cs); // cerr<<"\n evaluate, components of output\n"; RVL::Components out(stpeval.getValue()); // cerr<<"\n components of components\n"; RVL::Components xout(out[1]); // cerr<<"\n linComb\n"; xout[0].linComb(-1.0,x1); EXPECT_LT(xout[0].norm()/x1.norm(),1.e-5); } TEST_F(TSOpTest, final_value_test_matrix_fwd) { RVL::Vector x1(dom); x1.zero(); RVL::Vector tsx2((stp.getTSDomain())[1]); tsx2.zero(); FwdEuler(A,x0,x1,dt,tmin,tmax); RVL::Vector cs(stp.getTSDomain()); copySubComponent(x0,cs,0,0); copySubComponent(x0,cs,1,0); ACopy src((stp.getTSDomain())[1],true,tmin,tmin,tmax); ACopy data((stp.getTSDomain())[1],false,tmin,tmin,tmax); RVL::Components ccs(cs); RVL::TimeStepOp op(stp,src,data); RVL::LinearRestrictOp lop(op,ccs[0]); lop.applyOp(ccs[1],tsx2); RVL::Components ctsx2(tsx2); ctsx2[0].linComb(-1.0,x1); EXPECT_LT(ctsx2[0].norm()/x1.norm(),1.e-5); } TEST_F(TSOpTest, final_value_test_matrix_bwd) { RVL::Vector x1(dom); x1.zero(); RVL::Vector tsx2((stp.getTSDomain())[1]); tsx2.zero(); BwdEuler(A,x0,x1,dt,tmin,tmax); RVL::Vector cs(stp.getTSDomain()); copySubComponent(x0,cs,0,0); copySubComponent(x0,cs,1,0); ACopy src((stp.getTSDomain())[1],true,tmin,tmin,tmax); ACopy data((stp.getTSDomain())[1],false,tmin,tmin,tmax); RVL::Components ccs(cs); RVL::TimeStepOp op(stp,src,data); RVL::LinearRestrictOp lop(op,ccs[0]); lop.applyAdjOp(ccs[1],tsx2); RVL::Components ctsx2(tsx2); ctsx2[0].linComb(-1.0,x1); EXPECT_LT(ctsx2[0].norm()/x1.norm(),1.e-5); } TEST_F(TSOpTest, src_adjoint) { ACopy src((stp.getTSDomain())[1],true,tmin,tmin,tmax); src.setTestTime(); RVL::RVLRandomize rnd(getpid(),-1.0,1.0); std::stringstream jnk; EXPECT_EQ(1,RVL::AdjointTest(src,rnd,jnk)); } TEST_F(TSOpTest, data_adjoint) { ACopy data((stp.getTSDomain())[1],true,tmin,tmin,tmax); data.setTestTime(); RVL::RVLRandomize rnd(getpid(),-1.0,1.0); std::stringstream jnk; EXPECT_EQ(1,RVL::AdjointTest(data,rnd,jnk)); } TEST_F(TSOpTest, step_adjoint_order0) { RVL::Vector cs(stp.getTSDomain()); copySubComponent(x0,cs,0,0); RVL::Components ccs(cs); RVL::LinRestrictTSStep lop(stp,ccs[0]); RVL::RVLRandomize rnd(getpid(),-1.0,1.0); std::stringstream jnk; bool res = RVL::AdjointTest(lop,rnd,jnk); EXPECT_EQ(1,res); } TEST_F(TSOpTest, timestep_src_adjoint) { ACopy src((stp.getTSDomain())[1],true,tmin,tmin,tmax); ACopy data((stp.getTSDomain())[1],false,tmin,tmin,tmax); RVL::TimeStepOp op(stp,src,data,true); EXPECT_EQ(1,op.testSrcAdj()); } TEST_F(TSOpTest, timestep_data_adjoint) { ACopy src((stp.getTSDomain())[1],true,tmin,tmin,tmax); ACopy data((stp.getTSDomain())[1],false,tmin,tmin,tmax); RVL::TimeStepOp op(stp,src,data,true); EXPECT_EQ(1,op.testDataAdj()); } TEST_F(TSOpTest, timestep_adjoint_order0) { RVL::Vector cs(stp.getTSDomain()); copySubComponent(x0,cs,0,0); RVL::Components ccs(cs); ACopy src((stp.getTSDomain())[1],true,tmin,tmin,tmax); ACopy data((stp.getTSDomain())[1],false,tmin,tmin,tmax); RVL::TimeStepOp op(stp,src,data,true); EXPECT_EQ(1,op.testStepAdj0(ccs[0])); } TEST_F(TSOpTest, timestep_test_all) { RVL::Vector cs(stp.getTSDomain()); copySubComponent(x0,cs,0,0); RVL::Components ccs(cs); ACopy src((stp.getTSDomain())[1],true,tmin,tmin,tmax); ACopy data((stp.getTSDomain())[1],false,tmin,tmin,tmax); RVL::TimeStepOp op(stp,src,data,true); EXPECT_EQ(1,op.testAll(ccs[0])); } TEST_F(TSOpTest, timestep_test_adjoint) { RVL::Vector cs(stp.getTSDomain()); copySubComponent(x0,cs,0,0); RVL::Components ccs(cs); ACopy src((stp.getTSDomain())[1],true,tmin,tmin,tmax); ACopy data((stp.getTSDomain())[1],false,tmin,tmin,tmax); RVL::TimeStepOp op(stp,src,data,true); RVL::LinearRestrictOp lop(op,ccs[0]); RVL::RVLRandomize rnd(getpid(),-1.0f,1.0f); std::stringstream jnk; EXPECT_EQ(1,RVL::AdjointTest(lop,rnd,jnk)); } } // namespace