MAST3
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
mat_null_space.hpp
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 #ifndef __mast_libmesh_wrapper_elasticity_null_space_h__
21 #define __mast_libmesh_wrapper_elasticity_null_space_h__
22 
23 // C++ includes
24 #include <limits>
25 
26 // MAST includes
28 #include <mast/base/exceptions.hpp>
29 
30 // libMesh includes
31 #include <libmesh/system.h>
32 #include <libmesh/dof_map.h>
33 #include <libmesh/mesh_base.h>
34 #include <libmesh/petsc_vector.h>
35 #include <libmesh/node.h>
36 
37 // PETSc includes
38 #include <petscmat.h>
39 
40 namespace MAST {
41 namespace Physics {
42 namespace Elasticity {
43 namespace libMeshWrapper {
44 
45 class NullSpace {
46 
47 public:
48 
49  NullSpace(libMesh::System& sys, uint_t dim, bool enable_rotation):
50  _sys (sys),
51  _dim (dim),
52  _if_rot (enable_rotation) {
53 
54  Assert1(_dim > 0, _dim, "Invalid dimension");
55  Assert2(_sys.n_vars() == _dim,
56  _sys.n_vars(), _dim,
57  "Number of unknowns should be equal to spatial dimension");
58 
59  // make sure all variable types are LAGRANGE
60  for (uint_t i=0; i<_dim; i++)
61  Assert0(_sys.variable_type(i).family == libMesh::LAGRANGE,
62  "Variables are expected to be LAGRANGE");
63 
64  // now initialize
65  if (_if_rot)
67  else
69  }
70 
71  virtual ~NullSpace() {
72 
73  PetscErrorCode ierr = 0;
74 
75  ierr = MatNullSpaceDestroy(&_mns);
76  CHKERRABORT(_sys.comm().get(), ierr);
77  }
78 
79 
80  inline MatNullSpace get() {
81 
82  Assert0(_mns, "Object not initialized");
83 
84  return _mns;
85  }
86 
87  inline void attach_to_matrix(Mat m) {
88 
89  PetscErrorCode ierr = 0;
90 
91  ierr = MatSetNearNullSpace(m, _mns);
92  CHKERRABORT(_sys.comm().get(), ierr);
93  }
94 
95 
96 private:
97 
98  inline void _init_with_rotation() {
99 
100  PetscErrorCode
101  ierr = 0;
102 
103  uint_t
104  n_translation = _dim,
105  n_rotation = 0;
106 
107  if (_dim == 2)
108  // an inplane problem has one single rotation about the z-axis
109  n_rotation = 1;
110  else if (_dim == 3)
111  // a three-dimensional problem can rotate about all three axes.
112  n_rotation = 3;
113 
114 
115  std::vector<libMesh::NumericVector<real_t>*>
116  vecs(n_translation+n_rotation, nullptr);
117 
118  std::vector<libMesh::dof_id_type>
119  dof_ids(_dim, 0);
120 
121  // create and initialize the vectors
122  for (uint_t i=0; i<vecs.size(); i++)
123  vecs[i] = _sys.solution->zero_clone().release();
124 
125  libMesh::MeshBase::const_node_iterator
126  it = _sys.get_mesh().local_nodes_begin(),
127  end = _sys.get_mesh().local_nodes_end();
128 
129  for ( ; it != end; it++) {
130 
131  const libMesh::Node& n = **it;
132 
133  // assuming that the dofs are sequentially numbered
134  dof_ids.clear();
135  _sys.get_dof_map().dof_indices(&n, dof_ids);
136 
137  // make sure that the correct number of dofs is found
138  Assert2(dof_ids.size() == n_translation,
139  dof_ids.size(), n_translation,
140  "Invalid number of dofs on node");
141 
142  // rigid-body translation
143  for (uint_t i=0; i<n_translation; i++)
144  vecs[i]->set(dof_ids[i], 1.);
145 
146  // rigid-body rotation, assumed to be about point (0,0,0)
147  for (uint_t i=0; i<n_rotation; i++) {
148 
149  libMesh::NumericVector<real_t>
150  &v = *vecs[n_translation + i];
151 
152  switch (i) {
153 
154  // first rotation about z-axis since this is the only one
155  // necessary for 2D elasticity
156  case 0: {
157 
158  real_t th = 1.e-5;
159  // set deformation assuming rotation about (x,y,z)=0
160  // theta-z is only going to lead to changes in x,y
161  v.set(dof_ids[0],
162  (cos(th) * n(0) - sin(th) * n(1)) - n(0));
163  v.set(dof_ids[1],
164  (sin(th) * n(0) + cos(th) * n(1)) - n(1));
165  }
166  break;
167 
168  // next rotation about x-axis
169  case 1: {
170 
171  real_t th = 1.e-5;
172  // also set deformation assuming rotation about (x,y,z)=0
173  // theta-x is only going to lead to changes in y,z
174  v.set(dof_ids[1],
175  (cos(th) * n(1) - sin(th) * n(2)) - n(1));
176  v.set(dof_ids[2],
177  (sin(th) * n(1) + cos(th) * n(2)) - n(2));
178  }
179  break;
180 
181  // finally, rotation about y-axis
182  case 2: {
183 
184  real_t th = 1.e-5;
185  // also set deformation assuming rotation about (x,y,z)=0
186  // theta-y is only going to lead to changes in x,z
187  v.set(dof_ids[0],
188  (cos(th) * n(0) + sin(th) * n(2)) - n(0));
189  v.set(dof_ids[2],
190  (-sin(th) * n(0) + cos(th) * n(2)) - n(2));
191  }
192  break;
193 
194  default:
195  Error(false, "Invalid rotation vector index");
196  }
197  }
198  }
199 
201 
202  // now delete the vectors
203  for (uint_t i=0; i<vecs.size(); i++)
204  delete vecs[i];
205  }
206 
207 
208  inline void _init_without_rotation() {
209 
210  PetscErrorCode
211  ierr = 0;
212 
213  uint_t
214  n_translation = _dim;
215 
216 
217  std::vector<libMesh::NumericVector<real_t>*>
218  vecs(n_translation, nullptr);
219 
220  std::vector<libMesh::dof_id_type>
221  dof_ids(_dim, 0);
222 
223  // create and initialize the vectors
224  for (uint_t i=0; i<vecs.size(); i++)
225  vecs[i] = _sys.solution->zero_clone().release();
226 
227  libMesh::MeshBase::const_node_iterator
228  it = _sys.get_mesh().local_nodes_begin(),
229  end = _sys.get_mesh().local_nodes_end();
230 
231  for ( ; it != end; it++) {
232 
233  const libMesh::Node& n = **it;
234 
235  // assuming that the dofs are sequentially numbered
236  dof_ids.clear();
237  _sys.get_dof_map().dof_indices(&n, dof_ids);
238 
239  // make sure that the correct number of dofs is found
240  Assert2(dof_ids.size() == n_translation,
241  dof_ids.size(), n_translation,
242  "Invalid number of dofs on node");
243 
244  // rigid-body translation
245  for (uint_t i=0; i<n_translation; i++)
246  vecs[i]->set(dof_ids[i], 1.);
247  }
248 
250 
251  // now delete the vectors
252  for (uint_t i=0; i<vecs.size(); i++)
253  delete vecs[i];
254  }
255 
256 
257  inline void
259  (std::vector<libMesh::NumericVector<real_t>*>& vecs) {
260 
261  PetscErrorCode
262  ierr = 0;
263 
264  // close the vectors and scale them to unit norm
265  for (uint_t i=0; i<vecs.size(); i++) {
266 
267  vecs[i]->close();
268 
269  // the vectors should form an orthonormal basis
270  // We use the Gram-Schmidt orthogonalization
271  for (uint_t j=0; j<i; j++) {
272 
273  real_t
274  v = vecs[i]->dot(*vecs[j]);
275 
276  vecs[i]->add(-v, *vecs[j]);
277  }
278 
279  real_t
280  l2 = vecs[i]->l2_norm();
281 
282  vecs[i]->scale(1./l2);
283 
284  l2 = vecs[i]->l2_norm();
285 
286  // the vectors should now be orthonormal basis
287  for (uint_t j=0; j<i; j++) {
288 
289  // use the Gram-Schmidt orthogonalization
290  real_t
291  v = vecs[i]->dot(*vecs[j]);
292 
293  Assert2(fabs(v) < std::sqrt(std::numeric_limits<real_t>::epsilon()),
294  fabs(v), std::sqrt(std::numeric_limits<real_t>::epsilon()),
295  "Vector should be orthogonal");
296  }
297  }
298 
299  // vector of vectors to be sent to PETSc
300  std::vector<Vec> v(vecs.size());
301  for (uint_t i=0; i<vecs.size(); i++)
302  v[i] = dynamic_cast<libMesh::PetscVector<real_t>*>(vecs[i])->vec();
303 
304  ierr = MatNullSpaceCreate(_sys.comm().get(),
305  PETSC_FALSE,
306  vecs.size(),
307  &v[0],
308  &_mns);
309  CHKERRABORT(_sys.comm().get(), ierr);
310  }
311 
312 
313 
314 
315  libMesh::System &_sys;
316  const uint_t _dim;
317  const bool _if_rot;
318  MatNullSpace _mns;
319 
320 };
321 } // namespace libMeshWrapper
322 } // namespace Elasticity
323 } // namespace Physics
324 } // namespace MAST
325 
326 
327 #endif // __mast_libmesh_wrapper_elasticity_null_space_h__
#define Error(cond, msg)
Definition: exceptions.hpp:166
void _orthonormalize_and_create_basis(std::vector< libMesh::NumericVector< real_t > *> &vecs)
#define Assert1(cond, v1, msg)
Definition: exceptions.hpp:143
NullSpace(libMesh::System &sys, uint_t dim, bool enable_rotation)
#define Assert0(cond, msg)
Definition: exceptions.hpp:134
unsigned int uint_t
#define Assert2(cond, v1, v2, msg)
Definition: exceptions.hpp:152
double real_t