MAST
level_set_nonlinear_implicit_assembly.cpp
Go to the documentation of this file.
1 /*
2  * MAST: Multidisciplinary-design Adaptation and Sensitivity Toolkit
3  * Copyright (C) 2013-2019 Manav Bhatia
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
26 #include "level_set/sub_cell_fe.h"
27 #include "level_set/filter_base.h"
30 #include "base/nonlinear_system.h"
34 #include "base/elem_base.h"
35 #include "numerics/utility.h"
36 
37 
38 // libMesh includes
39 #include "libmesh/nonlinear_solver.h"
40 #include "libmesh/numeric_vector.h"
41 #include "libmesh/sparse_matrix.h"
42 #include "libmesh/dof_map.h"
43 
44 
45 
47 LevelSetNonlinearImplicitAssembly(bool enable_dof_handler):
49 _enable_dof_handler (enable_dof_handler),
50 _evaluate_output_on_negative_phi (false),
51 _level_set (nullptr),
52 _indicator (nullptr),
53 _intersection (nullptr),
54 _dof_handler (nullptr),
55 _void_solution_monitor (nullptr),
56 _velocity (nullptr),
57 _filter (nullptr) {
58 
59 }
60 
61 
62 
64 
65  if (_intersection) delete _intersection;
66  if (_dof_handler) delete _dof_handler;
68 }
69 
70 
73 
74  libmesh_assert(_level_set);
75  return *_intersection;
76 }
77 
78 
79 
80 void
82 
84 }
85 
86 
87 bool
89  return _enable_dof_handler;
90 }
91 
92 
95 
96  libmesh_assert(_level_set);
97  libmesh_assert(_dof_handler);
98  return *_dof_handler;
99 }
100 
101 
102 void
105  const MAST::FilterBase& filter) {
106 
107  libmesh_assert(!_level_set);
108  libmesh_assert(!_intersection);
109  libmesh_assert(_system);
110 
111  _level_set = &level_set;
112  _filter = &filter;
114  if (_enable_dof_handler) {
119  }
120 }
121 
122 
123 
124 void
127 
128  libmesh_assert(!_indicator);
129  libmesh_assert(_system);
130 
131  _indicator = &indicator;
132 }
133 
134 
135 
136 void
138 
139  _level_set = nullptr;
140  _filter = nullptr;
141 
142  if (_intersection) {
143  delete _intersection;
144  delete _dof_handler;
145  delete _void_solution_monitor;
146 
147  _intersection = nullptr;
148  _dof_handler = nullptr;
149  _void_solution_monitor = nullptr;
150  }
151 }
152 
153 
154 
155 
156 void
159 
160  libmesh_assert(_level_set);
161  libmesh_assert(_intersection);
162  libmesh_assert(_system);
163  libmesh_assert(!_velocity);
164 
165  _velocity = &velocity;
166 }
167 
168 
169 
170 void
172 
173  _velocity = nullptr;
174 }
175 
176 
177 
178 #if MAST_ENABLE_PLPLOT == 1
179 
180 #include <numeric>
181 #include "plplot/plplot.h"
182 
183 void plot_elem(const libMesh::Elem& e) {
184 
185  unsigned int
186  n = e.n_nodes();
187 
189  x = RealVectorX::Zero(n+1),
190  y = RealVectorX::Zero(n+1);
191 
192  for (unsigned int i=0; i<n+1; i++) {
193  x(i) = e.point(i%n)(0);
194  y(i) = e.point(i%n)(1);
195  }
196 
197  plline(n+1, x.data(), y.data());
198  plflush();
199 }
200 
201 
202 void plot_points(const std::vector<libMesh::Point>& pts) {
203 
204  unsigned int
205  n = pts.size();
206 
208  x = RealVectorX::Zero(n),
209  y = RealVectorX::Zero(n);
210 
211  for (unsigned int i=0; i<n; i++) {
212  x(i) = pts[i](0);
213  y(i) = pts[i](1);
214  }
215 
216  plpoin(n, x.data(), y.data(), -1);
217  plflush();
218 }
219 
220 
221 void
222 MAST::LevelSetNonlinearImplicitAssembly::plot_sub_elems(bool plot_reference_elem,
223  bool plot_low_phi_elem,
224  bool plot_high_phi_elem) {
225 
226  libmesh_assert(_system);
227  libmesh_assert(_discipline);
228  libmesh_assert(_level_set);
229 
230  MAST::NonlinearSystem& nonlin_sys = _system->system();
231 
232 
233  libMesh::MeshBase::const_element_iterator el =
234  nonlin_sys.get_mesh().active_local_elements_begin();
235  const libMesh::MeshBase::const_element_iterator end_el =
236  nonlin_sys.get_mesh().active_local_elements_end();
237 
238 
239  plsdev("xwin");
240  plinit();
241  plenv(0,.3,0,.3,0,0);
242 
243 
244  for ( ; el != end_el; ++el) {
245 
246  const libMesh::Elem* elem = *el;
247 
248  {
249  MAST::FEBase fe(*_system);
250  fe.init(*elem);
251  const std::vector<Real>& JxW = fe.get_JxW();
252  std::cout << "==== original JxW: " << std::accumulate(JxW.begin(),
253  JxW.end(), 0.) << std::endl;
254  }
255 
256 
257  if (plot_reference_elem) {
258  plcol0(1); // red color for elements
259  plot_elem(*elem);
260  }
261 
262  _intersection->init(*_level_set, *elem, nonlin_sys.time);
263 
264  // now get elements on either side and plot
265  const std::vector<const libMesh::Elem *> &
268 
269 
270  if (plot_low_phi_elem) {
271 
272  for (unsigned int i = 0; i < elems_low.size(); i++) {
273 
274  plcol0(3); // green color for sub elements
275  plot_elem(*elems_low[i]);
276 
277  // create FE
278  std::unique_ptr<MAST::FEBase> fe(new MAST::SubCellFE(*_system, *_intersection));
279  fe->init(*elems_low[i]);
280  const std::vector<Real>& JxW = fe->get_JxW();
281  const std::vector<libMesh::Point>& xyz = fe->get_xyz();
282  std::cout << "low: JxW: " << std::accumulate(JxW.begin(),
283  JxW.end(), 0.) << std::endl;
284  plot_points(xyz);
285  }
286  }
287 
288 
289  if (plot_high_phi_elem) {
290 
291  for (unsigned int i=0; i<elems_hi.size(); i++) {
292 
293  plcol0(15); // white color for sub elements
294  plot_elem(*elems_hi[i]);
295 
296  // create FE
297  std::unique_ptr<MAST::FEBase> fe(new MAST::SubCellFE(*_system, *_intersection));
298  fe->init(*elems_hi[i]);
299  const std::vector<Real>& JxW = fe->get_JxW();
300  const std::vector<libMesh::Point>& xyz = fe->get_xyz();
301  std::cout << "hi: JxW: " << std::accumulate(JxW.begin(),
302  JxW.end(), 0.) << std::endl;
303  plot_points(xyz);
304  }
305  }
306 
307  _intersection->clear();
308  }
309 
310  // if a solution function is attached, clear it
311  if (_sol_function)
312  _sol_function->clear();
313 }
314 
315 #endif // HAVE_PLPLOT
316 
317 
318 
319 
320 void
322 residual_and_jacobian (const libMesh::NumericVector<Real>& X,
323  libMesh::NumericVector<Real>* R,
324  libMesh::SparseMatrix<Real>* J,
325  libMesh::NonlinearImplicitSystem& S) {
326 
327  libmesh_assert(_system);
328  libmesh_assert(_discipline);
329  libmesh_assert(_elem_ops);
330  libmesh_assert(_level_set);
331 
332  MAST::NonlinearSystem& nonlin_sys = _system->system();
333 
334  // make sure that the system for which this object was created,
335  // and the system passed through the function call are the same
336  libmesh_assert_equal_to(&S, &(nonlin_sys));
337 
338  if (R) R->zero();
339  if (J) J->zero();
340 
341  const Real
342  tol = 1.e-10;
343 
344  // iterate over each element, initialize it and get the relevant
345  // analysis quantities
347  vec,
348  sol,
349  sub_elem_vec,
350  res_factored_u,
351  nd_indicator = RealVectorX::Ones(1),
352  indicator = RealVectorX::Zero(1);
354  mat,
355  sub_elem_mat,
356  jac_factored_uu;
357 
358  std::vector<libMesh::dof_id_type>
359  dof_indices,
360  material_rows;
361  const libMesh::DofMap& dof_map = _system->system().get_dof_map();
362 
363 
364  std::unique_ptr<libMesh::NumericVector<Real> > localized_solution;
365  localized_solution.reset(build_localized_vector(nonlin_sys,
366  X).release());
367 
368 
369  // if a solution function is attached, initialize it
370  if (_sol_function)
371  _sol_function->init( X);
372 
373 
374  libMesh::MeshBase::const_element_iterator el =
375  nonlin_sys.get_mesh().active_local_elements_begin();
376  const libMesh::MeshBase::const_element_iterator end_el =
377  nonlin_sys.get_mesh().active_local_elements_end();
378 
380  &ops = dynamic_cast<MAST::NonlinearImplicitAssemblyElemOperations&>(*_elem_ops);
381 
382  for ( ; el != end_el; ++el) {
383 
384  const libMesh::Elem* elem = *el;
385 
386  _intersection->init(*_level_set, *elem, nonlin_sys.time,
387  nonlin_sys.get_mesh().max_elem_id(),
388  nonlin_sys.get_mesh().max_node_id());
389  dof_map.dof_indices (elem, dof_indices);
390 
391  // use the indicator if it was provided
392  if (_indicator) {
393 
394  nd_indicator.setZero(elem->n_nodes());
395  for (unsigned int i=0; i<elem->n_nodes(); i++) {
396  (*_indicator)(elem->node_ref(i), nonlin_sys.time, indicator);
397  nd_indicator(i) = indicator(0);
398  }
399  }
400 
401  unsigned int ndofs = (unsigned int)dof_indices.size();
402 
403  // Petsc needs that every diagonal term be provided some contribution,
404  // even if zero. Otherwise, it complains about lack of diagonal entry.
405  // So, if the element is NOT completely on the positive side, we still
406  // add a zero matrix to get around this issue.
408  nd_indicator.maxCoeff() < tol) && J) {
409 
410  DenseRealMatrix m(ndofs, ndofs);
411  //dof_map.constrain_element_matrix(m, dof_indices);
412  for (unsigned int i=0; i<ndofs; i++)
413  m(i,i) = 1.e-14;
414  dof_map.constrain_element_matrix(m, dof_indices);
415  J->add_matrix(m, dof_indices);
416  }
417 
418 
419  if (nd_indicator.maxCoeff() > tol &&
421 
422  // get the solution
423  sol.setZero(ndofs);
424  vec.setZero(ndofs);
425  sub_elem_vec.setZero(ndofs);
426  mat.setZero(ndofs, ndofs);
427  sub_elem_mat.setZero(ndofs, ndofs);
428 
429  for (unsigned int i=0; i<dof_indices.size(); i++)
430  sol(i) = (*localized_solution)(dof_indices[i]);
431 
432  // if the element has been marked for factorization then
433  // get the void solution from the storage
436 
437  // if the element has been marked for factorization,
438  // get the factorized jacobian and residual contributions
440 
441  // the Jacobian is based on the homogenizaton method to maintain
442  // a well conditioned global Jacobian.
443  MAST::GeomElem geom_elem;
444  ops.set_elem_data(elem->dim(), *elem, geom_elem);
445  geom_elem.init(*elem, *_system);
446 
447  ops.init(geom_elem);
448  ops.set_elem_solution(sol);
449  ops.elem_calculations(true, vec, mat);
450  ops.clear_elem();
452  // the residual based on homogenization is used for factorized
453  // elements since the factorization depends on exact Jacobian
454  // and the homogenization based Jacobian is not exact linearization
455  // of residual based on sub cells.
457 
459  mat,
460  vec,
461  material_rows,
462  jac_factored_uu,
463  res_factored_u);
464 
465  // zero the element matrix and update with the
466  // factored matrix
467  mat.setIdentity(); mat *= 1.e-6; // set a small value on the diagonal to avoid nans
468  vec.setZero();
469 
470  for (unsigned int i=0; i<material_rows.size(); i++) {
471 
472  vec(material_rows[i]) = res_factored_u(i);
473 
474  for (unsigned int j=0; j<material_rows.size(); j++)
475  mat(material_rows[i], material_rows[j]) = jac_factored_uu(i,j);
476  }
477  }
478  else {
479 
480  // get the residual from the sub elements
481  mat.setZero();
482  vec.setZero();
483 
484  const std::vector<const libMesh::Elem *> &
486 
487  std::vector<const libMesh::Elem*>::const_iterator
488  hi_sub_elem_it = elems_hi.begin(),
489  hi_sub_elem_end = elems_hi.end();
490 
491  for (; hi_sub_elem_it != hi_sub_elem_end; hi_sub_elem_it++ ) {
492 
493  const libMesh::Elem* sub_elem = *hi_sub_elem_it;
494 
496  ops.set_elem_data(elem->dim(), *elem, geom_elem);
497  geom_elem.init(*sub_elem, *_system, *_intersection);
498 
499  ops.init(geom_elem);
500  ops.set_elem_solution(sol);
501 
502  ops.elem_calculations(J!=nullptr?true:false, sub_elem_vec, sub_elem_mat);
503 
504  mat += sub_elem_mat;
505  vec += sub_elem_vec;
506 
507  ops.clear_elem();
508  }
509  }
510 
511  // copy to the libMesh matrix for further processing
512  DenseRealVector v;
513  DenseRealMatrix m;
514  if (R)
515  MAST::copy(v, vec);
516  if (J)
517  MAST::copy(m, mat);
518 
519  // constrain the quantities to account for hanging dofs,
520  // Dirichlet constraints, etc.
521  if (R && J)
522  dof_map.constrain_element_matrix_and_vector(m, v, dof_indices);
523  else if (R)
524  dof_map.constrain_element_vector(v, dof_indices);
525  else
526  dof_map.constrain_element_matrix(m, dof_indices);
527 
528  // add to the global matrices
529  if (R) R->add_vector(v, dof_indices);
530  if (J) J->add_matrix(m, dof_indices);
531  dof_indices.clear();
532  }
533 
534  _intersection->clear();
535  }
536 
537  // call the post assembly object, if provided by user
538  if (_post_assembly)
539  _post_assembly->post_assembly(X, R, J, S);
540 
541 
542  // if a solution function is attached, clear it
543  if (_sol_function)
544  _sol_function->clear();
545 
546  if (R) R->close();
547  if (J && close_matrix) J->close();
548 }
549 
550 
551 bool
554  libMesh::NumericVector<Real>& sensitivity_rhs) {
555 
556  libmesh_assert(_system);
557  libmesh_assert(_discipline);
558  libmesh_assert(_elem_ops);
559  // we need the velocity for topology parameter
560  if (f.is_topology_parameter()) libmesh_assert(_velocity);
561 
562  // we need the velocity for topology parameter
564  *p_ls = nullptr;
565  if (f.is_topology_parameter()) {
566  libmesh_assert(_velocity);
567  p_ls = dynamic_cast<const MAST::LevelSetParameter*>(&f);
568  }
569 
570  MAST::NonlinearSystem& nonlin_sys = _system->system();
571 
572  sensitivity_rhs.zero();
573 
574  const Real
575  tol = 1.e-10;
576 
577  // iterate over each element, initialize it and get the relevant
578  // analysis quantities
580  vec1,
581  vec2,
582  vec_total,
583  sol,
584  res_factored_u,
585  nd_indicator = RealVectorX::Ones(1),
586  indicator = RealVectorX::Zero(1);
588  mat,
589  jac_factored_uu;
590 
591  std::vector<libMesh::dof_id_type>
592  dof_indices,
593  material_rows;
594  const libMesh::DofMap& dof_map = nonlin_sys.get_dof_map();
595 
596 
597  std::unique_ptr<libMesh::NumericVector<Real> > localized_solution;
598  localized_solution.reset(build_localized_vector(nonlin_sys,
599  *nonlin_sys.solution).release());
600 
601  // if a solution function is attached, initialize it
602  if (_sol_function)
603  _sol_function->init( *nonlin_sys.solution);
604 
605  libMesh::MeshBase::const_element_iterator el =
606  nonlin_sys.get_mesh().active_local_elements_begin();
607  const libMesh::MeshBase::const_element_iterator end_el =
608  nonlin_sys.get_mesh().active_local_elements_end();
609 
611  ops = dynamic_cast<MAST::NonlinearImplicitAssemblyElemOperations&>(*_elem_ops);
612 
613  for ( ; el != end_el; ++el) {
614 
615  const libMesh::Elem* elem = *el;
616 
617  // no sensitivity computation assembly is neeed in these cases
618  if (_param_dependence &&
619  // if object is specified and elem does not depend on it
621  continue;
622 
623  _intersection->init(*_level_set, *elem, nonlin_sys.time,
624  nonlin_sys.get_mesh().max_elem_id(),
625  nonlin_sys.get_mesh().max_node_id());
626 
627  dof_map.dof_indices (elem, dof_indices);
628 
629  // use the indicator if it was provided
630  if (_indicator) {
631 
632  nd_indicator.setZero(elem->n_nodes());
633  for (unsigned int i=0; i<elem->n_nodes(); i++) {
634  (*_indicator)(elem->node_ref(i), nonlin_sys.time, indicator);
635  nd_indicator(i) = indicator(0);
636  }
637  }
638 
639  if (nd_indicator.maxCoeff() > tol &&
641 
642  // get the solution
643  unsigned int ndofs = (unsigned int)dof_indices.size();
644  sol.setZero(ndofs);
645  vec_total.setZero(ndofs);
646  vec1.setZero(ndofs);
647  vec2.setZero(ndofs);
648 
649  for (unsigned int i=0; i<dof_indices.size(); i++)
650  sol(i) = (*localized_solution)(dof_indices[i]);
651 
652  // if the element has been marked for factorization then
653  // get the void solution from the storage
656 
657  const std::vector<const libMesh::Elem *> &
659 
660  std::vector<const libMesh::Elem*>::const_iterator
661  hi_sub_elem_it = elems_hi.begin(),
662  hi_sub_elem_end = elems_hi.end();
663 
664  for (; hi_sub_elem_it != hi_sub_elem_end; hi_sub_elem_it++ ) {
665 
666  const libMesh::Elem* sub_elem = *hi_sub_elem_it;
667 
669  ops.set_elem_data(elem->dim(), *elem, geom_elem);
670  geom_elem.init(*sub_elem, *_system, *_intersection);
671 
672  ops.init(geom_elem);
673  ops.set_elem_solution(sol);
674 
675  // if (_sol_function)
676  // physics_elem->attach_active_solution_function(*_sol_function);
677 
678  // perform the element level calculations
679  ops.elem_sensitivity_calculations(f, vec1);
680 
681  // if the quantity is also defined as a topology parameter,
682  // then calculate sensitivity from boundary movement.
683  if (f.is_topology_parameter()) {
684 
686  *_velocity,
687  vec2);
688  vec1 += vec2;
689  }
690  ops.clear_elem();
691 
692  // if the element has been identified for factoring then
693  // we will factor the residual and replace it in the
694  // residual vector. For this we need to compute the
695  // element Jacobian matrix
697 
698  vec2.setZero(ndofs);
699  mat.setZero(ndofs, ndofs);
700 
701  MAST::GeomElem geom_elem;
702  ops.set_elem_data(elem->dim(), *elem, geom_elem);
703  geom_elem.init(*elem, *_system);
704 
705  ops.init(geom_elem);
706  ops.set_elem_solution(sol);
707  ops.elem_calculations(true, vec2, mat);
708  ops.clear_elem();
710 
712  mat,
713  vec1,
714  material_rows,
715  jac_factored_uu,
716  res_factored_u);
717 
718  vec1.setZero();
719 
720  for (unsigned int i=0; i<material_rows.size(); i++)
721  vec1(material_rows[i]) = res_factored_u(i);
722  }
723 
724  vec_total += vec1;
725 
726 
727  // physics_elem->detach_active_solution_function();
728  ops.clear_elem();
729  }
730 
731  // copy to the libMesh matrix for further processing
732  DenseRealVector v;
733  MAST::copy(v, vec_total);
734 
735  // constrain the quantities to account for hanging dofs,
736  // Dirichlet constraints, etc.
737  dof_map.constrain_element_vector(v, dof_indices);
738 
739  // add to the global matrices
740  sensitivity_rhs.add_vector(v, dof_indices);
741  dof_indices.clear();
742  }
743 
744  _intersection->clear();
745  }
746 
747  // if a solution function is attached, initialize it
748  if (_sol_function)
749  _sol_function->clear();
750 
751  sensitivity_rhs.close();
752 
753  return true;
754 }
755 
756 
757 
758 
759 void
761 calculate_output(const libMesh::NumericVector<Real>& X,
763 
764  libmesh_assert(_system);
765  libmesh_assert(_discipline);
766  libmesh_assert(_level_set);
767 
768  output.zero_for_analysis();
769 
770  MAST::NonlinearSystem& nonlin_sys = _system->system();
771  output.set_assembly(*this);
772 
773  const Real
774  tol = 1.e-10;
775 
777  sol,
778  nd_indicator = RealVectorX::Ones(1),
779  indicator = RealVectorX::Zero(1);
780 
781  std::vector<libMesh::dof_id_type> dof_indices;
782  const libMesh::DofMap& dof_map = _system->system().get_dof_map();
783 
784 
785  std::unique_ptr<libMesh::NumericVector<Real> > localized_solution;
786  localized_solution.reset(build_localized_vector(nonlin_sys,
787  X).release());
788 
789 
790  // if a solution function is attached, initialize it
791  //if (_sol_function)
792  // _sol_function->init( X);
793 
794 
795  libMesh::MeshBase::const_element_iterator el =
796  nonlin_sys.get_mesh().active_local_elements_begin();
797  const libMesh::MeshBase::const_element_iterator end_el =
798  nonlin_sys.get_mesh().active_local_elements_end();
799 
800 
801  for ( ; el != end_el; ++el) {
802 
803  const libMesh::Elem* elem = *el;
804 
805  // use the indicator if it was provided
806  if (_indicator) {
807 
808  nd_indicator.setZero(elem->n_nodes());
809  for (unsigned int i=0; i<elem->n_nodes(); i++) {
810  (*_indicator)(elem->node_ref(i), nonlin_sys.time, indicator);
811  nd_indicator(i) = indicator(0);
812  }
813  }
814 
815  _intersection->init(*_level_set, *elem, nonlin_sys.time,
816  nonlin_sys.get_mesh().max_elem_id(),
817  nonlin_sys.get_mesh().max_node_id());
818 
821 
822  dof_map.dof_indices (elem, dof_indices);
823 
824  // get the solution
825  unsigned int ndofs = (unsigned int)dof_indices.size();
826  sol.setZero(ndofs);
827 
828  for (unsigned int i=0; i<dof_indices.size(); i++)
829  sol(i) = (*localized_solution)(dof_indices[i]);
830 
831  // if the element has been marked for factorization then
832  // get the void solution from the storage
835 
836  const std::vector<const libMesh::Elem *> &
838 
839  std::vector<const libMesh::Elem*>::const_iterator
840  low_sub_elem_it = elems_low.begin(),
841  low_sub_elem_end = elems_low.end();
842 
843  for (; low_sub_elem_it != low_sub_elem_end; low_sub_elem_it++ ) {
844 
845  const libMesh::Elem* sub_elem = *low_sub_elem_it;
846 
847  // if (_sol_function)
848  // physics_elem->attach_active_solution_function(*_sol_function);
850  output.set_elem_data(elem->dim(), *elem, geom_elem);
851  geom_elem.init(*sub_elem, *_system, *_intersection);
852 
853  output.init(geom_elem);
854  output.set_elem_solution(sol);
855  output.evaluate();
856  output.clear_elem();
857  }
858  }
859 
860  if (nd_indicator.maxCoeff() > tol &&
862 
863  dof_map.dof_indices (elem, dof_indices);
864 
865  // get the solution
866  unsigned int ndofs = (unsigned int)dof_indices.size();
867  sol.setZero(ndofs);
868 
869  for (unsigned int i=0; i<dof_indices.size(); i++)
870  sol(i) = (*localized_solution)(dof_indices[i]);
871 
872  // if the element has been marked for factorization then
873  // get the void solution from the storage
876 
877  const std::vector<const libMesh::Elem *> &
878  //elems_low = intersect.get_sub_elems_negative_phi(),
880 
881  std::vector<const libMesh::Elem*>::const_iterator
882  hi_sub_elem_it = elems_hi.begin(),
883  hi_sub_elem_end = elems_hi.end();
884 
885  for (; hi_sub_elem_it != hi_sub_elem_end; hi_sub_elem_it++ ) {
886 
887  const libMesh::Elem* sub_elem = *hi_sub_elem_it;
888 
889  // if (_sol_function)
890  // physics_elem->attach_active_solution_function(*_sol_function);
892  output.set_elem_data(elem->dim(), *elem, geom_elem);
893  geom_elem.init(*sub_elem, *_system, *_intersection);
894 
895  output.init(geom_elem);
896  output.set_elem_solution(sol);
897  output.evaluate();
898  output.clear_elem();
899  }
900  }
901 
902  _intersection->clear();
903  }
904 
905  // if a solution function is attached, clear it
906  if (_sol_function)
907  _sol_function->clear();
908  output.clear_assembly();
909 }
910 
911 
912 
913 
914 void
916 calculate_output_derivative(const libMesh::NumericVector<Real>& X,
918  libMesh::NumericVector<Real>& dq_dX) {
919 
920  libmesh_assert(_discipline);
921  libmesh_assert(_system);
922 
923  output.zero_for_sensitivity();
924 
925  MAST::NonlinearSystem& nonlin_sys = _system->system();
926  output.set_assembly(*this);
927 
928  dq_dX.zero();
929 
930  const Real
931  tol = 1.e-10;
932 
933  // iterate over each element, initialize it and get the relevant
934  // analysis quantities
936  vec1,
937  vec2,
938  vec_total,
939  sol,
940  res_factored_u,
941  nd_indicator = RealVectorX::Ones(1),
942  indicator = RealVectorX::Zero(1);
944  mat,
945  jac_factored_uu;
946 
947  std::vector<libMesh::dof_id_type>
948  dof_indices,
949  material_rows;
950  const libMesh::DofMap& dof_map = _system->system().get_dof_map();
951 
953  ops = dynamic_cast<MAST::NonlinearImplicitAssemblyElemOperations&>(*_elem_ops);
954 
955  std::unique_ptr<libMesh::NumericVector<Real> > localized_solution;
956  localized_solution.reset(build_localized_vector(nonlin_sys,
957  X).release());
958 
959 
960  // if a solution function is attached, initialize it
961  if (_sol_function)
962  _sol_function->init( X);
963 
964 
965  libMesh::MeshBase::const_element_iterator el =
966  nonlin_sys.get_mesh().active_local_elements_begin();
967  const libMesh::MeshBase::const_element_iterator end_el =
968  nonlin_sys.get_mesh().active_local_elements_end();
969 
970 
971  for ( ; el != end_el; ++el) {
972 
973  const libMesh::Elem* elem = *el;
974 
975  _intersection->init(*_level_set, *elem, nonlin_sys.time,
976  nonlin_sys.get_mesh().max_elem_id(),
977  nonlin_sys.get_mesh().max_node_id());
978 
979  // use the indicator if it was provided
980  if (_indicator) {
981 
982  nd_indicator.setZero(elem->n_nodes());
983  for (unsigned int i=0; i<elem->n_nodes(); i++) {
984  (*_indicator)(elem->node_ref(i), nonlin_sys.time, indicator);
985  nd_indicator(i) = indicator(0);
986  }
987  }
988 
989 
992 
993  dof_map.dof_indices (elem, dof_indices);
994 
995  // get the solution
996  unsigned int ndofs = (unsigned int)dof_indices.size();
997  sol.setZero(ndofs);
998  vec1.setZero(ndofs);
999  vec2.setZero(ndofs);
1000  vec_total.setZero(ndofs);
1001 
1002  for (unsigned int i=0; i<dof_indices.size(); i++)
1003  sol(i) = (*localized_solution)(dof_indices[i]);
1004 
1005  // if the element has been marked for factorization then
1006  // get the void solution from the storage
1009 
1010  const std::vector<const libMesh::Elem *> &
1012 
1013  std::vector<const libMesh::Elem*>::const_iterator
1014  low_sub_elem_it = elems_low.begin(),
1015  low_sub_elem_end = elems_low.end();
1016 
1017  for (; low_sub_elem_it != low_sub_elem_end; low_sub_elem_it++ ) {
1018 
1019  const libMesh::Elem* sub_elem = *low_sub_elem_it;
1020 
1021  // if (_sol_function)
1022  // physics_elem->attach_active_solution_function(*_sol_function);
1023  MAST::LevelSetIntersectedElem geom_sub_elem;
1024  output.set_elem_data(elem->dim(), *elem, geom_sub_elem);
1025  geom_sub_elem.init(*sub_elem, *_system, *_intersection);
1026 
1027  output.init(geom_sub_elem);
1028  output.set_elem_solution(sol);
1029  output.output_derivative_for_elem(vec1);
1030  output.clear_elem();
1031 
1032  vec_total += vec1;
1033  }
1034 
1035  DenseRealVector v;
1036  MAST::copy(v, vec_total);
1037  dof_map.constrain_element_vector(v, dof_indices);
1038  dq_dX.add_vector(v, dof_indices);
1039  dof_indices.clear();
1040  }
1041 
1042 
1043  if (nd_indicator.maxCoeff() > tol &&
1045 
1046  dof_map.dof_indices (elem, dof_indices);
1047 
1048  // get the solution
1049  unsigned int ndofs = (unsigned int)dof_indices.size();
1050  sol.setZero(ndofs);
1051  vec1.setZero(ndofs);
1052  vec2.setZero(ndofs);
1053  vec_total.setZero(ndofs);
1054 
1055  for (unsigned int i=0; i<dof_indices.size(); i++)
1056  sol(i) = (*localized_solution)(dof_indices[i]);
1057 
1058  // if the element has been marked for factorization then
1059  // get the void solution from the storage
1062 
1063  const std::vector<const libMesh::Elem *> &
1065 
1066  std::vector<const libMesh::Elem*>::const_iterator
1067  hi_sub_elem_it = elems_hi.begin(),
1068  hi_sub_elem_end = elems_hi.end();
1069 
1070  for (; hi_sub_elem_it != hi_sub_elem_end; hi_sub_elem_it++ ) {
1071 
1072  const libMesh::Elem* sub_elem = *hi_sub_elem_it;
1073 
1074  // if (_sol_function)
1075  // physics_elem->attach_active_solution_function(*_sol_function);
1076  MAST::LevelSetIntersectedElem geom_sub_elem;
1077  output.set_elem_data(elem->dim(), *elem, geom_sub_elem);
1078  geom_sub_elem.init(*sub_elem, *_system, *_intersection);
1079 
1080  output.init(geom_sub_elem);
1081  output.set_elem_solution(sol);
1082  output.output_derivative_for_elem(vec1);
1083  output.clear_elem();
1084 
1085  if (_dof_handler && _dof_handler->if_factor_element(*elem)) {
1086 
1087  vec2.setZero(ndofs);
1088  mat.setZero(ndofs, ndofs);
1089 
1090  MAST::GeomElem geom_elem;
1091  ops.set_elem_data(elem->dim(), *elem, geom_elem);
1092  geom_elem.init(*elem, *_system);
1093 
1094  ops.init(geom_elem);
1095  ops.set_elem_solution(sol);
1096  ops.elem_calculations(true, vec2, mat);
1097  ops.clear_elem();
1099 
1101  mat.transpose(),
1102  vec1,
1103  material_rows,
1104  jac_factored_uu,
1105  res_factored_u);
1106 
1107  vec1.setZero();
1108 
1109  for (unsigned int i=0; i<material_rows.size(); i++)
1110  vec1(material_rows[i]) = res_factored_u(i);
1111  }
1112 
1113  vec_total += vec1;
1114  }
1115 
1116  DenseRealVector v;
1117  MAST::copy(v, vec_total);
1118  dof_map.constrain_element_vector(v, dof_indices);
1119  dq_dX.add_vector(v, dof_indices);
1120  dof_indices.clear();
1121  }
1122 
1123  _intersection->clear();
1124  }
1125 
1126  // if a solution function is attached, clear it
1127  if (_sol_function)
1128  _sol_function->clear();
1129 
1130  dq_dX.close();
1131  output.clear_assembly();
1132 }
1133 
1134 
1135 
1136 
1137 void
1139 calculate_output_direct_sensitivity(const libMesh::NumericVector<Real>& X,
1140  const libMesh::NumericVector<Real>* dXdp,
1141  const MAST::FunctionBase& p,
1143 
1144  libmesh_assert(_system);
1145  libmesh_assert(_discipline);
1146  libmesh_assert(_level_set);
1147 
1148  // we need the velocity for topology parameter
1150  *p_ls = nullptr;
1151  if (p.is_topology_parameter()) {
1152  libmesh_assert(_velocity);
1153  p_ls = dynamic_cast<const MAST::LevelSetParameter*>(&p);
1154  }
1155 
1156  output.zero_for_sensitivity();
1157 
1158  MAST::NonlinearSystem& nonlin_sys = _system->system();
1159  output.set_assembly(*this);
1160 
1161  const Real
1162  tol = 1.e-10;
1163 
1164  // iterate over each element, initialize it and get the relevant
1165  // analysis quantities
1166  RealVectorX
1167  sol,
1168  dsol,
1169  nd_indicator = RealVectorX::Ones(1),
1170  indicator = RealVectorX::Zero(1);
1171 
1172  std::vector<libMesh::dof_id_type> dof_indices;
1173  const libMesh::DofMap& dof_map = _system->system().get_dof_map();
1174 
1175 
1176  std::unique_ptr<libMesh::NumericVector<Real> >
1177  localized_solution,
1178  localized_solution_sens;
1179  localized_solution.reset(build_localized_vector(nonlin_sys,
1180  X).release());
1181  if (dXdp)
1182  localized_solution_sens.reset(build_localized_vector(nonlin_sys,
1183  *dXdp).release());
1184 
1185 
1186  // if a solution function is attached, initialize it
1187  //if (_sol_function)
1188  // _sol_function->init( X);
1189 
1190 
1191  libMesh::MeshBase::const_element_iterator el =
1192  nonlin_sys.get_mesh().active_local_elements_begin();
1193  const libMesh::MeshBase::const_element_iterator end_el =
1194  nonlin_sys.get_mesh().active_local_elements_end();
1195 
1196 
1197  for ( ; el != end_el; ++el) {
1198 
1199  const libMesh::Elem* elem = *el;
1200 
1201  // no sensitivity computation assembly is neeed in these cases
1202  if (_param_dependence &&
1203  // if object is specified and elem does not depend on it
1205  // and if no sol_sens is given
1206  (!dXdp ||
1207  // or if it can be ignored for elem
1208  (dXdp && _param_dependence->override_flag)))
1209  continue;
1210 
1211  // use the indicator if it was provided
1212  if (_indicator) {
1213 
1214  nd_indicator.setZero(elem->n_nodes());
1215  for (unsigned int i=0; i<elem->n_nodes(); i++) {
1216  (*_indicator)(elem->node_ref(i), nonlin_sys.time, indicator);
1217  nd_indicator(i) = indicator(0);
1218  }
1219  }
1220 
1221  _intersection->init(*_level_set, *elem, nonlin_sys.time,
1222  nonlin_sys.get_mesh().max_elem_id(),
1223  nonlin_sys.get_mesh().max_node_id());
1224 
1227 
1228  dof_map.dof_indices (elem, dof_indices);
1229 
1230 
1231  // get the solution
1232  unsigned int ndofs = (unsigned int)dof_indices.size();
1233  sol.setZero(ndofs);
1234  dsol.setZero(ndofs);
1235 
1236  for (unsigned int i=0; i<dof_indices.size(); i++) {
1237  sol(i) = (*localized_solution)(dof_indices[i]);
1238  if (dXdp)
1239  dsol(i) = (*localized_solution_sens)(dof_indices[i]);
1240  }
1241 
1242  // if the element has been marked for factorization then
1243  // get the void solution from the storage
1246 
1247  const std::vector<const libMesh::Elem *> &
1249 
1250  std::vector<const libMesh::Elem*>::const_iterator
1251  low_sub_elem_it = elems_low.begin(),
1252  low_sub_elem_end = elems_low.end();
1253 
1254  for (; low_sub_elem_it != low_sub_elem_end; low_sub_elem_it++ ) {
1255 
1256  const libMesh::Elem* sub_elem = *low_sub_elem_it;
1257 
1258  // if (_sol_function)
1259  // physics_elem->attach_active_solution_function(*_sol_function);
1261  output.set_elem_data(elem->dim(), *elem, geom_elem);
1262  geom_elem.init(*sub_elem, *_system, *_intersection);
1263 
1264  output.init(geom_elem);
1265  output.set_elem_solution(sol);
1266  output.set_elem_solution_sensitivity(dsol);
1267  output.evaluate_sensitivity(p);
1268  if (p.is_topology_parameter())
1270 
1271  output.clear_elem();
1272  }
1273  }
1274 
1275 
1276  if (nd_indicator.maxCoeff() > tol &&
1278 
1279  dof_map.dof_indices (elem, dof_indices);
1280 
1281 
1282  // get the solution
1283  unsigned int ndofs = (unsigned int)dof_indices.size();
1284  sol.setZero(ndofs);
1285  dsol.setZero(ndofs);
1286 
1287  for (unsigned int i=0; i<dof_indices.size(); i++) {
1288  sol(i) = (*localized_solution)(dof_indices[i]);
1289  if (dXdp)
1290  dsol(i) = (*localized_solution_sens)(dof_indices[i]);
1291  }
1292 
1293  // if the element has been marked for factorization then
1294  // get the void solution from the storage
1297 
1298  const std::vector<const libMesh::Elem *> &
1299  //elems_low = intersect.get_sub_elems_negative_phi(),
1301 
1302  std::vector<const libMesh::Elem*>::const_iterator
1303  hi_sub_elem_it = elems_hi.begin(),
1304  hi_sub_elem_end = elems_hi.end();
1305 
1306  for (; hi_sub_elem_it != hi_sub_elem_end; hi_sub_elem_it++ ) {
1307 
1308  const libMesh::Elem* sub_elem = *hi_sub_elem_it;
1309 
1310  // if (_sol_function)
1311  // physics_elem->attach_active_solution_function(*_sol_function);
1313  output.set_elem_data(elem->dim(), *elem, geom_elem);
1314  geom_elem.init(*sub_elem, *_system, *_intersection);
1315 
1316  output.init(geom_elem);
1317  output.set_elem_solution(sol);
1318  output.set_elem_solution_sensitivity(dsol);
1319  output.evaluate_sensitivity(p);
1320  if (p.is_topology_parameter())
1322 
1323  output.clear_elem();
1324  }
1325  }
1326 
1327  _intersection->clear();
1328  }
1329 
1330  // if a solution function is attached, clear it
1331  if (_sol_function)
1332  _sol_function->clear();
1333 
1334  output.clear_assembly();
1335 }
1336 
MAST::AssemblyElemOperations * _elem_ops
provides assembly elem operations for use by this class
virtual void calculate_output(const libMesh::NumericVector< Real > &X, MAST::OutputAssemblyElemOperations &output)
calculates the value of quantity .
MAST::NonlinearSystem & system()
virtual bool if_elem_depends_on_parameter(const libMesh::Elem &e, const MAST::FunctionBase &p) const =0
libMesh::DenseMatrix< Real > DenseRealMatrix
virtual void init(MAST::AssemblyBase &assembly)
This class implements a system for solution of nonlinear systems.
This defines a parameter that is a level set function and stores a pointer to the node in the level-s...
bool override_flag
if true, assume zero solution sensitivity when elem does not dependent on parameter.
Definition: assembly_base.h:97
void solution_of_factored_element(const libMesh::Elem &elem, RealVectorX &elem_sol)
updates the components of the solution vector in elem_sol for the void domain using the stored soluti...
virtual const std::vector< Real > & get_JxW() const
Definition: fe_base.cpp:220
virtual void calculate_output_derivative(const libMesh::NumericVector< Real > &X, MAST::OutputAssemblyElemOperations &output, libMesh::NumericVector< Real > &dq_dX)
calculates
virtual void set_elem_solution_sensitivity(const RealVectorX &sol)
sets the element solution sensitivity
bool _enable_dof_handler
Evaluates the total sensitivity of output wrt p using the adjoint solution provided in dq_dX for a li...
virtual void set_assembly(MAST::AssemblyBase &assembly)
sets the assembly object
virtual void init(const libMesh::Elem &elem, const MAST::SystemInitialization &sys_init)
This method should not get called for this class.
This provides the base class for definitin of element level contribution of output quantity in an ana...
virtual void calculate_output_direct_sensitivity(const libMesh::NumericVector< Real > &X, const libMesh::NumericVector< Real > *dXdp, const MAST::FunctionBase &p, MAST::OutputAssemblyElemOperations &output)
evaluates the sensitivity of the outputs in the attached discipline with respect to the parametrs in ...
LevelSetNonlinearImplicitAssembly(bool enable_dof_handler)
constructor associates this assembly object with the system
const std::vector< const libMesh::Elem * > & get_sub_elems_negative_phi() const
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_indicator_function(MAST::FieldFunction< RealVectorX > &indicator)
attaches indicator function to this.
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.
void init(const MAST::FieldFunction< Real > &phi, const libMesh::Elem &e, const Real t, unsigned int max_elem_id, unsigned int max_node_id)
MAST::SystemInitialization * _system
System for which this assembly is performed.
virtual void elem_sensitivity_calculations(const MAST::FunctionBase &f, RealVectorX &vec)=0
performs the element sensitivity calculations over elem, and returns the element residual sensitivity...
virtual void clear_level_set_function()
clears association with level set function
virtual void residual_and_jacobian(const libMesh::NumericVector< Real > &X, libMesh::NumericVector< Real > *R, libMesh::SparseMatrix< Real > *J, libMesh::NonlinearImplicitSystem &S)
function that assembles the matrices and vectors quantities for nonlinear solution ...
virtual void elem_calculations(bool if_jac, RealVectorX &vec, RealMatrixX &mat)=0
performs the element calculations over elem, and returns the element vector and matrix quantities in ...
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 post_assembly(const libMesh::NumericVector< Real > &X, libMesh::NumericVector< Real > *R, libMesh::SparseMatrix< Real > *J, libMesh::NonlinearImplicitSystem &S)=0
libMesh::DenseVector< Real > DenseRealVector
MAST::NonlinearImplicitAssembly::PostAssemblyOperation * _post_assembly
this object, if non-NULL is user-provided to perform actions after assembly and before returning to t...
Matrix< Real, Dynamic, Dynamic > RealMatrixX
virtual void clear_assembly()
clears the assembly object
void copy(DenseRealMatrix &m1, const RealMatrixX &m2)
Definition: utility.h:167
This will compute the solution at the interface under the assumption of zero surface normal flux...
Creates a geometric filter for the level-set design variables.
Definition: filter_base.h:39
void element_factored_residual_and_jacobian(const libMesh::Elem &elem, const RealMatrixX &jac, const RealVectorX &res, std::vector< libMesh::dof_id_type > &material_dof_ids, RealMatrixX &jac_factored_uu, RealVectorX &res_factored_u)
factorizes the residual and jacobian into the components for the dofs on material nodes...
void clear()
clear the solution
This class inherits from MAST::GeomElem and provides an interface to initialize FE objects on sub-ele...
Matrix< Real, Dynamic, 1 > RealVectorX
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 set_level_set_function(MAST::FieldFunction< Real > &level_set, const MAST::FilterBase &filter)
attaches level set function to this
virtual void elem_topology_sensitivity_calculations(const MAST::FunctionBase &f, const MAST::FieldFunction< RealVectorX > &vel, RealVectorX &vec)=0
performs the element topology sensitivity calculations over elem, and returns the element residual se...
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_level_set_velocity_function()
clears the velocity function
This class acts as a wrapper around libMesh::Elem for the purpose of providing a uniform interface fo...
Definition: geom_elem.h:59
virtual void init(const MAST::GeomElem &elem, bool init_grads, const std::vector< libMesh::Point > *pts=nullptr)
Initializes the quadrature and finite element for element volume integration.
Definition: fe_base.cpp:64
virtual bool sensitivity_assemble(const MAST::FunctionBase &f, libMesh::NumericVector< Real > &sensitivity_rhs)
Assembly function.
virtual void zero_for_analysis()=0
zeroes the output quantity values stored inside this object so that assembly process can begin...
virtual void evaluate_topology_sensitivity(const MAST::FunctionBase &f, const MAST::FieldFunction< RealVectorX > &vel)=0
this evaluates all relevant topological sensitivity components on the element.
const std::vector< const libMesh::Elem * > & get_sub_elems_positive_phi() const
void init(const MAST::SystemInitialization &sys_init, MAST::LevelSetIntersection &intersection, MAST::FieldFunction< Real > &phi)
void init(const libMesh::NumericVector< Real > &sol, const libMesh::NumericVector< Real > *dsol=nullptr)
initializes the data structures to perform the interpolation function of sol.
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 clear_elem()
clears the element initialization
bool if_factor_element(const libMesh::Elem &elem) const
virtual void init(const libMesh::Elem &elem, const MAST::SystemInitialization &sys_init)
initialize the object for the specified reference elem.
Definition: geom_elem.cpp:128
virtual ~LevelSetNonlinearImplicitAssembly()
destructor resets the association of this assembly object with the system
This class specializes the MAST::FEBase class for level-set applications where integration is to be p...
Definition: sub_cell_fe.h:40
virtual void set_level_set_velocity_function(MAST::FieldFunction< RealVectorX > &velocity)
the velocity function used to calculate topology sensitivity
void set_evaluate_output_on_negative_phi(bool f)
sets the flag on whether or not to evaluate the output on negative level set function ...
virtual bool is_topology_parameter() const
Definition: function_base.h:97
virtual void evaluate_sensitivity(const MAST::FunctionBase &f)=0
this evaluates all relevant sensitivity components on the element.
void clear()
clears the data structures
MAST::MeshFieldFunction * _sol_function
system solution that will be initialized before each solution