void ExplicitModelEvaluator<Scalar>::
buildInverseMassMatrix() const
{
  typedef Thyra::ModelEvaluatorBase MEB;
  using Teuchos::RCP;
  using Thyra::createMember;
  
  RCP<const Thyra::ModelEvaluator<Scalar> > me = this->getUnderlyingModel();

  // first allocate space for the mass matrix
  RCP<Thyra::LinearOpBase<Scalar> > mass = me->create_W_op();

  // intialize a zero to get rid of the x-dot 
  if(zero_==Teuchos::null) {
    zero_ = Thyra::createMember(*me->get_x_space());
    Thyra::assign(zero_.ptr(),0.0);
  }
  
  // request only the mass matrix from the physics
  // Model evaluator builds: alpha*u_dot + beta*F(u) = 0
  MEB::InArgs<Scalar>  inArgs  = me->createInArgs();
  inArgs.set_x(createMember(me->get_x_space()));
  inArgs.set_x_dot(zero_);
  inArgs.set_alpha(-1.0);
  inArgs.set_beta(0.0);

  // set the one time beta to ensure dirichlet conditions
  // are correctly included in the mass matrix: do it for
  // both epetra and Tpetra. If a panzer model evaluator has
  // not been passed in...oh well you get what you asked for!
  if(panzerModel_!=Teuchos::null)
    panzerModel_->setOneTimeDirichletBeta(-1.0);
  else if(panzerEpetraModel_!=Teuchos::null)
    panzerEpetraModel_->setOneTimeDirichletBeta(-1.0);

  // set only the mass matrix
  MEB::OutArgs<Scalar> outArgs = me->createOutArgs();
  outArgs.set_W_op(mass);

  // this will fill the mass matrix operator 
  me->evalModel(inArgs,outArgs);

  if(!massLumping_) {
    invMassMatrix_ = Thyra::inverse<Scalar>(*me->get_W_factory(),mass);
  }
  else {
    // build lumped mass matrix (assumes all positive mass entries, does a simple sum)
    Teuchos::RCP<Thyra::VectorBase<Scalar> > ones = Thyra::createMember(*mass->domain());
    Thyra::assign(ones.ptr(),1.0);

    RCP<Thyra::VectorBase<Scalar> > invLumpMass = Thyra::createMember(*mass->range());
    Thyra::apply(*mass,Thyra::NOTRANS,*ones,invLumpMass.ptr());
    Thyra::reciprocal(*invLumpMass,invLumpMass.ptr());

    invMassMatrix_ = Thyra::diagonal(invLumpMass);
  }
}
void ForwardSensitivityExplicitModelEvaluator<Scalar>::computeDerivativeMatrices(
  const Thyra::ModelEvaluatorBase::InArgs<Scalar> &point
  ) const
{
  TEUCHOS_ASSERT( !is_null(stateModel_) );

  typedef Thyra::ModelEvaluatorBase MEB;
  typedef Teuchos::VerboseObjectTempState<MEB> VOTSME;

  Teuchos::RCP<Teuchos::FancyOStream> out = this->getOStream();
  Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();

  MEB::InArgs<Scalar> inArgs = stateBasePoint_;
  MEB::OutArgs<Scalar> outArgs = stateModel_->createOutArgs();
  
  if (is_null(DfDx_)) {
    DfDx_ = stateModel_->create_W_op();
  }
  if (inArgs.supports(MEB::IN_ARG_beta)) {
    inArgs.set_beta(1.0);
  }
  outArgs.set_W_op(DfDx_);

  if (is_null(DfDp_)) {
    DfDp_ = Thyra::create_DfDp_mv(
      *stateModel_,p_index_,
      MEB::DERIV_MV_BY_COL
      ).getMultiVector();
  }
  outArgs.set_DfDp(
    p_index_,
    MEB::Derivative<Scalar>(DfDp_,MEB::DERIV_MV_BY_COL)
    );
  
  VOTSME stateModel_outputTempState(stateModel_,out,verbLevel);
  stateModel_->evalModel(inArgs,outArgs);
  

}
void DiagonalImplicitRKModelEvaluator<Scalar>::evalModelImpl(
  const Thyra::ModelEvaluatorBase::InArgs<Scalar>& inArgs_stage,
  const Thyra::ModelEvaluatorBase::OutArgs<Scalar>& outArgs_stage
  ) const
{

  typedef ScalarTraits<Scalar> ST;
  typedef Thyra::ModelEvaluatorBase MEB;

  TEUCHOS_TEST_FOR_EXCEPTION( !isInitialized_, std::logic_error,
      "Error!  initializeDIRKModel must be called before evalModel\n"
      );

  TEUCHOS_TEST_FOR_EXCEPTION( !setTimeStepPointCalled_, std::logic_error,
      "Error!  setTimeStepPoint must be called before evalModel"
      );

  TEUCHOS_TEST_FOR_EXCEPTION( currentStage_ == -1, std::logic_error,
      "Error!  setCurrentStage must be called before evalModel"
      );

  THYRA_MODEL_EVALUATOR_DECORATOR_EVAL_MODEL_GEN_BEGIN(
    "Rythmos::DiagonalImplicitRKModelEvaluator",inArgs_stage,outArgs_stage,daeModel_
    );

  //
  // A) Unwrap the inArgs and outArgs 
  //

  const RCP<const Thyra::VectorBase<Scalar> > x_in = inArgs_stage.get_x();
  const RCP<Thyra::VectorBase<Scalar> > f_out = outArgs_stage.get_f();
  const RCP<Thyra::LinearOpBase<Scalar> > W_op_out = outArgs_stage.get_W_op();

  //
  // B) Assemble f_out and W_op_out for given stage
  //

  MEB::InArgs<Scalar> daeInArgs = daeModel_->createInArgs();
  MEB::OutArgs<Scalar> daeOutArgs = daeModel_->createOutArgs();
  const RCP<Thyra::VectorBase<Scalar> > x_i = createMember(daeModel_->get_x_space());
  daeInArgs.setArgs(basePoint_);
  
  // B.1) Setup the DAE's inArgs for stage f(currentStage_) ...
  V_V(stage_derivatives_->getNonconstVectorBlock(currentStage_).ptr(),*x_in);
  assembleIRKState( currentStage_, dirkButcherTableau_->A(), delta_t_, *x_old_, *stage_derivatives_, outArg(*x_i) );
  daeInArgs.set_x( x_i );
  daeInArgs.set_x_dot( x_in );
  daeInArgs.set_t( t_old_ + dirkButcherTableau_->c()(currentStage_) * delta_t_ );
  daeInArgs.set_alpha(ST::one());
  daeInArgs.set_beta( delta_t_ * dirkButcherTableau_->A()(currentStage_,currentStage_) );

  // B.2) Setup the DAE's outArgs for stage f(i) ...
  if (!is_null(f_out))
    daeOutArgs.set_f( f_out );
  if (!is_null(W_op_out))
    daeOutArgs.set_W_op(W_op_out);

  // B.3) Compute f_out(i) and/or W_op_out ...
  daeModel_->evalModel( daeInArgs, daeOutArgs );
  daeOutArgs.set_f(Teuchos::null);
  daeOutArgs.set_W_op(Teuchos::null);
  
  THYRA_MODEL_EVALUATOR_DECORATOR_EVAL_MODEL_END();
  
}
void DefaultModelEvaluatorWithSolveFactory<Scalar>::evalModelImpl(
  const ModelEvaluatorBase::InArgs<Scalar> &inArgs,
  const ModelEvaluatorBase::OutArgs<Scalar> &outArgs
  ) const
{
  typedef ModelEvaluatorBase MEB;
  using Teuchos::rcp;
  using Teuchos::rcp_const_cast;
  using Teuchos::rcp_dynamic_cast;
  using Teuchos::OSTab;

  THYRA_MODEL_EVALUATOR_DECORATOR_EVAL_MODEL_BEGIN(
    "Thyra::DefaultModelEvaluatorWithSolveFactory",inArgs,outArgs
    );

  Teuchos::Time timer("");

  typedef Teuchos::VerboseObjectTempState<LinearOpWithSolveFactoryBase<Scalar> >
    VOTSLOWSF;
  VOTSLOWSF W_factory_outputTempState(W_factory_,out,verbLevel);

  // InArgs

  MEB::InArgs<Scalar> wrappedInArgs = thyraModel->createInArgs();

  wrappedInArgs.setArgs(inArgs,true);

  // OutArgs

  MEB::OutArgs<Scalar> wrappedOutArgs = thyraModel->createOutArgs();

  wrappedOutArgs.setArgs(outArgs,true);

  RCP<LinearOpWithSolveBase<Scalar> > W;
  RCP<const LinearOpBase<Scalar> > fwdW;
  if( outArgs.supports(MEB::OUT_ARG_W) && (W = outArgs.get_W()).get() ) {
    Thyra::uninitializeOp<Scalar>(*W_factory_, W.ptr(), outArg(fwdW));

    {
      // Handle this case later if we need to!
      const bool both_W_and_W_op_requested = nonnull(outArgs.get_W_op());
      TEUCHOS_TEST_FOR_EXCEPT(both_W_and_W_op_requested);
    }

    RCP<LinearOpBase<Scalar> > nonconst_fwdW;
    if(fwdW.get()) {
      nonconst_fwdW = rcp_const_cast<LinearOpBase<Scalar> >(fwdW);
    }
    else {
      nonconst_fwdW = thyraModel->create_W_op();
      fwdW = nonconst_fwdW;
    }

    wrappedOutArgs.set_W_op(nonconst_fwdW);
  }

  // Do the evaluation

  if(out.get() && includesVerbLevel(verbLevel,Teuchos::VERB_LOW))
    *out << "\nEvaluating the output functions on model \'"
         << thyraModel->description() << "\' ...\n";
  timer.start(true);

  thyraModel->evalModel(wrappedInArgs,wrappedOutArgs);

  timer.stop();
  if(out.get() && includesVerbLevel(verbLevel,Teuchos::VERB_LOW))
    OSTab(out).o() << "\nTime to evaluate underlying model = "
                   << timer.totalElapsedTime()<<" sec\n";

  // Postprocess arguments

  if(out.get() && includesVerbLevel(verbLevel,Teuchos::VERB_LOW))
    *out << "\nPost processing the output objects ...\n";
  timer.start(true);

  if( W.get() ) {
    Thyra::initializeOp<Scalar>(*W_factory_, fwdW, W.ptr());
    W->setVerbLevel(this->getVerbLevel());
    W->setOStream(this->getOStream());
  }

  timer.stop();
  if(out.get() && includesVerbLevel(verbLevel,Teuchos::VERB_LOW))
    OSTab(out).o() << "\nTime to process output objects = "
                   << timer.totalElapsedTime()<<" sec\n";

  THYRA_MODEL_EVALUATOR_DECORATOR_EVAL_MODEL_END();

}
void TimeDiscretizedBackwardEulerModelEvaluator<Scalar>::evalModelImpl(
  const Thyra::ModelEvaluatorBase::InArgs<Scalar>& inArgs_bar,
  const Thyra::ModelEvaluatorBase::OutArgs<Scalar>& outArgs_bar
  ) const
{


  using Teuchos::rcp_dynamic_cast;
  typedef ScalarTraits<Scalar> ST;
  typedef Thyra::ModelEvaluatorBase MEB;
  typedef Thyra::VectorBase<Scalar> VB;
  typedef Thyra::ProductVectorBase<Scalar> PVB;
  typedef Thyra::BlockedLinearOpBase<Scalar> BLWB;

/*
  THYRA_MODEL_EVALUATOR_DECORATOR_EVAL_MODEL_GEN_BEGIN(
    "Rythmos::ImplicitRKModelEvaluator",inArgs_bar,outArgs_bar,daeModel_
    );
*/

  TEST_FOR_EXCEPTION( delta_t_ <= 0.0, std::logic_error,
    "Error, you have not initialized this object correctly!" );

  //
  // A) Unwrap the inArgs and outArgs to get at product vectors and block op
  //

  const RCP<const PVB> x_bar = rcp_dynamic_cast<const PVB>(inArgs_bar.get_x(), true);
  const RCP<PVB> f_bar = rcp_dynamic_cast<PVB>(outArgs_bar.get_f(), true);
  RCP<BLWB> W_op_bar = rcp_dynamic_cast<BLWB>(outArgs_bar.get_W_op(), true);

  //
  // B) Assemble f_bar and W_op_bar by looping over stages
  //

  MEB::InArgs<Scalar> daeInArgs = daeModel_->createInArgs();
  MEB::OutArgs<Scalar> daeOutArgs = daeModel_->createOutArgs();
  const RCP<VB> x_dot_i = createMember(daeModel_->get_x_space());
  daeInArgs.setArgs(initCond_);
  
  Scalar t_i = initTime_; // ToDo: Define t_init!

  const Scalar oneOverDeltaT = 1.0/delta_t_;

  for ( int i = 0; i < numTimeSteps_; ++i ) {

    // B.1) Setup the DAE's inArgs for time step eqn f(i) ...
    const RCP<const Thyra::VectorBase<Scalar> >
      x_i = x_bar->getVectorBlock(i),
      x_im1 = ( i==0 ? initCond_.get_x() : x_bar->getVectorBlock(i-1) );
    V_VmV( x_dot_i.ptr(), *x_i, *x_im1 ); // x_dot_i = 1/dt * ( x[i] - x[i-1] )
    Vt_S( x_dot_i.ptr(), oneOverDeltaT ); // ... 
    daeInArgs.set_x_dot( x_dot_i );
    daeInArgs.set_x( x_i );
    daeInArgs.set_t( t_i );
    daeInArgs.set_alpha( oneOverDeltaT );
    daeInArgs.set_beta( 1.0 );

    // B.2) Setup the DAE's outArgs for f(i) and/or W(i,i) ...
    if (!is_null(f_bar))
      daeOutArgs.set_f( f_bar->getNonconstVectorBlock(i) );
    if (!is_null(W_op_bar))
      daeOutArgs.set_W_op(W_op_bar->getNonconstBlock(i,i).assert_not_null());

    // B.3) Compute f_bar(i) and/or W_op_bar(i,i) ...
    daeModel_->evalModel( daeInArgs, daeOutArgs );
    daeOutArgs.set_f(Teuchos::null);
    daeOutArgs.set_W_op(Teuchos::null);
    
    // B.4) Evaluate W_op_bar(i,i-1)
    if ( !is_null(W_op_bar) && i > 0 ) {
      daeInArgs.set_alpha( -oneOverDeltaT );
      daeInArgs.set_beta( 0.0 );
      daeOutArgs.set_W_op(W_op_bar->getNonconstBlock(i,i-1).assert_not_null());
      daeModel_->evalModel( daeInArgs, daeOutArgs );
      daeOutArgs.set_W_op(Teuchos::null);
    }

    //
    t_i += delta_t_;

  }

/*  
  THYRA_MODEL_EVALUATOR_DECORATOR_EVAL_MODEL_END();
*/

}
void ImplicitRKModelEvaluator<Scalar>::evalModelImpl(
  const Thyra::ModelEvaluatorBase::InArgs<Scalar>& inArgs_bar,
  const Thyra::ModelEvaluatorBase::OutArgs<Scalar>& outArgs_bar
  ) const
{

  using Teuchos::rcp_dynamic_cast;
  typedef ScalarTraits<Scalar> ST;
  typedef Thyra::ModelEvaluatorBase MEB;
  typedef Thyra::VectorBase<Scalar> VB;
  typedef Thyra::ProductVectorBase<Scalar> PVB;
  typedef Thyra::BlockedLinearOpBase<Scalar> BLWB;

  TEST_FOR_EXCEPTION( !isInitialized_, std::logic_error,
      "Error!  initializeIRKModel must be called before evalModel\n"
      );

  TEST_FOR_EXCEPTION( !setTimeStepPointCalled_, std::logic_error,
      "Error!  setTimeStepPoint must be called before evalModel"
      );

  THYRA_MODEL_EVALUATOR_DECORATOR_EVAL_MODEL_GEN_BEGIN(
    "Rythmos::ImplicitRKModelEvaluator",inArgs_bar,outArgs_bar,daeModel_
    );

  //
  // A) Unwrap the inArgs and outArgs to get at product vectors and block op
  //

  const RCP<const PVB> x_bar = rcp_dynamic_cast<const PVB>(inArgs_bar.get_x(), true);
  const RCP<PVB> f_bar = rcp_dynamic_cast<PVB>(outArgs_bar.get_f(), true);
  const RCP<BLWB> W_op_bar = rcp_dynamic_cast<BLWB>(outArgs_bar.get_W_op(), true);

  //
  // B) Assemble f_bar and W_op_bar by looping over stages
  //

  MEB::InArgs<Scalar> daeInArgs = daeModel_->createInArgs();
  MEB::OutArgs<Scalar> daeOutArgs = daeModel_->createOutArgs();
  const RCP<VB> x_i = createMember(daeModel_->get_x_space());
  daeInArgs.setArgs(basePoint_);
  
  const int numStages = irkButcherTableau_->numStages();

  for ( int i = 0; i < numStages; ++i ) {

    // B.1) Setup the DAE's inArgs for stage f(i) ...
    assembleIRKState( i, irkButcherTableau_->A(), delta_t_, *x_old_, *x_bar, outArg(*x_i) );
    daeInArgs.set_x( x_i );
    daeInArgs.set_x_dot( x_bar->getVectorBlock(i) );
    daeInArgs.set_t( t_old_ + irkButcherTableau_->c()(i) * delta_t_ );
    Scalar alpha = ST::zero();
    if (i == 0) {
      alpha = ST::one();
    } else {
      alpha = ST::zero();
    }
    Scalar beta = delta_t_ * irkButcherTableau_->A()(i,0);
    daeInArgs.set_alpha( alpha );
    daeInArgs.set_beta( beta );

    // B.2) Setup the DAE's outArgs for stage f(i) ...
    if (!is_null(f_bar))
      daeOutArgs.set_f( f_bar->getNonconstVectorBlock(i) );
    if (!is_null(W_op_bar)) {
      daeOutArgs.set_W_op(W_op_bar->getNonconstBlock(i,0));
    }

    // B.3) Compute f_bar(i) and/or W_op_bar(i,0) ...
    daeModel_->evalModel( daeInArgs, daeOutArgs );
    daeOutArgs.set_f(Teuchos::null);
    daeOutArgs.set_W_op(Teuchos::null);
    
    // B.4) Evaluate the rest of the W_op_bar(i,j=1...numStages-1) ...
    if (!is_null(W_op_bar)) {
      for ( int j = 1; j < numStages; ++j ) {
        alpha = ST::zero();
        if (i == j) {
          alpha = ST::one();
        } else {
          alpha = ST::zero();
        }
        beta = delta_t_ * irkButcherTableau_->A()(i,j);
        daeInArgs.set_alpha( alpha );
        daeInArgs.set_beta( beta );
        daeOutArgs.set_W_op(W_op_bar->getNonconstBlock(i,j));
        daeModel_->evalModel( daeInArgs, daeOutArgs );
        daeOutArgs.set_W_op(Teuchos::null);
      }
    }

  }
  
  THYRA_MODEL_EVALUATOR_DECORATOR_EVAL_MODEL_END();
  
}
Exemplo n.º 7
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());
    }
  }
  
}