30 const Teuchos::RCP<const Teuchos::ParameterList>& pList,
31 const Teuchos::RCP<MultiVector>& dxdp_init,
32 const Teuchos::RCP<MultiVector>& dx_dotdp_init,
33 const Teuchos::RCP<MultiVector>& dx_dotdotdp_init)
35 sens_residual_model_(sens_residual_model),
36 sens_solve_model_(sens_solve_model),
37 dxdp_init_(dxdp_init),
38 dx_dotdp_init_(dx_dotdp_init),
39 dx_dotdotdp_init_(dx_dotdotdp_init),
43 xdot_tangent_index_(2),
44 xdotdot_tangent_index_(3),
45 use_dfdp_as_tangent_(false),
46 use_dgdp_as_tangent_(false),
51 typedef Thyra::ModelEvaluatorBase MEB;
54 Teuchos::RCP<Teuchos::ParameterList> pl =
55 Teuchos::rcp(
new Teuchos::ParameterList);
56 if (pList != Teuchos::null) *pl = *pList;
60 p_index_ = pl->get<
int>(
"Sensitivity Parameter Index");
61 g_index_ = pl->get<
int>(
"Response Function Index");
84 MEB::InArgs<Scalar> me_inArgs =
model_->createInArgs();
88 MEB::InArgsSetup<Scalar> inArgs;
89 inArgs.setModelEvalDescription(this->description());
90 inArgs.setSupports(MEB::IN_ARG_x);
91 if (me_inArgs.supports(MEB::IN_ARG_x_dot))
92 inArgs.setSupports(MEB::IN_ARG_x_dot);
93 if (me_inArgs.supports(MEB::IN_ARG_t)) inArgs.setSupports(MEB::IN_ARG_t);
94 if (me_inArgs.supports(MEB::IN_ARG_alpha))
95 inArgs.setSupports(MEB::IN_ARG_alpha);
96 if (me_inArgs.supports(MEB::IN_ARG_beta))
97 inArgs.setSupports(MEB::IN_ARG_beta);
98 if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
99 inArgs.setSupports(MEB::IN_ARG_W_x_dot_dot_coeff);
102 inArgs.set_Np(me_inArgs.Np());
105 MEB::OutArgs<Scalar> me_outArgs =
model_->createOutArgs();
108 MEB::OutArgsSetup<Scalar> outArgs;
109 outArgs.setModelEvalDescription(this->description());
110 outArgs.set_Np_Ng(me_outArgs.Np(), me_outArgs.Ng() +
g_offset_);
111 outArgs.setSupports(MEB::OUT_ARG_f);
112 if (sens_mer_outArgs.supports(MEB::OUT_ARG_W_op) ||
113 sens_mes_outArgs.supports(MEB::OUT_ARG_W_op))
114 outArgs.setSupports(MEB::OUT_ARG_W_op);
118 for (
int j = 0; j < me_outArgs.Ng(); ++j) {
119 outArgs.setSupports(MEB::OUT_ARG_DgDx_dot, j +
g_offset_,
120 me_outArgs.supports(MEB::OUT_ARG_DgDx_dot, j));
121 outArgs.setSupports(MEB::OUT_ARG_DgDx, j +
g_offset_,
122 me_outArgs.supports(MEB::OUT_ARG_DgDx, j));
123 for (
int l = 0; l < me_outArgs.Np(); ++l) {
124 outArgs.setSupports(MEB::OUT_ARG_DgDp, j +
g_offset_, l,
125 me_outArgs.supports(MEB::OUT_ARG_DgDp, j, l));
132 TEUCHOS_ASSERT(me_inArgs.supports(MEB::IN_ARG_x));
134 TEUCHOS_ASSERT(sens_mer_outArgs.supports(MEB::OUT_ARG_W_op));
135 if (me_inArgs.supports(MEB::IN_ARG_x_dot)) {
136 TEUCHOS_ASSERT(me_inArgs.supports(MEB::IN_ARG_alpha));
137 TEUCHOS_ASSERT(me_inArgs.supports(MEB::IN_ARG_beta));
139 TEUCHOS_ASSERT(me_outArgs.supports(MEB::OUT_ARG_DfDp,
p_index_)
140 .supports(MEB::DERIV_MV_JACOBIAN_FORM));
257 typedef Thyra::ModelEvaluatorBase MEB;
258 typedef Thyra::DefaultMultiVectorProductVector<Scalar> DMVPV;
259 using Teuchos::Range1D;
261 using Teuchos::rcp_dynamic_cast;
263 MEB::InArgs<Scalar> me_nominal = model_->getNominalValues();
264 MEB::InArgs<Scalar> nominal = this->createInArgs();
266 const Teuchos::Range1D rng(1, num_param_);
267 const Scalar zero = Teuchos::ScalarTraits<Scalar>::zero();
270 RCP<const Thyra::VectorBase<Scalar> > me_x = me_nominal.get_x();
271 if (me_x != Teuchos::null) {
272 RCP<Thyra::VectorBase<Scalar> > x = Thyra::createMember(*x_dxdp_space_);
273 RCP<DMVPV> x_dxdp = rcp_dynamic_cast<DMVPV>(x,
true);
274 Thyra::assign(x_dxdp->getNonconstMultiVector()->col(0).ptr(), *me_x);
275 if (dxdp_init_ == Teuchos::null)
276 Thyra::assign(x_dxdp->getNonconstMultiVector()->subView(rng).ptr(), zero);
278 Thyra::assign(x_dxdp->getNonconstMultiVector()->subView(rng).ptr(),
284 RCP<const Thyra::VectorBase<Scalar> > me_xdot;
285 if (me_nominal.supports(MEB::IN_ARG_x_dot)) me_xdot = me_nominal.get_x_dot();
286 if (me_xdot != Teuchos::null) {
287 RCP<Thyra::VectorBase<Scalar> > xdot = Thyra::createMember(*x_dxdp_space_);
288 RCP<DMVPV> xdot_dxdp = rcp_dynamic_cast<DMVPV>(xdot,
true);
289 Thyra::assign(xdot_dxdp->getNonconstMultiVector()->col(0).ptr(), *me_xdot);
290 if (dx_dotdp_init_ == Teuchos::null)
291 Thyra::assign(xdot_dxdp->getNonconstMultiVector()->subView(rng).ptr(),
294 Thyra::assign(xdot_dxdp->getNonconstMultiVector()->subView(rng).ptr(),
296 nominal.set_x_dot(xdot);
301 RCP<const Thyra::VectorBase<Scalar> > me_xdotdot;
302 if (me_nominal.supports(MEB::IN_ARG_x_dot_dot))
303 me_xdotdot = me_nominal.get_x_dot_dot();
304 if (me_xdotdot != Teuchos::null) {
305 RCP<Thyra::VectorBase<Scalar> > xdotdot =
306 Thyra::createMember(*x_dxdp_space_);
307 RCP<DMVPV> xdotdot_dxdp = rcp_dynamic_cast<DMVPV>(xdotdot,
true);
308 Thyra::assign(xdotdot_dxdp->getNonconstMultiVector()->col(0).ptr(),
310 if (dx_dotdotdp_init_ == Teuchos::null)
311 Thyra::assign(xdotdot_dxdp->getNonconstMultiVector()->subView(rng).ptr(),
314 Thyra::assign(xdotdot_dxdp->getNonconstMultiVector()->subView(rng).ptr(),
316 nominal.set_x_dot_dot(xdotdot);
319 const int np = model_->Np();
320 for (
int i = 0; i < np; ++i) nominal.set_p(i, me_nominal.get_p(i));
334 const Thyra::ModelEvaluatorBase::InArgs<Scalar>& inArgs,
335 const Thyra::ModelEvaluatorBase::OutArgs<Scalar>& outArgs)
const
337 typedef Thyra::ModelEvaluatorBase MEB;
338 typedef Thyra::DefaultMultiVectorProductVector<Scalar> DMVPV;
339 using Teuchos::Range1D;
341 using Teuchos::rcp_dynamic_cast;
343 const bool use_tangent = use_dfdp_as_tangent_ || use_dgdp_as_tangent_;
346 RCP<const Thyra::VectorBase<Scalar> > x, xdot, xdotdot;
347 RCP<const Thyra::MultiVectorBase<Scalar> > dxdp, dxdotdp, dxdotdotdp;
348 RCP<const Thyra::VectorBase<Scalar> > dxdp_vec, dxdotdp_vec, dxdotdotdp_vec;
349 MEB::InArgs<Scalar> me_inArgs = model_->getNominalValues();
350 RCP<const DMVPV> x_dxdp = rcp_dynamic_cast<const DMVPV>(inArgs.get_x(),
true);
351 x = x_dxdp->getMultiVector()->col(0);
352 dxdp = x_dxdp->getMultiVector()->subView(Range1D(1, num_param_));
355 dxdp_vec = Thyra::multiVectorProductVector(dxdp_space_, dxdp);
356 if (use_dfdp_as_tangent_) me_inArgs.set_p(x_tangent_index_, dxdp_vec);
358 if (me_inArgs.supports(MEB::IN_ARG_x_dot)) {
359 if (inArgs.get_x_dot() != Teuchos::null) {
360 RCP<const DMVPV> xdot_dxdotdp =
361 rcp_dynamic_cast<const DMVPV>(inArgs.get_x_dot(),
true);
362 xdot = xdot_dxdotdp->getMultiVector()->col(0);
363 dxdotdp = xdot_dxdotdp->getMultiVector()->subView(Range1D(1, num_param_));
364 me_inArgs.set_x_dot(xdot);
366 dxdotdp_vec = Thyra::multiVectorProductVector(dxdp_space_, dxdotdp);
367 if (use_dfdp_as_tangent_)
368 me_inArgs.set_p(xdot_tangent_index_, dxdotdp_vec);
372 me_inArgs.set_x_dot(Teuchos::null);
374 if (me_inArgs.supports(MEB::IN_ARG_x_dot_dot)) {
375 if (inArgs.get_x_dot_dot() != Teuchos::null) {
376 RCP<const DMVPV> xdotdot_dxdotdotdp =
377 rcp_dynamic_cast<const DMVPV>(inArgs.get_x_dot_dot(),
true);
378 xdotdot = xdotdot_dxdotdotdp->getMultiVector()->col(0);
380 xdotdot_dxdotdotdp->getMultiVector()->subView(Range1D(1, num_param_));
381 me_inArgs.set_x_dot_dot(xdotdot);
384 Thyra::multiVectorProductVector(dxdp_space_, dxdotdotdp);
385 if (use_dfdp_as_tangent_)
386 me_inArgs.set_p(xdotdot_tangent_index_, dxdotdotdp_vec);
390 me_inArgs.set_x_dot_dot(Teuchos::null);
392 if (me_inArgs.supports(MEB::IN_ARG_t)) me_inArgs.set_t(inArgs.get_t());
393 if (me_inArgs.supports(MEB::IN_ARG_alpha))
394 me_inArgs.set_alpha(inArgs.get_alpha());
395 if (me_inArgs.supports(MEB::IN_ARG_beta))
396 me_inArgs.set_beta(inArgs.get_beta());
397 if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
398 me_inArgs.set_W_x_dot_dot_coeff(inArgs.get_W_x_dot_dot_coeff());
403 const int np = me_inArgs.Np();
404 for (
int i = 0; i < np; ++i) {
405 if (inArgs.get_p(i) != Teuchos::null)
407 (use_tangent && i != x_tangent_index_ && i != xdot_tangent_index_ &&
408 i != xdotdot_tangent_index_))
409 me_inArgs.set_p(i, inArgs.get_p(i));
413 RCP<Thyra::VectorBase<Scalar> > f;
414 RCP<Thyra::MultiVectorBase<Scalar> > dfdp;
415 MEB::OutArgs<Scalar> me_outArgs = model_->createOutArgs();
416 if (outArgs.get_f() != Teuchos::null) {
417 RCP<DMVPV> f_dfdp = rcp_dynamic_cast<DMVPV>(outArgs.get_f(),
true);
418 f = f_dfdp->getNonconstMultiVector()->col(0);
419 dfdp = f_dfdp->getNonconstMultiVector()->subView(Range1D(1, num_param_));
421 me_outArgs.set_DfDp(p_index_, dfdp);
423 if (outArgs.supports(MEB::OUT_ARG_W_op) &&
424 outArgs.get_W_op() != Teuchos::null &&
425 model_.ptr() == sens_solve_model_.ptr()) {
426 RCP<Thyra::LinearOpBase<Scalar> > op = outArgs.get_W_op();
427 RCP<Thyra::MultiVectorLinearOp<Scalar> > mv_op =
428 rcp_dynamic_cast<Thyra::MultiVectorLinearOp<Scalar> >(op,
true);
429 me_outArgs.set_W_op(mv_op->getNonconstLinearOp());
431 for (
int j = g_offset_; j < outArgs.Ng(); ++j) {
432 if (!me_outArgs.supports(MEB::OUT_ARG_DgDx_dot, j - g_offset_).none())
433 me_outArgs.set_DgDx_dot(j - g_offset_, outArgs.get_DgDx_dot(j));
434 if (!me_outArgs.supports(MEB::OUT_ARG_DgDx, j - g_offset_).none())
435 me_outArgs.set_DgDx(j - g_offset_, outArgs.get_DgDx(j));
436 for (
int l = 0; l < outArgs.Np(); ++l)
437 if (!me_outArgs.supports(MEB::OUT_ARG_DgDp, j - g_offset_, l).none())
438 me_outArgs.set_DgDp(j - g_offset_, l, outArgs.get_DgDp(j, l));
440 if (g_index_ >= 0 && outArgs.get_g(1) != Teuchos::null)
441 me_outArgs.set_g(g_index_, outArgs.get_g(1));
444 model_->evalModel(me_inArgs, me_outArgs);
447 if (outArgs.supports(MEB::OUT_ARG_W_op) &&
448 outArgs.get_W_op() != Teuchos::null &&
449 model_.ptr() != sens_solve_model_.ptr()) {
450 MEB::OutArgs<Scalar> sens_me_outArgs = sens_solve_model_->createOutArgs();
451 RCP<Thyra::LinearOpBase<Scalar> > op = outArgs.get_W_op();
452 RCP<Thyra::MultiVectorLinearOp<Scalar> > mv_op =
453 rcp_dynamic_cast<Thyra::MultiVectorLinearOp<Scalar> >(op,
true);
454 sens_me_outArgs.set_W_op(mv_op->getNonconstLinearOp());
455 sens_solve_model_->evalModel(me_inArgs, sens_me_outArgs);
461 if (!use_dfdp_as_tangent_) {
462 if (dxdp != Teuchos::null && dfdp != Teuchos::null) {
463 if (my_dfdx_ == Teuchos::null)
464 my_dfdx_ = sens_residual_model_->create_W_op();
465 MEB::OutArgs<Scalar> meo = sens_residual_model_->createOutArgs();
466 meo.set_W_op(my_dfdx_);
467 if (me_inArgs.supports(MEB::IN_ARG_alpha)) me_inArgs.set_alpha(0.0);
468 if (me_inArgs.supports(MEB::IN_ARG_beta)) me_inArgs.set_beta(1.0);
469 if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
470 me_inArgs.set_W_x_dot_dot_coeff(0.0);
471 sens_residual_model_->evalModel(me_inArgs, meo);
472 my_dfdx_->apply(Thyra::NOTRANS, *dxdp, dfdp.ptr(), Scalar(1.0),
475 if (dxdotdp != Teuchos::null && dfdp != Teuchos::null) {
476 if (my_dfdxdot_ == Teuchos::null)
477 my_dfdxdot_ = sens_residual_model_->create_W_op();
478 MEB::OutArgs<Scalar> meo = sens_residual_model_->createOutArgs();
479 meo.set_W_op(my_dfdxdot_);
480 if (me_inArgs.supports(MEB::IN_ARG_alpha)) me_inArgs.set_alpha(1.0);
481 if (me_inArgs.supports(MEB::IN_ARG_beta)) me_inArgs.set_beta(0.0);
482 if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
483 me_inArgs.set_W_x_dot_dot_coeff(0.0);
484 sens_residual_model_->evalModel(me_inArgs, meo);
485 my_dfdxdot_->apply(Thyra::NOTRANS, *dxdotdp, dfdp.ptr(), Scalar(1.0),
488 if (dxdotdotdp != Teuchos::null && dfdp != Teuchos::null) {
489 if (my_dfdxdotdot_ == Teuchos::null)
490 my_dfdxdotdot_ = sens_residual_model_->create_W_op();
491 MEB::OutArgs<Scalar> meo = sens_residual_model_->createOutArgs();
492 meo.set_W_op(my_dfdxdotdot_);
493 if (me_inArgs.supports(MEB::IN_ARG_alpha)) me_inArgs.set_alpha(0.0);
494 if (me_inArgs.supports(MEB::IN_ARG_beta)) me_inArgs.set_beta(0.0);
495 if (me_inArgs.supports(MEB::IN_ARG_W_x_dot_dot_coeff))
496 me_inArgs.set_W_x_dot_dot_coeff(1.0);
497 sens_residual_model_->evalModel(me_inArgs, meo);
498 my_dfdxdotdot_->apply(Thyra::NOTRANS, *dxdotdotdp, dfdp.ptr(),
499 Scalar(1.0), Scalar(1.0));
504 if (g_index_ >= 0 && outArgs.get_g(0) != Teuchos::null) {
505 MEB::OutArgs<Scalar> meo = model_->createOutArgs();
506 RCP<Thyra::MultiVectorBase<Scalar> > dgdp =
507 rcp_dynamic_cast<DMVPV>(outArgs.get_g(0),
true)
508 ->getNonconstMultiVector();
509 RCP<Thyra::MultiVectorBase<Scalar> > dgdp_trans;
510 MEB::DerivativeSupport dgdp_support =
511 meo.supports(MEB::OUT_ARG_DgDp, g_index_, p_index_);
512 if (dgdp_support.supports(MEB::DERIV_MV_JACOBIAN_FORM))
513 meo.set_DgDp(g_index_, p_index_,
514 MEB::Derivative<Scalar>(dgdp, MEB::DERIV_MV_JACOBIAN_FORM));
515 else if (dgdp_support.supports(MEB::DERIV_MV_GRADIENT_FORM)) {
516 dgdp_trans = createMembers(model_->get_p_space(p_index_), num_response_);
519 MEB::Derivative<Scalar>(dgdp_trans, MEB::DERIV_MV_GRADIENT_FORM));
522 TEUCHOS_TEST_FOR_EXCEPTION(
523 true, std::logic_error,
524 "Operator form of dg/dp not supported for reduced sensitivity");
526 if (!use_dgdp_as_tangent_ || dxdp == Teuchos::null) {
527 MEB::DerivativeSupport dgdx_support =
528 meo.supports(MEB::OUT_ARG_DgDx, g_index_);
529 if (dgdx_support.supports(MEB::DERIV_LINEAR_OP)) {
530 if (my_dgdx_ == Teuchos::null)
531 my_dgdx_ = model_->create_DgDx_op(g_index_);
532 meo.set_DgDx(g_index_, my_dgdx_);
534 else if (dgdx_support.supports(MEB::DERIV_MV_GRADIENT_FORM)) {
535 if (my_dgdx_mv_ == Teuchos::null)
537 createMembers(model_->get_g_space(g_index_), num_param_);
538 meo.set_DgDx(g_index_, MEB::Derivative<Scalar>(
539 my_dgdx_mv_, MEB::DERIV_MV_GRADIENT_FORM));
542 TEUCHOS_TEST_FOR_EXCEPTION(
543 true, std::logic_error,
544 "Jacobian form of dg/dx not supported for reduced sensitivity");
549 if (!use_dgdp_as_tangent_ && use_dfdp_as_tangent_ &&
550 dxdp_vec != Teuchos::null)
551 me_inArgs.set_p(x_tangent_index_, Teuchos::null);
552 if (!use_dgdp_as_tangent_ && use_dfdp_as_tangent_ &&
553 dxdotdp_vec != Teuchos::null)
554 me_inArgs.set_p(xdot_tangent_index_, Teuchos::null);
555 if (!use_dgdp_as_tangent_ && use_dfdp_as_tangent_ &&
556 dxdotdotdp_vec != Teuchos::null)
557 me_inArgs.set_p(xdotdot_tangent_index_, Teuchos::null);
560 if (use_dgdp_as_tangent_ && !use_dfdp_as_tangent_ &&
561 dxdp_vec != Teuchos::null)
562 me_inArgs.set_p(x_tangent_index_, dxdp_vec);
563 if (use_dgdp_as_tangent_ && !use_dfdp_as_tangent_ &&
564 dxdotdp_vec != Teuchos::null)
565 me_inArgs.set_p(xdot_tangent_index_, dxdotdp_vec);
566 if (use_dgdp_as_tangent_ && !use_dfdp_as_tangent_ &&
567 dxdotdotdp_vec != Teuchos::null)
568 me_inArgs.set_p(xdotdot_tangent_index_, dxdotdotdp_vec);
570 model_->evalModel(me_inArgs, meo);
573 if (dgdp_trans != Teuchos::null) {
574 Thyra::DetachedMultiVectorView<Scalar> dgdp_view(*dgdp);
575 Thyra::DetachedMultiVectorView<Scalar> dgdp_trans_view(*dgdp_trans);
576 for (
int i = 0; i < num_param_; ++i)
577 for (
int j = 0; j < num_response_; ++j)
578 dgdp_view(j, i) = dgdp_trans_view(i, j);
583 if (!use_dgdp_as_tangent_ && dxdp != Teuchos::null) {
584 MEB::DerivativeSupport dgdx_support =
585 meo.supports(MEB::OUT_ARG_DgDx, g_index_);
586 if (dgdx_support.supports(MEB::DERIV_LINEAR_OP))
587 my_dgdx_->apply(Thyra::NOTRANS, *dxdp, dgdp.ptr(), Scalar(1.0),
589 else if (dgdx_support.supports(MEB::DERIV_MV_GRADIENT_FORM))
590 my_dgdx_mv_->apply(Thyra::TRANS, *dxdp, dgdp.ptr(), Scalar(1.0),
593 TEUCHOS_TEST_FOR_EXCEPTION(
594 true, std::logic_error,
595 "Jacobian form of dg/dx not supported for reduced sensitivity");