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); } }
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()); } } }