void DefaultStateEliminationModelEvaluator<Scalar>::evalModelImpl(
  const ModelEvaluatorBase::InArgs<Scalar> &inArgs,
  const ModelEvaluatorBase::OutArgs<Scalar> &outArgs
  ) const
{
  typedef ModelEvaluatorBase MEB;
  using Teuchos::RCP;
  using Teuchos::rcp;
  using Teuchos::rcp_const_cast;
  using Teuchos::rcp_dynamic_cast;
  using Teuchos::OSTab;

  Teuchos::Time totalTimer(""), timer("");
  totalTimer.start(true);

  const Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
  const Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
  Teuchos::OSTab tab(out);
  if(out.get() && static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_LOW))
    *out << "\nEntering Thyra::DefaultStateEliminationModelEvaluator<Scalar>::evalModel(...) ...\n";

  const Teuchos::RCP<const ModelEvaluator<Scalar> >
    thyraModel = this->getUnderlyingModel();

  const int Np = outArgs.Np(), Ng = outArgs.Ng();

  // Get the intial state guess if not already gotten
  if (is_null(x_guess_solu_)) {
    const ModelEvaluatorBase::InArgs<Scalar>
      nominalValues = thyraModel->getNominalValues();
    if(nominalValues.get_x().get()) {
      x_guess_solu_ = nominalValues.get_x()->clone_v();
    }
    else {
      x_guess_solu_ = createMember(thyraModel->get_x_space());
      assign(&*x_guess_solu_,Scalar(0.0));
    }
  }

  // Reset the nominal values
  MEB::InArgs<Scalar> wrappedNominalValues = thyraModel->getNominalValues();
  wrappedNominalValues.setArgs(inArgs,true);
  wrappedNominalValues.set_x(x_guess_solu_);
  
  typedef Teuchos::VerboseObjectTempState<ModelEvaluatorBase> VOTSME;
  //VOTSME thyraModel_outputTempState(rcp(&wrappedThyraModel,false),out,verbLevel);

  typedef Teuchos::VerboseObjectTempState<NonlinearSolverBase<Scalar> > VOTSNSB;
  VOTSNSB statSolver_outputTempState(
    stateSolver_,out
    ,static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_LOW) ? Teuchos::VERB_LOW : Teuchos::VERB_NONE 
    );

  if(out.get() && static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_EXTREME))
    *out
      << "\ninArgs =\n" << Teuchos::describe(inArgs,verbLevel)
      << "\noutArgs on input =\n" << Teuchos::describe(outArgs,Teuchos::VERB_LOW);

  if(out.get() && static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_LOW))
    *out << "\nSolving f(x,...) for x ...\n";

  wrappedThyraModel_->setNominalValues(
    rcp(new MEB::InArgs<Scalar>(wrappedNominalValues))
    );
  
  SolveStatus<Scalar> solveStatus = stateSolver_->solve(&*x_guess_solu_,NULL);

  if( solveStatus.solveStatus == SOLVE_STATUS_CONVERGED ) {
    
    if(out.get() && static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_LOW))
      *out << "\nComputing the output functions at the solved state solution ...\n";

    MEB::InArgs<Scalar>   wrappedInArgs  = thyraModel->createInArgs();
    MEB::OutArgs<Scalar>  wrappedOutArgs = thyraModel->createOutArgs();
    wrappedInArgs.setArgs(inArgs,true);
    wrappedInArgs.set_x(x_guess_solu_);
    wrappedOutArgs.setArgs(outArgs,true);
    
    for( int l = 0; l < Np; ++l ) {
      for( int j = 0; j < Ng; ++j ) {
        if(
          outArgs.supports(MEB::OUT_ARG_DgDp,j,l).none()==false
          && outArgs.get_DgDp(j,l).isEmpty()==false
          )
        {
          // Set DfDp(l) and DgDx(j) to be computed!
          //wrappedOutArgs.set_DfDp(l,...);
          //wrappedOutArgs.set_DgDx(j,...);
          TEST_FOR_EXCEPT(true);
        }
      }
    }
    
    thyraModel->evalModel(wrappedInArgs,wrappedOutArgs);

    //
    // Compute DgDp(j,l) using direct sensitivties
    //
    for( int l = 0; l < Np; ++l ) {
      if(
        wrappedOutArgs.supports(MEB::OUT_ARG_DfDp,l).none()==false
        && wrappedOutArgs.get_DfDp(l).isEmpty()==false
        )
      {
        //
        // Compute:  D(l) = -inv(DfDx)*DfDp(l)
        //
        TEST_FOR_EXCEPT(true);
        for( int j = 0; j < Ng; ++j ) {
          if(
            outArgs.supports(MEB::OUT_ARG_DgDp,j,l).none()==false
            && outArgs.get_DgDp(j,l).isEmpty()==false
            )
          {
            //
            // Compute:  DgDp(j,l) = DgDp(j,l) + DgDx(j)*D
            //
            TEST_FOR_EXCEPT(true);
          }
        }
      }
    }
    // ToDo: Add a mode to compute DgDp(l) using adjoint sensitivities?
    
  }
  else {
    
    if(out.get() && static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_LOW))
      *out << "\nFailed to converge, returning NaNs ...\n";
    outArgs.setFailed();
    
  }
  
  if(out.get() && static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_EXTREME))
    *out
      << "\noutArgs on output =\n" << Teuchos::describe(outArgs,verbLevel);

  totalTimer.stop();
  if(out.get() && static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_LOW))
    *out
      << "\nTotal evaluation time = "<<totalTimer.totalElapsedTime()<<" sec\n"
      << "\nLeaving Thyra::DefaultStateEliminationModelEvaluator<Scalar>::evalModel(...) ...\n";
  
}
Exemplo n.º 2
0
void ModelEvaluatorDefaultBase<Scalar>::evalModel(
  const ModelEvaluatorBase::InArgs<Scalar> &inArgs,
  const ModelEvaluatorBase::OutArgs<Scalar> &outArgs
  ) const
{

  using Teuchos::outArg;
  typedef ModelEvaluatorBase MEB;

  lazyInitializeDefaultBase();

  const int l_Np = outArgs.Np();
  const int l_Ng = outArgs.Ng();

  //
  // A) Assert that the inArgs and outArgs object match this class!
  //

#ifdef TEUCHOS_DEBUG
  assertInArgsEvalObjects(*this,inArgs);
  assertOutArgsEvalObjects(*this,outArgs,&inArgs);
#endif  
  
  //
  // B) Setup the OutArgs object for the underlying implementation's
  // evalModelImpl(...) function
  //

  MEB::OutArgs<Scalar> outArgsImpl = this->createOutArgsImpl();
  Array<MultiVectorAdjointPair> DgDp_temp_adjoint_copies;

  {

    outArgsImpl.setArgs(outArgs,true);

    // DfDp(l)
    if (outArgsImpl.supports(MEB::OUT_ARG_f)) {
      for ( int l = 0; l < l_Np; ++l ) {
        const DefaultDerivLinearOpSupport defaultLinearOpSupport =
          DfDp_default_op_support_[l];
        if (defaultLinearOpSupport.provideDefaultLinearOp()) {
          outArgsImpl.set_DfDp( l,
            getOutArgImplForDefaultLinearOpSupport(
              outArgs.get_DfDp(l), defaultLinearOpSupport
              )
            );
        }
        else {
          // DfDp(l) already set by outArgsImpl.setArgs(...)!
        }
      }
    }

    // DgDx_dot(j)
    for ( int j = 0; j < l_Ng; ++j ) {
      const DefaultDerivLinearOpSupport defaultLinearOpSupport =
        DgDx_dot_default_op_support_[j];
      if (defaultLinearOpSupport.provideDefaultLinearOp()) {
        outArgsImpl.set_DgDx_dot( j,
          getOutArgImplForDefaultLinearOpSupport(
            outArgs.get_DgDx_dot(j), defaultLinearOpSupport
            )
          );
      }
      else {
        // DgDx_dot(j) already set by outArgsImpl.setArgs(...)!
      }
    }

    // DgDx(j)
    for ( int j = 0; j < l_Ng; ++j ) {
      const DefaultDerivLinearOpSupport defaultLinearOpSupport =
        DgDx_default_op_support_[j];
      if (defaultLinearOpSupport.provideDefaultLinearOp()) {
        outArgsImpl.set_DgDx( j,
          getOutArgImplForDefaultLinearOpSupport(
            outArgs.get_DgDx(j), defaultLinearOpSupport
            )
          );
      }
      else {
        // DgDx(j) already set by outArgsImpl.setArgs(...)!
      }
    }

    // DgDp(j,l)
    for ( int j = 0; j < l_Ng; ++j ) {
      const Array<DefaultDerivLinearOpSupport> &DgDp_default_op_support_j =
        DgDp_default_op_support_[j];
      const Array<DefaultDerivMvAdjointSupport> &DgDp_default_mv_support_j =
        DgDp_default_mv_support_[j];
      for ( int l = 0; l < l_Np; ++l ) {
        const DefaultDerivLinearOpSupport defaultLinearOpSupport =
          DgDp_default_op_support_j[l];
        const DefaultDerivMvAdjointSupport defaultMvAdjointSupport =
          DgDp_default_mv_support_j[l];
        MEB::Derivative<Scalar> DgDp_j_l;
        if (!outArgs.supports(MEB::OUT_ARG_DgDp,j,l).none())
          DgDp_j_l = outArgs.get_DgDp(j,l);
        if (
          defaultLinearOpSupport.provideDefaultLinearOp()
          && !is_null(DgDp_j_l.getLinearOp())
          )
        {
          outArgsImpl.set_DgDp( j, l,
            getOutArgImplForDefaultLinearOpSupport(
              DgDp_j_l, defaultLinearOpSupport
              )
            );
        }
        else if (
          defaultMvAdjointSupport.provideDefaultAdjoint()
          && !is_null(DgDp_j_l.getMultiVector())
          )
        {
          const RCP<MultiVectorBase<Scalar> > DgDp_j_l_mv = 
            DgDp_j_l.getMultiVector();
          if (
            defaultMvAdjointSupport.mvAdjointCopyOrientation()
            ==
            DgDp_j_l.getMultiVectorOrientation()
            )
          {
            // The orientation of the multi-vector is different so we need to
            // create a temporary copy to pass to evalModelImpl(...) and then
            // copy it back again!
            const RCP<MultiVectorBase<Scalar> > DgDp_j_l_mv_adj =
              createMembers(DgDp_j_l_mv->domain(), DgDp_j_l_mv->range()->dim());
            outArgsImpl.set_DgDp( j, l,
              MEB::Derivative<Scalar>(
                DgDp_j_l_mv_adj,
                getOtherDerivativeMultiVectorOrientation(
                  defaultMvAdjointSupport.mvAdjointCopyOrientation()
                  )
                )
              );
            // Remember these multi-vectors so that we can do the transpose copy
            // back after the evaluation!
            DgDp_temp_adjoint_copies.push_back(
              MultiVectorAdjointPair(DgDp_j_l_mv, DgDp_j_l_mv_adj)
              );
          }
          else {
            // The form of the multi-vector is supported by evalModelImpl(..)
            // and is already set on the outArgsImpl object.
          }
        }
        else {
          // DgDp(j,l) already set by outArgsImpl.setArgs(...)!
        }
      }
    }

    // W
    {
      RCP<LinearOpWithSolveBase<Scalar> > W;
      if ( default_W_support_ && !is_null(W=outArgs.get_W()) ) {
        const RCP<const LinearOpWithSolveFactoryBase<Scalar> >
          W_factory = this->get_W_factory();
        // Extract the underlying W_op object (if it exists)
        RCP<const LinearOpBase<Scalar> > W_op_const;
        uninitializeOp<Scalar>(*W_factory, W.ptr(), outArg(W_op_const));
        RCP<LinearOpBase<Scalar> > W_op;
        if (!is_null(W_op_const)) {
          // Here we remove the const.  This is perfectly safe since
          // w.r.t. this class, we put a non-const object in there and we can
          // expect to change that object after the fact.  That is our
          // prerogative.
          W_op = Teuchos::rcp_const_cast<LinearOpBase<Scalar> >(W_op_const);
        }
        else {
          // The W_op object has not been initialized yet so create it.  The
          // next time through, we should not have to do this!
          W_op = this->create_W_op();
        }
        outArgsImpl.set_W_op(W_op);
      }
    }
    
  }

  //
  // C) Evaluate the underlying model implementation!
  //

  this->evalModelImpl( inArgs, outArgsImpl );

  //
  // D) Post-process the output arguments
  //

  // Do explicit transposes for DgDp(j,l) if needed
  const int numMvAdjointCopies = DgDp_temp_adjoint_copies.size();
  for ( int adj_copy_i = 0; adj_copy_i < numMvAdjointCopies; ++adj_copy_i ) {
    const MultiVectorAdjointPair adjPair =
      DgDp_temp_adjoint_copies[adj_copy_i];
    doExplicitMultiVectorAdjoint( *adjPair.mvImplAdjoint, &*adjPair.mvOuter );
  }
  
  // Update W given W_op and W_factory
  {
    RCP<LinearOpWithSolveBase<Scalar> > W;
    if ( default_W_support_ && !is_null(W=outArgs.get_W()) ) {
      const RCP<const LinearOpWithSolveFactoryBase<Scalar> >
        W_factory = this->get_W_factory();
      W_factory->setOStream(this->getOStream());
      W_factory->setVerbLevel(this->getVerbLevel());
      initializeOp<Scalar>(*W_factory, outArgsImpl.get_W_op().getConst(), W.ptr());
    }
  }
  
}