Panzer  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Panzer_EquationSet_DefaultImpl_impl.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Panzer: A partial differential equation assembly
4 // engine for strongly coupled complex multiphysics systems
5 //
6 // Copyright 2011 NTESS and the Panzer contributors.
7 // SPDX-License-Identifier: BSD-3-Clause
8 // *****************************************************************************
9 // @HEADER
10 
11 #ifndef PANZER_EQUATIONSET_DEFAULT_IMPL_IMPL_HPP
12 #define PANZER_EQUATIONSET_DEFAULT_IMPL_IMPL_HPP
13 
14 #include "Panzer_DOF.hpp"
16 #include "Panzer_DOFGradient.hpp"
17 #include "Panzer_DOFCurl.hpp"
18 #include "Panzer_DOFDiv.hpp"
19 #include "Panzer_GatherBasisCoordinates.hpp"
20 #include "Panzer_GatherIntegrationCoordinates.hpp"
21 #include "Panzer_GatherOrientation.hpp"
22 #include "Panzer_GlobalIndexer.hpp"
23 
24 #include "Phalanx_MDField.hpp"
25 #include "Phalanx_DataLayout.hpp"
26 #include "Phalanx_DataLayout_MDALayout.hpp"
28 
29 // For convenience we automate some evalautor registration
30 #include "Panzer_Sum.hpp"
31 
32 // ***********************************************************************
33 template <typename EvalT>
36  const int& default_integration_order,
37  const panzer::CellData& cell_data,
38  const Teuchos::RCP<panzer::GlobalData>& global_data,
39  const bool build_transient_support) :
40  panzer::GlobalDataAcceptorDefaultImpl(global_data),
41  m_input_params(params),
42  m_default_integration_order(default_integration_order),
43  m_cell_data(cell_data),
44  m_build_transient_support(build_transient_support)
45 {
47 
49 }
50 
51 // ***********************************************************************
52 template <typename EvalT>
55 {
56  // Get defaultparameters
57  m_type = m_input_params->get<std::string>("Type");
58 
59  // for(typename std::map<std::string,DOFDescriptor>::const_iterator itr=m_provided_dofs_desc.begin();
60  // itr!=m_provided_dofs_desc.end();++itr) {
61  // itr->second.print(std::cout); std::cout << std::endl;
62  // }
63 
64  this->m_provided_dofs.clear();
65  this->m_int_rules.clear();
66 
67  // load up the provided dofs and unique int rules from the descriptor map
68  for(typename std::map<std::string,DOFDescriptor>::iterator itr=m_provided_dofs_desc.begin();
69  itr!=m_provided_dofs_desc.end();++itr) {
70 
71  // Create the bases
72  TEUCHOS_ASSERT(nonnull(itr->second.basis));
73  this->m_provided_dofs.push_back(std::make_pair(itr->first, itr->second.basis));
74 
75  //{
76  // Teuchos::FancyOStream out(Teuchos::rcpFromRef(std::cout));
77  // out.setOutputToRootOnly(0);
78  // itr->second.print(out);
79  // out << "Int Order = " << itr->second.integrationOrder << " (" << itr->second.intRule->order() << ")" << std::endl;
80  //}
81 
82  // Create the unique integration rule map and complete descriptor objects
83  TEUCHOS_ASSERT(nonnull(itr->second.intRule));
84  m_int_rules[itr->second.intRule->order()] = itr->second.intRule;
85 
86  }
87 
88  // Setup the basis to dof mapping
89  for (DescriptorIterator dof_iter = m_provided_dofs_desc.begin(); dof_iter != m_provided_dofs_desc.end(); ++dof_iter) {
90 
91  std::string basis_name = dof_iter->second.basis->name();
92  Teuchos::RCP<panzer::PureBasis> basis = dof_iter->second.basis;
93  std::string dof_name = dof_iter->first;
94 
95  if (is_null(m_basis_to_dofs[basis_name].first)) {
96  m_basis_to_dofs[basis_name].first = basis;
97  m_basis_to_dofs[basis_name].second = Teuchos::rcp(new std::vector<std::string>);
98  }
99 
100  m_basis_to_dofs[basis_name].second->push_back(dof_name);
101  }
102 
103  // Generate a unique list of bases
104  for (DescriptorIterator dof_iter = m_provided_dofs_desc.begin(); dof_iter != m_provided_dofs_desc.end(); ++dof_iter) {
105  m_unique_bases[dof_iter->second.basis->name()] = dof_iter->second.basis;
106  }
107 
108  // Setup the default parameter list for closure models
109  this->m_eval_plist->set("Block ID", getElementBlockId());
110  this->setupDeprecatedDOFsSupport();
111 }
112 
113 // ***********************************************************************
114 template <typename EvalT>
116 {
117  TEUCHOS_ASSERT(m_provided_dofs.size() > 0);
118  TEUCHOS_ASSERT(m_int_rules.size() > 0);
119 
120  // Deprecated support assumes all equations in set use the same
121  // basis and integration rule
122  Teuchos::RCP<panzer::PureBasis> pure_basis = m_provided_dofs.begin()->second;
123  Teuchos::RCP<panzer::IntegrationRule> int_rule = m_int_rules.begin()->second;
124  Teuchos::RCP<panzer::BasisIRLayout> basis = panzer::basisIRLayout(pure_basis,*int_rule);
125 
126  this->m_eval_plist->set("Basis", basis);
127  this->m_eval_plist->set("IR", int_rule);
128 }
129 
130 // ***********************************************************************
131 template <typename EvalT>
134  const panzer::FieldLibrary& /* fl */,
136  const Teuchos::ParameterList& /* user_data */) const
137 {
139  using Teuchos::RCP;
140  using Teuchos::rcp;
141 
142  // ********************
143  // DOFs (unknowns)
144  // ********************
145 
146  // Gather, includes construction of orientation gathers
147  for (BasisIterator basis_it = m_basis_to_dofs.begin(); basis_it != m_basis_to_dofs.end(); ++basis_it) {
148 
149  // Set tangent field names (first dimension is DOF, second is parameter)
151  if (m_tangent_param_names.size() > 0) {
152  tangent_field_names = rcp(new std::vector< std::vector<std::string> >(basis_it->second.second->size()));
153  for (std::size_t i=0; i<basis_it->second.second->size(); ++i) {
154  for (std::size_t j=0; j<m_tangent_param_names.size(); ++j) {
155  const std::string tname =
156  (*(basis_it->second.second))[i] + " SENSITIVITY " + m_tangent_param_names[j];
157  (*tangent_field_names)[i].push_back(tname);
158  }
159  }
160  }
161 
162  {
163  ParameterList p("Gather");
164  p.set("Basis", basis_it->second.first);
165  p.set("DOF Names", basis_it->second.second);
166  p.set("Indexer Names", basis_it->second.second);
167  p.set("Sensitivities Name", "");
168  p.set("First Sensitivities Available", true);
169  p.set("Second Sensitivities Available", true);
170 
171  // Set tangent field names
172  if (tangent_field_names != Teuchos::null)
173  p.set("Tangent Names", tangent_field_names);
174 
176 
177  this->template registerEvaluator<EvalT>(fm, op);
178  }
179 
180  // Create a second gather evaluator for each tangent field,
181  // we never compute derivatives with respect to this field
182  if (tangent_field_names != Teuchos::null) {
183  for (std::size_t i=0; i<m_tangent_param_names.size(); ++i) {
184 
185  Teuchos::RCP< std::vector<std::string> > names = rcp(new std::vector<std::string>);
186  for (std::size_t j=0; j<basis_it->second.second->size(); ++j)
187  names->push_back((*tangent_field_names)[j][i]);
188 
189  ParameterList p(std::string("Gather Tangent ") + this->m_tangent_param_names[i]);
190  p.set("Basis", basis_it->second.first);
191  p.set("DOF Names", names);
192  p.set("Indexer Names", basis_it->second.second);
193  p.set("Sensitivities Name", "");
194  p.set("First Sensitivities Available", false);
195  p.set("Second Sensitivities Available", false);
196  p.set("Global Data Key", "X TANGENT GATHER CONTAINER: " + this->m_tangent_param_names[i]);
197 
199 
200  this->template registerEvaluator<EvalT>(fm, op);
201  }
202  }
203  }
204 
205  // **************************
206  // Coordinates for integration points and basis functions
207  // **************************
208  {
209  // add basis coordinates
210  for (std::map<std::string,Teuchos::RCP<panzer::PureBasis> >::const_iterator basis = m_unique_bases.begin();
211  basis != m_unique_bases.end(); ++ basis) {
214  this->template registerEvaluator<EvalT>(fm, basis_op);
215  }
216 
217  // add integration coordinates
218  for (std::map<int,Teuchos::RCP<panzer::IntegrationRule> >::const_iterator ir = m_int_rules.begin();
219  ir != m_int_rules.end(); ++ir) {
222  this->template registerEvaluator<EvalT>(fm, quad_op);
223  }
224 
225  // NOTE: You can look up the name of either coordinate field name by doing
226  // GatherBasisCoordinates<EvalT,Traits>::fieldName();
227  // GatherIntegrationCoordinates<EvalT,Traits>::fieldName();
228  }
229 
230  // **************************
231  // Time derivative terms
232  // **************************
233 
234  // Gather of time derivative terms: One evaluator for each unique basis
235  for (BasisIterator basis_it = m_basis_to_dofs.begin(); basis_it != m_basis_to_dofs.end(); ++basis_it) {
236 
237  RCP< std::vector<std::string> > t_dof_names = rcp(new std::vector<std::string>); // time derivative indexer names
238  RCP< std::vector<std::string> > t_field_names = rcp(new std::vector<std::string>); // time derivative field names
239  RCP< std::vector< std::vector<std::string> > > tangent_field_names = rcp(new std::vector< std::vector<std::string> >); // tangent field names
240 
241  // determine which fields associated with this basis need time derivatives
242  for (typename std::vector<std::string>::const_iterator dof_name = basis_it->second.second->begin();
243  dof_name != basis_it->second.second->end(); ++dof_name) {
244 
245  DescriptorIterator desc = m_provided_dofs_desc.find(*dof_name);
246  TEUCHOS_ASSERT(desc != m_provided_dofs_desc.end());
247 
248  // does this field need a time derivative?
249  if(desc->second.timeDerivative.first) {
250  // time derivative needed
251  t_dof_names->push_back(*dof_name);
252  t_field_names->push_back(desc->second.timeDerivative.second);
253 
254  // Set tangent field names (first dimension is DOF, second is parameter)
255  if (m_tangent_param_names.size() > 0) {
256  std::vector<std::string> tfn;
257  for (std::size_t j=0; j<m_tangent_param_names.size(); ++j) {
258  const std::string tname =
259  desc->second.timeDerivative.second + " SENSITIVITY " + m_tangent_param_names[j];
260  tfn.push_back(tname);
261  }
262  tangent_field_names->push_back(tfn);
263  }
264  }
265  }
266 
267  {
268  ParameterList p("Gather");
269  p.set("Basis", basis_it->second.first);
270  p.set("DOF Names", t_field_names);
271  p.set("Indexer Names", t_dof_names);
272  p.set("Use Time Derivative Solution Vector", true);
273 
274  // Set tangent field names
275  if (m_tangent_param_names.size() > 0)
276  p.set("Tangent Names", tangent_field_names);
277 
279 
280  this->template registerEvaluator<EvalT>(fm, op);
281  }
282 
283  // Create a second gather evaluator for each tangent field,
284  // we never compute derivatives with respect to this field
285  if (m_tangent_param_names.size() > 0) {
286  for (std::size_t i=0; i<m_tangent_param_names.size(); ++i) {
287 
289  rcp(new std::vector<std::string>);
290  for (std::size_t j=0; j<tangent_field_names->size(); ++j)
291  names->push_back((*tangent_field_names)[j][i]);
292 
293  ParameterList p(std::string("Gather Tangent ") + this->m_tangent_param_names[i]);
294  p.set("Basis", basis_it->second.first);
295  p.set("DOF Names", names);
296  p.set("Indexer Names", t_dof_names);
297  p.set("Use Time Derivative Solution Vector", true);
298  p.set("Global Data Key", "DXDT TANGENT GATHER CONTAINER: " + this->m_tangent_param_names[i]);
299 
301 
302  this->template registerEvaluator<EvalT>(fm, op);
303  }
304  }
305  }
306 
307  // **************************
308  // Orientation terms
309  // **************************
310 
311  for (BasisIterator basis_it = m_basis_to_dofs.begin(); basis_it != m_basis_to_dofs.end(); ++basis_it) {
312  if(basis_it->second.first->requiresOrientations()) {
313  ParameterList p("Gather Orientation");
314  p.set("Basis", basis_it->second.first);
315  p.set("DOF Names", basis_it->second.second);
316  p.set("Indexer Names", basis_it->second.second);
317 
319 
320  this->template registerEvaluator<EvalT>(fm, op);
321  }
322  }
323 
324 }
325 
326 // ***********************************************************************
327 template <typename EvalT>
330  const panzer::FieldLayoutLibrary& fl,
333  const Teuchos::ParameterList& /* user_data */) const
334 {
336  using Teuchos::RCP;
337  using Teuchos::rcp;
338 
340  if(lof!=Teuchos::null)
341  globalIndexer = lof->getRangeGlobalIndexer();
342 
343  // DOFs: Scalar value @ basis --> Scalar value @ IP
344  for (DescriptorIterator dof_iter = m_provided_dofs_desc.begin(); dof_iter != m_provided_dofs_desc.end(); ++dof_iter) {
345 
346  ParameterList p;
347  p.set("Name", dof_iter->first);
348  p.set("Basis", fl.lookupLayout(dof_iter->first));
349  p.set("IR", ir);
350 
351  if(globalIndexer!=Teuchos::null) {
352  // build the offsets for this field
353  int fieldNum = globalIndexer->getFieldNum(dof_iter->first);
355  rcp(new std::vector<int>(globalIndexer->getGIDFieldOffsets(m_block_id,fieldNum)));
356  p.set("Jacobian Offsets Vector", offsets);
357  }
358  // else default to the slow DOF call
359 
362 
363  this->template registerEvaluator<EvalT>(fm, op);
364  }
365 
366  // Gradients of DOFs: Scalar value @ basis --> Vector value @ IP
367 
368  for(typename std::map<std::string,DOFDescriptor>::const_iterator itr=m_provided_dofs_desc.begin();
369  itr!=m_provided_dofs_desc.end();++itr) {
370 
371  if(itr->second.basis->supportsGrad()) {
372 
373  // is gradient required for this variable
374  if(!itr->second.grad.first)
375  continue; // its not required, quit the loop
376 
377  const std::string dof_name = itr->first;
378  const std::string dof_grad_name = itr->second.grad.second;
379 
380  ParameterList p;
381  p.set("Name", dof_name);
382  p.set("Gradient Name", dof_grad_name);
383  p.set("Basis", fl.lookupLayout(dof_name));
384  p.set("IR", ir);
385 
388 
389  this->template registerEvaluator<EvalT>(fm, op);
390  }
391  }
392 
393  // Curl of DOFs: Vector value @ basis --> Vector value @ IP (3D) or Scalar value @ IP (2D)
394 
395  for(typename std::map<std::string,DOFDescriptor>::const_iterator itr=m_provided_dofs_desc.begin();
396  itr!=m_provided_dofs_desc.end();++itr) {
397 
398  if(itr->second.basis->supportsCurl()) {
399 
400  // is curl required for this variable
401  if(!itr->second.curl.first)
402  continue; // its not required, quit the loop
403 
404  const std::string dof_name = itr->first;
405  const std::string dof_curl_name = itr->second.curl.second;
406 
407  ParameterList p;
408  p.set("Name", dof_name);
409  p.set("Curl Name", dof_curl_name);
410  p.set("Basis", fl.lookupLayout(dof_name));
411  p.set("IR", ir);
412 
413  // this will help accelerate the DOFCurl evaluator when Jacobians are needed
414  if(globalIndexer!=Teuchos::null) {
415  // build the offsets for this field
416  int fieldNum = globalIndexer->getFieldNum(dof_name);
418  rcp(new std::vector<int>(globalIndexer->getGIDFieldOffsets(m_block_id,fieldNum)));
419  p.set("Jacobian Offsets Vector", offsets);
420  }
421  // else default to the slow DOF call
422 
423 
426 
427  this->template registerEvaluator<EvalT>(fm, op);
428  }
429 
430  }
431 
432  // Div of DOFs: Vector value @ basis --> Scalar value @ IP
433 
434  for(typename std::map<std::string,DOFDescriptor>::const_iterator itr=m_provided_dofs_desc.begin();
435  itr!=m_provided_dofs_desc.end();++itr) {
436 
437  if(itr->second.basis->supportsDiv()) {
438 
439  // is div required for this variable
440  if(!itr->second.div.first)
441  continue; // its not required, quit the loop
442 
443  const std::string dof_name = itr->first;
444  const std::string dof_div_name = itr->second.div.second;
445 
446  ParameterList p;
447  p.set("Name", dof_name);
448  p.set("Div Name", dof_div_name);
449  p.set("Basis", fl.lookupLayout(dof_name));
450  p.set("IR", ir);
451 
452  // this will help accelerate the DOFDiv evaluator when Jacobians are needed
453  if(globalIndexer!=Teuchos::null) {
454  // build the offsets for this field
455  int fieldNum = globalIndexer->getFieldNum(dof_name);
457  rcp(new std::vector<int>(globalIndexer->getGIDFieldOffsets(m_block_id,fieldNum)));
458  p.set("Jacobian Offsets Vector", offsets);
459  }
460  // else default to the slow DOF call
461 
462 
465 
466  this->template registerEvaluator<EvalT>(fm, op);
467  }
468  }
469 
470  // Time derivative of DOFs: Scalar value @ basis --> Scalar value @ IP
471  for(typename std::map<std::string,DOFDescriptor>::const_iterator itr=m_provided_dofs_desc.begin();
472  itr!=m_provided_dofs_desc.end();++itr) {
473  // is td required for this variable
474  if(!itr->second.timeDerivative.first)
475  continue; // its not required, quit the loop
476 
477  const std::string td_name = itr->second.timeDerivative.second;
478 
479  ParameterList p;
480  p.set("Name", td_name);
481  p.set("Basis", fl.lookupLayout(itr->first));
482  p.set("IR", ir);
483 
484  if(globalIndexer!=Teuchos::null) {
485  // build the offsets for this field
486  int fieldNum = globalIndexer->getFieldNum(itr->first);
488  rcp(new std::vector<int>(globalIndexer->getGIDFieldOffsets(m_block_id,fieldNum)));
489  p.set("Jacobian Offsets Vector", offsets);
490  }
491  // else default to the slow DOF call
492 
493  // set the orientiation field name explicitly if orientations are
494  // required for the basis
495  if(itr->second.basis->requiresOrientations())
496  p.set("Orientation Field Name", itr->first+" Orientation");
497 
500 
501  this->template registerEvaluator<EvalT>(fm, op);
502  }
503 
504 }
505 
506 // ***********************************************************************
507 template <typename EvalT>
510  const panzer::FieldLibrary& /* fl */,
512  const Teuchos::ParameterList& user_data) const
513 {
515  using Teuchos::RCP;
516  using Teuchos::rcp;
517 
518  // this turns off the scatter contribution, and does
519  // only the gather
520  bool ignoreScatter = false;
521  if(user_data.isParameter("Ignore Scatter"))
522  ignoreScatter = user_data.get<bool>("Ignore Scatter");
523 
524  if(!ignoreScatter) {
525 
526  for(typename std::map<std::string,DOFDescriptor>::const_iterator itr=m_provided_dofs_desc.begin();
527  itr!=m_provided_dofs_desc.end();++itr) {
528 
529  RCP<std::map<std::string,std::string> > names_map = rcp(new std::map<std::string,std::string>);
530  RCP< std::vector<std::string> > residual_names = rcp(new std::vector<std::string>);
531 
532  // sanity check to make sure a residual name was registered for each provided variable
533  TEUCHOS_ASSERT(itr->second.residualName.first);
534 
535  names_map->insert(std::make_pair(itr->second.residualName.second,itr->first));
536  residual_names->push_back(itr->second.residualName.second);
537 
538  {
539  ParameterList p("Scatter");
540  p.set("Scatter Name", itr->second.scatterName);
541  p.set("Basis", itr->second.basis.getConst());
542  p.set("Dependent Names", residual_names);
543  p.set("Dependent Map", names_map);
544 
546 
547  this->template registerEvaluator<EvalT>(fm, op);
548  }
549 
550  // Require variables
551  {
552  PHX::Tag<typename EvalT::ScalarT> tag(itr->second.scatterName,
554  fm.template requireField<EvalT>(tag);
555  }
556 
557  }
558 
559  }
560 
561 }
562 
563 // ***********************************************************************
564 
565 template <typename EvalT>
568  const panzer::FieldLayoutLibrary& fl,
571  const Teuchos::ParameterList& models,
572  const Teuchos::ParameterList& user_data) const
573 {
574  for (std::vector<std::string>::const_iterator model_name = m_closure_model_ids.begin();
575  model_name != m_closure_model_ids.end(); ++model_name) {
576 
577  this->buildAndRegisterClosureModelEvaluators(fm,fl,ir,factory,*model_name,models,user_data);
578  }
579 }
580 
581 // ***********************************************************************
582 
583 template <typename EvalT>
586  const panzer::FieldLayoutLibrary& fl,
589  const std::string& model_name,
590  const Teuchos::ParameterList& models,
591  const Teuchos::ParameterList& user_data) const
592 {
594  factory.getAsObject<EvalT>()->buildClosureModels(model_name,
595  models,
596  fl,
597  ir,
598  *(this->m_eval_plist),
599  user_data,
600  this->getGlobalData(),
601  fm);
602 
603  for (std::vector< Teuchos::RCP<PHX::Evaluator<panzer::Traits> > >::size_type i=0; i < evaluators->size(); ++i)
604  this->template registerEvaluator<EvalT>(fm, (*evaluators)[i]);
605 }
606 
607 // ***********************************************************************
608 template <typename EvalT>
611  const panzer::FieldLibrary& fl,
613  const std::string& model_name,
614  const Teuchos::ParameterList& models,
616  const Teuchos::ParameterList& user_data) const
617 {
618  // add basis coordinates
619  for (std::map<std::string,Teuchos::RCP<panzer::PureBasis> >::const_iterator basis = m_unique_bases.begin();
620  basis != m_unique_bases.end(); ++ basis) {
623  this->template registerEvaluator<EvalT>(fm, basis_op);
624  }
625 
626  for(typename std::map<std::string,DOFDescriptor>::const_iterator itr=m_provided_dofs_desc.begin();
627  itr!=m_provided_dofs_desc.end();++itr) {
628 
629  Teuchos::ParameterList p("Scatter");
630  p.set("Scatter Name", itr->second.scatterName);
631  p.set("Basis", itr->second.basis.getConst());
632  Teuchos::RCP<std::vector<std::string> > name = Teuchos::rcp(new std::vector<std::string>);
633  name->push_back(itr->first);
634  p.set("Dependent Names", name);
635 
636  // Create an identity map
637  Teuchos::RCP<std::map<std::string,std::string> > names_map = Teuchos::rcp(new std::map<std::string,std::string>);
638  names_map->insert(std::make_pair(itr->first,itr->first));
639  p.set("Dependent Map", names_map);
640 
641  // Set flag for ScatterDirichlet evaluators
642  p.set("Scatter Initial Condition", true);
643 
644  // Use ScatterDirichlet to scatter the initial condition
646 
647  this->template registerEvaluator<EvalT>(fm, op);
648 
649 
650  // Require field
651  PHX::Tag<typename EvalT::ScalarT> tag(itr->second.scatterName,Teuchos::rcp(new PHX::MDALayout<Dummy>(0)));
652  fm.template requireField<EvalT>(tag);
653  }
654 
655  // Add in closure models. This is a hack that we should revisit.
656  {
657  // Closure models are normally evaluated at integration points,
658  // but some evaluator models support evaluation at both basis and
659  // integration points. For initial guesses, we should only
660  // evaluate at basis points, so integration rule is meaningless.
661  // We use this to build all closure model evaluators in model
662  // (including integration point based ones that will never be
663  // used). In the future we may need ir for using L2 projection to
664  // basis points for initial guesses (for non-nodal bases).
666  if (m_int_rules.size() > 0)
667  dummy_ir = m_int_rules.begin()->second;
669 
671  factory.getAsObject<EvalT>()->buildClosureModels(model_name, models, *fll, dummy_ir, *(this->m_eval_plist), user_data, this->getGlobalData(), fm);
672 
673  for (std::vector< Teuchos::RCP<PHX::Evaluator<panzer::Traits> > >::size_type i=0; i < evaluators->size(); ++i)
674  this->template registerEvaluator<EvalT>(fm, (*evaluators)[i]);
675  }
676 
677  // **************************
678  // Add Orientation terms
679  // **************************
680 
681  for (BasisIterator basis_it = m_basis_to_dofs.begin(); basis_it != m_basis_to_dofs.end(); ++basis_it) {
682  if(basis_it->second.first->requiresOrientations()) {
683  Teuchos::ParameterList p("Gather Orientation");
684  p.set("Basis", basis_it->second.first);
685  p.set("DOF Names", basis_it->second.second);
686  p.set("Indexer Names", basis_it->second.second);
687 
689 
690  this->template registerEvaluator<EvalT>(fm, op);
691  }
692  }
693 
694 }
695 
696 // ***********************************************************************
697 template <typename EvalT>
700 {
701  return m_eval_plist;
702 }
703 
704 // ***********************************************************************
705 template <typename EvalT>
706 const std::vector<std::pair<std::string,Teuchos::RCP<panzer::PureBasis> > >&
708 {
709  return m_provided_dofs;
710 }
711 
712 // ***********************************************************************
713 template <typename EvalT>
714 const std::vector<std::vector<std::string> > &
716 {
717  return m_coordinate_dofs;
718 }
719 
720 // ***********************************************************************
721 template <typename EvalT>
722 const std::map<int,Teuchos::RCP<panzer::IntegrationRule> > &
724 {
725  return m_int_rules;
726 }
727 
728 // ***********************************************************************
729 template <typename EvalT>
731 setElementBlockId(const std::string & blockId)
732 {
733  TEUCHOS_ASSERT(m_block_id=="");
734  m_block_id = blockId;
735  this->m_eval_plist->set("Block ID", getElementBlockId()); // set the value in parameter list
736  // used by closure model factory
737 }
738 
739 // ***********************************************************************
740 template <typename EvalT>
743 {
744  return m_block_id;
745 }
746 
747 // ***********************************************************************
748 template <typename EvalT>
750 {
751  return m_type;
752 }
753 
754 // ***********************************************************************
755 template <typename EvalT>
756 void panzer::EquationSet_DefaultImpl<EvalT>::setTangentParamNames(const std::vector<std::string>& tangent_param_names)
757 {
758  m_tangent_param_names = tangent_param_names;
759 }
760 
761 // ***********************************************************************
762 template <typename EvalT>
764 {
765  return m_build_transient_support;
766 }
767 
768 // ***********************************************************************
769 template <typename EvalT>
771 getAddedDOFs(std::vector<std::string> & dofNames) const
772 {
773  dofNames.clear();
774  for(typename std::map<std::string,DOFDescriptor>::const_iterator itr=m_provided_dofs_desc.begin();
775  itr!=m_provided_dofs_desc.end();++itr)
776  dofNames.push_back(itr->first);
777 }
778 
779 // ***********************************************************************
780 template <typename EvalT>
782 updateDOF(const std::string & dofName,
783  int basisOrder,
784  int integrationOrder)
785 {
786  typename std::map<std::string,DOFDescriptor>::const_iterator itr = m_provided_dofs_desc.find(dofName);
787 
788  TEUCHOS_TEST_FOR_EXCEPTION(itr==m_provided_dofs_desc.end(),std::runtime_error,
789  "EquationSet_DefaultImpl::updateDOF: DOF \"" << dofName << "\" has not been specified "
790  "by derived equation set \"" << this->getType() << "\".");
791 
792  // allocate and populate a dof descriptor associated with the field "dofName"
793  DOFDescriptor & desc = m_provided_dofs_desc[dofName];
794  desc.basisOrder = basisOrder;
795  desc.basis = Teuchos::rcp(new panzer::PureBasis(desc.basisType,desc.basisOrder,m_cell_data));
796 
797  if (integrationOrder == -1)
798  desc.integrationOrder = m_default_integration_order;
799  else
800  desc.integrationOrder = integrationOrder;
801 
802  desc.intRule = Teuchos::rcp(new panzer::IntegrationRule(desc.integrationOrder,m_cell_data));
803 }
804 
805 // ***********************************************************************
806 template <typename EvalT>
808 getBasisOrder(const std::string & dofName) const
809 {
810  typename std::map<std::string,DOFDescriptor>::const_iterator itr = m_provided_dofs_desc.find(dofName);
811 
812  TEUCHOS_TEST_FOR_EXCEPTION(itr==m_provided_dofs_desc.end(),std::runtime_error,
813  "EquationSet_DefaultImpl::getBasisOrder: DOF \"" << dofName << "\" has not been specified "
814  "by derived equation set \"" << this->getType() << "\".");
815 
816  return itr->second.basisOrder;
817 }
818 
819 // ***********************************************************************
820 template <typename EvalT>
822 getIntegrationOrder(const std::string & dofName) const
823 {
824  typename std::map<std::string,DOFDescriptor>::const_iterator itr = m_provided_dofs_desc.find(dofName);
825 
826  TEUCHOS_TEST_FOR_EXCEPTION(itr==m_provided_dofs_desc.end(),std::runtime_error,
827  "EquationSet_DefaultImpl::getIntegrationOrder: DOF \"" << dofName << "\" has not been specified "
828  "by derived equation set \"" << this->getType() << "\".");
829 
830  return itr->second.integrationOrder;
831 }
832 
833 // ***********************************************************************
834 template <typename EvalT>
836 addDOF(const std::string & dofName,
837  const std::string & basisType,
838  const int & basisOrder,
839  const int integrationOrder,
840  const std::string residualName,
841  const std::string scatterName)
842 {
843  typename std::map<std::string,DOFDescriptor>::const_iterator itr = m_provided_dofs_desc.find(dofName);
844 
845  TEUCHOS_TEST_FOR_EXCEPTION(itr!=m_provided_dofs_desc.end(),std::runtime_error,
846  "EquationSet_DefaultImpl::addProvidedDOF: DOF \"" << dofName << "\" was previously specified "
847  "by derived equation set \"" << this->getType() << "\".");
848 
849  // allocate and populate a dof descriptor associated with the field "dofName"
850  DOFDescriptor & desc = m_provided_dofs_desc[dofName];
851  desc.dofName = dofName;
852  desc.basisType = basisType;
853  desc.basisOrder = basisOrder;
854  desc.basis = Teuchos::rcp(new panzer::PureBasis(desc.basisType,desc.basisOrder,m_cell_data));
855 
856  if (integrationOrder == -1)
857  desc.integrationOrder = m_default_integration_order;
858  else
859  desc.integrationOrder = integrationOrder;
860 
861  desc.intRule = Teuchos::rcp(new panzer::IntegrationRule(desc.integrationOrder,m_cell_data));
862 
863  // this function always creates a residual and scatter
864  desc.residualName.first = true;
865 
866  if (residualName == "")
867  desc.residualName.second = "RESIDUAL_" + dofName;
868  else
869  desc.residualName.second = residualName;
870 
871  if (scatterName == "")
872  desc.scatterName = "SCATTER_" + dofName;
873  else
874  desc.scatterName = scatterName;
875 
876 }
877 
878 // ***********************************************************************
879 template <typename EvalT>
881 addDOFGrad(const std::string & dofName,
882  const std::string & gradName)
883 {
884  typename std::map<std::string,DOFDescriptor>::iterator itr = m_provided_dofs_desc.find(dofName);
885 
886  TEUCHOS_TEST_FOR_EXCEPTION(itr==m_provided_dofs_desc.end(),std::runtime_error,
887  "EquationSet_DefaultImpl::addDOFGrad: DOF \"" << dofName << "\" has not been specified as a DOF "
888  "by derived equation set \"" << this->getType() << "\".");
889 
890  // allocate and populate a dof descriptor associated with the field "dofName"
891  DOFDescriptor & desc = m_provided_dofs_desc[dofName];
892  TEUCHOS_ASSERT(desc.dofName==dofName); // safety check
893 
894  if (gradName == "")
895  desc.grad = std::make_pair(true,std::string("GRAD_")+dofName);
896  else
897  desc.grad = std::make_pair(true,gradName);
898 }
899 
900 // ***********************************************************************
901 template <typename EvalT>
903 addDOFCurl(const std::string & dofName,
904  const std::string & curlName)
905 {
906  typename std::map<std::string,DOFDescriptor>::iterator itr = m_provided_dofs_desc.find(dofName);
907 
908  TEUCHOS_TEST_FOR_EXCEPTION(itr==m_provided_dofs_desc.end(),std::runtime_error,
909  "EquationSet_DefaultImpl::addDOFCurl: DOF \"" << dofName << "\" has not been specified as a DOF "
910  "by derived equation set \"" << this->getType() << "\".");
911 
912  // allocate and populate a dof descriptor associated with the field "dofName"
913  DOFDescriptor & desc = m_provided_dofs_desc[dofName];
914  TEUCHOS_ASSERT(desc.dofName==dofName); // safety check
915 
916  if (curlName == "")
917  desc.curl = std::make_pair(true,std::string("CURL_")+dofName);
918  else
919  desc.curl = std::make_pair(true,curlName);
920 }
921 
922 // ***********************************************************************
923 template <typename EvalT>
925 addDOFDiv(const std::string & dofName,
926  const std::string & divName)
927 {
928  typename std::map<std::string,DOFDescriptor>::iterator itr = m_provided_dofs_desc.find(dofName);
929 
930  TEUCHOS_TEST_FOR_EXCEPTION(itr==m_provided_dofs_desc.end(),std::runtime_error,
931  "EquationSet_DefaultImpl::addDOFDiv: DOF \"" << dofName << "\" has not been specified as a DOF "
932  "by derived equation set \"" << this->getType() << "\".");
933 
934  // allocate and populate a dof descriptor associated with the field "dofName"
935  DOFDescriptor & desc = m_provided_dofs_desc[dofName];
936  TEUCHOS_ASSERT(desc.dofName==dofName); // safety check
937 
938  if (divName == "")
939  desc.div = std::make_pair(true,std::string("DIV_")+dofName);
940  else
941  desc.div = std::make_pair(true,divName);
942 }
943 
944 // ***********************************************************************
945 template <typename EvalT>
947 addDOFTimeDerivative(const std::string & dofName,
948  const std::string & dotName)
949 {
950  typename std::map<std::string,DOFDescriptor>::iterator itr = m_provided_dofs_desc.find(dofName);
951 
952  TEUCHOS_TEST_FOR_EXCEPTION(itr==m_provided_dofs_desc.end(),std::runtime_error,
953  "EquationSet_DefaultImpl::addDOFTimeDerivative: DOF \"" << dofName << "\" has not been specified as a DOF "
954  "by derived equation set \"" << this->getType() << "\".");
955 
956  // allocate and populate a dof descriptor associated with the field "dofName"
957  DOFDescriptor & desc = m_provided_dofs_desc[dofName];
958  TEUCHOS_ASSERT(desc.dofName==dofName); // safety check
959 
960  if (dotName == "")
961  desc.timeDerivative = std::make_pair(true,std::string("DXDT_")+dofName);
962  else
963  desc.timeDerivative = std::make_pair(true,dotName);
964 }
965 
966 // ***********************************************************************
967 template <typename EvalT>
969 setCoordinateDOFs(const std::vector<std::string> & dofNames)
970 {
971  TEUCHOS_TEST_FOR_EXCEPTION(m_cell_data.baseCellDimension()!=Teuchos::as<int>(dofNames.size()),std::invalid_argument,
972  "EquationSet_DefaultImpl::setCoordinateDOFs: Size of vector is not equal to the "
973  "spatial dimension.");
974 
975  for(std::size_t d=0;d<dofNames.size();d++) {
976  typename std::map<std::string,DOFDescriptor>::const_iterator desc_it = m_provided_dofs_desc.find(dofNames[d]);
977  TEUCHOS_TEST_FOR_EXCEPTION(desc_it == m_provided_dofs_desc.end(),std::invalid_argument,
978  "EquationSet_DefaultImpl::setCoordinateDOFs: DOF of name \"" + dofNames[d] + "\" "
979  "has not been added, thus cannot be set as a coordinate DOF.");
980  }
981 
982  m_coordinate_dofs.push_back(dofNames);
983 }
984 
985 // ***********************************************************************
986 template <typename EvalT>
989 {
990  std::string default_type = "";
991  valid_parameters.set("Type",default_type,"The equation set type. This must corespond to the type keyword used to build the equation set in the equation set factory.");
992 }
993 
994 // ***********************************************************************
995 template <typename EvalT>
998 {
999  typename std::map<std::string,DOFDescriptor>::const_iterator desc_it = m_provided_dofs_desc.find(dof_name);
1000  TEUCHOS_ASSERT(desc_it != m_provided_dofs_desc.end());
1001  return desc_it->second.basis;
1002 }
1003 
1004 // ***********************************************************************
1005 template <typename EvalT>
1008 {
1009  typename std::map<std::string,DOFDescriptor>::const_iterator desc_it = m_provided_dofs_desc.find(dof_name);
1010  TEUCHOS_TEST_FOR_EXCEPTION(desc_it == m_provided_dofs_desc.end(),std::logic_error,
1011  "EquationSet_DefaultImpl::getIntRuleForDOF: Failed to find degree of freedom "
1012  "with name \"" << dof_name << "\".");
1013  return desc_it->second.intRule;
1014 }
1015 
1016 // ***********************************************************************
1017 template <typename EvalT>
1020 {
1021  typename std::map<std::string,DOFDescriptor>::const_iterator desc_it = m_provided_dofs_desc.find(dof_name);
1022  TEUCHOS_TEST_FOR_EXCEPTION(desc_it == m_provided_dofs_desc.end(),std::logic_error,
1023  "EquationSet_DefaultImpl::getBasisIRLayoutForDOF: Failed to find degree of freedom "
1024  "with name \"" << dof_name << "\".");
1025 
1026  return panzer::basisIRLayout(desc_it->second.basis,*(desc_it->second.intRule));
1027 }
1028 
1029 // ***********************************************************************
1030 template <typename EvalT>
1033  const std::string dof_name,
1034  const std::vector<std::string>& residual_contributions,
1035  const std::string residual_field_name) const
1036 {
1037  using Teuchos::rcp;
1038  using Teuchos::RCP;
1039 
1041 
1042  if (residual_field_name != "")
1043  p.set("Sum Name", residual_field_name);
1044  else
1045  p.set("Sum Name", "RESIDUAL_" + dof_name);
1046 
1047  RCP<std::vector<std::string> > rcp_residual_contributions = rcp(new std::vector<std::string>);
1048  *rcp_residual_contributions = residual_contributions;
1049 
1050  p.set("Values Names", rcp_residual_contributions);
1051 
1052  DescriptorIterator desc_it = m_provided_dofs_desc.find(dof_name);
1053  TEUCHOS_ASSERT(desc_it != m_provided_dofs_desc.end());
1054 
1055  p.set("Data Layout", desc_it->second.basis->functional);
1056 
1058 
1059  this->template registerEvaluator<EvalT>(fm, op);
1060 }
1061 
1062 // ***********************************************************************
1063 template <typename EvalT>
1066  const std::string dof_name,
1067  const std::vector<std::string>& residual_contributions,
1068  const std::vector<double>& scale_contributions,
1069  const std::string residual_field_name) const
1070 {
1071  using Teuchos::rcp;
1072  using Teuchos::RCP;
1073 
1075 
1076  if (residual_field_name != "")
1077  p.set("Sum Name", residual_field_name);
1078  else
1079  p.set("Sum Name", "RESIDUAL_" + dof_name);
1080 
1081  RCP<std::vector<std::string> > rcp_residual_contributions = rcp(new std::vector<std::string>);
1082  *rcp_residual_contributions = residual_contributions;
1083  p.set("Values Names", rcp_residual_contributions);
1084 
1085  RCP<const std::vector<double> > rcp_scale_contributions = rcp(new std::vector<double>(scale_contributions));
1086  p.set("Scalars", rcp_scale_contributions);
1087 
1088  DescriptorIterator desc_it = m_provided_dofs_desc.find(dof_name);
1089  TEUCHOS_ASSERT(desc_it != m_provided_dofs_desc.end());
1090 
1091  p.set("Data Layout", desc_it->second.basis->functional);
1092 
1094 
1095  this->template registerEvaluator<EvalT>(fm, op);
1096 }
1097 
1098 // ***********************************************************************
1099 template <typename EvalT>
1100 void panzer::EquationSet_DefaultImpl<EvalT>::addClosureModel(const std::string& closure_model)
1101 {
1102  m_closure_model_ids.push_back(closure_model);
1103 }
1104 
1105 // ***********************************************************************
1106 template <typename EvalT>
1109 {
1110  return m_input_params;
1111 }
1112 
1113 // ***********************************************************************
1114 #endif
void buildAndRegisterResidualSummationEvaluator(PHX::FieldManager< panzer::Traits > &fm, const std::string dof_name, const std::vector< std::string > &residual_contributions, const std::string residual_field_name="") const
Teuchos::RCP< panzer::BasisIRLayout > lookupLayout(const std::string &fieldName) const
Get the basis associated with a particular field.
Teuchos::RCP< panzer::IntegrationRule > getIntRuleForDOF(const std::string &dof_name) const
Returns the integration rule associated with the residual contributions for the dof_name.
std::map< std::string, DOFDescriptor >::const_iterator DescriptorIterator
For convenience, declare the DOFDescriptor iterator.
Interpolates basis DOF values to IP DOF Gradient values.
void addDOFGrad(const std::string &dofName, const std::string &gradName="")
bool is_null(const boost::shared_ptr< T > &p)
virtual void setTangentParamNames(const std::vector< std::string > &tangent_param_names)
Set the list of tangent parameter names.
virtual std::string getType() const
Returns the type of the equation set object. Corresponds to the keyword used by the equation set fact...
Teuchos::RCP< typename Sacado::mpl::apply< panzer::ClosureModelFactory< _ >, ScalarT >::type > getAsObject()
int getIntegrationOrder(const std::string &dofName) const
Get the integration order for an existing degree of freedom.
Default implementation for accessing the GlobalData object.
virtual const std::map< int, Teuchos::RCP< panzer::IntegrationRule > > & getIntegrationRules() const
Return a map of unique integration rules for the equation set, key is the integration order...
T & get(const std::string &name, T def_value)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
virtual void buildAndRegisterInitialConditionEvaluators(PHX::FieldManager< panzer::Traits > &fm, const panzer::FieldLibrary &fl, const panzer::ClosureModelFactory_TemplateManager< panzer::Traits > &factory, const std::string &model_name, const Teuchos::ParameterList &models, const LinearObjFactory< panzer::Traits > &lof, const Teuchos::ParameterList &user_data) const
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Teuchos::RCP< Teuchos::ParameterList > m_eval_plist
virtual void buildAndRegisterDOFProjectionsToIPEvaluators(PHX::FieldManager< panzer::Traits > &fm, const panzer::FieldLayoutLibrary &fl, const Teuchos::RCP< panzer::IntegrationRule > &ir, const Teuchos::Ptr< const panzer::LinearObjFactory< panzer::Traits > > &lof, const Teuchos::ParameterList &user_data) const
int getBasisOrder(const std::string &dofName) const
Get the basis order for an existing degree of freedom.
Teuchos::RCP< PHX::Evaluator< Traits > > buildGatherTangent(const Teuchos::ParameterList &pl) const
Use preconstructed gather evaluators.
Teuchos::RCP< panzer::PureBasis > getBasisForDOF(const std::string &dof_name) const
Returns the PureBasis associated with the residual contributions for the dof_name.
Interpolates basis DOF values to IP DOF Div values.
void setDefaultValidParameters(Teuchos::ParameterList &valid_parameters)
PHX::View< const int * > offsets
Teuchos::RCP< Teuchos::ParameterList > getEquationSetParameterList() const
Returns the parameter list used to build this equation set.
Teuchos::RCP< panzer::BasisIRLayout > basisIRLayout(std::string basis_type, const int basis_order, const PointRule &pt_rule)
Nonmember constructor.
bool isParameter(const std::string &name) const
void setCoordinateDOFs(const std::vector< std::string > &dofNames)
Teuchos::RCP< PHX::Evaluator< Traits > > buildScatterDirichlet(const Teuchos::ParameterList &pl) const
Use preconstructed dirichlet scatter evaluators.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Data for determining cell topology and dimensionality.
void addDOFDiv(const std::string &dofName, const std::string &divName="")
virtual const Teuchos::RCP< Teuchos::ParameterList > getEvaluatorParameterList() const
Returns the parameter list that will be passed off from the equaiton set to the closure model evaluat...
Gathers coordinates for the quadrature from the workset and stores them in the field manager...
virtual void setupDOFs()
Builds the integration rule, basis, DOFs, and default parameter list. This MUST be called in the cons...
std::map< std::string, std::pair< Teuchos::RCP< panzer::PureBasis >, Teuchos::RCP< std::vector< std::string > > > >::const_iterator BasisIterator
For convenience, declare a basis iterator.
Interpolates basis DOF values to IP DOF Curl values.
virtual int getFieldNum(const std::string &str) const =0
Get the number used for access to this field.
Teuchos::RCP< PHX::Evaluator< Traits > > buildGather(const Teuchos::ParameterList &pl) const
Use preconstructed gather evaluators.
void addDOF(const std::string &dofName, const std::string &basisType, const int &basisOrder, const int integrationOrder=-1, const std::string residualName="", const std::string scatterName="")
void updateDOF(const std::string &dofName, int basisOrder, int integrationOrder=-1)
Modifying an existing DOF&#39;s basis function and integration rule.
virtual void buildAndRegisterClosureModelEvaluators(PHX::FieldManager< panzer::Traits > &fm, const panzer::FieldLayoutLibrary &fl, const Teuchos::RCP< panzer::IntegrationRule > &ir, const panzer::ClosureModelFactory_TemplateManager< panzer::Traits > &factory, const Teuchos::ParameterList &models, const Teuchos::ParameterList &user_data) const
Register closure model evaluators with the model name internally specified by the equation set...
Teuchos::RCP< panzer::BasisIRLayout > getBasisIRLayoutForDOF(const std::string &dof_name) const
Returns the BasisIRLayout for the dof_name.
virtual void buildAndRegisterGatherAndOrientationEvaluators(PHX::FieldManager< panzer::Traits > &fm, const panzer::FieldLibrary &fl, const LinearObjFactory< panzer::Traits > &lof, const Teuchos::ParameterList &user_data) const
bool nonnull(const boost::shared_ptr< T > &p)
Teuchos::RCP< const FieldLayoutLibrary > buildFieldLayoutLibrary(panzer::PointRule &ir) const
Teuchos::RCP< PHX::Evaluator< Traits > > buildGatherOrientation(const Teuchos::ParameterList &pl) const
Use preconstructed gather evaluators.
const Teuchos::RCP< Teuchos::ParameterList > m_input_params
virtual const std::vector< int > & getGIDFieldOffsets(const std::string &blockId, int fieldNum) const =0
Use the field pattern so that you can find a particular field in the GIDs array.
void getAddedDOFs(std::vector< std::string > &dofNames) const
virtual const std::vector< std::pair< std::string, Teuchos::RCP< panzer::PureBasis > > > & getProvidedDOFs() const
Return the Basis for the equation set, key is the DOF name (note coordinate DOFs are NOT included) ...
Interpolates basis DOF values to IP DOF values.
Definition: Panzer_DOF.hpp:24
virtual const std::vector< std::vector< std::string > > & getCoordinateDOFs() const
Return a vector of vectors that correspond to DOFs set as coordinate fields.
void addDOFTimeDerivative(const std::string &dofName, const std::string &dotName="")
Teuchos::RCP< PHX::Evaluator< Traits > > buildScatter(const Teuchos::ParameterList &pl) const
Use preconstructed scatter evaluators.
bool buildTransientSupport() const
Returns true if transient support should be enabled in the equation set.
virtual void buildAndRegisterScatterEvaluators(PHX::FieldManager< panzer::Traits > &fm, const panzer::FieldLibrary &fl, const LinearObjFactory< panzer::Traits > &lof, const Teuchos::ParameterList &user_data) const
Description and data layouts associated with a particular basis.
#define TEUCHOS_ASSERT(assertion_test)
void addDOFCurl(const std::string &dofName, const std::string &curlName="")
EquationSet_DefaultImpl(const Teuchos::RCP< Teuchos::ParameterList > &params, const int &default_integration_order, const panzer::CellData &cell_data, const Teuchos::RCP< panzer::GlobalData > &global_data, const bool build_transient_support)
virtual void setElementBlockId(const std::string &blockId)
Gathers coordinates for the basis function from the workset and stores them in the field manager...
void addClosureModel(const std::string &closure_model)