MAST
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
assembly_base.cpp
Go to the documentation of this file.
1 /*
2  * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3  * Copyright (C) 2013-2020 Manav Bhatia and MAST authors
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 // MAST includes
21 #include "base/assembly_base.h"
24 #include "base/elem_base.h"
26 #include "base/nonlinear_system.h"
29 #include "mesh/fe_base.h"
30 #include "mesh/geom_elem.h"
31 #include "numerics/utility.h"
32 
33 
34 // libMesh includes
35 #include "libmesh/numeric_vector.h"
36 #include "libmesh/dof_map.h"
37 
38 
40 close_matrix (true),
41 _elem_ops (nullptr),
42 _discipline (nullptr),
43 _system (nullptr),
44 _sol_function (nullptr),
45 _solver_monitor (nullptr),
46 _param_dependence (nullptr) {
47 
48 }
49 
50 
51 
52 
54 
57 }
58 
59 
60 
63 
64  libmesh_assert_msg(_discipline,
65  "Error: Discipline not yet attached to Assembly.");
66  return *_discipline;
67 }
68 
69 
70 
73 
74  libmesh_assert_msg(_discipline,
75  "Error: Discipline not yet attached to Assembly.");
76  return *_discipline;
77 }
78 
79 
80 
81 
84 
85  libmesh_assert_msg(_discipline,
86  "Error: System not yet attached to Assembly.");
87  return _system->system();
88 }
89 
90 
93 
94  libmesh_assert_msg(_discipline,
95  "Error: System not yet attached to Assembly.");
96  return _system->system();
97 }
98 
99 
102 
103  libmesh_assert_msg(_elem_ops,
104  "Error: Not yet initialized.");
105  return *_elem_ops;
106 }
107 
108 
111 
112  libmesh_assert_msg(_system,
113  "Error: System not yet attached to Assembly.");
114  return *_system;
115 }
116 
117 
118 void
120 
121  libmesh_assert(!_solver_monitor);
122  _solver_monitor = &monitor;
123 }
124 
125 
126 
127 void
130 
131  libmesh_assert(!_param_dependence);
132 
133  _param_dependence = &dep;
134 }
135 
136 
137 
138 void
140 
141  _param_dependence = nullptr;
142 }
143 
144 
145 
148 
149  return _solver_monitor;
150 }
151 
152 
153 void
155 
156  _solver_monitor = nullptr;
157 }
158 
159 
160 void
164 
165  libmesh_assert_msg(!_discipline && !_system,
166  "Error: Assembly should be cleared before attaching System.");
167 
169  _system = &system;
170 }
171 
172 
173 
174 void
177 
178  close_matrix = true;
179  _discipline = nullptr;
180  _system = nullptr;
181  _param_dependence = nullptr;
182 }
183 
184 
185 
186 void
188 
189  libmesh_assert_msg(!_elem_ops,
190  "Error: Assembly should be cleared before attaching Elem.");
191 
192  _elem_ops = &elem_ops;
193  _elem_ops->set_assembly(*this);
194 }
195 
196 
197 
198 void
200 
201  if (_elem_ops) {
203  _elem_ops = nullptr;
204  }
205 }
206 
207 
208 
209 std::unique_ptr<libMesh::NumericVector<Real> >
211 build_localized_vector(const libMesh::System& sys,
212  const libMesh::NumericVector<Real>& global) const {
213 
214  libMesh::NumericVector<Real>* local =
215  libMesh::NumericVector<Real>::build(sys.comm()).release();
216 
217  const std::vector<libMesh::dof_id_type>& send_list =
218  sys.get_dof_map().get_send_list();
219 
220  local->init(sys.n_dofs(),
221  sys.n_local_dofs(),
222  send_list,
223  false,
224  libMesh::GHOSTED);
225  global.localize(*local, send_list);
226 
227  return std::unique_ptr<libMesh::NumericVector<Real> >(local);
228 }
229 
230 
231 
232 
233 void
235 
236  // make sure that no prior association is specified
237  libmesh_assert(!_sol_function);
238 
239  _sol_function = &f;
240 }
241 
242 
243 
244 
245 void
247  _sol_function = nullptr;
248 }
249 
250 
251 
252 
253 void
254 MAST::AssemblyBase::calculate_output(const libMesh::NumericVector<Real>& X,
255  bool if_localize_sol,
257 
258  libmesh_assert(_discipline);
259  libmesh_assert(_system);
260 
261  MAST::NonlinearSystem& nonlin_sys = _system->system();
262  output.set_assembly(*this);
263 
264  output.zero_for_analysis();
265 
266  // iterate over each element, initialize it and get the relevant
267  // analysis quantities
268  RealVectorX sol;
269 
270  std::vector<libMesh::dof_id_type> dof_indices;
271  const libMesh::DofMap& dof_map = _system->system().get_dof_map();
272 
273  const libMesh::NumericVector<Real>*
274  sol_vec = nullptr;
275 
276  std::unique_ptr<libMesh::NumericVector<Real> > localized_solution;
277  if (if_localize_sol) {
278  localized_solution.reset(build_localized_vector(nonlin_sys, X).release());
279  sol_vec = localized_solution.get();
280  }
281  else
282  sol_vec = &X;
283 
284 
285  // if a solution function is attached, initialize it
286  //if (_sol_function)
287  // _sol_function->init( X, false);
288 
289  libMesh::MeshBase::const_element_iterator el =
290  nonlin_sys.get_mesh().active_local_elements_begin();
291  const libMesh::MeshBase::const_element_iterator end_el =
292  nonlin_sys.get_mesh().active_local_elements_end();
293 
294 
295  for ( ; el != end_el; ++el) {
296 
297  const libMesh::Elem* elem = *el;
298 
299  if (diagonal_elem_subdomain_id.count(elem->subdomain_id()))
300  continue;
301 
302  //if (_sol_function)
303  // physics_elem->attach_active_solution_function(*_sol_function);
304 
305  MAST::GeomElem geom_elem;
306  output.set_elem_data(elem->dim(), *elem, geom_elem);
307  geom_elem.init(*elem, *_system);
308 
309  if (!output.if_evaluate_for_element(geom_elem)) continue;
310 
311  dof_map.dof_indices (elem, dof_indices);
312 
313  // get the solution
314  unsigned int ndofs = (unsigned int)dof_indices.size();
315  sol.setZero(ndofs);
316 
317  for (unsigned int i=0; i<dof_indices.size(); i++)
318  sol(i) = (*sol_vec)(dof_indices[i]);
319 
320  output.init(geom_elem);
321  output.set_elem_solution(sol);
322  output.evaluate();
323  output.clear_elem();
324 
325  //physics_elem->detach_active_solution_function();
326  }
327 
328  // if a solution function is attached, clear it
329  if (_sol_function)
330  _sol_function->clear();
331 
332  output.clear_assembly();
333 }
334 
335 
336 
337 
338 void
340 calculate_output_derivative(const libMesh::NumericVector<Real>& X,
341  bool if_localize_sol,
343  libMesh::NumericVector<Real>& dq_dX) {
344 
345  libmesh_assert(_discipline);
346  libmesh_assert(_system);
347 
348  output.zero_for_sensitivity();
349 
350  MAST::NonlinearSystem& nonlin_sys = _system->system();
351  output.set_assembly(*this);
352 
353  dq_dX.zero();
354 
355  // iterate over each element, initialize it and get the relevant
356  // analysis quantities
357  RealVectorX vec, sol;
358 
359  std::vector<libMesh::dof_id_type> dof_indices;
360  const libMesh::DofMap& dof_map = _system->system().get_dof_map();
361 
362  const libMesh::NumericVector<Real>*
363  sol_vec = nullptr;
364 
365  std::unique_ptr<libMesh::NumericVector<Real> > localized_solution;
366 
367  if (if_localize_sol) {
368  localized_solution.reset(build_localized_vector(nonlin_sys, X).release());
369  sol_vec = localized_solution.get();
370  }
371  else
372  sol_vec = &X;
373 
374  // if a solution function is attached, initialize it
375  if (_sol_function)
376  _sol_function->init( X, false);
377 
378 
379  libMesh::MeshBase::const_element_iterator el =
380  nonlin_sys.get_mesh().active_local_elements_begin();
381  const libMesh::MeshBase::const_element_iterator end_el =
382  nonlin_sys.get_mesh().active_local_elements_end();
383 
384 
385  for ( ; el != end_el; ++el) {
386 
387  const libMesh::Elem* elem = *el;
388 
389  if (diagonal_elem_subdomain_id.count(elem->subdomain_id()))
390  continue;
391 
392  MAST::GeomElem geom_elem;
393  output.set_elem_data(elem->dim(), *elem, geom_elem);
394  geom_elem.init(*elem, *_system);
395 
396  if (!output.if_evaluate_for_element(geom_elem)) continue;
397 
398  dof_map.dof_indices (elem, dof_indices);
399 
400  // get the solution
401  unsigned int ndofs = (unsigned int)dof_indices.size();
402  sol.setZero(ndofs);
403  vec.setZero(ndofs);
404 
405  for (unsigned int i=0; i<dof_indices.size(); i++)
406  sol(i) = (*sol_vec)(dof_indices[i]);
407 
408  // if (_sol_function)
409  // physics_elem->attach_active_solution_function(*_sol_function);
410 
411  output.init(geom_elem);
412  output.set_elem_solution(sol);
413  output.output_derivative_for_elem(vec);
414  output.clear_elem();
415 
416  DenseRealVector v;
417  MAST::copy(v, vec);
418  dof_map.constrain_element_vector(v, dof_indices);
419  dq_dX.add_vector(v, dof_indices);
420  dof_indices.clear();
421  }
422 
423  // if a solution function is attached, clear it
424  if (_sol_function)
425  _sol_function->clear();
426 
427  dq_dX.close();
428 
429  output.clear_assembly();
430 }
431 
432 
433 
434 void
436 calculate_output_direct_sensitivity(const libMesh::NumericVector<Real>& X,
437  bool if_localize_sol,
438  const libMesh::NumericVector<Real>* dXdp,
439  bool if_localize_sol_sens,
440  const MAST::FunctionBase& p,
442 
443  libmesh_assert(_discipline);
444  libmesh_assert(_system);
445 
446  output.zero_for_sensitivity();
447 
448  MAST::NonlinearSystem& nonlin_sys = _system->system();
449  output.set_assembly(*this);
450 
451  // iterate over each element, initialize it and get the relevant
452  // analysis quantities
454  sol,
455  dsol;
456 
457  std::vector<libMesh::dof_id_type> dof_indices;
458  const libMesh::DofMap& dof_map = _system->system().get_dof_map();
459 
460  const libMesh::NumericVector<Real>
461  *sol_vec = nullptr,
462  *dsol_vec = nullptr;
463 
464  std::unique_ptr<libMesh::NumericVector<Real> >
465  localized_solution,
466  localized_solution_sens;
467 
468  if (if_localize_sol) {
469  localized_solution.reset(build_localized_vector(nonlin_sys, X).release());
470  sol_vec = localized_solution.get();
471  }
472  else
473  sol_vec = &X;
474 
475  if (dXdp) {
476  if (if_localize_sol_sens) {
477  localized_solution_sens.reset(build_localized_vector(nonlin_sys, *dXdp).release());
478  dsol_vec = localized_solution_sens.get();
479  }
480  else
481  dsol_vec = dXdp;
482  }
483 
484 
485  // if a solution function is attached, initialize it
486  if (_sol_function)
487  _sol_function->init( X, false);
488 
489 
490  libMesh::MeshBase::const_element_iterator el =
491  nonlin_sys.get_mesh().active_local_elements_begin();
492  const libMesh::MeshBase::const_element_iterator end_el =
493  nonlin_sys.get_mesh().active_local_elements_end();
494 
495 
496  for ( ; el != end_el; ++el) {
497 
498  const libMesh::Elem* elem = *el;
499 
500  if (diagonal_elem_subdomain_id.count(elem->subdomain_id()))
501  continue;
502 
503  // no sensitivity computation assembly is neeed in these cases
504  if (_param_dependence &&
505  // if object is specified and elem does not depend on it
507  // and if no sol_sens is given
508  (!dXdp ||
509  // or if it can be ignored for elem
510  (dXdp && _param_dependence->override_flag)))
511  continue;
512 
513  MAST::GeomElem geom_elem;
514  output.set_elem_data(elem->dim(), *elem, geom_elem);
515  geom_elem.init(*elem, *_system);
516 
517  if (!output.if_evaluate_for_element(geom_elem)) continue;
518 
519  dof_map.dof_indices (elem, dof_indices);
520 
521  // get the solution
522  unsigned int ndofs = (unsigned int)dof_indices.size();
523  sol.setZero(ndofs);
524  dsol.setZero(ndofs);
525 
526  for (unsigned int i=0; i<dof_indices.size(); i++) {
527  sol(i) = (*sol_vec)(dof_indices[i]);
528  if (dXdp)
529  dsol(i) = (*dsol_vec)(dof_indices[i]);
530  }
531 
532  // if (_sol_function)
533  // physics_elem->attach_active_solution_function(*_sol_function);
534 
535 
536  output.init(geom_elem);
537  output.set_elem_solution(sol);
538  output.set_elem_solution_sensitivity(dsol);
539  output.evaluate_sensitivity(p);
540  output.clear_elem();
541 
542  // physics_elem->detach_active_solution_function();
543  }
544 
545  // if a solution function is attached, clear it
546  if (_sol_function)
547  _sol_function->clear();
548 
549  output.clear_assembly();
550 }
551 
552 
553 
554 
555 Real
557 calculate_output_adjoint_sensitivity(const libMesh::NumericVector<Real>& X,
558  bool if_localize_sol,
559  const libMesh::NumericVector<Real>& adj_sol,
560  const MAST::FunctionBase& p,
563  const bool include_partial_sens) {
564 
565  libmesh_assert(_discipline);
566  libmesh_assert(_system);
567 
568  MAST::NonlinearSystem& nonlin_sys = _system->system();
569 
570  libMesh::NumericVector<Real>
571  &dres_dp = nonlin_sys.add_sensitivity_rhs();
572 
573  this->set_elem_operation_object(elem_ops);
574  this->sensitivity_assemble(X, if_localize_sol, p, dres_dp);
576 
577  Real
578  dq_dp = adj_sol.dot(dres_dp);
579 
580  if (include_partial_sens) {
581 
582  // calculate the partial sensitivity of the output, which is done
583  // with zero solution vector
584  this->calculate_output_direct_sensitivity(X, if_localize_sol, nullptr, false, p, output);
585 
586  dq_dp += output.output_sensitivity_total(p);
587  }
588 
589  return dq_dp;
590 }
591 
592 
593 
594 void
596 (const libMesh::NumericVector<Real>& X,
597  bool if_localize_sol,
598  const libMesh::NumericVector<Real>& adj_sol,
599  const std::vector<const MAST::FunctionBase*>& p_vec,
602  std::vector<Real>& sens) {
603 
604  libmesh_assert(_discipline);
605  libmesh_assert(_system);
606  libmesh_assert_equal_to(sens.size(), p_vec.size());
607 
608  MAST::NonlinearSystem& nonlin_sys = _system->system();
609 
610  // zero the sensitivity data first
611  std::fill(sens.begin(), sens.end(), 0.);
612 
613  // add vectors before computing sensitivity
614  for (unsigned int i=0; i<p_vec.size(); i++) nonlin_sys.add_sensitivity_rhs(i);
615 
616  // first compute all the residual vectors without closing them. later we will close them
617  // and then compute the sensitivity
618  for (unsigned int i=0; i<p_vec.size(); i++) {
619 
620  const MAST::FunctionBase& p = *p_vec[i];
621 
622  libMesh::NumericVector<Real>
623  &dres_dp = nonlin_sys.get_sensitivity_rhs(i);
624 
625  this->set_elem_operation_object(elem_ops);
626  this->sensitivity_assemble(X, if_localize_sol, p, dres_dp, false);
628  }
629 
630  for (unsigned int i=0; i<p_vec.size(); i++) {
631 
632  const MAST::FunctionBase& p = *p_vec[i];
633 
634  libMesh::NumericVector<Real>
635  &dres_dp = nonlin_sys.add_sensitivity_rhs(i);
636  dres_dp.close();
637  sens[i] = adj_sol.dot(dres_dp);
638  }
639 }
640 
MAST::AssemblyElemOperations * _elem_ops
provides assembly elem operations for use by this class
const MAST::NonlinearSystem & system() const
MAST::NonlinearSystem & system()
void init(const libMesh::NumericVector< Real > &sol, bool reuse_vector)
initializes the data structures to perform the interpolation function of sol.
virtual bool if_elem_depends_on_parameter(const libMesh::Elem &e, const MAST::FunctionBase &p) const =0
AssemblyBase()
constructor takes a reference to the discipline that provides the boundary conditions, volume loads, properties, etc.
void clear_solver_monitor()
clears the monitor object
This class implements a system for solution of nonlinear systems.
virtual bool if_evaluate_for_element(const MAST::GeomElem &elem) const
checks to see if the object has been told about the subset of elements and if the specified element i...
virtual void calculate_output_derivative(const libMesh::NumericVector< Real > &X, bool if_localize_sol, MAST::OutputAssemblyElemOperations &output, libMesh::NumericVector< Real > &dq_dX)
calculates
bool override_flag
if true, assume zero solution sensitivity when elem does not dependent on parameter.
virtual Real calculate_output_adjoint_sensitivity(const libMesh::NumericVector< Real > &X, bool if_localize_sol, const libMesh::NumericVector< Real > &adj_sol, const MAST::FunctionBase &p, MAST::AssemblyElemOperations &elem_ops, MAST::OutputAssemblyElemOperations &output, const bool include_partial_sens=true)
Evaluates the total sensitivity of output wrt p using the adjoint solution provided in adj_sol for a ...
virtual void clear_elem_operation_object()
clears the association of this object with the assembly element operation object. ...
This provides a wrapper FieldFunction compatible class that interpolates the solution using libMesh&#39;s...
void attach_solution_function(MAST::MeshFieldFunction &f)
tells the assembly object that this function is will need to be initialized before each residual eval...
void attach_elem_parameter_dependence_object(MAST::AssemblyBase::ElemParameterDependence &dep)
This object, if provided by user, will be used to reduce unnecessary computations in sensitivity anal...
virtual void set_elem_solution_sensitivity(const RealVectorX &sol)
sets the element solution sensitivity
void set_solver_monitor(MAST::AssemblyBase::SolverMonitor &monitor)
attaches the solver monitor, which is a user provided routine that is called each time ...
virtual void set_assembly(MAST::AssemblyBase &assembly)
sets the assembly object
This provides the base class for definitin of element level contribution of output quantity in an ana...
virtual void zero_for_sensitivity()=0
zeroes the output quantity values stored inside this object so that assembly process can begin...
bool close_matrix
flag to control the closing fo the Jacobian after assembly
virtual void set_elem_operation_object(MAST::AssemblyElemOperations &elem_ops)
attaches a element operation to this object, and associated this with the element operation object...
virtual void set_elem_solution(const RealVectorX &sol)
sets the element solution
libMesh::Real Real
virtual void evaluate()=0
this is the abstract interface to be implemented by derived classes.
std::set< unsigned int > diagonal_elem_subdomain_id
subdomain ids for which residuakl and Jacobian contributions will not be computed.
Definition: assembly_base.h:71
MAST::SystemInitialization * _system
System for which this assembly is performed.
virtual void calculate_output(const libMesh::NumericVector< Real > &X, bool if_localize_sol, MAST::OutputAssemblyElemOperations &output)
calculates the value of quantity .
void detach_solution_function()
removes the attachment of the solution function
MAST::PhysicsDisciplineBase * _discipline
PhysicsDisciplineBase object for which this class is assembling.
virtual void set_elem_data(unsigned int dim, const libMesh::Elem &ref_elem, MAST::GeomElem &elem) const =0
some analyses may want to set additional element data before initialization of the GeomElem...
virtual void clear_discipline_and_system()
clears association with a system to this discipline
libMesh::DenseVector< Real > DenseRealVector
std::unique_ptr< libMesh::NumericVector< Real > > build_localized_vector(const libMesh::System &sys, const libMesh::NumericVector< Real > &global) const
localizes the parallel vector so that the local copy stores all values necessary for calculation of t...
virtual void clear_assembly()
clears the assembly object
void copy(DenseRealMatrix &m1, const RealMatrixX &m2)
Definition: utility.h:167
void clear()
clear the solution
Matrix< Real, Dynamic, 1 > RealVectorX
virtual Real output_sensitivity_total(const MAST::FunctionBase &p)=0
virtual void init(const MAST::GeomElem &elem)=0
initializes the object for calculation of element quantities for the specified elem.
virtual void output_derivative_for_elem(RealVectorX &dq_dX)=0
returns the output quantity derivative with respect to state vector in dq_dX.
virtual void calculate_output_direct_sensitivity(const libMesh::NumericVector< Real > &X, bool if_localize_sol, const libMesh::NumericVector< Real > *dXdp, bool if_localize_sol_sens, const MAST::FunctionBase &p, MAST::OutputAssemblyElemOperations &output)
evaluates the sensitivity of the outputs in the attached discipline with respect to the parametrs in ...
void clear_elem_parameter_dependence_object()
MAST::AssemblyBase::SolverMonitor * get_solver_monitor()
This class acts as a wrapper around libMesh::Elem for the purpose of providing a uniform interface fo...
Definition: geom_elem.h:59
Inherited objects from this class can be provided by the user provide assessment of whether or not an...
Definition: assembly_base.h:93
virtual void calculate_output_adjoint_sensitivity_multiple_parameters_no_direct(const libMesh::NumericVector< Real > &X, bool if_localize_sol, const libMesh::NumericVector< Real > &adj_sol, const std::vector< const MAST::FunctionBase *> &p_vec, MAST::AssemblyElemOperations &elem_ops, MAST::OutputAssemblyElemOperations &output, std::vector< Real > &sens)
Evaluates the dot product between adj_sol and sensitivity of residual about X for multiple parameter_...
MAST::SystemInitialization & system_init()
virtual void zero_for_analysis()=0
zeroes the output quantity values stored inside this object so that assembly process can begin...
MAST::AssemblyBase::ElemParameterDependence * _param_dependence
If provided by user, this object is used by sensitiivty analysis to check for whether or the current ...
virtual void set_discipline_and_system(MAST::PhysicsDisciplineBase &discipline, MAST::SystemInitialization &system)
attaches a system to this discipline
virtual void clear_elem()
clears the element initialization
const MAST::PhysicsDisciplineBase & discipline() const
virtual ~AssemblyBase()
virtual destructor
MAST::AssemblyElemOperations & get_elem_ops()
virtual void init(const libMesh::Elem &elem, const MAST::SystemInitialization &sys_init)
initialize the object for the specified reference elem.
Definition: geom_elem.cpp:134
MAST::AssemblyBase::SolverMonitor * _solver_monitor
User provided solver monitor is attached to the linear nonlinear solvers, if provided.
virtual void evaluate_sensitivity(const MAST::FunctionBase &f)=0
this evaluates all relevant sensitivity components on the element.
MAST::MeshFieldFunction * _sol_function
system solution that will be initialized before each solution
virtual bool sensitivity_assemble(const libMesh::NumericVector< Real > &X, bool if_localize_sol, const MAST::FunctionBase &f, libMesh::NumericVector< Real > &sensitivity_rhs, bool close_vector=true)
Assembly function.