//-----------------------------------------------------------------------------------------------
// Calculates the derivatives of the objective
//-----------------------------------------------------------------------------------------------
bool BonminInterfaceGradients::eval_grad_f(Index n, const Number* x, bool new_x, Number* grad_f)
{
    // running model if needed
    update(n, x);


    // ---- copying the gradients from the case to grad_f ----
    // checking that gradients for all variables are available
    Derivative *df = p_case_last->objectiveDerivative();

    if(df->numberOfPartials() == n)
    {
        for(int i = 0; i < n; ++i)
        {
            grad_f[i] = df->value(i);
        }

    }
    else
    {
        cout << endl << "### BONMIN Error! ###" << endl
             << "Number of df/dx in case does not match problem size..." << endl;

        exit(1);
    }


    return true;
}
Example #2
0
void QRSDetection::transform_enter (ssi_stream_t &stream_in,
	ssi_stream_t &stream_out,
	ssi_size_t xtra_stream_in_num,
	ssi_stream_t xtra_stream_in[]) {

	//bandpass
	Butfilt *bandpass = ssi_pcast (Butfilt, Factory::Create (Butfilt::GetCreateName (), 0, false));
	bandpass->getOptions()->type = Butfilt::BAND;
	bandpass->getOptions()->norm = false;
	bandpass->getOptions()->high = 15;
	bandpass->getOptions()->low = 5;
	bandpass->getOptions()->order = 13;
	_bandpass = bandpass;
	ssi_stream_init (_bandpass_stream, 0, _bandpass->getSampleDimensionOut (stream_in.dim), _bandpass->getSampleBytesOut (stream_in.byte), _bandpass->getSampleTypeOut (stream_in.type), stream_in.sr);
	_bandpass->transform_enter (stream_in, _bandpass_stream);

	//diff
	Derivative *diff = ssi_pcast(Derivative, Factory::Create (Derivative::GetCreateName (), 0, false));
	ssi_strcpy (diff->getOptions()->names, "1st");
	_diff = diff;
	ssi_stream_init (_diff_stream, 0, _diff->getSampleDimensionOut (_bandpass_stream.dim), _diff->getSampleBytesOut (_bandpass_stream.byte), _diff->getSampleTypeOut (_bandpass_stream.type), _bandpass_stream.sr);
	_diff->transform_enter (_bandpass_stream, _diff_stream);

	//qrs-pre-process
	QRSPreProcess *pre = ssi_pcast(QRSPreProcess, Factory::Create (QRSPreProcess::GetCreateName (), 0, false));
	_pre = pre;
	ssi_stream_init (_pre_stream, 0, _pre->getSampleDimensionOut (_diff_stream.dim), _pre->getSampleBytesOut (_diff_stream.byte), _pre->getSampleTypeOut (_diff_stream.type), _diff_stream.sr);
	_pre->transform_enter(_diff_stream, _pre_stream);

	Butfilt *pre_low = ssi_create (Butfilt, 0, false);
	pre_low->getOptions()->zero = true;
	pre_low->getOptions()->norm = false;
	pre_low->getOptions ()->low = 6.4;
	pre_low->getOptions ()->order = 3;
	pre_low->getOptions ()->type = Butfilt::LOW;	
	_pre_low = pre_low;
	ssi_stream_init (_pre_low_stream, 0, _pre_low->getSampleDimensionOut (_pre_stream.dim), _pre_low->getSampleBytesOut (_pre_stream.byte), _pre_low->getSampleTypeOut (_pre_stream.type), _pre_stream.sr);
	_pre_low->transform_enter(_pre_stream, _pre_low_stream);

	//qrs-detect
	ssi_size_t sample_dimension = _pre_low_stream.dim;
	_pulsed = false;
	_n_R = 0;
	_samples_since_last_R = 0;
	_sum_RR = 0;
	_average_RR = 0.0f;
	_history_RR = new ssi_size_t[_options.depthRR];
	_last_R = 0;
	for (ssi_size_t k = 0; k < _options.depthRR; k++) {
		_history_RR[k] = 0;
	}

	_first_call = true;
		
}
Example #3
0
void StrPrinter::bvisit(const Derivative &x) {
    std::ostringstream o;
    o << "Derivative(" << this->apply(x.get_arg());
    multiset_basic m1 = x.get_symbols();
    std::multiset<RCP<const Basic>, RCPBasicKeyLessCmp> m2(m1.begin(), m1.end());
    for (auto p = m2.begin(); p != m2.end(); p++) {
        o << ", " << this->apply(*p);
    }
    o << ")";
    str_ = o.str();
}
//-----------------------------------------------------------------------------------------------
// Passes the Jacobian to Bonmin
//-----------------------------------------------------------------------------------------------
bool BonminInterfaceGradients::eval_jac_g(Index n, const Number* x, bool new_x,
                        Index m, Index nele_jac, Index* iRow, Index *jCol,
                        Number* values)
{
    // checking if the structure of the jacobian has been set
    if (values == NULL)
    {
        cout << "Giving bonmin the structure of the jacobian..." << endl;

        int entry = 0;

        for(int row = 0; row < m; ++row)
        {
            for(int col = 0; col < n; ++col)
            {
                iRow[entry] = row;
                jCol[entry] = col;

                ++entry;
            }
        }
    }
    else    // the structure is already set, getting the values
    {

        // running model if needed
        update(n, x);


        // copying gradients to Bonmin

        int entry = 0;
        for(int i = 0; i < p_case_last->numberOfConstraintDerivatives(); ++i)
        {
            Derivative *dc = p_case_last->constraintDerivative(i);
            for(int j = 0; j < dc->numberOfPartials(); ++j)
            {
                values[entry] = dc->value(j);

                ++entry;
            }
        }


    }

    return true;
}
Example #5
0
void StrPrinter::bvisit(const Derivative &x) {
    std::ostringstream o;
    o << "Derivative(";
    vec_basic vec = x.get_args();
    o << this->apply(vec) << ")";
    str_ = o.str();
}
Example #6
0
 static RCP<const Basic> diff(const Derivative &self,
         const RCP<const Symbol> &x) {
     RCP<const Basic> ret = self.get_arg()->diff(x);
     if (eq(*ret, *zero)) return zero;
     multiset_basic t = self.get_symbols();
     for (auto &p: t) {
         // If x is already there in symbols multi-set add x to the symbols multi-set
         if (eq(*p, *x)) {
             t.insert(x);
             return Derivative::create(self.get_arg(), t);
         }
     }
     // Avoid cycles
     if (is_a<Derivative>(*ret) && eq(*static_cast<const Derivative &>(*ret).get_arg(), *self.get_arg())) {
         t.insert(x);
         return Derivative::create(self.get_arg(), t);
     }
     for (auto &p: t) {
         ret = ret->diff(rcp_static_cast<const Symbol>(p));
     }
     return ret;
 }
