MAST3
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
inplane2d.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_mesh_generation_inplane_2d_h__
21 #define __mast_mesh_generation_inplane_2d_h__
22 
23 // MAST includes
28 
29 // libMesh includes
30 #include <libmesh/system.h>
31 #include <libmesh/unstructured_mesh.h>
32 #include <libmesh/fe_type.h>
33 #include <libmesh/string_to_enum.h>
34 #include <libmesh/mesh_generation.h>
35 #include <libmesh/elem.h>
36 #include <libmesh/node.h>
37 #include <libmesh/boundary_info.h>
38 #include <libmesh/dirichlet_boundaries.h>
39 #include <libmesh/zero_function.h>
40 
41 
42 
43 namespace MAST {
44 namespace Mesh {
45 namespace Generation {
46 
53 struct Inplane2D {
54 
55  template <typename ScalarType>
56  class Pressure {
57  public:
59  real_t l1,
60  real_t frac):
61  _p(p), _l1(l1), _frac(frac)
62  {}
63  virtual ~Pressure() {}
64 
65  template <typename ContextType>
66  inline ScalarType value(ContextType& c) const {
67  ScalarType v=(fabs(c.qp_location(0)-_l1*0.5) <= 0.5*_frac*_l1)?_p:0.;
68  return v;
69  }
70 
71  template <typename ContextType, typename ScalarFieldType>
72  inline ScalarType derivative(ContextType& c,
73  const ScalarFieldType& f) const {
74  return 0.;
75  }
76 
77  private:
79  };
80 
81  static const uint_t dim = 2;
82  template <typename ScalarType>
84 
85  template <typename Context>
86  inline real_t
87  reference_volume(Context& c) {
88 
89  real_t
90  length = c.input("length", "length of domain along x-axis", 1.0),
91  height = c.input("height", "length of domain along y-axis", 1.0);
92 
93  return length * height;
94  }
95 
96 
97  inline uint_t idx(const libMesh::ElemType type,
98  const uint_t nx,
99  const uint_t i,
100  const uint_t j)
101  {
102  switch(type)
103  {
104  case libMesh::QUAD4:
105  {
106  return i + (nx+1)*j;
107  }
108 
109  case libMesh::QUAD9:
110  {
111  return i + (2*nx+1)*j;
112  }
113 
114  default:
115  Error(false, "Invalid element type");
116  }
117 
118  return libMesh::invalid_uint;
119  }
120 
121 
122 
123  inline void build_mesh(libMesh::UnstructuredMesh & mesh,
124  const uint_t nx,
125  const uint_t ny,
126  const real_t length,
127  const real_t height,
128  const libMesh::ElemType type) {
129 
130  Assert0(type == libMesh::QUAD4 || type == libMesh::QUAD9,
131  "Method only implemented for Quad4/Quad9");
132 
133  // Clear the mesh and start from scratch
134  mesh.clear();
135 
136  libMesh::BoundaryInfo & boundary_info = mesh.get_boundary_info();
137 
138  mesh.set_mesh_dimension(3);
139  mesh.set_spatial_dimension(3);
140  mesh.reserve_elem(nx*ny);
141 
142  if (type == libMesh::QUAD4)
143  mesh.reserve_nodes( (nx+1)*(ny+1));
144  else if (type == libMesh::QUAD9)
145  mesh.reserve_nodes( (2*nx+1)*(2*ny+1));
146 
147  real_t
148  xmax = length,
149  ymax = height;
150 
151 
152  std::map<uint_t, libMesh::Node*> nodes;
153 
154  // Build the nodes.
155  uint_t
156  node_id = 0,
157  n = 0;
158  switch (type)
159  {
160  case libMesh::QUAD4: {
161 
162  for (uint_t j=0; j<=ny; j++)
163  for (uint_t i=0; i<=nx; i++) {
164  nodes[node_id] =
165  mesh.add_point(libMesh::Point(static_cast<real_t>(i)/static_cast<real_t>(nx)*length,
166  static_cast<real_t>(j)/static_cast<real_t>(ny)*height,
167  0.),
168  n++);
169  node_id++;
170  }
171 
172 
173  break;
174  }
175 
176  case libMesh::QUAD9: {
177 
178  for (uint_t j=0; j<=(2*ny); j++)
179  for (uint_t i=0; i<=(2*nx); i++) {
180  nodes[node_id] =
181  mesh.add_point(libMesh::Point(static_cast<real_t>(i)/static_cast<real_t>(2*nx)*length,
182  static_cast<real_t>(j)/static_cast<real_t>(2*ny)*height,
183  0.),
184  n++);
185  node_id++;
186  }
187 
188  break;
189  }
190 
191 
192  default:
193  Assert0(false, "ERROR: Unrecognized 2D element type.");
194  }
195 
196  // Build the elements.
197  uint_t
198  elem_id = 0;
199  switch (type) {
200 
201  case libMesh::QUAD4: {
202 
203  for (uint_t j=0; j<ny; j++)
204  for (uint_t i=0; i<nx; i++) {
205 
206  libMesh::Elem
207  *elem = libMesh::Elem::build(libMesh::QUAD4).release();
208  elem->set_id(elem_id++);
209  mesh.add_elem(elem);
210 
211  elem->set_node(0) = nodes[idx(type,nx,i,j) ];
212  elem->set_node(1) = nodes[idx(type,nx,i+1,j) ];
213  elem->set_node(2) = nodes[idx(type,nx,i+1,j+1) ];
214  elem->set_node(3) = nodes[idx(type,nx,i,j+1) ];
215 
216  if (j == 0)
217  boundary_info.add_side(elem, 0, 0);
218 
219  if (j == (ny-1))
220  boundary_info.add_side(elem, 2, 2);
221 
222  if (i == 0)
223  boundary_info.add_side(elem, 3, 3);
224 
225  if (i == (nx-1))
226  boundary_info.add_side(elem, 1, 1);
227  }
228  break;
229  }
230 
231 
232  case libMesh::QUAD9: {
233 
234  for (uint_t j=0; j<(2*ny); j += 2)
235  for (uint_t i=0; i<(2*nx); i += 2) {
236 
237  libMesh::Elem
238  *elem = libMesh::Elem::build(libMesh::QUAD9).release();
239  elem->set_id(elem_id++);
240  mesh.add_elem(elem);
241 
242  elem->set_node(0) = nodes[idx(type,nx,i, j) ];
243  elem->set_node(1) = nodes[idx(type,nx,i+2,j) ];
244  elem->set_node(2) = nodes[idx(type,nx,i+2,j+2) ];
245  elem->set_node(3) = nodes[idx(type,nx,i, j+2) ];
246  elem->set_node(4) = nodes[idx(type,nx,i+1,j) ];
247  elem->set_node(5) = nodes[idx(type,nx,i+2,j+1) ];
248  elem->set_node(6) = nodes[idx(type,nx,i+1,j+2) ];
249  elem->set_node(7) = nodes[idx(type,nx,i, j+1) ];
250  elem->set_node(8) = nodes[idx(type,nx,i+1,j+1) ];
251 
252  if (j == 0)
253  boundary_info.add_side(elem, 0, 0);
254 
255  if (j == 2*(ny-1))
256  boundary_info.add_side(elem, 2, 2);
257 
258  if (i == 0)
259  boundary_info.add_side(elem, 3, 3);
260 
261  if (i == 2*(nx-1))
262  boundary_info.add_side(elem, 1, 1);
263  }
264  break;
265  }
266 
267  default:
268  Assert0(false, "ERROR: Unrecognized 2D element type.");
269  }
270 
271  // Add sideset names to boundary info (Z axis out of the screen)
272  boundary_info.sideset_name(0) = "bottom";
273  boundary_info.sideset_name(1) = "right";
274  boundary_info.sideset_name(2) = "top";
275  boundary_info.sideset_name(3) = "left";
276 
277  // Add nodeset names to boundary info
278  boundary_info.nodeset_name(0) = "bottom";
279  boundary_info.nodeset_name(1) = "right";
280  boundary_info.nodeset_name(2) = "top";
281  boundary_info.nodeset_name(3) = "left";
282 
283  // Done building the mesh. Now prepare it for use.
284  mesh.prepare_for_use ();
285  }
286 
287 
288  template <typename Context>
289  inline void
290  init_analysis_mesh(Context& c,
291  libMesh::UnstructuredMesh& mesh) {
292 
293  real_t
294  length = c.input("length", "length of domain along x-axis", 1.0),
295  height = c.input("height", "length of domain along y-axis", 1.0);
296 
297  uint_t
298  nx_divs = c.input("nx_divs", "number of elements along x-axis", 30),
299  ny_divs = c.input("ny_divs", "number of elements along y-axis", 30);
300 
301  std::string
302  t = c.input("elem_type", "type of geometric element in the mesh", "quad4");
303 
304  libMesh::ElemType
305  e_type = libMesh::Utility::string_to_enum<libMesh::ElemType>(t);
306 
307  //
308  // if high order FE is used, libMesh requires atleast a second order
309  // geometric element.
310  //
311  if (c.sol_fe_order > 1 && e_type == libMesh::QUAD4)
312  e_type = libMesh::QUAD9;
313 
314  //
315  // initialize the mesh with one element
316  //
317  build_mesh(mesh,
318  nx_divs, ny_divs,
319  length,
320  height,
321  e_type);
322  }
323 
324 
328  template <typename Context>
329  inline void
331 
332  c.sys->get_dof_map().add_dirichlet_boundary
333  (libMesh::DirichletBoundary({1, 3}, {0, 1}, libMesh::ZeroFunction<real_t>()));
334  }
335 
336 
337 
338  template <typename ScalarType, typename InitType>
339  std::unique_ptr<pressure_t<ScalarType>>
340  build_pressure_load(InitType& c) {
341 
342  real_t
343  length = c.input("length", "length of domain along x-axis", 1.0),
344  frac = c.input("loadlength_fraction", "fraction of boundary length on which pressure will act", 0.2),
345  p_val = c.input("pressure", "pressure on side of domain", 2.e6);
346  c.p_side_id = 2;
347 
348  std::unique_ptr<pressure_t<ScalarType>>
349  press(new pressure_t<ScalarType>(p_val, length, frac));
350 
351  return press;
352  }
353 
354 
355 
356  template <typename ScalarType, typename Context>
357  inline void
359  (Context &c,
361 
362  //
363  // this assumes that density variable has a constant value per element
364  //
365  Assert2(c.rho_fe_family == libMesh::LAGRANGE,
366  c.rho_fe_family, libMesh::LAGRANGE,
367  "Method assumes Lagrange interpolation function for density");
368  Assert2(c.rho_fe_order == libMesh::FIRST,
369  c.rho_fe_order, libMesh::FIRST,
370  "Method assumes Lagrange interpolation function for density");
371 
372  real_t
373  tol = 1.e-12,
374  length = c.input("length", "length of domain along x-axis", 1.0),
375  height = c.input("height", "length of domain along y-axis", 1.0),
376  frac = c.input("loadlength_fraction", "fraction of boundary length on which pressure will act", 0.2),
377  filter_radius = c.input("filter_radius", "radius of geometric filter for level set field", 0.07),
378  vf = c.input("volume_fraction", "upper limit for the volume fraction", 0.2);
379 
380  uint_t
381  sys_num = c.rho_sys->number(),
382  first_dof = c.rho_sys->get_dof_map().first_dof(c.rho_sys->comm().rank()),
383  end_dof = c.rho_sys->get_dof_map().end_dof(c.rho_sys->comm().rank()),
384  dof_id = 0;
385 
386  real_t
387  val = 0.;
388 
389  libMesh::MeshBase::const_element_iterator
390  e_it = c.mesh->active_local_elements_begin(),
391  e_end = c.mesh->active_local_elements_end();
392 
393  std::set<const libMesh::Node*> nodes;
394 
395  for ( ; e_it != e_end; e_it++) {
396 
397  const libMesh::Elem* e = *e_it;
398 
399  Assert0(e->type() == libMesh::QUAD4 ||
400  e->type() == libMesh::QUAD9,
401  "Method requires Quad4/Quad9 element");
402 
403  // only the first four nodes of the quad element are used
404  for (uint_t i=0; i<4; i++) {
405 
406  const libMesh::Node& n = *e->node_ptr(i);
407 
408  // if we have alredy operated on this node, then
409  // we skip it
410  if (nodes.count(&n))
411  continue;
412 
413  // otherwise, we add it to the set of operated nodes and
414  // check if a design parameter should be computed for this
415  nodes.insert(&n);
416 
417  dof_id = n.dof_number(sys_num, 0, 0);
418 
421  dv->set_point(n(0), n(1), n(2));
422 
423  if (dof_id >= first_dof &&
424  dof_id < end_dof)
425  dvs.add_topology_parameter(*dv, dof_id);
426  else
427  dvs.add_ghosted_topology_parameter(*dv, dof_id);
428  }
429  }
430 
431  dvs.synchronize(c.rho_sys->get_dof_map());
432  c.rho_sys->solution->close();
433  }
434 };
435 
436 } // namespace Generation
437 } // namespace Mesh
438 } // namespace MAST
439 
440 
441 #endif // __mast_mesh_generation_inplane_2d_h__
#define Error(cond, msg)
Definition: exceptions.hpp:166
void init_analysis_dirichlet_conditions(Context &c)
This constrains the u and v displacements on the left (id: 3) and right (id: 1) boundaries.
Definition: inplane2d.hpp:330
std::unique_ptr< pressure_t< ScalarType > > build_pressure_load(InitType &c)
Definition: inplane2d.hpp:340
This struct provides the methods to populate the mesh, load, Dirichlet conditions and design variable...
Definition: inplane2d.hpp:53
MAST::Base::ParameterData & add_ghosted_topology_parameter(MAST::Optimization::DesignParameter< ScalarType > &p, const uint_t id)
void init_simp_dvs(Context &c, MAST::Optimization::DesignParameterVector< ScalarType > &dvs)
Definition: inplane2d.hpp:359
ScalarType derivative(ContextType &c, const ScalarFieldType &f) const
Definition: inplane2d.hpp:72
void init_analysis_mesh(Context &c, libMesh::UnstructuredMesh &mesh)
Definition: inplane2d.hpp:290
MAST::Base::ParameterData & add_topology_parameter(MAST::Optimization::DesignParameter< ScalarType > &p, const uint_t id)
Pressure(real_t p, real_t l1, real_t frac)
Definition: inplane2d.hpp:58
uint_t idx(const libMesh::ElemType type, const uint_t nx, const uint_t i, const uint_t j)
Definition: inplane2d.hpp:97
ScalarType value(ContextType &c) const
Definition: inplane2d.hpp:66
#define Assert0(cond, msg)
Definition: exceptions.hpp:134
real_t reference_volume(Context &c)
Definition: inplane2d.hpp:87
unsigned int uint_t
#define Assert2(cond, v1, v2, msg)
Definition: exceptions.hpp:152
void build_mesh(libMesh::UnstructuredMesh &mesh, const uint_t nx, const uint_t ny, const real_t length, const real_t height, const libMesh::ElemType type)
Definition: inplane2d.hpp:123
void set_point(real_t x, real_t y=0., real_t z=0.)
double real_t
void synchronize(const libMesh::DofMap &dof_map)
std::unique_ptr< ValType > build(const libMesh::System &sys)
Definition: utility.hpp:284