MAST3
Multidisciplinary-design Adaptation and Sensitivity Toolkit (MAST)
heat_sink3d.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_heat_sink_3d_h__
21 #define __mast_mesh_generation_heat_sink_3d_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 #include <libmesh/mesh_refinement.h>
41 #include <libmesh/mesh_modification.h>
42 
43 
44 namespace MAST {
45 namespace Mesh {
46 namespace Generation {
47 
48 
49 struct HeatSink3D {
50 
51  static const uint_t dim = 3;
52 
53  template <typename Context>
54  inline real_t
55  reference_volume(Context& c) {
56 
57  real_t
58  length = c.input("length", "length of domain along x-axis", 1.),
59  height = c.input("height", "length of domain along y-axis", 1.),
60  width = c.input("width", "length of domain along z-axis", 1.);
61 
62  return length * height * width;
63  }
64 
65 
66  inline uint_t idx(const libMesh::ElemType type,
67  const uint_t nx,
68  const uint_t ny,
69  const uint_t i,
70  const uint_t j,
71  const uint_t k)
72  {
73  switch(type)
74  {
75  case libMesh::HEX8:
76  {
77  return i + (nx+1)*(j + k*(ny+1));
78  }
79 
80  case libMesh::HEX27:
81  {
82  return i + (2*nx+1)*(j + k*(2*ny+1));
83  }
84 
85  default:
86  Error(false, "Invalid element type");
87  }
88 
89  return libMesh::invalid_uint;
90  }
91 
92 
93  inline void build_cube(libMesh::UnstructuredMesh & mesh,
94  const uint_t nx,
95  const uint_t ny,
96  const uint_t nz,
97  const real_t length,
98  const real_t height,
99  const real_t width,
100  const real_t dirichlet_length_fraction,
101  const libMesh::ElemType type) {
102 
103  Assert0(type == libMesh::HEX8 || type == libMesh::HEX27,
104  "Method only implemented for Hex8/Hex27");
105 
106  // Clear the mesh and start from scratch
107  mesh.clear();
108 
109  libMesh::BoundaryInfo & boundary_info = mesh.get_boundary_info();
110 
111  mesh.set_mesh_dimension(3);
112  mesh.set_spatial_dimension(3);
113  mesh.reserve_elem(nx*ny*nz);
114 
115  if (type == libMesh::HEX8)
116  mesh.reserve_nodes( (nx+1)*(ny+1)*(nz+1) );
117  else if (type == libMesh::HEX27)
118  mesh.reserve_nodes( (2*nx+1)*(2*ny+1)*(2*nz+1) );
119 
120  real_t
121  xmax = length,
122  ymax = height,
123  zmax = width;
124 
125 
126 
127  std::map<uint_t, libMesh::Node*> nodes;
128 
129  // Build the nodes.
130  uint_t
131  node_id = 0,
132  n = 0;
133  switch (type)
134  {
135  case libMesh::HEX8: {
136 
137  for (uint_t k=0; k<=nz; k++)
138  for (uint_t j=0; j<=ny; j++)
139  for (uint_t i=0; i<=nx; i++) {
140  nodes[node_id] =
141  mesh.add_point(libMesh::Point(static_cast<real_t>(i)/static_cast<real_t>(nx)*length,
142  static_cast<real_t>(j)/static_cast<real_t>(ny)*height,
143  static_cast<real_t>(k)/static_cast<real_t>(nz)*width),
144  n++);
145  node_id++;
146  }
147 
148 
149  break;
150  }
151 
152  case libMesh::HEX27: {
153 
154  for (uint_t k=0; k<=(2*nz); k++)
155  for (uint_t j=0; j<=(2*ny); j++)
156  for (uint_t i=0; i<=(2*nx); i++) {
157  nodes[node_id] =
158  mesh.add_point(libMesh::Point(static_cast<real_t>(i)/static_cast<real_t>(2*nx)*length,
159  static_cast<real_t>(j)/static_cast<real_t>(2*ny)*height,
160  static_cast<real_t>(k)/static_cast<real_t>(2*nz)*width),
161  n++);
162  node_id++;
163  }
164 
165  break;
166  }
167 
168 
169  default:
170  Assert0(false, "ERROR: Unrecognized 3D element type.");
171  }
172 
173  // Build the elements.
174  uint_t
175  elem_id = 0;
176  switch (type)
177  {
178  case libMesh::HEX8:
179  {
180  for (uint_t k=0; k<nz; k++)
181  for (uint_t j=0; j<ny; j++)
182  for (uint_t i=0; i<nx; i++) {
183 
184  libMesh::Elem
185  *elem = libMesh::Elem::build(libMesh::HEX8).release();
186  elem->set_id(elem_id++);
187  mesh.add_elem(elem);
188 
189  elem->set_node(0) = nodes[idx(type,nx,ny,i,j,k) ];
190  elem->set_node(1) = nodes[idx(type,nx,ny,i+1,j,k) ];
191  elem->set_node(2) = nodes[idx(type,nx,ny,i+1,j+1,k) ];
192  elem->set_node(3) = nodes[idx(type,nx,ny,i,j+1,k) ];
193  elem->set_node(4) = nodes[idx(type,nx,ny,i,j,k+1) ];
194  elem->set_node(5) = nodes[idx(type,nx,ny,i+1,j,k+1) ];
195  elem->set_node(6) = nodes[idx(type,nx,ny,i+1,j+1,k+1)];
196  elem->set_node(7) = nodes[idx(type,nx,ny,i,j+1,k+1) ];
197 
198  if (k == 0)
199  boundary_info.add_side(elem, 0, 0);
200 
201  if (k == (nz-1))
202  boundary_info.add_side(elem, 5, 5);
203 
204  if (j == 0)
205  boundary_info.add_side(elem, 1, 1);
206 
207  if (j == (ny-1))
208  boundary_info.add_side(elem, 3, 3);
209 
210  if (i == 0)
211  boundary_info.add_side(elem, 4, 4);
212 
213  if (i == (nx-1))
214  boundary_info.add_side(elem, 2, 2);
215 
216  if ((j == 0) &&
217  (i <= .5*(1.+dirichlet_length_fraction) * nx) &&
218  (i >= .5*(1.-dirichlet_length_fraction) * nx) &&
219  (k <= .5*(1.+dirichlet_length_fraction) * nz) &&
220  (k >= .5*(1.-dirichlet_length_fraction) * nz))
221  boundary_info.add_side(elem, 1, 6);
222  }
223  break;
224  }
225 
226 
227  case libMesh::HEX27: {
228 
229  for (uint_t k=0; k<(2*nz); k += 2)
230  for (uint_t j=0; j<(2*ny); j += 2)
231  for (uint_t i=0; i<(2*nx); i += 2)
232  {
233  libMesh::Elem
234  *elem = libMesh::Elem::build(libMesh::HEX27).release();
235  elem->set_id(elem_id++);
236  mesh.add_elem(elem);
237 
238  elem->set_node(0) = nodes[idx(type,nx,ny,i, j, k) ];
239  elem->set_node(1) = nodes[idx(type,nx,ny,i+2,j, k) ];
240  elem->set_node(2) = nodes[idx(type,nx,ny,i+2,j+2,k) ];
241  elem->set_node(3) = nodes[idx(type,nx,ny,i, j+2,k) ];
242  elem->set_node(4) = nodes[idx(type,nx,ny,i, j, k+2)];
243  elem->set_node(5) = nodes[idx(type,nx,ny,i+2,j, k+2)];
244  elem->set_node(6) = nodes[idx(type,nx,ny,i+2,j+2,k+2)];
245  elem->set_node(7) = nodes[idx(type,nx,ny,i, j+2,k+2)];
246  elem->set_node(8) = nodes[idx(type,nx,ny,i+1,j, k) ];
247  elem->set_node(9) = nodes[idx(type,nx,ny,i+2,j+1,k) ];
248  elem->set_node(10) = nodes[idx(type,nx,ny,i+1,j+2,k) ];
249  elem->set_node(11) = nodes[idx(type,nx,ny,i, j+1,k) ];
250  elem->set_node(12) = nodes[idx(type,nx,ny,i, j, k+1)];
251  elem->set_node(13) = nodes[idx(type,nx,ny,i+2,j, k+1)];
252  elem->set_node(14) = nodes[idx(type,nx,ny,i+2,j+2,k+1)];
253  elem->set_node(15) = nodes[idx(type,nx,ny,i, j+2,k+1)];
254  elem->set_node(16) = nodes[idx(type,nx,ny,i+1,j, k+2)];
255  elem->set_node(17) = nodes[idx(type,nx,ny,i+2,j+1,k+2)];
256  elem->set_node(18) = nodes[idx(type,nx,ny,i+1,j+2,k+2)];
257  elem->set_node(19) = nodes[idx(type,nx,ny,i, j+1,k+2)];
258 
259  elem->set_node(20) = nodes[idx(type,nx,ny,i+1,j+1,k) ];
260  elem->set_node(21) = nodes[idx(type,nx,ny,i+1,j, k+1)];
261  elem->set_node(22) = nodes[idx(type,nx,ny,i+2,j+1,k+1)];
262  elem->set_node(23) = nodes[idx(type,nx,ny,i+1,j+2,k+1)];
263  elem->set_node(24) = nodes[idx(type,nx,ny,i, j+1,k+1)];
264  elem->set_node(25) = nodes[idx(type,nx,ny,i+1,j+1,k+2)];
265  elem->set_node(26) = nodes[idx(type,nx,ny,i+1,j+1,k+1)];
266 
267  if (k == 0)
268  boundary_info.add_side(elem, 0, 0);
269 
270  if (k == 2*(nz-1))
271  boundary_info.add_side(elem, 5, 5);
272 
273  if (j == 0)
274  boundary_info.add_side(elem, 1, 1);
275 
276  if (j == 2*(ny-1))
277  boundary_info.add_side(elem, 3, 3);
278 
279  if (i == 0)
280  boundary_info.add_side(elem, 4, 4);
281 
282  if (i == 2*(nx-1))
283  boundary_info.add_side(elem, 2, 2);
284 
285  if ((j == 0) &&
286  (i <= .5*(1.+dirichlet_length_fraction) * 2*nx) &&
287  (i >= .5*(1.-dirichlet_length_fraction) * 2*nx) &&
288  (k <= .5*(1.+dirichlet_length_fraction) * 2*nz) &&
289  (k >= .5*(1.-dirichlet_length_fraction) * 2*nz))
290  boundary_info.add_side(elem, 1, 6);
291  }
292  break;
293  }
294 
295  default:
296  Assert0(false, "ERROR: Unrecognized 3D element type.");
297  }
298 
299  // Add sideset names to boundary info (Z axis out of the screen)
300  boundary_info.sideset_name(0) = "back";
301  boundary_info.sideset_name(1) = "bottom";
302  boundary_info.sideset_name(2) = "right";
303  boundary_info.sideset_name(3) = "top";
304  boundary_info.sideset_name(4) = "left";
305  boundary_info.sideset_name(5) = "front";
306  boundary_info.sideset_name(6) = "dirichlet";
307 
308  // Add nodeset names to boundary info
309  boundary_info.nodeset_name(0) = "back";
310  boundary_info.nodeset_name(1) = "bottom";
311  boundary_info.nodeset_name(2) = "right";
312  boundary_info.nodeset_name(3) = "top";
313  boundary_info.nodeset_name(4) = "left";
314  boundary_info.nodeset_name(5) = "front";
315 
316  // Done building the mesh. Now prepare it for use.
317  mesh.prepare_for_use ();
318  }
319 
320 
321 
322  template <typename Context>
323  inline void
324  init_analysis_mesh(Context& c,
325  libMesh::UnstructuredMesh& mesh) {
326 
327  real_t
328  length = c.input("length", "length of domain along x-axis", 1.),
329  height = c.input("height", "length of domain along y-axis", 1.),
330  width = c.input("width", "length of domain along z-axis", 1.),
331  dirichlet_length_fraction = c.input
332  ("dirichlet_length_fraction",
333  "length fraction of the truss boundary where dirichlet condition is applied",
334  0.1);
335 
336  uint_t
337  nx_divs = c.input("nx_divs", "number of elements along x-axis", 20),
338  ny_divs = c.input("ny_divs", "number of elements along y-axis", 20),
339  nz_divs = c.input("nz_divs", "number of elements along z-axis", 20),
340  n_refine= c.input("n_uniform_refinement", "number of times the mesh is uniformly refined", 0);
341 
342  std::string
343  t = c.input("elem_type", "type of geometric element in the mesh", "hex8");
344 
345  libMesh::ElemType
346  e_type = libMesh::Utility::string_to_enum<libMesh::ElemType>(t);
347 
348  //
349  // if high order FE is used, libMesh requires atleast a second order
350  // geometric element.
351  //
352  if (c.fe_order > 1 && e_type == libMesh::HEX8)
353  e_type = libMesh::HEX27;
354  else if (c.fe_order > 1 && e_type == libMesh::TET4)
355  e_type = libMesh::TET10;
356 
357  //
358  // initialize the mesh with one element
359  //
360  build_cube(mesh,
361  nx_divs, ny_divs, nz_divs,
362  length,
363  height,
364  width,
365  dirichlet_length_fraction,
366  e_type);
367 
368  // we now uniformly refine this mesh
369  if (n_refine) {
370 
371  libMesh::MeshRefinement(mesh).uniformly_refine(n_refine);
372  libMesh::MeshTools::Modification::flatten(mesh);
373  }
374  }
375 
376 
377 
378  template <typename Context>
379  inline void
381 
382  c.sys->get_dof_map().add_dirichlet_boundary
383  (libMesh::DirichletBoundary({6}, {0}, libMesh::ZeroFunction<real_t>()));
384  }
385 
386 
387  template <typename ScalarType, typename Context>
388  inline void
390  (Context &c,
392 
393  //
394  // this assumes that density variable has a constant value per element
395  //
396  Assert2(c.fe_family == libMesh::LAGRANGE,
397  c.fe_family, libMesh::LAGRANGE,
398  "Method assumes Lagrange interpolation function for density");
399 
400  real_t
401  tol = 1.e-12,
402  length = c.input("length", "length of domain along x-axis", 1.),
403  height = c.input("height", "length of domain along y-axis", 1.),
404  filter_radius = c.input("filter_radius", "radius of geometric filter for level set field", 0.1),
405  vf = c.input("volume_fraction", "upper limit for the volume fraction", 0.3);
406 
407  uint_t
408  sys_num = c.rho_sys->number(),
409  first_dof = c.rho_sys->get_dof_map().first_dof(c.rho_sys->comm().rank()),
410  end_dof = c.rho_sys->get_dof_map().end_dof(c.rho_sys->comm().rank()),
411  dof_id = 0;
412 
413  real_t
414  val = 0.;
415 
416  libMesh::MeshBase::const_element_iterator
417  e_it = c.mesh->active_local_elements_begin(),
418  e_end = c.mesh->active_local_elements_end();
419 
420  std::set<const libMesh::Node*> nodes;
421 
422  for ( ; e_it != e_end; e_it++) {
423 
424  const libMesh::Elem* e = *e_it;
425 
426  for (uint_t i=0; i<e->n_nodes(); i++) {
427 
428  const libMesh::Node& n = *e->node_ptr(i);
429 
430  // if we have alredy operated on this node, then
431  // we skip it
432  if (nodes.count(&n))
433  continue;
434 
435  // otherwise, we add it to the set of operated nodes and
436  // check if a design parameter should be computed for this
437  nodes.insert(&n);
438 
439  dof_id = n.dof_number(sys_num, 0, 0);
440 
443  dv->set_point(n(0), n(1), n(2));
444 
445  if (dof_id >= first_dof &&
446  dof_id < end_dof)
447  dvs.add_topology_parameter(*dv, dof_id);
448  else
449  dvs.add_ghosted_topology_parameter(*dv, dof_id);
450  }
451  }
452 
453  dvs.synchronize(c.rho_sys->get_dof_map());
454  c.rho_sys->solution->close();
455  }
456 };
457 
458 } // namespace Generation
459 } // namespace Mesh
460 } // namespace MAST
461 
462 
463 #endif // __mast_mesh_generation_truss_3d_h__
#define Error(cond, msg)
Definition: exceptions.hpp:166
uint_t idx(const libMesh::ElemType type, const uint_t nx, const uint_t ny, const uint_t i, const uint_t j, const uint_t k)
Definition: heat_sink3d.hpp:66
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)
MAST::Base::ParameterData & add_topology_parameter(MAST::Optimization::DesignParameter< ScalarType > &p, const uint_t id)
real_t reference_volume(Context &c)
Definition: heat_sink3d.hpp:55
void init_analysis_dirichlet_conditions(Context &c)
#define Assert0(cond, msg)
Definition: exceptions.hpp:134
unsigned int uint_t
#define Assert2(cond, v1, v2, msg)
Definition: exceptions.hpp:152
void build_cube(libMesh::UnstructuredMesh &mesh, const uint_t nx, const uint_t ny, const uint_t nz, const real_t length, const real_t height, const real_t width, const real_t dirichlet_length_fraction, const libMesh::ElemType type)
Definition: heat_sink3d.hpp:93
void set_point(real_t x, real_t y=0., real_t z=0.)
void init_analysis_mesh(Context &c, libMesh::UnstructuredMesh &mesh)
double real_t
void synchronize(const libMesh::DofMap &dof_map)
std::unique_ptr< ValType > build(const libMesh::System &sys)
Definition: utility.hpp:284