void Piro::Epetra::NOXSolver::evalModel(const InArgs& inArgs,
				const OutArgs& outArgs ) const
{
  // Parse input parameters
  for (int i=0; i<num_p; i++) {
    Teuchos::RCP<const Epetra_Vector> p_in = inArgs.get_p(i);
    if (p_in != Teuchos::null)
      interface->inargs_set_p(p_in, i); // Pass "p_in" through to inargs 
  }

  // Reset initial guess, if the user requests
  if(piroParams->sublist("NOX").get("Reset Initial Guess",false)==true)
    *currentSolution=*model->get_x_init();

  // Solve
  solver->reset(*currentSolution);
  NOX::StatusTest::StatusType status = solver->solve();

  // Print status
  if (status == NOX::StatusTest::Converged) 
    //utils.out() << "Step Converged" << std::endl;
    ;
  else {
    utils.out() << "Nonlinear solver failed to converge!" << std::endl;
    outArgs.setFailed();
  }

  // Get the NOX and Epetra_Vector with the final solution from the solver
  (*currentSolution)=grp->getX();
  Teuchos::RCP<const Epetra_Vector> finalSolution = 
    Teuchos::rcp(&(currentSolution->getEpetraVector()), false);

  // Print solution
  if (utils.isPrintType(NOX::Utils::Details)) {
    utils.out() << std::endl << "Final Solution" << std::endl
		<< "****************" << std::endl;
    finalSolution->Print(utils.pout());
  }

  // Output the parameter list
  if (utils.isPrintType(NOX::Utils::Parameters)) {
    utils.out() << std::endl << "Final Parameters" << std::endl
		<< "****************" << std::endl;
    piroParams->print(utils.out());
    utils.out() << std::endl;
  }

  // Print stats
  bool print_stats = piroParams->get("Print Convergence Stats", true);
  if (print_stats) {
    static int totalNewtonIters=0;
    static int totalKrylovIters=0;
    static int stepNum=0;
    int NewtonIters = piroParams->sublist("NOX").
      sublist("Output").get("Nonlinear Iterations", -1000);

    int KrylovIters = linsys->getLinearItersTotal() - totalKrylovIters;
    int lastSolveKrylovIters = linsys->getLinearItersLastSolve();

    totalNewtonIters += NewtonIters;
    totalKrylovIters += KrylovIters;
    stepNum++;

    utils.out() << "Convergence Stats: for step  #" << stepNum << " : Newton, Krylov, Kr/Ne; LastKrylov, LastTol: " 
	 << NewtonIters << "  " << KrylovIters << "  " 
	 << (double) KrylovIters / (double) NewtonIters << "  " 
         << lastSolveKrylovIters << " " <<  linsys->getAchievedTol() << std::endl;

    if (stepNum > 1)
     utils.out() << "Convergence Stats: running total: Newton, Krylov, Kr/Ne, Kr/Step: " 
           << totalNewtonIters << "  " << totalKrylovIters << "  " 
           << (double) totalKrylovIters / (double) totalNewtonIters 
           << "  " << (double) totalKrylovIters / (double) stepNum << std::endl;
    
  }
    
  //
  // Do Sensitivity Calc, if requested. See 3 main steps 
  //

  // Set inargs and outargs
  EpetraExt::ModelEvaluator::InArgs model_inargs = model->createInArgs();
  EpetraExt::ModelEvaluator::OutArgs model_outargs = model->createOutArgs();
  model_inargs.set_x(finalSolution);

  // We make different choices for layouts of df/dp, dg/dx depending on
  // whether we are doing forward or adjoint sensitivities
  std::string sensitivity_method = piroParams->get("Sensitivity Method",
						   "Forward");

  bool do_sens = false;
  for (int i=0; i<num_p; i++) {
    // p
    model_inargs.set_p(i, inArgs.get_p(i));
    
    // df/dp
    do_sens = false;
    for (int j=0; j<num_g; j++) {
      if (!outArgs.supports(OUT_ARG_DgDp, j, i).none() && 
	  !outArgs.get_DgDp(j,i).isEmpty()) {
	do_sens = true;
        
        // This code does not work with non-empty p_indexes.  The reason is
        // each p_indexes could theoretically be different for each g.
        // We would then need to make one df/dp for all the chosen p's
        // and then index into them properly below.  Note that the number of
        // columns in df/dp should be the number of chosen p's, not the total
        // number of p's.
	if (outArgs.get_DgDp(j,i).getMultiVector() != Teuchos::null) {
	  Teuchos::Array<int> p_indexes = 
	    outArgs.get_DgDp(j,i).getDerivativeMultiVector().getParamIndexes();
	  TEUCHOS_TEST_FOR_EXCEPTION(p_indexes.size() > 0, 
			     Teuchos::Exceptions::InvalidParameter,
			     std::endl <<
			     "Piro::Epetra::NOXSolver::evalModel():  " <<
			     "Non-empty paramIndexes for dg/dp(" << i << "," <<
			     j << ") is not currently supported." << std::endl);
	}
      }
    }
    if (do_sens) {
      Teuchos::RCP<const Epetra_Map> p_map = model->get_p_map(i);
      Teuchos::RCP<const Epetra_Map> f_map = model->get_f_map();
      int num_params = p_map->NumGlobalElements();
      int num_resids = f_map->NumGlobalElements();
      bool p_dist = p_map->DistributedGlobal();
      bool f_dist = f_map->DistributedGlobal();
      DerivativeSupport ds =  model_outargs.supports(OUT_ARG_DfDp,i);
      // Determine which layout to use for df/dp.  Ideally one would look
      // at num_params, num_resids, what is supported by the underlying
      // model evaluator, and the sensitivity method, and make the best 
      // choice to minimze the number of solves.  However this choice depends 
      // also on what layout of dg/dx is supported (e.g., if only the operator 
      // form is supported for forward sensitivities, then df/dp must be
      // DERIV_MV_BY_COL).  For simplicity, we order the conditional tests
      // to get the right layout in most situations.
      DerivativeLayout dfdp_layout;
      if (sensitivity_method == "Forward") {
        if (ds.supports(DERIV_MV_BY_COL) && !p_dist)
          dfdp_layout = COL;
        else if (ds.supports(DERIV_TRANS_MV_BY_ROW) && !f_dist)
          dfdp_layout = ROW;
	else if (ds.supports(DERIV_LINEAR_OP))
          dfdp_layout = OP;
        else
	  TEUCHOS_TEST_FOR_EXCEPTION(
	    true, std::logic_error, 
	    std::endl << "Piro::Epetra::NOXSolver::evalModel():  " << 
	    "For df/dp(" << i <<") with forward sensitivities, " <<
	    "underlying ModelEvaluator must support DERIV_LINEAR_OP, " <<
	    "DERIV_MV_BY_COL with p not distributed, or "
	    "DERIV_TRANS_MV_BY_ROW with f not distributed." <<
	    std::endl);
      }
      else if (sensitivity_method == "Adjoint") {
        if (ds.supports(DERIV_LINEAR_OP))
          dfdp_layout = OP;
	else if (ds.supports(DERIV_TRANS_MV_BY_ROW) && !f_dist)
          dfdp_layout = ROW;
	else if (ds.supports(DERIV_MV_BY_COL) && !p_dist)
          dfdp_layout = COL;
        else
	  TEUCHOS_TEST_FOR_EXCEPTION(
	    true, std::logic_error, 
	    std::endl << "Piro::Epetra::NOXSolver::evalModel():  " << 
	    "For df/dp(" << i <<") with adjoint sensitivities, " <<
	    "underlying ModelEvaluator must support DERIV_LINEAR_OP, " <<
	    "DERIV_MV_BY_COL with p not distributed, or "
	    "DERIV_TRANS_MV_BY_ROW with f not distributed." <<
	    std::endl);
      }
      else
        TEUCHOS_TEST_FOR_EXCEPTION(true, 
       		           Teuchos::Exceptions::InvalidParameter,
		           std::endl <<
		           "Piro::Epetra::NOXSolver::evalModel():  " <<
		           "Unknown sensitivity method" << sensitivity_method <<
		           ".  Valid choices are \"Forward\" and \"Adjoint\"." 
                           << std::endl);

      if (dfdp_layout == COL) {
	Teuchos::RCP<Epetra_MultiVector> dfdp =
	  Teuchos::rcp(new Epetra_MultiVector(*f_map, num_params));
	// Teuchos::Array<int> p_indexes = 
	// 	outArgs.get_DgDp(i,0).getDerivativeMultiVector().getParamIndexes();
	// EpetraExt::ModelEvaluator::DerivativeMultiVector 
	// 	dmv_dfdp(dfdp, DERIV_MV_BY_COL, p_indexes);
	EpetraExt::ModelEvaluator::DerivativeMultiVector 
	  dmv_dfdp(dfdp, DERIV_MV_BY_COL);
	model_outargs.set_DfDp(i,dmv_dfdp);
      }
      else if (dfdp_layout == ROW) {
	Teuchos::RCP<Epetra_MultiVector> dfdp =
	  Teuchos::rcp(new Epetra_MultiVector(*p_map, num_resids));
	// Teuchos::Array<int> p_indexes = 
	// 	outArgs.get_DgDp(i,0).getDerivativeMultiVector().getParamIndexes();
	// EpetraExt::ModelEvaluator::DerivativeMultiVector 
	// 	dmv_dfdp(dfdp, DERIV_TRANS_MV_BY_ROW, p_indexes);
	EpetraExt::ModelEvaluator::DerivativeMultiVector 
	  dmv_dfdp(dfdp, DERIV_TRANS_MV_BY_ROW);
	model_outargs.set_DfDp(i,dmv_dfdp);
      }
      else if (dfdp_layout == OP) {
	Teuchos::RCP<Epetra_Operator> dfdp_op = model->create_DfDp_op(i);
	TEUCHOS_TEST_FOR_EXCEPTION(
	  dfdp_op == Teuchos::null, std::logic_error, 
	  std::endl << "Piro::Epetra::NOXSolver::evalModel():  " << 
	  "Needed df/dp operator (" << i << ") is null!" << std::endl);
	model_outargs.set_DfDp(i,dfdp_op);
      }
    }
  }

  for (int j=0; j<num_g; j++) {
    // g
    Teuchos::RCP<Epetra_Vector> g_out = outArgs.get_g(j);
    if (g_out != Teuchos::null) {
      g_out->PutScalar(0.0);
      model_outargs.set_g(j, g_out);
    }

    // dg/dx
    do_sens = false;
    for (int i=0; i<num_p; i++) {
      Teuchos::RCP<Epetra_MultiVector> dgdp_out;
      if (!outArgs.supports(OUT_ARG_DgDp, j, i).none() &&
	  !outArgs.get_DgDp(j,i).isEmpty()) {
	do_sens = true;
      }
    }
    if (do_sens) {
      Teuchos::RCP<const Epetra_Map> g_map = model->get_g_map(j);
      Teuchos::RCP<const Epetra_Map> x_map = model->get_x_map();
      int num_responses = g_map->NumGlobalElements();
      int num_solution = x_map->NumGlobalElements();
      bool g_dist = g_map->DistributedGlobal();
      bool x_dist = x_map->DistributedGlobal();
      DerivativeSupport ds =  model_outargs.supports(OUT_ARG_DgDx,j);
      DerivativeLayout dgdx_layout;
      if (sensitivity_method == "Forward") {
	if (ds.supports(DERIV_LINEAR_OP))
          dgdx_layout = OP;
        else if (ds.supports(DERIV_MV_BY_COL) && !x_dist)
          dgdx_layout = COL;
        else if (ds.supports(DERIV_TRANS_MV_BY_ROW) && !g_dist)
          dgdx_layout = ROW;
	else
	  TEUCHOS_TEST_FOR_EXCEPTION(
	    true, std::logic_error, 
	    std::endl << "Piro::Epetra::NOXSolver::evalModel():  " << 
	    "For dg/dx(" << j <<") with forward sensitivities, " <<
	    "underlying ModelEvaluator must support DERIV_LINEAR_OP, " <<
	    "DERIV_MV_BY_COL with x not distributed, or "
	    "DERIV_TRANS_MV_BY_ROW with g not distributed." <<
	    std::endl);
      }
      else if (sensitivity_method == "Adjoint") {
	if (ds.supports(DERIV_TRANS_MV_BY_ROW) && !g_dist)
          dgdx_layout = ROW;
	else if (ds.supports(DERIV_MV_BY_COL) && !x_dist)
          dgdx_layout = COL;
	else if (ds.supports(DERIV_LINEAR_OP))
          dgdx_layout = OP;
        else
	  TEUCHOS_TEST_FOR_EXCEPTION(
	    true, std::logic_error, 
	    std::endl << "Piro::Epetra::NOXSolver::evalModel():  " << 
	    "For dg/dx(" << j <<") with adjoint sensitivities, " <<
	    "underlying ModelEvaluator must support DERIV_LINEAR_OP, " <<
	    "DERIV_MV_BY_COL with x not distributed, or "
	    "DERIV_TRANS_MV_BY_ROW with g not distributed." <<
	    std::endl);
      }
      else
        TEUCHOS_TEST_FOR_EXCEPTION(true, 
       		           Teuchos::Exceptions::InvalidParameter,
		           std::endl <<
		           "Piro::Epetra::NOXSolver::evalModel():  " <<
		           "Unknown sensitivity method" << sensitivity_method <<
		           ".  Valid choices are \"Forward\" and \"Adjoint\"." 
                           << std::endl);

      if (dgdx_layout == OP) {
	Teuchos::RCP<Epetra_Operator> dgdx_op = model->create_DgDx_op(j);
	TEUCHOS_TEST_FOR_EXCEPTION(
	  dgdx_op == Teuchos::null, std::logic_error, 
	  std::endl << "Piro::Epetra::NOXSolver::evalModel():  " << 
	  "Needed dg/dx operator (" << j << ") is null!" << std::endl);
	model_outargs.set_DgDx(j,dgdx_op);
      }
      else if (dgdx_layout == ROW) {
	Teuchos::RCP<Epetra_MultiVector> dgdx = 
	  Teuchos::rcp(new Epetra_MultiVector(*x_map, num_responses));
	EpetraExt::ModelEvaluator::DerivativeMultiVector 
	  dmv_dgdx(dgdx, DERIV_TRANS_MV_BY_ROW);
	model_outargs.set_DgDx(j,dmv_dgdx);
      }
      else if (dgdx_layout == COL) {
	Teuchos::RCP<Epetra_MultiVector> dgdx = 
	  Teuchos::rcp(new Epetra_MultiVector(*g_map, num_solution));
	EpetraExt::ModelEvaluator::DerivativeMultiVector 
	  dmv_dgdx(dgdx, DERIV_MV_BY_COL);
	model_outargs.set_DgDx(j,dmv_dgdx);
      }

      // dg/dp
      for (int i=0; i<num_p; i++) {
	if (!outArgs.supports(OUT_ARG_DgDp,j,i).none()) {
	  Derivative dgdp = outArgs.get_DgDp(j,i);
	  if (dgdp.getLinearOp() != Teuchos::null) {
	    Teuchos::RCP<const Epetra_Map> g_map = model->get_g_map(j);
	    Teuchos::RCP<const Epetra_Map> p_map = model->get_p_map(i);
	    int num_responses = g_map->NumGlobalElements();
	    int num_params = p_map->NumGlobalElements();
	    bool g_dist = g_map->DistributedGlobal();
	    bool p_dist = p_map->DistributedGlobal();
	    DerivativeSupport ds = model_outargs.supports(OUT_ARG_DgDp,j,i);
	    if (ds.supports(DERIV_LINEAR_OP)) {
	      Teuchos::RCP<Epetra_Operator> dgdp_op = 
		model->create_DgDp_op(j,i);
	      TEUCHOS_TEST_FOR_EXCEPTION(
		dgdp_op == Teuchos::null, std::logic_error, 
		std::endl << "Piro::Epetra::NOXSolver::evalModel():  " << 
		"Needed dg/dp operator (" << j << "," << i << ") is null!" << 
		std::endl);
	      model_outargs.set_DgDp(j,i,dgdp_op);
	    }
	    else if (ds.supports(DERIV_MV_BY_COL) && !p_dist) {
	      Teuchos::RCP<Epetra_MultiVector> dgdp =
		Teuchos::rcp(new Epetra_MultiVector(*g_map, num_params));
	      EpetraExt::ModelEvaluator::DerivativeMultiVector 
		dmv_dgdp(dgdp, DERIV_MV_BY_COL);
	      model_outargs.set_DgDp(j,i,dmv_dgdp);
	    }
	    else if (ds.supports(DERIV_TRANS_MV_BY_ROW) && !g_dist) {
	      Teuchos::RCP<Epetra_MultiVector> dgdp =
		Teuchos::rcp(new Epetra_MultiVector(*p_map, num_responses));
	      EpetraExt::ModelEvaluator::DerivativeMultiVector 
		dmv_dgdp(dgdp, DERIV_TRANS_MV_BY_ROW);
	      model_outargs.set_DgDp(j,i,dmv_dgdp);
	    }
	    else
	      TEUCHOS_TEST_FOR_EXCEPTION(
		true, std::logic_error, 
		std::endl << "Piro::Epetra::NOXSolver::evalModel():  " << 
		"For dg/dp(" << j << "," << i <<
		") with operator sensitivities, "<<
		"underlying ModelEvaluator must support DERIV_LINEAR_OP, " <<
		"DERIV_MV_BY_COL with p not distributed, or "
		"DERIV_TRANS_MV_BY_ROW with g not distributed." <<
		std::endl);
	  }
	  else
	    model_outargs.set_DgDp(j,i,outArgs.get_DgDp(j,i));
	}
      }
    }
  }
    
  // (1) Calculate g, df/dp, dg/dp, dg/dx
  model->evalModel(model_inargs, model_outargs);

  // Ensure Jacobian is up-to-date
  if (do_sens)
    grp->computeJacobian();

  // Handle operator dg/dp
  for (int i=0; i<num_p; i++) {
    for (int j=0; j<num_g; j++) {
      if (!outArgs.supports(OUT_ARG_DgDp, j, i).none()) {
	if (outArgs.get_DgDp(j,i).getLinearOp() != Teuchos::null) {
	  Teuchos::RCP<Epetra_Operator> op = 
	    outArgs.get_DgDp(j,i).getLinearOp();
	  Teuchos::RCP<SensitivityOperator> sens_op =
	    Teuchos::rcp_dynamic_cast<SensitivityOperator>(op);
	  sens_op->setup(model_outargs.get_DfDp(i), 
			 model_outargs.get_DgDx(j),
			 model_outargs.get_DgDp(j,i), 
			 piroParams, grp, tls_strategy);
	}
      }
    }
  }
    
  if (sensitivity_method == "Forward") {
    for (int i=0; i<num_p; i++) {

      // See if there are any forward sensitivities we need to do
      // that aren't handled by the operator
      do_sens = false;
      for (int j=0; j<num_g; j++) {
	if (!outArgs.supports(OUT_ARG_DgDp, j, i).none()) {
	  if (outArgs.get_DgDp(j,i).getMultiVector() != Teuchos::null)
	    do_sens = true;
	}
      }
      if (!do_sens)
	continue;

      if (!model_outargs.supports(OUT_ARG_DfDp, i).none()) {
	TEUCHOS_TEST_FOR_EXCEPTION(
	  model_outargs.get_DfDp(i).getLinearOp()!=Teuchos::null,
	  std::logic_error,
	  std::endl <<"Piro::Epetra::NOXSolver::evalModel():  " <<
	  "Can\'t use df/dp operator " << i << " with non-operator " <<
	  "forward sensitivities." << std::endl);
	Teuchos::RCP<Epetra_MultiVector> dfdp  = 
	  model_outargs.get_DfDp(i).getMultiVector();
	if (dfdp != Teuchos::null) {
	  int num_cols = dfdp->NumVectors();
	
	  // (2) Calculate dx/dp multivector from -(J^{-1}*df/dp)
	  Teuchos::RCP<Epetra_MultiVector> dxdp = 
	    Teuchos::rcp(new Epetra_MultiVector(dfdp->Map(), num_cols));
	  NOX::Epetra::MultiVector dfdp_nox(
	    dfdp, NOX::DeepCopy,  
	    NOX::Epetra::MultiVector::CreateView);
	  NOX::Epetra::MultiVector dxdp_nox(
	    dxdp, NOX::DeepCopy,  
	    NOX::Epetra::MultiVector::CreateView);
	  
	  grp->applyJacobianInverseMultiVector(*piroParams, dfdp_nox, dxdp_nox);
	  dxdp_nox.scale(-1.0);
	
	  // (3) Calculate dg/dp = dg/dx*dx/dp + dg/dp
	  for (int j=0; j<num_g; j++) {
	    if (!outArgs.supports(OUT_ARG_DgDp, j, i).none()) {
	      Teuchos::RCP<Epetra_MultiVector> dgdp_out = 
		outArgs.get_DgDp(j,i).getMultiVector();
	      if (dgdp_out != Teuchos::null) {
		Derivative dgdx_dv = model_outargs.get_DgDx(j);
		Teuchos::RCP<Epetra_Operator> dgdx_op = dgdx_dv.getLinearOp();
		Teuchos::RCP<Epetra_MultiVector> dgdx = 
		  dgdx_dv.getMultiVector();
		Derivative dfdp_dv = model_outargs.get_DfDp(i);
		EDerivativeMultiVectorOrientation dgdp_orient =
		  outArgs.get_DgDp(j,i).getMultiVectorOrientation();
		if (dgdx_op != Teuchos::null) {
		  bool transpose = false;
		  if (dgdp_orient == DERIV_TRANS_MV_BY_ROW)
		    transpose = true;
		  Epetra_MultiVector tmp(dgdx_op->OperatorRangeMap(),
					 dxdp->NumVectors());
		  dgdx_op->Apply(*dxdp, tmp);
		  if (transpose) {
		    TEUCHOS_TEST_FOR_EXCEPTION(
		      dgdp_out->Map().DistributedGlobal(), 
		      std::logic_error,
		      std::endl << 
		      "Piro::Epetra::NOXSolver::evalModel():  " <<
		      "Can\'t handle special case:  " << 
		      " dg/dx operator, " <<
		      " transposed, distributed dg/dp. " << std::endl);
		    for (int j=0; j<dgdp_out->NumVectors(); j++)
		      for (int i=0; i<dgdp_out->MyLength(); i++)
			(*dgdp_out)[j][i] += tmp[i][j];
		  }
		  else
		    dgdp_out->Update(1.0, tmp, 1.0);
		}
		else {
		  Teuchos::RCP<Epetra_MultiVector> arg1, arg2;
		  EDerivativeMultiVectorOrientation dfdp_orient =
		    model_outargs.get_DfDp(i).getMultiVectorOrientation();
		  EDerivativeMultiVectorOrientation dgdx_orient =
		    model_outargs.get_DgDx(j).getMultiVectorOrientation();
		  char flag1, flag2;
		  if (dgdp_orient == DERIV_MV_BY_COL) {
		    arg1 = dgdx;
		    arg2 = dxdp;
		    if (dgdx_orient == DERIV_MV_BY_COL)
		      flag1 = 'N';
		    else
		      flag1 = 'T';
		    if (dfdp_orient == DERIV_MV_BY_COL)
		      flag2 = 'N';
		    else
		      flag2 = 'T';
		  }
		  else {
		    arg1 = dxdp;
		    arg2 = dgdx;
		    if (dfdp_orient == DERIV_MV_BY_COL)
		      flag1 = 'T';
		    else
		      flag1 = 'N';
		    if (dgdx_orient == DERIV_MV_BY_COL)
		      flag2 = 'T';
		    else
		      flag2 = 'N';
		  }
		  dgdp_out->Multiply(flag1, flag2, 1.0, *arg1, *arg2, 1.0);
		}
	      }
	    }
	  }
	}
      }
    }
  }

  else if (sensitivity_method == "Adjoint") {
    
    // Hold on to original Jacobian operator
    Teuchos::RCP<NOX::Epetra::LinearSystem> linSys = grp->getLinearSystem();
    Teuchos::RCP<Epetra_Operator> jac = linSys->getJacobianOperator();

    tls_strategy->createJacobianTranspose();
    const NOX::Epetra::Vector& x_nox = 
      dynamic_cast<const NOX::Epetra::Vector&>(grp->getX());
    tls_strategy->createTransposePreconditioner(x_nox, *piroParams);

    for (int j=0; j<num_g; j++) {

      // See if there are any forward sensitivities we need to do
      // that aren't handled by the operator
      do_sens = false;
      for (int i=0; i<num_p; i++) {
	if (!outArgs.supports(OUT_ARG_DgDp, j, i).none()) {
	  if (outArgs.get_DgDp(j,i).getMultiVector() != Teuchos::null)
	    do_sens = true;
	}
      }
      if (!do_sens)
	continue;

      if (!model_outargs.supports(OUT_ARG_DgDx, j).none()) {
	TEUCHOS_TEST_FOR_EXCEPTION(
	  model_outargs.get_DgDx(j).getLinearOp()!=Teuchos::null,
	  std::logic_error,
	  std::endl << "Piro::Epetra::NOXSolver::evalModel():  " <<
	  "Can\'t use dg/dx operator " << j << " with non-operator " << 
	  "adjoint sensitivities." << std::endl);
	Teuchos::RCP<Epetra_MultiVector> dgdx  = 
	  model_outargs.get_DgDx(j).getMultiVector();
	if (dgdx != Teuchos::null) {
	  int num_cols = dgdx->NumVectors();
	
	  // (2) Calculate xbar multivector from -(J^{-T}*dg/dx)
	  Teuchos::RCP<Epetra_MultiVector> xbar = 
	    Teuchos::rcp(new Epetra_MultiVector(dgdx->Map(), num_cols));
	  for (int col=0; col<num_cols; col++) {
	    Teuchos::RCP<Epetra_Vector> gx =
	      Teuchos::rcp((*dgdx)(col),false);
	    Teuchos::RCP<Epetra_Vector> xb =
	      Teuchos::rcp((*xbar)(col),false);
	    NOX::Epetra::Vector dgdx_nox(
	      gx, NOX::Epetra::Vector::CreateView, NOX::DeepCopy);
	    NOX::Epetra::Vector xbar_nox(
	      xb, NOX::Epetra::Vector::CreateView, NOX::DeepCopy);
	  
	    // Solve
	    tls_strategy->applyJacobianTransposeInverse(
	      *piroParams, dgdx_nox, xbar_nox);
	  }
	  xbar->Scale(-1.0);
	
	  // (3) Calculate dg/dp^T = df/dp^T*xbar + dg/dp^T
	  for (int i=0; i<num_p; i++) {
	    if (!outArgs.supports(OUT_ARG_DgDp, j, i).none()) {
	      Teuchos::RCP<Epetra_MultiVector> dgdp_out = 
		outArgs.get_DgDp(j,i).getMultiVector();
	      if (dgdp_out != Teuchos::null) {
		Derivative dfdp_dv = model_outargs.get_DfDp(i);
		Teuchos::RCP<Epetra_Operator> dfdp_op = dfdp_dv.getLinearOp();
		Teuchos::RCP<Epetra_MultiVector> dfdp = 
		  dfdp_dv.getMultiVector();
		Derivative dgdx_dv = model_outargs.get_DgDx(j);
		EDerivativeMultiVectorOrientation dgdp_orient =
		  outArgs.get_DgDp(j,i).getMultiVectorOrientation();
		if (dfdp_op != Teuchos::null) {
		  bool transpose = false;
		  if (dgdp_orient == DERIV_MV_BY_COL)
		    transpose = true;
		  Epetra_MultiVector tmp(dfdp_op->OperatorDomainMap(),
					 xbar->NumVectors());
		  dfdp_op->SetUseTranspose(true);
		  dfdp_op->Apply(*xbar, tmp);
		  dfdp_op->SetUseTranspose(false);
		  if (transpose) {
		    TEUCHOS_TEST_FOR_EXCEPTION(
		      dgdp_out->Map().DistributedGlobal(), 
		      std::logic_error,
		      std::endl <<
		      "Piro::Epetra::NOXSolver::evalModel():  " <<
		      "Can\'t handle special case:  " << 
		      " df/dp operator, " <<
		      " transposed, distributed dg/dp. " << std::endl);
		    for (int j=0; j<dgdp_out->NumVectors(); j++)
		      for (int i=0; i<dgdp_out->MyLength(); i++)
			(*dgdp_out)[j][i] += tmp[i][j];
		  }
		  else
		    dgdp_out->Update(1.0, tmp, 1.0);
		}
		else {
		  Teuchos::RCP<Epetra_MultiVector> arg1, arg2;
		  EDerivativeMultiVectorOrientation dgdp_orient =
		    model_outargs.get_DgDp(j,i).getMultiVectorOrientation();
		  EDerivativeMultiVectorOrientation dfdp_orient =
		    model_outargs.get_DfDp(i).getMultiVectorOrientation();
		  EDerivativeMultiVectorOrientation dgdx_orient =
		    model_outargs.get_DgDx(j).getMultiVectorOrientation();
		  char flag1, flag2;
		  if (dgdp_orient == DERIV_TRANS_MV_BY_ROW) {
		    arg1 = dfdp;
		    arg2 = xbar;
		    if (dfdp_orient == DERIV_TRANS_MV_BY_ROW)
		      flag1 = 'N';
		    else
		      flag1 = 'T';
		    if (dgdx_orient == DERIV_TRANS_MV_BY_ROW)
		      flag2 = 'N';
		    else
		      flag2 = 'T';
		  }
		  else {
		    arg1 = xbar;
		    arg2 = dfdp;
		    if (dgdx_orient == DERIV_TRANS_MV_BY_ROW)
		      flag1 = 'T';
		    else
		      flag1 = 'N';
		    if (dfdp_orient == DERIV_TRANS_MV_BY_ROW)
		      flag2 = 'T';
		    else
		      flag2 = 'N';
		    
		  }
		  dgdp_out->Multiply(flag1, flag2, 1.0, *arg1, *arg2, 1.0);
		}
	      }
	    }
	  }
	}
      }
    }

    // Set original operators in linear system
    jac->SetUseTranspose(false);
    linSys->setJacobianOperatorForSolve(jac);
    linSys->destroyPreconditioner();
  }

  if (status == NOX::StatusTest::Converged) 
    if (observer != Teuchos::null)
      observer->observeSolution(*finalSolution);

  // return the final solution as an additional g-vector, if requested
  Teuchos::RCP<Epetra_Vector> gx_out = outArgs.get_g(num_g); 
  if (gx_out != Teuchos::null)  *gx_out = *finalSolution; 

  // Clear RCPs to parameter vectors
  for (int i=0; i<num_p; i++)
    interface->inargs_set_p(Teuchos::null, i); 
 
}
Example #8
0
void VanderPolModel::evalModelImpl(
  const ModelEvaluatorBase::InArgs<double> &inArgs,
  const ModelEvaluatorBase::OutArgs<double> &outArgs
  ) const
{

  using Teuchos::as;
  using Teuchos::outArg;
  using Teuchos::optInArg;
  using Teuchos::inOutArg;
  using Sacado::Fad::DFad;

  TEST_FOR_EXCEPTION( !isInitialized_, std::logic_error,
      "Error, setParameterList must be called first!\n"
      );

  const RCP<const VectorBase<double> > x_in = inArgs.get_x().assert_not_null();
  Thyra::ConstDetachedVectorView<double> x_in_view( *x_in ); 

  double t = inArgs.get_t();
  double eps = epsilon_;
  if (acceptModelParams_) {
    const RCP<const VectorBase<double> > p_in = inArgs.get_p(0).assert_not_null();
    Thyra::ConstDetachedVectorView<double> p_in_view( *p_in ); 
    eps = p_in_view[0];
  }

  RCP<const VectorBase<double> > x_dot_in;
  double alpha = -1.0;
  double beta = -1.0;
  if (isImplicit_) {
    x_dot_in = inArgs.get_x_dot().assert_not_null();
    alpha = inArgs.get_alpha();
    beta = inArgs.get_beta();
  }

  const RCP<VectorBase<double> > f_out = outArgs.get_f();
  const RCP<Thyra::LinearOpBase<double> > W_out = outArgs.get_W_op();
  RCP<Thyra::MultiVectorBase<double> > DfDp_out; 
  if (acceptModelParams_) {
    Derivative<double> DfDp = outArgs.get_DfDp(0); 
    DfDp_out = DfDp.getMultiVector();
  }

  // Determine how many derivatives we will compute
  
  int num_derivs = 0;
  if (nonnull(W_out)) {
    num_derivs += 2;
    if (isImplicit_) {
      num_derivs += 2;
    }
  }
  if (nonnull(DfDp_out))
    num_derivs += 1;

  // Set up the FAD derivative objects

  int deriv_i = 0;

  Array<DFad<double> > x_dot_fad;
  int x_dot_idx_offset = 0;
  if (isImplicit_) {
    Thyra::ConstDetachedVectorView<double> x_dot_in_view( *x_dot_in );
    if (nonnull(W_out)) {
      x_dot_idx_offset = deriv_i;
      x_dot_fad = convertToIndepVarFadArray<double>(x_dot_in_view.sv().values()(),
        num_derivs, inOutArg(deriv_i));
    }
    else {
      x_dot_fad = convertToPassiveFadArray<double>(x_dot_in_view.sv().values()());
    }
  }

  Array<DFad<double> > x_fad;
  int x_idx_offset = 0;
  if (nonnull(W_out)) {
    x_idx_offset = deriv_i;
    x_fad = convertToIndepVarFadArray<double>(x_in_view.sv().values()(),
      num_derivs, inOutArg(deriv_i));
  }
  else {
    x_fad = convertToPassiveFadArray<double>(x_in_view.sv().values()());
  }

  DFad<double> eps_fad(eps); // Default passive
  int eps_idx_offset = 0;
  if (nonnull(DfDp_out)) {
    eps_idx_offset = deriv_i;
    eps_fad = DFad<double>(num_derivs, deriv_i++, eps);
  }
  
  // Compute the function

  Array<DFad<double> > f_fad(2);
  this->eval_f<DFad<double> >( x_dot_fad, x_fad, eps_fad, t, f_fad );

  // Extract the output

  if (nonnull(f_out)) {
    Thyra::DetachedVectorView<double> f_out_view( *f_out ); 
    for ( int i = 0; i < as<int>(f_fad.size()); ++i )
      f_out_view[i] = f_fad[i].val();
  }

  if (nonnull(W_out)) {
    const RCP<Thyra::MultiVectorBase<double> > matrix =
      Teuchos::rcp_dynamic_cast<Thyra::MultiVectorBase<double> >(W_out, true);
    Thyra::DetachedMultiVectorView<double> matrix_view( *matrix );
    if (isImplicit_) {
      for ( int i = 0; i < matrix_view.subDim(); ++i) {
        for ( int j = 0; j < matrix_view.numSubCols(); ++j) {
          matrix_view(i, j) = alpha * f_fad[i].dx(x_dot_idx_offset+j)
            + beta * f_fad[i].dx(x_idx_offset + j);
        }
      }
    }
    else {
      for ( int i = 0; i < matrix_view.subDim(); ++i) {
        for ( int j = 0; j < matrix_view.numSubCols(); ++j) {
          matrix_view(i, j) = f_fad[i].dx(x_idx_offset + j);
        }
      }
    }
  }

  if (nonnull(DfDp_out)) {
    Thyra::DetachedMultiVectorView<double> DfDp_out_view( *DfDp_out );
    for ( int i = 0; i < DfDp_out_view.subDim(); ++i )
      DfDp_out_view(i,0) = f_fad[i].dx(eps_idx_offset);
  }

}