int main(){ // For all problems enum Problems{ODE,DAE,NUM_PROBLEMS}; for(int problem=0; problem<NUM_PROBLEMS; ++problem){ // Get problem FX ffcn; // Callback function vector<double> x0; // Initial value double u0; // Parameter value double tf; // End time switch(problem){ case ODE: cout << endl << "** Testing ODE example **" << endl; simpleODE(ffcn,tf,x0,u0); break; case DAE: cout << endl << "** Testing DAE example **" << endl; simpleDAE(ffcn,tf,x0,u0); break; } // For all integrators enum Integrators{CVODES,IDAS,COLLOCATION,NUM_INTEGRATORS}; for(int integrator=0; integrator<NUM_INTEGRATORS; ++integrator){ // Get integrator Integrator I; switch(integrator){ case CVODES: if(problem==DAE) continue; // Skip if DAE cout << endl << "== CVodesIntegrator == " << endl; I = CVodesIntegrator(ffcn); break; case IDAS: cout << endl << "== IdasIntegrator == " << endl; I = IdasIntegrator(ffcn); break; case COLLOCATION: cout << endl << "== CollocationIntegrator == " << endl; I = CollocationIntegrator(ffcn); // Set collocation integrator specific options I.setOption("expand_f",true); I.setOption("implicit_solver",KinsolSolver::creator); Dictionary kinsol_options; kinsol_options["linear_solver"] = CSparse::creator; I.setOption("implicit_solver_options",kinsol_options); break; } // Set common options I.setOption("tf",tf); // Initialize the integrator I.init(); // Integrate to get results I.setInput(x0,INTEGRATOR_X0); I.setInput(u0,INTEGRATOR_P); I.evaluate(); DMatrix xf = I.output(INTEGRATOR_XF); DMatrix qf = I.output(INTEGRATOR_QF); cout << setw(50) << "Unperturbed solution: " << "xf = " << xf << ", qf = " << qf << endl; // Perturb solution to get a finite difference approximation double h = 0.001; I.setInput(u0+h,INTEGRATOR_P); I.evaluate(); DMatrix xf_pert = I.output(INTEGRATOR_XF); DMatrix qf_pert = I.output(INTEGRATOR_QF); cout << setw(50) << "Finite difference approximation: " << "d(xf)/d(p) = " << (xf_pert-xf)/h << ", d(qf)/d(p) = " << (qf_pert-qf)/h << endl; // Operator overloading approach I.setInput(x0,INTEGRATOR_X0); I.setInput(u0,INTEGRATOR_P); I.setFwdSeed(0.,INTEGRATOR_X0); I.setFwdSeed(1.,INTEGRATOR_P); I.reset(1,0,0); I.integrate(tf); DMatrix oo_xf = I.fwdSens(INTEGRATOR_XF); DMatrix oo_qf = I.fwdSens(INTEGRATOR_QF); cout << setw(50) << "Forward sensitivities via OO: " << "d(xf)/d(p) = " << oo_xf << ", d(qf)/d(p) = " << oo_qf << endl; // Calculate once, forward FX I_fwd = I.derivative(1,0); I_fwd.setInput(x0,INTEGRATOR_X0); I_fwd.setInput(u0,INTEGRATOR_P); I_fwd.setInput(0.,INTEGRATOR_NUM_IN+INTEGRATOR_X0); I_fwd.setInput(1.,INTEGRATOR_NUM_IN+INTEGRATOR_P); I_fwd.evaluate(); DMatrix fwd_xf = I_fwd.output(INTEGRATOR_NUM_OUT+INTEGRATOR_XF); DMatrix fwd_qf = I_fwd.output(INTEGRATOR_NUM_OUT+INTEGRATOR_QF); cout << setw(50) << "Forward sensitivities: " << "d(xf)/d(p) = " << fwd_xf << ", d(qf)/d(p) = " << fwd_qf << endl; // Calculate once, adjoint FX I_adj = I.derivative(0,1); I_adj.setInput(x0,INTEGRATOR_X0); I_adj.setInput(u0,INTEGRATOR_P); I_adj.setInput(0.,INTEGRATOR_NUM_IN+INTEGRATOR_XF); I_adj.setInput(1.,INTEGRATOR_NUM_IN+INTEGRATOR_QF); I_adj.evaluate(); DMatrix adj_x0 = I_adj.output(INTEGRATOR_NUM_OUT+INTEGRATOR_X0); DMatrix adj_p = I_adj.output(INTEGRATOR_NUM_OUT+INTEGRATOR_P); cout << setw(50) << "Adjoint sensitivities: " << "d(qf)/d(x0) = " << adj_x0 << ", d(qf)/d(p) = " << adj_p << endl; // Perturb adjoint solution to get a finite difference approximation of the second order sensitivities I_adj.setInput(x0,INTEGRATOR_X0); I_adj.setInput(u0+h,INTEGRATOR_P); I_adj.setInput(0.,INTEGRATOR_NUM_IN+INTEGRATOR_XF); I_adj.setInput(1.,INTEGRATOR_NUM_IN+INTEGRATOR_QF); I_adj.evaluate(); DMatrix adj_x0_pert = I_adj.output(INTEGRATOR_NUM_OUT+INTEGRATOR_X0); DMatrix adj_p_pert = I_adj.output(INTEGRATOR_NUM_OUT+INTEGRATOR_P); cout << setw(50) << "FD of adjoint sensitivities: " << "d2(qf)/d(x0)d(p) = " << (adj_x0_pert-adj_x0)/h << ", d2(qf)/d(p)d(p) = " << (adj_p_pert-adj_p)/h << endl; // Forward over adjoint to get the second order sensitivities I_adj.setInput(x0,INTEGRATOR_X0); I_adj.setInput(u0,INTEGRATOR_P); I_adj.setFwdSeed(1.,INTEGRATOR_P); I_adj.setInput(0.,INTEGRATOR_NUM_IN+INTEGRATOR_XF); I_adj.setInput(1.,INTEGRATOR_NUM_IN+INTEGRATOR_QF); I_adj.evaluate(1,0); DMatrix fwd_adj_x0 = I_adj.fwdSens(INTEGRATOR_NUM_OUT+INTEGRATOR_X0); DMatrix fwd_adj_p = I_adj.fwdSens(INTEGRATOR_NUM_OUT+INTEGRATOR_P); cout << setw(50) << "Forward over adjoint sensitivities: " << "d2(qf)/d(x0)d(p) = " << fwd_adj_x0 << ", d2(qf)/d(p)d(p) = " << fwd_adj_p << endl; // Adjoint over adjoint to get the second order sensitivities I_adj.setInput(x0,INTEGRATOR_X0); I_adj.setInput(u0,INTEGRATOR_P); I_adj.setInput(0.,INTEGRATOR_NUM_IN+INTEGRATOR_XF); I_adj.setInput(1.,INTEGRATOR_NUM_IN+INTEGRATOR_QF); I_adj.setAdjSeed(1.,INTEGRATOR_NUM_OUT+INTEGRATOR_P); I_adj.evaluate(0,1); DMatrix adj_adj_x0 = I_adj.adjSens(INTEGRATOR_X0); DMatrix adj_adj_p = I_adj.adjSens(INTEGRATOR_P); cout << setw(50) << "Adjoint over adjoint sensitivities: " << "d2(qf)/d(x0)d(p) = " << adj_adj_x0 << ", d2(qf)/d(p)d(p) = " << adj_adj_p << endl; } } return 0; }
int main(){ // Time horizon double t0 = 0, tf = 10; // Bounds on the control double /*u_lb = -0.5, u_ub = 1.3,*/ u_init = 1; // Initial conditions vector<double> x0(3); x0[0] = 0; x0[1] = 0; x0[2] = 1; // Integrator Integrator integrator = create_Sundials(); // Attach user-defined linear solver if(user_defined_solver){ if(sparse_direct){ integrator.setOption("linear_solver_creator",CSparse::creator); // integrator.setOption("linear_solver_creator",SuperLU::creator); } else { integrator.setOption("linear_solver_creator",LapackLUDense::creator); integrator.setOption("linear_solver","user_defined"); } // integrator.setOption("linear_solver","user_defined"); // FIXME: bug for second order } // Set common integrator options integrator.setOption("fsens_err_con",true); integrator.setOption("quad_err_con",true); integrator.setOption("abstol",1e-12); integrator.setOption("reltol",1e-12); integrator.setOption("fsens_abstol",1e-6); integrator.setOption("fsens_reltol",1e-6); integrator.setOption("asens_abstol",1e-6); integrator.setOption("asens_reltol",1e-6); integrator.setOption("exact_jacobian",exact_jacobian); integrator.setOption("finite_difference_fsens",finite_difference_fsens); integrator.setOption("max_num_steps",100000); // integrator.setOption("max_multistep_order",4); integrator.setOption("t0",t0); integrator.setOption("tf",tf); // Initialize the integrator integrator.init(); // Set parameters integrator.setInput(u_init,INTEGRATOR_P); // Set inital state integrator.setInput(x0,INTEGRATOR_X0); // Integrate integrator.evaluate(); // Save the result Matrix<double> res0_xf = integrator.output(INTEGRATOR_XF); Matrix<double> res0_qf = integrator.output(INTEGRATOR_QF); // Perturb in some direction if(perturb_u){ double u_pert = u_init + 0.01; integrator.setInput(u_pert,INTEGRATOR_P); } else { vector<double> x_pert = x0; x_pert[1] += 0.01; integrator.setInput(x_pert,INTEGRATOR_X0); } // Integrate again integrator.evaluate(); // Print statistics integrator.printStats(); // Calculate finite difference approximation Matrix<double> fd_xf = (integrator.output(INTEGRATOR_XF) - res0_xf)/0.01; Matrix<double> fd_qf = (integrator.output(INTEGRATOR_QF) - res0_qf)/0.01; cout << "unperturbed " << res0_xf << "; " << res0_qf << endl; cout << "perturbed " << integrator.output(INTEGRATOR_XF) << "; " << integrator.output(INTEGRATOR_QF) << endl; cout << "finite_difference approximation " << fd_xf << "; " << fd_qf << endl; if(perturb_u){ integrator.setFwdSeed(1.0,INTEGRATOR_P); } else { vector<double> x0_seed(x0.size(),0); x0_seed[1] = 1; integrator.setFwdSeed(x0_seed,INTEGRATOR_X0); } // Reset parameters integrator.setInput(u_init,INTEGRATOR_P); // Reset initial state integrator.setInput(x0,INTEGRATOR_X0); if(with_asens){ // backward seeds vector<double> &bseed = integrator.adjSeed(INTEGRATOR_XF).data(); fill(bseed.begin(),bseed.end(),0); bseed[1] = 1; // evaluate with forward and adjoint sensitivities integrator.evaluate(1,1); } else { // evaluate with only forward sensitivities integrator.evaluate(1,0); } Matrix<double> fsens_xf = integrator.fwdSens(INTEGRATOR_XF); Matrix<double> fsens_qf = integrator.fwdSens(INTEGRATOR_QF); cout << "forward sensitivities " << fsens_xf << "; " << fsens_qf << endl; if(with_asens){ cout << "adjoint sensitivities "; cout << integrator.adjSens(INTEGRATOR_X0) << "; "; cout << integrator.adjSens(INTEGRATOR_P) << "; "; cout << endl; } if(second_order){ // Preturb the forward seeds if(perturb_u){ double u_seed = 1.001; integrator.setFwdSeed(u_seed,INTEGRATOR_P); } else { vector<double> x0_seed(x0.size(),0); x0_seed[1] = 1.001; integrator.setFwdSeed(x0_seed,INTEGRATOR_X0); } // evaluate again with forward sensitivities integrator.evaluate(1,0); vector<double> fsens_pret_xf = integrator.fwdSens(INTEGRATOR_XF).data(); vector<double> fsens_pret_qf = integrator.fwdSens(INTEGRATOR_QF).data(); cout << "forward sensitivities preturbed " << fsens_pret_xf << "; " << fsens_pret_qf << endl; vector<double> fd2_xf(fsens_xf.size()); vector<double> fd2_qf(fsens_qf.size()); for(int i=0; i<fd2_xf.size(); ++i) fd2_xf[i] = (fsens_pret_xf.at(i)-fsens_xf.at(i))/0.001; for(int i=0; i<fd2_qf.size(); ++i) fd2_qf[i] = (fsens_pret_qf.at(i)-fsens_qf.at(i))/0.001; cout << "finite differences, 2nd order " << fd2_xf << "; " << fd2_qf << endl; // Generate the jacobian by creating a new integrator for the sensitivity equations by source transformation FX intjac = integrator.jacobian(INTEGRATOR_P,INTEGRATOR_XF); // Set options intjac.setOption("number_of_fwd_dir",0); intjac.setOption("number_of_adj_dir",1); // Initialize the integrator intjac.init(); // Set inputs intjac.setInput(u_init,INTEGRATOR_P); intjac.setInput(x0,INTEGRATOR_X0); // Set adjoint seed vector<double> jacseed(3*1,0); jacseed[0] = 1; intjac.setAdjSeed(jacseed); // Evaluate the Jacobian intjac.evaluate(0,0); cout << "jacobian " << intjac.output(0) << endl; // Get the results /* cout << "unperturbed via jacobian " << intjac.output(1+INTEGRATOR_XF) << endl;*/ cout << "second order (fwd-over-adj) " ; cout << intjac.adjSens(INTEGRATOR_X0) << ", "; cout << intjac.adjSens(INTEGRATOR_P) << endl; // Save the unpreturbed value Matrix<double> unpret = intjac.output(); // Perturb X0 intjac.setInput(u_init+0.01,INTEGRATOR_P); intjac.evaluate(); Matrix<double> pret = intjac.output(); cout << "unperturbed fwd sens " << unpret << endl; cout << "perturbed fwd sens " << pret << endl; cout << "finite diff. (augmented dae) " << (pret-unpret)/0.01 << endl; } return 0; }