Ejemplo n.º 1
0
void
Piro::LOCASolver<Scalar>::evalModelImpl(
    const Thyra::ModelEvaluatorBase::InArgs<Scalar>& inArgs,
    const Thyra::ModelEvaluatorBase::OutArgs<Scalar>& outArgs) const
{
  const int l = 0; // TODO: Allow user to select parameter index
  const Teuchos::RCP<const Thyra::VectorBase<Scalar> > p_inargs = inArgs.get_p(l);

  // Forward parameter values to the LOCA stepper
  {
    const Teuchos::RCP<const Thyra::VectorBase<Scalar> > p_inargs_or_nominal =
      Teuchos::nonnull(p_inargs) ? p_inargs : this->getNominalValues().get_p(l);
    const Thyra::ConstDetachedVectorView<Scalar> p_init_values(p_inargs_or_nominal);
    const Teuchos_Ordinal p_entry_count = p_init_values.subDim();
    TEUCHOS_ASSERT(p_entry_count == Teuchos::as<Teuchos_Ordinal>(paramVector_.length()));

    for (Teuchos_Ordinal k = 0; k < p_entry_count; ++k) {
      paramVector_[k] = p_init_values[k];
    }

    group_->setParams(paramVector_);
  }

  stepper_->reset(globalData_, group_, locaStatusTests_, noxStatusTests_, piroParams_);
  const LOCA::Abstract::Iterator::IteratorStatus status = stepper_->run();

  if (status == LOCA::Abstract::Iterator::Finished) {
    std::cerr << "Continuation Stepper Finished.\n";
  } else if (status == LOCA::Abstract::Iterator::NotFinished) {
    std::cerr << "Continuation Stepper did not reach final value.\n";
  } else {
    std::cerr << "Nonlinear solver failed to converge.\n";
    outArgs.setFailed();
  }

  const Teuchos::RCP<Thyra::VectorBase<Scalar> > x_outargs = outArgs.get_g(this->num_g());
  const Teuchos::RCP<Thyra::VectorBase<Scalar> > x_final =
    Teuchos::nonnull(x_outargs) ? x_outargs : Thyra::createMember(this->get_g_space(this->num_g()));

  {
    // Deep copy final solution from LOCA group
    NOX::Thyra::Vector finalSolution(x_final);
    finalSolution = group_->getX();
  }

  // Compute responses for the final solution
  {
    Thyra::ModelEvaluatorBase::InArgs<Scalar> modelInArgs =
      this->getModel().createInArgs();
    {
      modelInArgs.set_x(x_final);
      modelInArgs.set_p(l, p_inargs);
    }

    this->evalConvergedModel(modelInArgs, outArgs);
  }
}
Thyra::ModelEvaluatorBase::InArgs<Scalar>
Piro::VelocityVerletSolver<Scalar>::getNominalValues() const
{
  Thyra::ModelEvaluatorBase::InArgs<Scalar> result = this->createInArgs();
  const Thyra::ModelEvaluatorBase::InArgs<Scalar> modelNominalValues = model->getNominalValues();
  for (int l = 0; l < num_p; ++l) {
    result.set_p(l, modelNominalValues.get_p(l));
  }
  return result;
}
Ejemplo n.º 3
0
Thyra::ModelEvaluatorBase::InArgs<Scalar>
DiagonalROME<Scalar>::getNominalValues() const
{
    Thyra::ModelEvaluatorBase::InArgs<Scalar> initialGuess =
        this->createInArgs();
    RCP<Thyra::VectorBase<Scalar> > p_init =
        Thyra::createMember<Scalar>(p_space_);
    Thyra::V_S( p_init.ptr(), 1.5 );
    initialGuess.set_p(0, p_init);
    return initialGuess;
}
Ejemplo n.º 4
0
TEUCHOS_UNIT_TEST( Rythmos_ExplicitRKStepper, basePoint ) {
  RCP<SinCosModel> model = sinCosModel(false);
  {
    RCP<ParameterList> pl = Teuchos::parameterList();
    pl->set("Accept model parameters",true);
    model->setParameterList(pl);
  }
  Thyra::ModelEvaluatorBase::InArgs<double> ic = model->getNominalValues();
  // t_ic
  double t_ic = 1.0; // not used
  // x_ic
  RCP<VectorBase<double> > x_ic = Thyra::createMember(*model->get_x_space());
  {
    Thyra::DetachedVectorView<double> x_ic_view( *x_ic );
    x_ic_view[0] = 5.0;
    x_ic_view[1] = 6.0;
  }
  // parameter 0 ic
  RCP<VectorBase<double> > p_ic = Thyra::createMember(*model->get_p_space(0));
  {
    Thyra::DetachedVectorView<double> p_ic_view( *p_ic );
    p_ic_view[0] = 2.0; // a
    p_ic_view[1] = 3.0; // f 
    p_ic_view[2] = 4.0; // L
  }
  ic.set_p(0,p_ic); 
  ic.set_x(x_ic);
  ic.set_t(t_ic);
  RCP<ExplicitRKStepper<double> > stepper = explicitRKStepper<double>();
  stepper->setModel(model);
  stepper->setInitialCondition(ic);
  stepper->setRKButcherTableau(createRKBT<double>("Forward Euler"));
  double dt = 0.2;
  double dt_taken;
  dt_taken = stepper->takeStep(dt,STEP_TYPE_FIXED);
  TEST_EQUALITY_CONST( dt_taken, 0.2 );
  const StepStatus<double> status = stepper->getStepStatus();
  TEST_ASSERT( !is_null(status.solution) );
  double tol = 1.0e-10;
  {
    Thyra::ConstDetachedVectorView<double> x_new_view( *(status.solution) );
    TEST_FLOATING_EQUALITY( x_new_view[0], 5.0 + 0.2*(6.0), tol );
    TEST_FLOATING_EQUALITY( x_new_view[1], 6.0 + 0.2*( (3.0/4.0)*(3.0/4.0)*(2.0-5.0) ), tol );
  }
}
void Piro::RythmosSolver<Scalar>::evalModelImpl(
#endif
    const Thyra::ModelEvaluatorBase::InArgs<Scalar>& inArgs,
    const Thyra::ModelEvaluatorBase::OutArgs<Scalar>& outArgs) const
{
    using Teuchos::RCP;
    using Teuchos::rcp;

    // TODO: Support more than 1 parameter and 1 response
    const int j = 0;
    const int l = 0;

    // Parse InArgs
    RCP<const Thyra::VectorBase<Scalar> > p_in;
    if (num_p > 0) {
        p_in = inArgs.get_p(l);
    }
    RCP<const Thyra::VectorBase<Scalar> > p_in2;  //JF add for multipoint
    if (num_p > 1) {
        p_in2 = inArgs.get_p(l+1);
    }

    // Parse OutArgs
    RCP<Thyra::VectorBase<Scalar> > g_out;
    if (num_g > 0) {
        g_out = outArgs.get_g(j);
    }
    const RCP<Thyra::VectorBase<Scalar> > gx_out = outArgs.get_g(num_g);

    Thyra::ModelEvaluatorBase::InArgs<Scalar> state_ic = model->getNominalValues();

    // Set initial time in ME if needed

    if(t_initial > 0.0 && state_ic.supports(Thyra::ModelEvaluatorBase::IN_ARG_t))

        state_ic.set_t(t_initial);

    if (Teuchos::nonnull(initialConditionModel)) {
        // The initial condition depends on the parameter
        // It is found by querying the auxiliary model evaluator as the last response
        const RCP<Thyra::VectorBase<Scalar> > initialState =
            Thyra::createMember(model->get_x_space());

        {
            Thyra::ModelEvaluatorBase::InArgs<Scalar> initCondInArgs = initialConditionModel->createInArgs();
            if (num_p > 0) {
                initCondInArgs.set_p(l, inArgs.get_p(l));
            }

            Thyra::ModelEvaluatorBase::OutArgs<Scalar> initCondOutArgs = initialConditionModel->createOutArgs();
            initCondOutArgs.set_g(initCondOutArgs.Ng() - 1, initialState);

            initialConditionModel->evalModel(initCondInArgs, initCondOutArgs);
        }

        state_ic.set_x(initialState);
    }

    // Set paramters p_in as part of initial conditions
    if (num_p > 0) {
        if (Teuchos::nonnull(p_in)) {
            state_ic.set_p(l, p_in);
        }
    }
    if (num_p > 1) { //JF added for multipoint
        if (Teuchos::nonnull(p_in2)) {
            state_ic.set_p(l+1, p_in2);
        }
    }

    *out << "\nstate_ic:\n" << Teuchos::describe(state_ic, solnVerbLevel);

    //JF  may need a version of the following for multipoint, i.e. num_p>1, l+1, if we want sensitivities
    RCP<Thyra::MultiVectorBase<Scalar> > dgxdp_out;
    Thyra::ModelEvaluatorBase::Derivative<Scalar> dgdp_deriv_out;
    if (num_p > 0) {
        const Thyra::ModelEvaluatorBase::DerivativeSupport dgxdp_support =
            outArgs.supports(Thyra::ModelEvaluatorBase::OUT_ARG_DgDp, num_g, l);
        if (dgxdp_support.supports(Thyra::ModelEvaluatorBase::DERIV_MV_JACOBIAN_FORM)) {
            const Thyra::ModelEvaluatorBase::Derivative<Scalar> dgxdp_deriv =
                outArgs.get_DgDp(num_g, l);
            dgxdp_out = dgxdp_deriv.getMultiVector();
        }

        if (num_g > 0) {
            const Thyra::ModelEvaluatorBase::DerivativeSupport dgdp_support =
                outArgs.supports(Thyra::ModelEvaluatorBase::OUT_ARG_DgDp, j, l);
            if (!dgdp_support.none()) {
                dgdp_deriv_out = outArgs.get_DgDp(j, l);
            }
        }
    }

    const bool requestedSensitivities =
        Teuchos::nonnull(dgxdp_out) || !dgdp_deriv_out.isEmpty();

    RCP<const Thyra::VectorBase<Scalar> > finalSolution;
    if (!requestedSensitivities) {
        //
        *out << "\nE) Solve the forward problem ...\n";
        //

        fwdStateStepper->setInitialCondition(state_ic);

        fwdStateIntegrator->setStepper(fwdStateStepper, t_final, true);
        *out << "T final : " << t_final << " \n";

        Teuchos::Array<RCP<const Thyra::VectorBase<Scalar> > > x_final_array;
        fwdStateIntegrator->getFwdPoints(
            Teuchos::tuple<Scalar>(t_final), &x_final_array, NULL, NULL);
        finalSolution = x_final_array[0];

        if (Teuchos::VERB_MEDIUM <= solnVerbLevel) {
            std::cout << "Final Solution\n" << *finalSolution << std::endl;
        }

    } else { // Computing sensitivities
        //
        *out << "\nE) Solve the forward problem with Sensitivities...\n";
        //
        RCP<Rythmos::ForwardSensitivityStepper<Scalar> > stateAndSensStepper =
            Rythmos::forwardSensitivityStepper<Scalar>();
        stateAndSensStepper->initializeSyncedSteppers(
            model, l, model->getNominalValues(),
            fwdStateStepper, fwdTimeStepSolver);

        //
        // Set the initial condition for the state and forward sensitivities
        //

        const RCP<Thyra::VectorBase<Scalar> > s_bar_init =
            Thyra::createMember(stateAndSensStepper->getFwdSensModel()->get_x_space());
        const RCP<Thyra::VectorBase<Scalar> > s_bar_dot_init =
            Thyra::createMember(stateAndSensStepper->getFwdSensModel()->get_x_space());

        if (Teuchos::is_null(initialConditionModel)) {
            // The initial condition is assumed to be independent from the parameters
            // Therefore, the initial condition for the sensitivity is zero
            Thyra::assign(s_bar_init.ptr(), Teuchos::ScalarTraits<Scalar>::zero());
        } else {
            // Use initialConditionModel to compute initial condition for sensitivity
            Thyra::ModelEvaluatorBase::InArgs<Scalar> initCondInArgs = initialConditionModel->createInArgs();
            initCondInArgs.set_p(l, inArgs.get_p(l));

            Thyra::ModelEvaluatorBase::OutArgs<Scalar> initCondOutArgs = initialConditionModel->createOutArgs();
            typedef Thyra::DefaultMultiVectorProductVector<Scalar> DMVPV;
            const RCP<DMVPV> s_bar_init_downcasted = Teuchos::rcp_dynamic_cast<DMVPV>(s_bar_init);
            const Thyra::ModelEvaluatorBase::Derivative<Scalar> initCond_deriv(
                s_bar_init_downcasted->getNonconstMultiVector(),
                Thyra::ModelEvaluatorBase::DERIV_MV_JACOBIAN_FORM);
            initCondOutArgs.set_DgDp(initCondOutArgs.Ng() - 1, l, initCond_deriv);

            initialConditionModel->evalModel(initCondInArgs, initCondOutArgs);
        }
        Thyra::assign(s_bar_dot_init.ptr(), Teuchos::ScalarTraits<Scalar>::zero());

        RCP<const Rythmos::StateAndForwardSensitivityModelEvaluator<Scalar> >
        stateAndSensModel = stateAndSensStepper->getStateAndFwdSensModel();

        Thyra::ModelEvaluatorBase::InArgs<Scalar>
        state_and_sens_ic = stateAndSensStepper->getModel()->createInArgs();

        // Copy time, parameters etc.
        state_and_sens_ic.setArgs(state_ic);
        // Set initial condition for x_bar = [ x; s_bar ]
        state_and_sens_ic.set_x(stateAndSensModel->create_x_bar_vec(state_ic.get_x(), s_bar_init));
        // Set initial condition for x_bar_dot = [ x_dot; s_bar_dot ]
        state_and_sens_ic.set_x_dot(stateAndSensModel->create_x_bar_vec(state_ic.get_x_dot(), s_bar_dot_init));

        stateAndSensStepper->setInitialCondition(state_and_sens_ic);

        //
        // Use a StepperAsModelEvaluator to integrate the state+sens
        //

        const RCP<Rythmos::StepperAsModelEvaluator<Scalar> >
        stateAndSensIntegratorAsModel = Rythmos::stepperAsModelEvaluator(
                                            Teuchos::rcp_implicit_cast<Rythmos::StepperBase<Scalar> >(stateAndSensStepper),
                                            Teuchos::rcp_implicit_cast<Rythmos::IntegratorBase<Scalar> >(fwdStateIntegrator),
                                            state_and_sens_ic);
        // StepperAsModelEvaluator outputs the solution as its last response
        const int stateAndSensModelStateResponseIndex = stateAndSensIntegratorAsModel->Ng() - 1;

        *out << "\nUse the StepperAsModelEvaluator to integrate state + sens x_bar(p,t_final) ... \n";
        Teuchos::OSTab tab(out);

        // Solution sensitivity in column-oriented (Jacobian) MultiVector form
        RCP<const Thyra::MultiVectorBase<Scalar> > dxdp;

        const RCP<Thyra::VectorBase<Scalar> > x_bar_final =
            Thyra::createMember(stateAndSensIntegratorAsModel->get_g_space(stateAndSensModelStateResponseIndex));
        // Extract pieces of x_bar_final to prepare output
        {
            const RCP<const Thyra::ProductVectorBase<Scalar> > x_bar_final_downcasted =
                Thyra::productVectorBase<Scalar>(x_bar_final);

            // Solution
            const int solutionBlockIndex = 0;
            finalSolution = x_bar_final_downcasted->getVectorBlock(solutionBlockIndex);

            // Sensitivity
            const int sensitivityBlockIndex = 1;
            const RCP<const Thyra::VectorBase<Scalar> > s_bar_final =
                x_bar_final_downcasted->getVectorBlock(sensitivityBlockIndex);
            {
                typedef Thyra::DefaultMultiVectorProductVector<Scalar> DMVPV;
                const RCP<const DMVPV> s_bar_final_downcasted = Teuchos::rcp_dynamic_cast<const DMVPV>(s_bar_final);

                dxdp = s_bar_final_downcasted->getMultiVector();
            }
        }

        Thyra::eval_g(
            *stateAndSensIntegratorAsModel,
            l, *state_ic.get_p(l),
            t_final,
            stateAndSensModelStateResponseIndex, x_bar_final.get()
        );

        *out
                << "\nx_bar_final = x_bar(p,t_final) evaluated using "
                << "stateAndSensIntegratorAsModel:\n"
                << Teuchos::describe(*x_bar_final,solnVerbLevel);

        if (Teuchos::nonnull(dgxdp_out)) {
            Thyra::assign(dgxdp_out.ptr(), *dxdp);
        }

        if (!dgdp_deriv_out.isEmpty()) {
            RCP<Thyra::DefaultAddedLinearOp<Scalar> > dgdp_op_out;
            {
                const RCP<Thyra::LinearOpBase<Scalar> > dgdp_op = dgdp_deriv_out.getLinearOp();
                if (Teuchos::nonnull(dgdp_op)) {
                    dgdp_op_out = Teuchos::rcp_dynamic_cast<Thyra::DefaultAddedLinearOp<Scalar> >(dgdp_op);
                    dgdp_op_out.assert_not_null();
                }
            }

            Thyra::ModelEvaluatorBase::InArgs<Scalar> modelInArgs = model->createInArgs();
            {
                modelInArgs.set_x(finalSolution);
                if (num_p > 0) {
                    modelInArgs.set_p(l, p_in);
                }
            }

            // require dgdx, dgdp from model
            Thyra::ModelEvaluatorBase::OutArgs<Scalar> modelOutArgs = model->createOutArgs();
            {
                const Thyra::ModelEvaluatorBase::Derivative<Scalar> dgdx_deriv(model->create_DgDx_op(j));
                modelOutArgs.set_DgDx(j, dgdx_deriv);

                Thyra::ModelEvaluatorBase::Derivative<Scalar> dgdp_deriv;
                if (Teuchos::nonnull(dgdp_op_out)) {
                    dgdp_deriv = model->create_DgDp_op(j, l);
                } else {
                    dgdp_deriv = dgdp_deriv_out;
                }
                modelOutArgs.set_DgDp(j, l, dgdp_deriv);
            }

            model->evalModel(modelInArgs, modelOutArgs);

            const RCP<const Thyra::LinearOpBase<Scalar> > dgdx =
                modelOutArgs.get_DgDx(j).getLinearOp();

            // dgdp_out = dgdp + <dgdx, dxdp>
            if (Teuchos::nonnull(dgdp_op_out)) {
                Teuchos::Array<RCP<const Thyra::LinearOpBase<Scalar> > > op_args(2);
                {
                    op_args[0] = modelOutArgs.get_DgDp(j, l).getLinearOp();
                    op_args[1] = Thyra::multiply<Scalar>(dgdx, dxdp);
                }
                dgdp_op_out->initialize(op_args);
            } else {
                const RCP<Thyra::MultiVectorBase<Scalar> > dgdp_mv_out = dgdp_deriv_out.getMultiVector();
                Thyra::apply(
                    *dgdx,
                    Thyra::NOTRANS,
                    *dxdp,
                    dgdp_mv_out.ptr(),
                    Teuchos::ScalarTraits<Scalar>::one(),
                    Teuchos::ScalarTraits<Scalar>::one());
            }
        }
    }

    *out << "\nF) Check the solution to the forward problem ...\n";

    // As post-processing step, calculate responses at final solution
    {
        Thyra::ModelEvaluatorBase::InArgs<Scalar> modelInArgs = model->createInArgs();
        {
            modelInArgs.set_x(finalSolution);
            if (num_p > 0) {
                modelInArgs.set_p(l, p_in);
            }
            if (num_p > 1) {  //JF added for multipoint
                modelInArgs.set_p(l+1, p_in2);
            }
            //Set time to be final time at which the solve occurs (< t_final in the case we don't make it to t_final).
            modelInArgs.set_t(fwdStateStepper->getTimeRange().lower());
        }

        Thyra::ModelEvaluatorBase::OutArgs<Scalar> modelOutArgs = model->createOutArgs();
        if (Teuchos::nonnull(g_out)) {
            Thyra::put_scalar(Teuchos::ScalarTraits<Scalar>::zero(), g_out.ptr());
            modelOutArgs.set_g(j, g_out);
        }

        model->evalModel(modelInArgs, modelOutArgs);
    }

    // Return the final solution as an additional g-vector, if requested
    if (Teuchos::nonnull(gx_out)) {
        Thyra::copy(*finalSolution, gx_out.ptr());
    }
}
void
Piro::LOCAAdaptiveSolver<Scalar>::evalModelImpl(
    const Thyra::ModelEvaluatorBase::InArgs<Scalar>& inArgs,
    const Thyra::ModelEvaluatorBase::OutArgs<Scalar>& outArgs) const
{
  const int l = 0; // TODO: Allow user to select parameter index
  const Teuchos::RCP<const Thyra::VectorBase<Scalar> > p_inargs = inArgs.get_p(l);

  // Forward parameter values to the LOCAAdaptive stepper
  {
    const Teuchos::RCP<const Thyra::VectorBase<Scalar> > p_inargs_or_nominal =
      Teuchos::nonnull(p_inargs) ? p_inargs : this->getNominalValues().get_p(l);
    const Thyra::ConstDetachedVectorView<Scalar> p_init_values(p_inargs_or_nominal);
    const Teuchos_Ordinal p_entry_count = p_init_values.subDim();
    TEUCHOS_ASSERT(p_entry_count == Teuchos::as<Teuchos_Ordinal>(paramVector_.length()));

    for (Teuchos_Ordinal k = 0; k < p_entry_count; ++k) {
      paramVector_[k] = p_init_values[k];
    }

//    solMgr_->getSolutionGroup()->setParams(paramVector_);
    Teuchos::rcp_dynamic_cast< ::Thyra::LOCAAdaptiveState >(solMgr_->getState())
                 ->getSolutionGroup()->setParams(paramVector_);
  }

  LOCA::Abstract::Iterator::IteratorStatus status;

  status = stepper_->run();

  if (status == LOCA::Abstract::Iterator::Finished) {
    utils_.out() << "Continuation Stepper Finished.\n";
  } else if (status == LOCA::Abstract::Iterator::NotFinished) {
    utils_.out() << "Continuation Stepper did not reach final value.\n";
  } else {
    utils_.out() << "Nonlinear solver failed to converge.\n";
    outArgs.setFailed();
  }

  // The time spent
  globalData_->locaUtils->out() << std::endl <<
    "#### Statistics ########" << std::endl;

  // Check number of steps
  int numSteps = stepper_->getStepNumber();
  globalData_->locaUtils->out() << std::endl <<
    " Number of continuation Steps = " << numSteps << std::endl;

  // Check number of failed steps
  int numFailedSteps = stepper_->getNumFailedSteps();
  globalData_->locaUtils->out() << std::endl <<
    " Number of failed continuation Steps = " << numFailedSteps << std::endl;

  globalData_->locaUtils->out() << std::endl;


  // Note: the last g is used to store the final solution. It can be null - if it is just
  // skip the store. If adaptation has occurred, g is not the correct size.

  const Teuchos::RCP<Thyra::VectorBase<Scalar> > x_outargs = outArgs.get_g(this->num_g());
  Teuchos::RCP<Thyra::VectorBase<Scalar> > x_final;

  int x_args_dim = 0;
  int f_sol_dim = 0;

  // Pardon the nasty cast to resize the last g in outArgs - need to fit the solution
  Thyra::ModelEvaluatorBase::OutArgs<Scalar>* mutable_outArgsPtr =
    const_cast<Thyra::ModelEvaluatorBase::OutArgs<Scalar>* >(&outArgs);

  if(Teuchos::nonnull(x_outargs)){ // g has been allocated, calculate the sizes of g and the solution

    x_args_dim = x_outargs->space()->dim();
//    f_sol_dim = solMgr_->getSolutionGroup()->getX().length();
    f_sol_dim = Teuchos::rcp_dynamic_cast< ::Thyra::LOCAAdaptiveState >(solMgr_->getState())
          ->getSolutionGroup()->getX().length();


  }

  if(Teuchos::is_null(x_outargs) || (x_args_dim != f_sol_dim)){ // g is not the right size

      x_final = Thyra::createMember(this->get_g_space(this->num_g()));

      mutable_outArgsPtr->set_g(this->num_g(), x_final);

  }
  else { // g is OK, use it
    x_final = x_outargs;
  }

  {
    // Deep copy final solution from LOCA group
    NOX::Thyra::Vector finalSolution(x_final);
//    finalSolution = solMgr_->getSolutionGroup()->getX();
    finalSolution = Teuchos::rcp_dynamic_cast< ::Thyra::LOCAAdaptiveState >(solMgr_->getState())
                      ->getSolutionGroup()->getX();

  }

  // If the arrays need resizing
  if(x_args_dim != f_sol_dim){

    const int parameterCount = this->Np();

    for (int pc = 0; pc < parameterCount; ++pc) {
      const Thyra::ModelEvaluatorBase::DerivativeSupport dgdp_support =
        outArgs.supports(Thyra::ModelEvaluatorBase::OUT_ARG_DgDp, this->num_g(), pc);
      const Thyra::ModelEvaluatorBase::EDerivativeMultiVectorOrientation dgdp_orient =
        Thyra::ModelEvaluatorBase::DERIV_MV_JACOBIAN_FORM;
      if (dgdp_support.supports(dgdp_orient)) {
        const Thyra::ModelEvaluatorBase::DerivativeMultiVector<Scalar> dgdp =
          Thyra::create_DgDp_mv(*this, this->num_g(), pc, dgdp_orient);
        mutable_outArgsPtr->set_DgDp(this->num_g(), pc, dgdp);
      }
    }
  }

  // Compute responses for the final solution
  {
    Thyra::ModelEvaluatorBase::InArgs<Scalar> modelInArgs =
      this->getModel().createInArgs();
    {
      modelInArgs.set_x(x_final);
      modelInArgs.set_p(l, p_inargs);
    }

    this->evalConvergedModel(modelInArgs, outArgs);

    // Save the final solution TODO: this needs to be redone

    Teuchos::RCP<Thyra::ModelEvaluatorBase::InArgs<Scalar> > fp
         = Teuchos::rcp_const_cast<Thyra::ModelEvaluatorBase::InArgs<Scalar> >(finalPoint_);
    Thyra::ModelEvaluatorBase::InArgsSetup<Scalar> ia;
    ia.setSupports(Thyra::ModelEvaluatorBase::IN_ARG_x, true);
    *fp = ia;
    fp->set_x(x_final);

  }
}
Ejemplo n.º 7
0
int main(int argc, char *argv[])
{
  // Create output stream. (Handy for multicore output.)
  auto out = Teuchos::VerboseObjectBase::getDefaultOStream();

  Teuchos::GlobalMPISession session(&argc, &argv, NULL);

  auto comm = Teuchos::DefaultComm<int>::getComm();

  // Wrap the whole code in a big try-catch-statement.
  bool success = true;
  try {
    // =========================================================================
    // Handle command line arguments.
    // Boost::program_options is somewhat more complete here (e.g. you can
    // specify options without the "--" syntax), but it isn't less complicated
    // to use. Stick with Teuchos for now.
    Teuchos::CommandLineProcessor myClp;

    myClp.setDocString(
      "Numerical parameter continuation for nonlinear Schr\"odinger equations.\n"
    );

    std::string xmlInputPath = "";
    myClp.setOption("xml-input-file", &xmlInputPath,
                    "XML file containing the parameter list", true );

    // Print warning for unrecognized arguments and make sure to throw an
    // exception if something went wrong.
    //myClp.throwExceptions(false);
    //myClp.recogniseAllOptions ( true );

    // Finally, parse the command line.
    myClp.parse(argc, argv);

    // Retrieve Piro parameter list from given file.
    std::shared_ptr<Teuchos::ParameterList> piroParams(
        new Teuchos::ParameterList()
        );
    Teuchos::updateParametersFromXmlFile(
        xmlInputPath,
        Teuchos::rcp(piroParams).ptr()
        );
    // =======================================================================
    // Extract the location of input and output files.
    const Teuchos::ParameterList outputList =
      piroParams->sublist("Output", true);

    // Set default directory to be the directory of the XML file itself
    const std::string xmlDirectory =
      xmlInputPath.substr(0, xmlInputPath.find_last_of( "/" ) + 1);

    // By default, take the current directory.
    std::string prefix = "./";
    if (!xmlDirectory.empty())
      prefix = xmlDirectory + "/";

    const std::string outputDirectory = prefix;

    const std::string contFilePath =
      prefix + outputList.get<std::string>("Continuation data file name");

    Teuchos::ParameterList & inputDataList = piroParams->sublist("Input", true);

    const std::string inputExodusFile =
      prefix + inputDataList.get<std::string>("File");
    const int step = inputDataList.get<int>("Initial Psi Step");

    //const bool useBordering = piroParams->get<bool>("Bordering");
    // =======================================================================
    // Read the data from the file.
    auto mesh = std::make_shared<Nosh::StkMesh>(
        Teuchos::get_shared_ptr(comm),
        inputExodusFile,
        step
        );

    // Cast the data into something more accessible.
    auto psi = mesh->getComplexVector("psi");
    //psi->Random();

    // Set the output directory for later plotting with this.
    std::stringstream outputFile;
    outputFile << outputDirectory << "/solution.e";
    mesh->openOutputChannel(outputFile.str());

    // Create a parameter map from the initial parameter values.
    Teuchos::ParameterList initialParameterValues =
      piroParams->sublist("Initial parameter values", true);

    // Check if we need to interpret the time value stored in the file
    // as a parameter.
    const std::string & timeName =
      piroParams->get<std::string>("Interpret time as", "");
    if (!timeName.empty()) {
      initialParameterValues.set(timeName, mesh->getTime());
    }

    // Explicitly set the initial parameter value for this list.
    const std::string & paramName =
      piroParams->sublist( "LOCA" )
      .sublist( "Stepper" )
      .get<std::string>("Continuation Parameter");
    *out << "Setting the initial parameter value of \""
         << paramName << "\" to " << initialParameterValues.get<double>(paramName) << "." << std::endl;
    piroParams->sublist( "LOCA" )
    .sublist( "Stepper" )
    .set("Initial Value", initialParameterValues.get<double>(paramName));

    // Set the thickness field.
    auto thickness = std::make_shared<Nosh::ScalarField::Constant>(*mesh, 1.0);

    // Some alternatives for the positive-definite operator.
    // (a) -\Delta (Laplace operator with Neumann boundary)
    //const std::shared_ptr<Nosh::ParameterMatrix::Virtual> matrixBuilder =
    //  rcp(new Nosh::ParameterMatrix::Laplace(mesh, thickness));

    // (b) (-i\nabla-A)^2 (Kinetic energy of a particle in magnetic field)
    // (b1) 'A' explicitly given in file.
    const double mu = initialParameterValues.get<double>("mu");
    auto mvp = std::make_shared<Nosh::VectorField::ExplicitValues>(*mesh, "A", mu);

    //const std::shared_ptr<Nosh::ParameterMatrix::Virtual> keoBuilder(
    //    new Nosh::ParameterMatrix::Keo(mesh, thickness, mvp)
    //    );
    //const std::shared_ptr<Nosh::ParameterMatrix::Virtual> DKeoDPBuilder(
    //    new Nosh::ParameterMatrix::DKeoDP(mesh, thickness, mvp, "mu")
    //    );

    // (b2) 'A' analytically given (here with constant curl).
    //      Optionally add a rotation axis u. This is important
    //      if continuation happens as a rotation of the vector
    //      field around an axis.
    //const std::shared_ptr<DoubleVector> b = rcp(new DoubleVector(3));
    //std::shared_ptr<Teuchos::SerialDenseVector<int,double> > u = Teuchos::null;
    //if ( piroParams->isSublist("Rotation vector") )
    //{
    //    u = rcp(new Teuchos::SerialDenseVector<int,double>(3));
    //    Teuchos::ParameterList & rotationVectorList =
    //        piroParams->sublist( "Rotation vector", false );
    //    (*u)[0] = rotationVectorList.get<double>("x");
    //    (*u)[1] = rotationVectorList.get<double>("y");
    //    (*u)[2] = rotationVectorList.get<double>("z");
    //}
    //std::shared_ptr<Nosh::VectorField::Virtual> mvp =
    //  rcp(new Nosh::VectorField::ConstantCurl(mesh, b, u));
    //const std::shared_ptr<Nosh::ParameterMatrix::Virtual> matrixBuilder =
    //  rcp(new Nosh::ParameterMatrix::Keo(mesh, thickness, mvp));
    // (b3) 'A' analytically given in a class you write yourself, derived
    //      from Nosh::ParameterMatrix::Virtual.
    // [...]
    //
    // Setup the scalar potential V.
    // (a) A constant potential.
    //std::shared_ptr<Nosh::ScalarField::Virtual> sp =
    //rcp(new Nosh::ScalarField::Constant(*mesh, -1.0));
    //const double T = initialParameterValues.get<double>("T");
    // (b) With explicit values.
    //std::shared_ptr<Nosh::ScalarField::Virtual> sp =
    //rcp(new Nosh::ScalarField::ExplicitValues(*mesh, "V"));
    // (c) One you built yourself by deriving from Nosh::ScalarField::Virtual.
    auto sp = std::make_shared<MyScalarField>(mesh);


    const double g = initialParameterValues.get<double>("g");
    // Finally, create the model evaluator.
    // This is the most important object in the whole stack.
    auto modelEvaluator = std::make_shared<Nosh::ModelEvaluator::Nls>(
        mesh,
        mvp,
        sp,
        g,
        thickness,
        psi,
        "mu"
        );

    // Build the Piro model evaluator. It's used to hook up with
    // several different backends (NOX, LOCA, Rhythmos,...).
    std::shared_ptr<Thyra::ModelEvaluator<double>> piro;

    // Declare the eigensaver; it will be used only for LOCA solvers, though.
    std::shared_ptr<Nosh::SaveEigenData> glEigenSaver;

    // Switch by solver type.
    std::string & solver = piroParams->get<std::string>("Piro Solver");

    if (solver == "NOX") {
      auto observer = std::make_shared<Nosh::Observer>(modelEvaluator);

      piro = std::make_shared<Piro::NOXSolver<double>>(
            Teuchos::rcp(piroParams),
            Teuchos::rcp(modelEvaluator),
            Teuchos::rcp(observer)
            );
    } else if (solver == "LOCA") {
      auto observer = std::make_shared<Nosh::Observer>(
          modelEvaluator,
          contFilePath,
          piroParams->sublist("LOCA")
          .sublist("Stepper")
          .get<std::string>("Continuation Parameter")
          );

      // Setup eigen saver.
#ifdef HAVE_LOCA_ANASAZI
      bool computeEigenvalues = piroParams->sublist( "LOCA" )
                                .sublist( "Stepper" )
                                .get<bool>("Compute Eigenvalues");
      if (computeEigenvalues) {
        Teuchos::ParameterList & eigenList = piroParams->sublist("LOCA")
                                             .sublist("Stepper")
                                             .sublist("Eigensolver");
        std::string eigenvaluesFilePath =
          xmlDirectory + "/" + outputList.get<std::string> ( "Eigenvalues file name" );

        glEigenSaver = std::make_shared<Nosh::SaveEigenData>(
            eigenList,
            modelEvaluator,
            eigenvaluesFilePath
            );

        std::shared_ptr<LOCA::SaveEigenData::AbstractStrategy>
          glSaveEigenDataStrategy = glEigenSaver;
        eigenList.set("Save Eigen Data Method",
                      "User-Defined");
        eigenList.set("User-Defined Save Eigen Data Name",
                      "glSaveEigenDataStrategy");
        eigenList.set("glSaveEigenDataStrategy",
                      glSaveEigenDataStrategy);
      }
#endif
      // Get the solver.
      std::shared_ptr<Piro::LOCASolver<double>> piroLOCASolver(
          new Piro::LOCASolver<double>(
            Teuchos::rcp(piroParams),
            Teuchos::rcp(modelEvaluator),
            Teuchos::null
            //Teuchos::rcp(observer)
            )
          );

//      // Get stepper and inject it into the eigensaver.
//      std::shared_ptr<LOCA::Stepper> stepper = Teuchos::get_shared_ptr(
//          piroLOCASolver->getLOCAStepperNonConst()
//          );
//#ifdef HAVE_LOCA_ANASAZI
//      if (computeEigenvalues)
//        glEigenSaver->setLocaStepper(stepper);
//#endif
      piro = piroLOCASolver;
    }
#if 0
    else if ( solver == "Turning Point" ) {
      std::shared_ptr<Nosh::Observer> observer;

      Teuchos::ParameterList & bifList =
        piroParams->sublist("LOCA").sublist("Bifurcation");

      // Fetch the (approximate) null state.
      auto nullstateZ = mesh->getVector("null");

      // Set the length normalization vector to be the initial null vector.
      TEUCHOS_ASSERT(nullstateZ);
      auto lengthNormVec = Teuchos::rcp(new NOX::Thyra::Vector(*nullstateZ));
      //lengthNormVec->init(1.0);
      bifList.set("Length Normalization Vector", lengthNormVec);

      // Set the initial null vector.
      auto initialNullAbstractVec =
        Teuchos::rcp(new NOX::Thyra::Vector(*nullstateZ));
      // initialNullAbstractVec->init(1.0);
      bifList.set("Initial Null Vector", initialNullAbstractVec);

      piro = std::make_shared<Piro::LOCASolver<double>>(
            Teuchos::rcp(piroParams),
            Teuchos::rcp(modelEvaluator),
            Teuchos::null
            //Teuchos::rcp(observer)
            );
    }
#endif
    else {
      TEUCHOS_TEST_FOR_EXCEPT_MSG(
          true,
          "Unknown solver type \"" << solver << "\"."
          );
    }
    // ----------------------------------------------------------------------

    // Now the setting of inputs and outputs.
    Thyra::ModelEvaluatorBase::InArgs<double> inArgs = piro->createInArgs();
    inArgs.set_p(
        0,
        piro->getNominalValues().get_p(0)
        );

    // Set output arguments to evalModel call.
    Thyra::ModelEvaluatorBase::OutArgs<double> outArgs = piro->createOutArgs();

    // Now solve the problem and return the responses.
    const Teuchos::RCP<Teuchos::Time> piroSolveTime =
      Teuchos::TimeMonitor::getNewTimer("Piro total solve time");;
    {
      Teuchos::TimeMonitor tm(*piroSolveTime);
      piro->evalModel(inArgs, outArgs);
    }

    // Manually release LOCA stepper.
#ifdef HAVE_LOCA_ANASAZI
    if (glEigenSaver)
      glEigenSaver->releaseLocaStepper();
#endif

    // Print timing data.
    Teuchos::TimeMonitor::summarize();
  } catch (Teuchos::CommandLineProcessor::HelpPrinted) {
  } catch (Teuchos::CommandLineProcessor::ParseError) {
  }
  TEUCHOS_STANDARD_CATCH_STATEMENTS(true, *out, success);

  return success ? EXIT_SUCCESS : EXIT_FAILURE;
}