Thyra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Thyra_DirectionalFiniteDiffCalculator_def.hpp
1 // @HEADER
2 // *****************************************************************************
3 // Thyra: Interfaces and Support for Abstract Numerical Algorithms
4 //
5 // Copyright 2004 NTESS and the Thyra contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef THYRA_DIRECTIONAL_FINITE_DIFF_CALCULATOR_DEF_HPP
11 #define THYRA_DIRECTIONAL_FINITE_DIFF_CALCULATOR_DEF_HPP
12 
13 
14 #include "Thyra_DirectionalFiniteDiffCalculator_decl.hpp"
15 #include "Thyra_ModelEvaluatorHelpers.hpp"
16 #include "Thyra_DetachedVectorView.hpp"
17 #include "Thyra_DetachedMultiVectorView.hpp"
18 #include "Thyra_StateFuncModelEvaluatorBase.hpp"
19 #include "Thyra_MultiVectorStdOps.hpp"
20 #include "Thyra_VectorStdOps.hpp"
21 #include "Teuchos_TimeMonitor.hpp"
22 #include "Teuchos_VerboseObjectParameterListHelpers.hpp"
23 
24 
25 namespace Thyra {
26 
27 
28 namespace DirectionalFiniteDiffCalculatorTypes {
29 
30 
31 //
32 // Undocumented utility class for setting support for new derivative objects
33 // on an OutArgs object! Warning, users should not attempt to play these
34 // tricks on their own!
35 //
36 // Note that because of the design of the OutArgs and OutArgsSetup classes,
37 // you can only change the list of supported arguments in a subclass of
38 // ModelEvaluatorBase since OutArgsSetup is a protected type. The fact that
39 // the only way to do this is convoluted is a feature!
40 //
41 template<class Scalar>
42 class OutArgsCreator : public StateFuncModelEvaluatorBase<Scalar>
43 {
44 public:
45  // Public functions overridden from ModelEvaulator.
46  RCP<const VectorSpaceBase<Scalar> > get_x_space() const
47  { TEUCHOS_TEST_FOR_EXCEPT(true); TEUCHOS_UNREACHABLE_RETURN(Teuchos::null); }
48  RCP<const VectorSpaceBase<Scalar> > get_f_space() const
49  { TEUCHOS_TEST_FOR_EXCEPT(true); TEUCHOS_UNREACHABLE_RETURN(Teuchos::null); }
50  ModelEvaluatorBase::InArgs<Scalar> createInArgs() const
51  { TEUCHOS_TEST_FOR_EXCEPT(true); TEUCHOS_UNREACHABLE_RETURN(ModelEvaluatorBase::InArgs<Scalar>()); }
52  ModelEvaluatorBase::OutArgs<Scalar> createOutArgs() const
53  { TEUCHOS_TEST_FOR_EXCEPT(true); TEUCHOS_UNREACHABLE_RETURN(ModelEvaluatorBase::OutArgs<Scalar>()); }
54  void evalModel(
55  const ModelEvaluatorBase::InArgs<Scalar> &inArgs,
56  const ModelEvaluatorBase::OutArgs<Scalar> &outArgs
57  ) const
58  { TEUCHOS_TEST_FOR_EXCEPT(true); }
59  // Static function that does the magic!
60  static ModelEvaluatorBase::OutArgs<Scalar> createOutArgs(
61  const ModelEvaluator<Scalar> &model,
62  const SelectedDerivatives &fdDerivatives
63  )
64  {
65 
66  typedef ModelEvaluatorBase MEB;
67 
68  const MEB::OutArgs<Scalar> wrappedOutArgs = model.createOutArgs();
69  const int Np = wrappedOutArgs.Np(), Ng = wrappedOutArgs.Ng();
70  MEB::OutArgsSetup<Scalar> outArgs;
71 
72  outArgs.setModelEvalDescription(
73  "DirectionalFiniteDiffCalculator: " + model.description()
74  );
75 
76  // Start off by supporting everything that the underlying model supports
77  // computing!
78 
79  outArgs.set_Np_Ng(Np,Ng);
80  outArgs.setSupports(wrappedOutArgs);
81 
82  // Add support for finite difference DfDp(l) if asked
83 
84  const SelectedDerivatives::supports_DfDp_t
85  &supports_DfDp = fdDerivatives.supports_DfDp_;
86  for(
87  SelectedDerivatives::supports_DfDp_t::const_iterator
88  itr = supports_DfDp.begin();
89  itr != supports_DfDp.end();
90  ++itr
91  )
92  {
93  const int l = *itr;
94  assert_p_space(model,l);
95  outArgs.setSupports(MEB::OUT_ARG_DfDp,l,MEB::DERIV_MV_BY_COL);
96  }
97 
98  // Add support for finite difference DgDp(j,l) if asked
99 
100  const SelectedDerivatives::supports_DgDp_t
101  &supports_DgDp = fdDerivatives.supports_DgDp_;
102  for(
103  SelectedDerivatives::supports_DgDp_t::const_iterator
104  itr = supports_DgDp.begin();
105  itr != supports_DgDp.end();
106  ++itr
107  )
108  {
109  const int j = itr->first;
110  const int l = itr->second;
111  assert_p_space(model,l);
112  outArgs.setSupports(MEB::OUT_ARG_DgDp,j,l,MEB::DERIV_MV_BY_COL);
113  }
114 
115  return outArgs;
116 
117  }
118 
119 private:
120 
121  static void assert_p_space( const ModelEvaluator<Scalar> &model, const int l )
122  {
123 #ifdef TEUCHOS_DEBUG
124  const bool p_space_l_is_in_core = model.get_p_space(l)->hasInCoreView();
126  !p_space_l_is_in_core, std::logic_error,
127  "Error, for the model " << model.description()
128  << ", the space p_space("<<l<<") must be in-core so that they can"
129  " act as the domain space for the multi-vector derivative!"
130  );
131 #else
132  (void)model;
133  (void)l;
134 #endif
135  }
136 
137 };
138 
139 
140 } // namespace DirectionalFiniteDiffCalculatorTypes
141 
142 
143 // Private static data members
144 
145 
146 template<class Scalar>
147 const std::string& DirectionalFiniteDiffCalculator<Scalar>::FDMethod_name()
148 {
149  static std::string loc_FDMethod_name = "FD Method";
150  return loc_FDMethod_name;
151 }
152 
153 
154 template<class Scalar>
155 const RCP<
157  Thyra::DirectionalFiniteDiffCalculatorTypes::EFDMethodType
158  >
159 >&
160 DirectionalFiniteDiffCalculator<Scalar>::fdMethodValidator()
161 {
162  static RCP<Teuchos::StringToIntegralParameterEntryValidator<EFDMethodType> >
163  loc_fdMethodValidator
164  = Teuchos::rcp(
166  Teuchos::tuple<std::string>(
167  "order-one"
168  ,"order-two"
169  ,"order-two-central"
170  ,"order-two-auto"
171  ,"order-four"
172  ,"order-four-central"
173  ,"order-four-auto"
174  )
175  ,Teuchos::tuple<std::string>(
176  "Use O(eps) one sided finite differences (cramped bounds)"
177  ,"Use O(eps^2) one sided finite differences (cramped bounds)"
178  ,"Use O(eps^2) two sided central finite differences"
179  ,"Use \"order-two-central\" when not cramped by bounds, otherwise use \"order-two\""
180  ,"Use O(eps^4) one sided finite differences (cramped bounds)"
181  ,"Use O(eps^4) two sided central finite differences"
182  ,"Use \"order-four-central\" when not cramped by bounds, otherwise use \"order-four\""
183  )
184  ,Teuchos::tuple<Thyra::DirectionalFiniteDiffCalculatorTypes::EFDMethodType>(
185  Thyra::DirectionalFiniteDiffCalculatorTypes::FD_ORDER_ONE
186  ,Thyra::DirectionalFiniteDiffCalculatorTypes::FD_ORDER_TWO
187  ,Thyra::DirectionalFiniteDiffCalculatorTypes::FD_ORDER_TWO_CENTRAL
188  ,Thyra::DirectionalFiniteDiffCalculatorTypes::FD_ORDER_TWO_AUTO
189  ,Thyra::DirectionalFiniteDiffCalculatorTypes::FD_ORDER_FOUR
190  ,Thyra::DirectionalFiniteDiffCalculatorTypes::FD_ORDER_FOUR_CENTRAL
191  ,Thyra::DirectionalFiniteDiffCalculatorTypes::FD_ORDER_FOUR_AUTO
192  )
193  ,""
194  )
195  );
196  return loc_fdMethodValidator;
197 }
198 
199 
200 template<class Scalar>
201 const std::string&
202 DirectionalFiniteDiffCalculator<Scalar>::FDMethod_default()
203 {
204  static std::string loc_FDMethod_default = "order-one";
205  return loc_FDMethod_default;
206 }
207 
208 
209 template<class Scalar>
210 const std::string&
211 DirectionalFiniteDiffCalculator<Scalar>::FDStepSelectType_name()
212 {
213  static std::string loc_FDStepSelectType_name = "FD Step Select Type";
214  return loc_FDStepSelectType_name;
215 }
216 
217 
218 template<class Scalar>
219 const RCP<
221  Thyra::DirectionalFiniteDiffCalculatorTypes::EFDStepSelectType
222  >
223  >&
224 DirectionalFiniteDiffCalculator<Scalar>::fdStepSelectTypeValidator()
225 {
226  static const RCP<Teuchos::StringToIntegralParameterEntryValidator<EFDStepSelectType> >
227  loc_fdStepSelectTypeValidator
228  = Teuchos::rcp(
230  Teuchos::tuple<std::string>(
231  "Absolute"
232  ,"Relative"
233  )
234  ,Teuchos::tuple<std::string>(
235  "Use absolute step size \""+FDStepLength_name()+"\""
236  ,"Use relative step size \""+FDStepLength_name()+"\"*||xo||inf"
237  )
238  ,Teuchos::tuple<Thyra::DirectionalFiniteDiffCalculatorTypes::EFDStepSelectType>(
239  Thyra::DirectionalFiniteDiffCalculatorTypes::FD_STEP_ABSOLUTE
240  ,Thyra::DirectionalFiniteDiffCalculatorTypes::FD_STEP_RELATIVE
241  )
242  ,""
243  )
244  );
245  return loc_fdStepSelectTypeValidator;
246 }
247 
248 
249 template<class Scalar>
250 const std::string&
251 DirectionalFiniteDiffCalculator<Scalar>::FDStepSelectType_default()
252 {
253  static std::string loc_FDStepSelectType_default = "Absolute";
254  return loc_FDStepSelectType_default;
255 }
256 
257 
258 template<class Scalar>
259 const std::string&
260 DirectionalFiniteDiffCalculator<Scalar>::FDStepLength_name()
261 {
262  static std::string loc_FDStepLength_name = "FD Step Length";
263  return loc_FDStepLength_name;
264 }
265 
266 
267 template<class Scalar>
268 const double&
269 DirectionalFiniteDiffCalculator<Scalar>::FDStepLength_default()
270 {
271  static double loc_FDStepLength_default = -1.0;
272  return loc_FDStepLength_default;
273 }
274 
275 
276 // Constructors/initializer
277 
278 
279 template<class Scalar>
281  EFDMethodType fd_method_type_in
282  ,EFDStepSelectType fd_step_select_type_in
283  ,ScalarMag fd_step_size_in
284  ,ScalarMag fd_step_size_min_in
285  )
286  :fd_method_type_(fd_method_type_in)
287  ,fd_step_select_type_(fd_step_select_type_in)
288  ,fd_step_size_(fd_step_size_in)
289  ,fd_step_size_min_(fd_step_size_min_in)
290 {}
291 
292 
293 // Overriden from ParameterListAcceptor
294 
295 
296 template<class Scalar>
298  RCP<ParameterList> const& paramList
299  )
300 {
301  TEUCHOS_TEST_FOR_EXCEPT(paramList.get()==0);
302  paramList->validateParameters(*getValidParameters());
303  paramList_ = paramList;
304  fd_method_type_ = fdMethodValidator()->getIntegralValue(
305  *paramList_, FDMethod_name(), FDMethod_default());
306  fd_step_select_type_ = fdStepSelectTypeValidator()->getIntegralValue(
307  *paramList_, FDStepSelectType_name(), FDStepSelectType_default());
308  fd_step_size_ = paramList_->get(
309  FDStepLength_name(),FDStepLength_default());
310  Teuchos::readVerboseObjectSublist(&*paramList_,this);
311 }
312 
313 
314 template<class Scalar>
317 {
318  return paramList_;
319 }
320 
321 
322 template<class Scalar>
325 {
326  RCP<ParameterList> _paramList = paramList_;
327  paramList_ = Teuchos::null;
328  return _paramList;
329 }
330 
331 
332 template<class Scalar>
335 {
336  return paramList_;
337 }
338 
339 
340 template<class Scalar>
343 {
344  using Teuchos::rcp_implicit_cast;
346  static RCP<ParameterList> pl;
347  if(pl.get()==NULL) {
348  pl = Teuchos::parameterList();
349  pl->set(
350  FDMethod_name(), FDMethod_default(),
351  "The method used to compute the finite differences.",
352  rcp_implicit_cast<const PEV>(fdMethodValidator())
353  );
354  pl->set(
355  FDStepSelectType_name(), FDStepSelectType_default(),
356  "Method used to select the finite difference step length.",
357  rcp_implicit_cast<const PEV>(fdStepSelectTypeValidator())
358  );
359  pl->set(
360  FDStepLength_name(), FDStepLength_default()
361  ,"The length of the finite difference step to take.\n"
362  "A value of < 0.0 means that the step length will be determined automatically."
363  );
364  Teuchos::setupVerboseObjectSublist(&*pl);
365  }
366  return pl;
367 }
368 
369 
370 template<class Scalar>
373  const ModelEvaluator<Scalar> &model,
374  const SelectedDerivatives &fdDerivatives
375  )
376 {
377  return DirectionalFiniteDiffCalculatorTypes::OutArgsCreator<Scalar>::createOutArgs(
378  model, fdDerivatives );
379 }
380 
381 
382 template<class Scalar>
384  const ModelEvaluator<Scalar> &model,
385  const ModelEvaluatorBase::InArgs<Scalar> &bp, // basePoint
386  const ModelEvaluatorBase::InArgs<Scalar> &dir, // directions
387  const ModelEvaluatorBase::OutArgs<Scalar> &bfunc, // baseFunctionValues
388  const ModelEvaluatorBase::OutArgs<Scalar> &var // variations
389  ) const
390 {
391 
392  using std::string;
393 
394  THYRA_FUNC_TIME_MONITOR(
395  string("Thyra::DirectionalFiniteDiffCalculator<")+ST::name()+">::calcVariations(...)"
396  );
397 
398  using std::setw;
399  using std::endl;
400  using std::right;
401  using Teuchos::as;
402  typedef ModelEvaluatorBase MEB;
403  namespace DFDCT = DirectionalFiniteDiffCalculatorTypes;
404  typedef RCP<VectorBase<Scalar> > VectorPtr;
405 
406  RCP<Teuchos::FancyOStream> out = this->getOStream();
407  Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
408  const bool trace = (static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_MEDIUM));
409  Teuchos::OSTab tab(out);
410 
411  if(out.get() && trace)
412  *out << "\nEntering DirectionalFiniteDiffCalculator<Scalar>::calcVariations(...)\n";
413 
414  if(out.get() && trace)
415  *out
416  << "\nbasePoint=\n" << describe(bp,verbLevel)
417  << "\ndirections=\n" << describe(dir,verbLevel)
418  << "\nbaseFunctionValues=\n" << describe(bfunc,verbLevel)
419  << "\nvariations=\n" << describe(var,Teuchos::VERB_LOW);
420 
421 #ifdef TEUCHOS_DEBUG
423  var.isEmpty(), std::logic_error,
424  "Error, all of the variations can not be null!"
425  );
426 #endif
427 
428  //
429  // To illustrate the theory behind this implementation consider
430  // the generic multi-variable function h(z) <: R^n -> R. Now let's
431  // consider we have the base point zo and the vector v to
432  // perturb h(z) along. First form the function h(zo+a*v) and then
433  // let's compute d(h)/d(a) at a = 0:
434  //
435  // (1) d(h(zo+a*v))/d(a) at a = 0
436  // = sum( d(h)/d(x(i)) * d(x(i))/d(a), i = 1...n)
437  // = sum( d(h)/d(x(i)) * v(i), i = 1...n)
438  // = d(h)/d(a) * v
439  //
440  // Now we can approximate (1) using, for example, central differences as:
441  //
442  // (2) d(h(zo+a*v))/d(a) at a = 0
443  // \approx ( h(zo+h*v) - h(zo+h*v) ) / (2*h)
444  //
445  // If we equate (1) and (2) we have the approximation:
446  //
447  // (3) d(h)/d(a) * v \approx ( h(zo+h*v) - g(zo+h*v) ) / (2*h)
448  //
449  //
450 
451  // /////////////////////////////////////////
452  // Validate the input
453 
454  // ToDo: Validate input!
455 
456  switch(this->fd_method_type()) {
457  case DFDCT::FD_ORDER_ONE:
458  if(out.get()&&trace) *out<<"\nUsing one-sided, first-order finite differences ...\n";
459  break;
460  case DFDCT::FD_ORDER_TWO:
461  if(out.get()&&trace) *out<<"\nUsing one-sided, second-order finite differences ...\n";
462  break;
463  case DFDCT::FD_ORDER_TWO_CENTRAL:
464  if(out.get()&&trace) *out<<"\nUsing second-order central finite differences ...\n";
465  break;
466  case DFDCT::FD_ORDER_TWO_AUTO:
467  if(out.get()&&trace) *out<<"\nUsing auto selection of some second-order finite difference method ...\n";
468  break;
469  case DFDCT::FD_ORDER_FOUR:
470  if(out.get()&&trace) *out<<"\nUsing one-sided, fourth-order finite differences ...\n";
471  break;
472  case DFDCT::FD_ORDER_FOUR_CENTRAL:
473  if(out.get()&&trace) *out<<"\nUsing fourth-order central finite differences ...\n";
474  break;
475  case DFDCT::FD_ORDER_FOUR_AUTO:
476  if(out.get()&&trace) *out<<"\nUsing auto selection of some fourth-order finite difference method ...\n";
477  break;
478  default:
479  TEUCHOS_TEST_FOR_EXCEPT(true); // Should not get here!
480  }
481 
482  // ////////////////////////
483  // Find the step size
484 
485  //
486  // Get defaults for the optimal step sizes
487  //
488 
489  const ScalarMag
490  sqrt_epsilon = SMT::squareroot(SMT::eps()),
491  u_optimal_1 = sqrt_epsilon,
492  u_optimal_2 = SMT::squareroot(sqrt_epsilon),
493  u_optimal_4 = SMT::squareroot(u_optimal_2);
494 
495  ScalarMag
496  bp_norm = SMT::zero();
497  // ToDo above: compute a reasonable norm somehow based on the base-point vector(s)!
498 
499  ScalarMag
500  uh_opt = 0.0;
501  switch(this->fd_method_type()) {
502  case DFDCT::FD_ORDER_ONE:
503  uh_opt = u_optimal_1 * ( fd_step_select_type() == DFDCT::FD_STEP_ABSOLUTE ? 1.0 : bp_norm + 1.0 );
504  break;
505  case DFDCT::FD_ORDER_TWO:
506  case DFDCT::FD_ORDER_TWO_CENTRAL:
507  case DFDCT::FD_ORDER_TWO_AUTO:
508  uh_opt = u_optimal_2 * ( fd_step_select_type() == DFDCT::FD_STEP_ABSOLUTE ? 1.0 : bp_norm + 1.0 );
509  break;
510  case DFDCT::FD_ORDER_FOUR:
511  case DFDCT::FD_ORDER_FOUR_CENTRAL:
512  case DFDCT::FD_ORDER_FOUR_AUTO:
513  uh_opt = u_optimal_4 * ( fd_step_select_type() == DFDCT::FD_STEP_ABSOLUTE ? 1.0 : bp_norm + 1.0 );
514  break;
515  default:
516  TEUCHOS_TEST_FOR_EXCEPT(true); // Should not get here!
517  }
518 
519  if(out.get()&&trace) *out<<"\nDefault optimal step length uh_opt = " << uh_opt << " ...\n";
520 
521  //
522  // Set the step sizes used.
523  //
524 
525  ScalarMag
526  uh = this->fd_step_size();
527 
528  if( uh < 0 )
529  uh = uh_opt;
530  else if( fd_step_select_type() == DFDCT::FD_STEP_RELATIVE )
531  uh *= (bp_norm + 1.0);
532 
533  if(out.get()&&trace) *out<<"\nStep size to be used uh="<<uh<<"\n";
534 
535  //
536  // Find step lengths that stay in bounds!
537  //
538 
539  // ToDo: Add logic for variable bounds when needed!
540 
541  //
542  // Set the actual method being used
543  //
544  // ToDo: Consider cramped bounds and method order.
545  //
546 
547  DFDCT::EFDMethodType l_fd_method_type = this->fd_method_type();
548  switch(l_fd_method_type) {
549  case DFDCT::FD_ORDER_TWO_AUTO:
550  l_fd_method_type = DFDCT::FD_ORDER_TWO_CENTRAL;
551  break;
552  case DFDCT::FD_ORDER_FOUR_AUTO:
553  l_fd_method_type = DFDCT::FD_ORDER_FOUR_CENTRAL;
554  break;
555  default:
556  break; // Okay
557  }
558 
559  //if(out.get()&&trace) *out<<"\nStep size to fit in bounds: uh="<<uh"\n";
560 
561  int p_saved = -1;
562  if(out.get())
563  p_saved = out->precision();
564 
565  // ///////////////////////////////////////////////
566  // Compute the directional derivatives
567 
568  const int Np = var.Np(), Ng = var.Ng();
569 
570  // Setup storage for perturbed variables
571  VectorPtr per_x, per_x_dot, per_x_dot_dot;
572  std::vector<VectorPtr> per_p(Np);
573  MEB::InArgs<Scalar> pp = model.createInArgs();
574  pp.setArgs(bp); // Set all args to start with
575  if( bp.supports(MEB::IN_ARG_x) ) {
576  if( dir.get_x().get() )
577  pp.set_x(per_x=createMember(model.get_x_space()));
578  else
579  pp.set_x(bp.get_x());
580  }
581  if( bp.supports(MEB::IN_ARG_x_dot) ) {
582  if( dir.get_x_dot().get() )
583  pp.set_x_dot(per_x_dot=createMember(model.get_x_space()));
584  else
585  pp.set_x_dot(bp.get_x_dot());
586  }
587  if( bp.supports(MEB::IN_ARG_x_dot_dot) ) {
588  if( dir.get_x_dot_dot().get() )
589  pp.set_x_dot_dot(per_x_dot_dot=createMember(model.get_x_space()));
590  else
591  pp.set_x_dot_dot(bp.get_x_dot_dot());
592  }
593  for( int l = 0; l < Np; ++l ) {
594  if( dir.get_p(l).get() )
595  pp.set_p(l,per_p[l]=createMember(model.get_p_space(l)));
596  else
597  pp.set_p(l,bp.get_p(l));
598  }
599  if(out.get() && trace)
600  *out
601  << "\nperturbedPoint after initial setup (with some uninitialized vectors) =\n"
602  << describe(pp,verbLevel);
603 
604  // Setup storage for perturbed functions
605  bool all_funcs_at_base_computed = true;
606  MEB::OutArgs<Scalar> pfunc = model.createOutArgs();
607  {
608  VectorPtr f;
609  if( var.supports(MEB::OUT_ARG_f) && (f=var.get_f()).get() ) {
610  pfunc.set_f(createMember(model.get_f_space()));
611  assign(f.ptr(),ST::zero());
612  if(!bfunc.get_f().get()) all_funcs_at_base_computed = false;
613  }
614  for( int j = 0; j < Ng; ++j ) {
615  VectorPtr g_j;
616  if( (g_j=var.get_g(j)).get() ) {
617  pfunc.set_g(j,createMember(model.get_g_space(j)));
618  assign(g_j.ptr(),ST::zero());
619  if(!bfunc.get_g(j).get()) all_funcs_at_base_computed = false;
620  }
621  }
622  }
623  if(out.get() && trace)
624  *out
625  << "\nperturbedFunctions after initial setup (with some uninitialized vectors) =\n"
626  << describe(pfunc,verbLevel);
627 
628  const int dbl_p = 15;
629  if(out.get())
630  *out << std::setprecision(dbl_p);
631 
632  //
633  // Compute the weighted sum of the terms
634  //
635 
636  int num_evals = 0;
637  ScalarMag dwgt = SMT::zero();
638  switch(l_fd_method_type) {
639  case DFDCT::FD_ORDER_ONE: // may only need one eval if f(xo) etc is passed in
640  num_evals = 2;
641  dwgt = ScalarMag(1.0);
642  break;
643  case DFDCT::FD_ORDER_TWO: // may only need two evals if c(xo) etc is passed in
644  num_evals = 3;
645  dwgt = ScalarMag(2.0);
646  break;
647  case DFDCT::FD_ORDER_TWO_CENTRAL:
648  num_evals = 2;
649  dwgt = ScalarMag(2.0);
650  break;
651  case DFDCT::FD_ORDER_FOUR:
652  num_evals = 5;
653  dwgt = ScalarMag(12.0);
654  break;
655  case DFDCT::FD_ORDER_FOUR_CENTRAL:
656  num_evals = 4;
657  dwgt = ScalarMag(12.0);
658  break;
659  default:
660  TEUCHOS_TEST_FOR_EXCEPT(true); // Should not get here!
661  }
662  for( int eval_i = 1; eval_i <= num_evals; ++eval_i ) {
663  // Set the step constant and the weighting constant
664  ScalarMag
665  uh_i = 0.0,
666  wgt_i = 0.0;
667  switch(l_fd_method_type) {
668  case DFDCT::FD_ORDER_ONE: {
669  switch(eval_i) {
670  case 1:
671  uh_i = +0.0;
672  wgt_i = -1.0;
673  break;
674  case 2:
675  uh_i = +1.0;
676  wgt_i = +1.0;
677  break;
678  }
679  break;
680  }
681  case DFDCT::FD_ORDER_TWO: {
682  switch(eval_i) {
683  case 1:
684  uh_i = +0.0;
685  wgt_i = -3.0;
686  break;
687  case 2:
688  uh_i = +1.0;
689  wgt_i = +4.0;
690  break;
691  case 3:
692  uh_i = +2.0;
693  wgt_i = -1.0;
694  break;
695  }
696  break;
697  }
698  case DFDCT::FD_ORDER_TWO_CENTRAL: {
699  switch(eval_i) {
700  case 1:
701  uh_i = -1.0;
702  wgt_i = -1.0;
703  break;
704  case 2:
705  uh_i = +1.0;
706  wgt_i = +1.0;
707  break;
708  }
709  break;
710  }
711  case DFDCT::FD_ORDER_FOUR: {
712  switch(eval_i) {
713  case 1:
714  uh_i = +0.0;
715  wgt_i = -25.0;
716  break;
717  case 2:
718  uh_i = +1.0;
719  wgt_i = +48.0;
720  break;
721  case 3:
722  uh_i = +2.0;
723  wgt_i = -36.0;
724  break;
725  case 4:
726  uh_i = +3.0;
727  wgt_i = +16.0;
728  break;
729  case 5:
730  uh_i = +4.0;
731  wgt_i = -3.0;
732  break;
733  }
734  break;
735  }
736  case DFDCT::FD_ORDER_FOUR_CENTRAL: {
737  switch(eval_i) {
738  case 1:
739  uh_i = -2.0;
740  wgt_i = +1.0;
741  break;
742  case 2:
743  uh_i = -1.0;
744  wgt_i = -8.0;
745  break;
746  case 3:
747  uh_i = +1.0;
748  wgt_i = +8.0;
749  break;
750  case 4:
751  uh_i = +2.0;
752  wgt_i = -1.0;
753  break;
754  }
755  break;
756  }
757  case DFDCT::FD_ORDER_TWO_AUTO:
758  case DFDCT::FD_ORDER_FOUR_AUTO:
759  break; // Okay
760  default:
762  }
763 
764  if(out.get() && trace)
765  *out << "\neval_i="<<eval_i<<", uh_i="<<uh_i<<", wgt_i="<<wgt_i<<"\n";
766  Teuchos::OSTab tab2(out);
767 
768  // Compute the weighted term and add it to the sum
769  if(uh_i == ST::zero()) {
770  MEB::OutArgs<Scalar> bfuncall;
771  if(!all_funcs_at_base_computed) {
772  // Compute missing functions at the base point
773  bfuncall = model.createOutArgs();
774  if( pfunc.supports(MEB::OUT_ARG_f) && pfunc.get_f().get() && !bfunc.get_f().get() ) {
775  bfuncall.set_f(createMember(model.get_f_space()));
776  }
777  for( int j = 0; j < Ng; ++j ) {
778  if( pfunc.get_g(j).get() && !bfunc.get_g(j).get() ) {
779  bfuncall.set_g(j,createMember(model.get_g_space(j)));
780  }
781  }
782  model.evalModel(bp,bfuncall);
783  bfuncall.setArgs(bfunc);
784  }
785  else {
786  bfuncall = bfunc;
787  }
788  // Use functions at the base point
789  if(out.get() && trace)
790  *out << "\nSetting variations = wgt_i * basePoint ...\n";
791  VectorPtr f;
792  if( pfunc.supports(MEB::OUT_ARG_f) && (f=var.get_f()).get() ) {
793  V_StV<Scalar>(f.ptr(), wgt_i, *bfuncall.get_f());
794  }
795  for( int j = 0; j < Ng; ++j ) {
796  VectorPtr g_j;
797  if( (g_j=var.get_g(j)).get() ) {
798  V_StV<Scalar>(g_j.ptr(), wgt_i, *bfuncall.get_g(j));
799  }
800  }
801  }
802  else {
803  if(out.get() && trace)
804  *out << "\nSetting perturbedPoint = basePoint + uh_i*uh*direction ...\n";
805  // z = zo + uh_i*uh*v
806  {
807  if ( dir.supports(MEB::IN_ARG_x) && dir.get_x().get() )
808  V_StVpV(per_x.ptr(),as<Scalar>(uh_i*uh),*dir.get_x(),*bp.get_x());
809  if ( dir.supports(MEB::IN_ARG_x_dot) && dir.get_x_dot().get() )
810  V_StVpV(per_x_dot.ptr(), as<Scalar>(uh_i*uh), *dir.get_x_dot(), *bp.get_x_dot());
811  if ( dir.supports(MEB::IN_ARG_x_dot_dot) && dir.get_x_dot_dot().get() )
812  V_StVpV(per_x_dot_dot.ptr(), as<Scalar>(uh_i*uh), *dir.get_x_dot_dot(), *bp.get_x_dot_dot());
813  for ( int l = 0; l < Np; ++l ) {
814  if( dir.get_p(l).get() )
815  V_StVpV(per_p[l].ptr(), as<Scalar>(uh_i*uh), *dir.get_p(l), *bp.get_p(l));
816  }
817  }
818  if(out.get() && trace)
819  *out << "\nperturbedPoint=\n" << describe(pp,verbLevel);
820  // Compute perturbed function values h(zo+uh_i*uh)
821  if(out.get() && trace)
822  *out << "\nCompute perturbedFunctions at perturbedPoint...\n";
823  model.evalModel(pp,pfunc);
824  if(out.get() && trace)
825  *out << "\nperturbedFunctions=\n" << describe(pfunc,verbLevel);
826  // Sum perturbed function values into total variation
827  {
828  // var_h += wgt_i*perturbed_h
829  if(out.get() && trace)
830  *out << "\nComputing variations += wgt_i*perturbedfunctions ...\n";
831  VectorPtr f;
832  if( pfunc.supports(MEB::OUT_ARG_f) && (f=pfunc.get_f()).get() )
833  Vp_StV<Scalar>(var.get_f().ptr(), wgt_i, *f);
834  for( int j = 0; j < Ng; ++j ) {
835  VectorPtr g_j;
836  if( (g_j=pfunc.get_g(j)).get() )
837  Vp_StV<Scalar>(var.get_g(j).ptr(), wgt_i, *g_j);
838  }
839  }
840  }
841  if(out.get() && trace)
842  *out << "\nvariations=\n" << describe(var,verbLevel);
843  }
844 
845  //
846  // Multiply by the scaling factor!
847  //
848 
849  {
850  // var_h *= 1.0/(dwgt*uh)
851  const Scalar alpha = ST::one()/(dwgt*uh);
852  if(out.get() && trace)
853  *out
854  << "\nComputing variations *= (1.0)/(dwgt*uh),"
855  << " where (1.0)/(dwgt*uh) = (1.0)/("<<dwgt<<"*"<<uh<<") = "<<alpha<<" ...\n";
856  VectorPtr f;
857  if( var.supports(MEB::OUT_ARG_f) && (f=var.get_f()).get() )
858  Vt_S(f.ptr(),alpha);
859  for( int j = 0; j < Ng; ++j ) {
860  VectorPtr g_j;
861  if( (g_j=var.get_g(j)).get() )
862  Vt_S(g_j.ptr(),alpha);
863  }
864  if(out.get() && trace)
865  *out << "\nFinal variations=\n" << describe(var,verbLevel);
866  }
867 
868  if(out.get())
869  *out << std::setprecision(p_saved);
870 
871  if(out.get() && trace)
872  *out << "\nLeaving DirectionalFiniteDiffCalculator<Scalar>::calcVariations(...)\n";
873 
874 }
875 
876 
877 template<class Scalar>
879  const ModelEvaluator<Scalar> &model,
880  const ModelEvaluatorBase::InArgs<Scalar> &bp, // basePoint
881  const ModelEvaluatorBase::OutArgs<Scalar> &bfunc, // baseFunctionValues
882  const ModelEvaluatorBase::OutArgs<Scalar> &deriv // derivatives
883  ) const
884 {
885 
886  using std::string;
887  //typedef Teuchos::ScalarTraits<Scalar> ST;
888 
889  THYRA_FUNC_TIME_MONITOR(
890  string("Thyra::DirectionalFiniteDiffCalculator<")+ST::name()+">::calcDerivatives(...)"
891  );
892 
893  typedef ModelEvaluatorBase MEB;
894  typedef RCP<VectorBase<Scalar> > VectorPtr;
895  typedef RCP<MultiVectorBase<Scalar> > MultiVectorPtr;
896 
897  RCP<Teuchos::FancyOStream> out = this->getOStream();
898  Teuchos::EVerbosityLevel verbLevel = this->getVerbLevel();
899  const bool trace = (static_cast<int>(verbLevel) >= static_cast<int>(Teuchos::VERB_MEDIUM));
900  Teuchos::OSTab tab(out);
901 
902  if(out.get() && trace)
903  *out << "\nEntering DirectionalFiniteDiffCalculator<Scalar>::calcDerivatives(...)\n";
904 
905  if(out.get() && trace)
906  *out
907  << "\nbasePoint=\n" << describe(bp,verbLevel)
908  << "\nbaseFunctionValues=\n" << describe(bfunc,verbLevel)
909  << "\nderivatives=\n" << describe(deriv,Teuchos::VERB_LOW);
910 
911  //
912  // We will only compute finite differences w.r.t. p(l) for now
913  //
914  const int Np = bp.Np(), Ng = bfunc.Ng();
915  MEB::InArgs<Scalar> dir = model.createInArgs();
916  MEB::OutArgs<Scalar> var = model.createOutArgs();
917  MultiVectorPtr DfDp_l;
918  std::vector<MEB::DerivativeMultiVector<Scalar> > DgDp_l(Ng);
919  std::vector<VectorPtr> var_g(Ng);
920  for( int l = 0; l < Np; ++l ) {
921  if(out.get() && trace)
922  *out << "\nComputing derivatives for parameter subvector p("<<l<<") ...\n";
923  Teuchos::OSTab tab2(out);
924  //
925  // Load up OutArgs var object of derivative variations to compute
926  //
927  bool hasDerivObject = false;
928  // DfDp(l)
929  if (
930  !deriv.supports(MEB::OUT_ARG_DfDp,l).none()
931  && !deriv.get_DfDp(l).isEmpty()
932  )
933  {
934  hasDerivObject = true;
935  std::ostringstream name; name << "DfDp("<<l<<")";
936  DfDp_l = get_mv(deriv.get_DfDp(l),name.str(),MEB::DERIV_MV_BY_COL);
937  }
938  else {
939  DfDp_l = Teuchos::null;
940  }
941  // DgDp(j=1...Ng,l)
942  for ( int j = 0; j < Ng; ++j ) {
943  if (
944  !deriv.supports(MEB::OUT_ARG_DgDp,j,l).none()
945  &&
946  !deriv.get_DgDp(j,l).isEmpty()
947  )
948  {
949  hasDerivObject = true;
950  std::ostringstream name; name << "DgDp("<<j<<","<<l<<")";
951  DgDp_l[j] = get_dmv(deriv.get_DgDp(j,l),name.str());
952  if( DgDp_l[j].getMultiVector().get() && !var_g[j].get() )
953  {
954  // Need a temporary vector for the variation for g(j)
955  var_g[j] = createMember(model.get_g_space(j));
956  }
957  }
958  else{
959  DgDp_l[j] = MEB::DerivativeMultiVector<Scalar>();
960  var_g[j] = Teuchos::null;
961  }
962  }
963  //
964  // Compute derivative variations by finite differences
965  //
966  if (hasDerivObject) {
967  VectorPtr e_i = createMember(model.get_p_space(l));
968  dir.set_p(l,e_i);
969  assign(e_i.ptr(),ST::zero());
970  const int np_l = e_i->space()->dim();
971  for( int i = 0 ; i < np_l; ++ i ) {
972  if(out.get() && trace)
973  *out << "\nComputing derivatives for single variable p("<<l<<")("<<i<<") ...\n";
974  Teuchos::OSTab tab3(out);
975  if(DfDp_l.get()) var.set_f(DfDp_l->col(i)); // Compute DfDp(l)(i) in place!
976  for(int j = 0; j < Ng; ++j) {
977  MultiVectorPtr DgDp_j_l;
978  if( (DgDp_j_l=DgDp_l[j].getMultiVector()).get() ) {
979  var.set_g(j,var_g[j]); // Computes d(g(j))/d(p(l)(i))
980  }
981  }
982  set_ele(i,ST::one(),e_i.ptr());
983  this->calcVariations(
984  model,bp,dir,bfunc,var
985  );
986  set_ele(i,ST::zero(),e_i.ptr());
987  if (DfDp_l.get()) var.set_f(Teuchos::null);
988  for (int j = 0; j < Ng; ++j) {
989  MultiVectorPtr DgDp_j_l;
990  if ( !is_null(DgDp_j_l=DgDp_l[j].getMultiVector()) ) {
991  assign( DgDp_j_l->col(i).ptr(), *var_g[j] );
992  }
993  }
994  }
995  dir.set_p(l,Teuchos::null);
996  }
997  }
998 
999  if(out.get() && trace)
1000  *out
1001  << "\nderivatives=\n" << describe(deriv,verbLevel);
1002 
1003  if(out.get() && trace)
1004  *out << "\nLeaving DirectionalFiniteDiffCalculator<Scalar>::calcDerivatives(...)\n";
1005 
1006 }
1007 
1008 
1009 } // namespace Thyra
1010 
1011 
1012 #endif // THYRA_DIRECTIONAL_FINITE_DIFF_CALCULATOR_DEF_HPP
virtual ModelEvaluatorBase::OutArgs< Scalar > createOutArgs() const =0
Create an empty output functions/derivatives object that can be set up and passed to evalModel()...
int Ng() const
Return the number of axillary response functions g(j)(...) supported (Ng &gt;= 0).
virtual RCP< const VectorSpaceBase< Scalar > > get_x_space() const =0
Return the vector space for the state variables x &lt;: RE^n_x.
ModelEvaluatorBase::OutArgs< Scalar > createOutArgs(const ModelEvaluator< Scalar > &model, const SelectedDerivatives &fdDerivatives)
Create an augmented out args object for holding finite difference objects.
Pure abstract base interface for evaluating a stateless &quot;model&quot; that can be mapped into a number of d...
Simple utility class used to select finite difference derivatives for OutArgs object.
void setParameterList(RCP< ParameterList > const &paramList)
bool is_null(const boost::shared_ptr< T > &p)
DirectionalFiniteDiffCalculatorTypes::EFDStepSelectType EFDStepSelectType
Concrete aggregate class for all output arguments computable by a ModelEvaluator subclass object...
Derivative< Scalar > get_DfDp(int l) const
Precondition: supports(OUT_ARG_DfDp,l)==true.
RCP< const VectorBase< Scalar > > get_x_dot() const
Precondition: supports(IN_ARG_x_dot)==true.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
virtual void evalModel(const ModelEvaluatorBase::InArgs< Scalar > &inArgs, const ModelEvaluatorBase::OutArgs< Scalar > &outArgs) const =0
Compute all of the requested functions/derivatives at the given point.
Evaluation< VectorBase< Scalar > > get_g(int j) const
Precondition: supports(OUT_ARG_g)==true..
Evaluation< VectorBase< Scalar > > get_f() const
Precondition: supports(OUT_ARG_f)==true.
T * get() const
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
virtual ModelEvaluatorBase::InArgs< Scalar > createInArgs() const =0
Create an empty input arguments object that can be set up and passed to evalModel().
bool supports(EOutArgsMembers arg) const
Determine if an input argument is supported or not.
Derivative< Scalar > get_DgDp(int j, int l) const
Precondition: supports(OUT_ARG_DgDp,j,l)==true.
IntegralType getIntegralValue(ParameterList const &paramList, std::string const &paramName)
DirectionalFiniteDiffCalculatorTypes::EFDMethodType EFDMethodType
void calcVariations(const ModelEvaluator< Scalar > &model, const ModelEvaluatorBase::InArgs< Scalar > &basePoint, const ModelEvaluatorBase::InArgs< Scalar > &directions, const ModelEvaluatorBase::OutArgs< Scalar > &baseFunctionValues, const ModelEvaluatorBase::OutArgs< Scalar > &variations) const
Compute variations using directional finite differences..
int Np() const
Return the number of parameter subvectors p(l) supported (Np &gt;= 0).
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
virtual RCP< const VectorSpaceBase< Scalar > > get_p_space(int l) const =0
Return the vector space for the auxiliary parameters p(l) &lt;: RE^n_p_l.
void calcDerivatives(const ModelEvaluator< Scalar > &model, const ModelEvaluatorBase::InArgs< Scalar > &basePoint, const ModelEvaluatorBase::OutArgs< Scalar > &baseFunctionValues, const ModelEvaluatorBase::OutArgs< Scalar > &derivatives) const
Compute entire derivative objects using finite differences.
void validateParameters(ParameterList const &validParamList, int const depth=1000, EValidateUsed const validateUsed=VALIDATE_USED_ENABLED, EValidateDefaults const validateDefaults=VALIDATE_DEFAULTS_ENABLED) const
Base subclass for ModelEvaluator that defines some basic types.
virtual RCP< const VectorSpaceBase< Scalar > > get_f_space() const =0
Return the vector space for the state function f(...) &lt;: RE^n_x.
DirectionalFiniteDiffCalculator(EFDMethodType fd_method_type=DirectionalFiniteDiffCalculatorTypes::FD_ORDER_FOUR_AUTO, EFDStepSelectType fd_step_select_type=DirectionalFiniteDiffCalculatorTypes::FD_STEP_ABSOLUTE, ScalarMag fd_step_size=-1.0, ScalarMag fd_step_size_min=-1.0)
#define TEUCHOS_UNREACHABLE_RETURN(dummyReturnVal)
TypeTo as(const TypeFrom &t)
virtual RCP< const VectorSpaceBase< Scalar > > get_g_space(int j) const =0
Return the vector space for the auxiliary response functions g(j) &lt;: RE^n_g_j.
int Np() const
Return the number of parameter subvectors p(l) supported (Np &gt;= 0).
RCP< const VectorBase< Scalar > > get_x_dot_dot() const
Precondition: supports(IN_ARG_x_dot_dot)==true.
bool supports(EInArgsMembers arg) const
Determines if an input argument is supported or not.
RCP< const VectorBase< Scalar > > get_x() const
Precondition: supports(IN_ARG_x)==true.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
RCP< const VectorBase< Scalar > > get_p(int l) const
Get p(l) where 0 &lt;= l &amp;&amp; l &lt; this-&gt;Np().
Concrete aggregate class for all input arguments computable by a ModelEvaluator subclass object...