applications/mp-melt-pool/cases/recoil_pressure/recoil_pressure.hpp Source File

Developer Documentation: applications/mp-melt-pool/cases/recoil_pressure/recoil_pressure.hpp Source File
Developer Documentation
recoil_pressure.hpp
Go to the documentation of this file.
1#pragma once
2#include <deal.II/base/bounding_box.h>
3#include <deal.II/base/exceptions.h>
4#include <deal.II/base/function.h>
5#include <deal.II/base/function_parser.h>
6#include <deal.II/base/function_signed_distance.h>
7#include <deal.II/base/mpi.h>
8#include <deal.II/base/parameter_handler.h>
9#include <deal.II/base/point.h>
10#include <deal.II/base/tensor.h>
11#include <deal.II/base/types.h>
12#include <deal.II/base/utilities.h>
13
14#include <deal.II/distributed/shared_tria.h>
15#include <deal.II/distributed/tria.h>
16
17#include <deal.II/grid/grid_generator.h>
18#include <deal.II/grid/grid_refinement.h>
19#include <deal.II/grid/grid_tools.h>
20#include <deal.II/grid/manifold_lib.h>
21
26
27#include <memory>
28#include <string>
29#include <vector>
30
31#include "../../melt_pool_case.hpp"
32
34{
35 static std::string T_bc_top = "";
36 static std::string T_bc_bottom = "";
37
38
39 template <int dim>
40 class InitialConditionTemperature : public dealii::Function<dim>
41 {
42 public:
44 const double T_initial_top,
45 const double y_min,
46 const double y_max)
47 : dealii::Function<dim>()
50 , y_min(y_min)
52 {}
53
54 double
55 value(const dealii::Point<dim> &p, const unsigned int /*component*/) const override
56 {
58 return T_initial_top;
59 else
60
61 return T_initial_bottom + grad_T * (p[dim - 1] - y_min);
62 }
63
64 const double T_initial_bottom;
65 const double T_initial_top;
66 const double y_min;
67 const double grad_T;
68 };
69
70 template <int dim, typename number>
71 class SimulationRecoilPressure : public MeltPoolCase<dim, number>
72 {
73 private:
74 double domain_x_min = 0;
75 double domain_x_max = 0;
76 double domain_y_min = 0;
77 double domain_y_max = 0;
78 std::vector<unsigned int> cell_repetitions;
79
80 bool periodic_boundary = false;
82 double outlet_pressure = 0.0;
83 bool slip_boundary = false;
84 unsigned int n_local_refinement = 0;
85 double T_initial_top = 500;
87
89 dealii::Point<dim> local_refinement_1_top_right;
91 dealii::Point<dim> local_refinement_2_top_right;
92
93 // triangulation of a slice for reduced output in 3D
94 dealii::parallel::distributed::Triangulation<2, 3> tria_slice;
95 mutable std::shared_ptr<PostProcessingTools::SliceCreator<3, double>> slice;
96 mutable unsigned int n_written_time_step_slice = 0;
97
98 struct SliceData
99 {
100 bool enable = false;
102 double coord = 0.0;
103 std::vector<std::string> output_variables;
104
106 {
107 unsigned int n_local_refinement = 0;
108 dealii::Point<3> bottom_left;
109 dealii::Point<3> top_right;
111
113
114 public:
120
121 bool
122 add_case_specific_parameters(dealii::ParameterHandler &prm) override
123 {
124 prm.add_parameter("domain x min", domain_x_min, "minimum x coordinate of simulation domain");
125 prm.add_parameter("domain y min", domain_y_min, "minimum y coordinate of simulation domain");
126 prm.add_parameter("domain x max", domain_x_max, "maximum x coordinate of simulation domain");
127 prm.add_parameter("domain y max", domain_y_max, "maximum y coordinate of simulation domain");
128 prm.add_parameter("cell repetitions",
130 "cell repetitions per dim applied before global refinement or amr");
131 prm.add_parameter("n local refinement",
133 "number of (additional to the global) refinements for local region.");
134 prm.add_parameter("local refinement 1 bottom left",
136 "Bottom left point of locally refined region.");
137 prm.add_parameter("local refinement 1 top right",
139 "Bottom left point of locally refined region.");
140 prm.add_parameter("local refinement 2 bottom left",
142 "Bottom left point of locally refined region.");
143 prm.add_parameter("local refinement 2 top right",
145 "Bottom left point of locally refined region.");
146 prm.add_parameter(
147 "periodic boundary",
149 "Set this parameter to true if the domain should be periodic in x direction.");
150 prm.add_parameter(
151 "evaporation boundary",
153 "Set this Parameter to true if the upper boundary of the domain should be open "
154 "to enable an outward mass flow.");
155 prm.add_parameter("outlet pressure",
157 "If evaporation boundary is enabled, set the outlet pressure.");
158 prm.add_parameter(
159 "slip boundary",
161 "Set this Parameter to true if the outer boundaries should be slip boundaries instead of no-slip.");
162 prm.enter_subsection("initial temperature");
163 {
164 prm.add_parameter("top", T_initial_top, "Set the initial temperature on the top boundary.");
165 prm.add_parameter("bottom",
167 "Set the initial temperature on the bottom boundary.");
168 }
169 prm.leave_subsection();
170 prm.enter_subsection("bc temperature");
171 {
172 prm.add_parameter("top", T_bc_top, "Set the initial temperature on the top boundary.");
173 prm.add_parameter("bottom",
175 "Set the initial temperature on the bottom boundary.");
176 }
177 prm.leave_subsection();
178 prm.enter_subsection("output slice");
179 {
180 prm.add_parameter("enable",
182 "Set this parameter to true, if a slice output should be"
183 " enabled.");
184 prm.add_parameter("output variables",
186 "Specify variables that you request to output for the slice."
187 "In the default case, the one specified within the output "
188 "section will be adopted.");
189 prm.add_parameter("n global refinement",
191 "Set the maximum (global) refinement level.");
192 prm.add_parameter("coord",
194 "Set the x/y coordinate where the slice should take place.");
195 prm.enter_subsection("refined region");
196 {
197 prm.add_parameter("n local refinement",
199 "Set the additional refinements of the locally refined region.");
200 prm.add_parameter("bottom left",
202 "Coordinates of the bottom left point of the refined domain");
203 prm.add_parameter("top right",
205 "Coordinates of the top right point of the refined domain");
206 }
207 prm.leave_subsection();
208 }
209 prm.leave_subsection();
210
211 return this->parameters.base.do_print_parameters;
212 }
213
214 void
216 {
217 // set default values of parameters @todo --> make own overwritten base function
220 this->parameters.output.output_variables;
221
222 if (this->parameters.base.fe.type == FiniteElementType::FE_SimplexP || dim == 1)
223 {
224#ifdef DEAL_II_WITH_METIS
225 this->triangulation = std::make_shared<dealii::parallel::shared::Triangulation<dim>>(
226 this->mpi_communicator,
227 dealii::Triangulation<dim>::MeshSmoothing::none,
228 true,
229 dealii::parallel::shared::Triangulation<dim>::Settings::partition_metis);
230#else
231 AssertThrow(
232 false,
233 dealii::ExcMessage(
234 "Missing Metis support of the deal.II installation. "
235 "Configure deal.II with -D DEAL_II_WITH_METIS='ON' to execute this example."));
236#endif
237 }
238 else
239 {
240 this->triangulation = std::make_shared<dealii::parallel::distributed::Triangulation<dim>>(
241 this->mpi_communicator);
242 }
243
244 const double &x_min = domain_x_min;
245 const double &x_max = domain_x_max;
246 const double &y_min = domain_y_min;
247 const double &y_max = domain_y_max;
248 // create mesh
249 //
250 // Note: For 1d we consider the coordinates along the y-axis.
251 const dealii::Point<dim> bottom_left = dim == 1 ? dealii::Point<dim>(y_min) :
252 dim == 2 ? dealii::Point<dim>(x_min, y_min) :
253 dealii::Point<dim>(x_min, x_min, y_min);
254 const dealii::Point<dim> top_right = dim == 1 ? dealii::Point<dim>(y_max) :
255 dim == 2 ? dealii::Point<dim>(x_max, y_max) :
256 dealii::Point<dim>(x_max, x_max, y_max);
257
258 if (this->parameters.base.fe.type == FiniteElementType::FE_SimplexP)
259 {
260 std::vector<unsigned int> subdivisions(
261 dim, 5 * dealii::Utilities::pow(2, this->parameters.base.global_refinements));
262 subdivisions[dim - 1] *= 2;
263 for (int d = 0; d < dim; d++)
264 subdivisions[d] *= cell_repetitions[d];
265
266 dealii::GridGenerator::subdivided_hyper_rectangle_with_simplices(
267 *this->triangulation, subdivisions, bottom_left, top_right, true /*colorize*/);
268 }
269 else
270 {
271 dealii::GridGenerator::subdivided_hyper_rectangle(
272 *this->triangulation, cell_repetitions, bottom_left, top_right, true /*colorize*/);
273 }
274
275 // create slice for postprocessing
276 if constexpr (dim == 3)
277 {
278 if (slice_data.enable)
279 {
280 dealii::GridGenerator::subdivided_hyper_rectangle(
282 {1, 1} /*subdivisions*/,
283 dealii::Point<2>(domain_x_min, domain_y_min),
284 dealii::Point<2>(domain_x_max, domain_y_max));
285 // rotate plane by 90° around x-axis
286 dealii::GridTools::rotate(dealii::Point<3>::unit_vector(0),
287 0.5 * dealii::numbers::PI,
288 tria_slice);
289 // shift plane along y-axis
290 dealii::GridTools::shift(dealii::Point<3>::unit_vector(1) * slice_data.coord,
291 tria_slice);
292
293 // refine globally
295
296 // refine local region if requested
298 {
299 const auto slice_refined = dealii::BoundingBox<3>(
301
302 for (unsigned int j = 0; j < slice_data.refined_region.n_local_refinement; ++j)
303 {
304 for (auto &cell : tria_slice.active_cell_iterators())
305 {
306 if (cell->is_locally_owned())
307 {
308 for (unsigned int i = 0; i < cell->n_vertices(); ++i)
309 if (slice_refined.point_inside(cell->vertex(i)))
310 {
311 cell->set_refine_flag();
312 break;
313 }
314 }
315 }
316 tria_slice.execute_coarsening_and_refinement();
317 }
318 }
319 }
320 }
321 }
322
323 void
325 {
326 /*
327 * upper_bc
328 * +-------------------+
329 * | |
330 * | ls = -1 |
331 * | |
332 * left_bc |-------------------| right_bc
333 * | |
334 * | ls = 1 |
335 * | |
336 * +-------------------+
337 * lower_bc
338 *
339 * -----------------------------------------------------------------------------
340 * evaporation boundary = false
341 * periodic boundary = false
342 * slip boundary = false
343 * | temperature | velocity | pressure | level set
344 * left_bc, right_bc | adiabatic | no-slip | - | -
345 * lower_bc | T = T_initial | no-slip | fixed constant | -
346 * upper_bc | T = T_initial | no-slip | - | -
347 * -----------------------------------------------------------------------------
348 * evaporation boundary = false
349 * periodic boundary = false
350 * slip boundary = true
351 * | temperature | velocity | pressure | level set
352 * left_bc, right_bc | adiabatic | slip | - | -
353 * lower_bc | T = T_initial | slip | fixed constant | -
354 * upper_bc | T = T_initial | slip | - | -
355 * -----------------------------------------------------------------------------
356 * evaporation boundary = false
357 * periodic boundary = true
358 * slip boundary = false
359 * | temperature | velocity | pressure | level set
360 * left_bc, right_bc | periodic | periodic | periodic | periodic
361 * lower_bc | T = T_initial | no-slip | fixed constant | -
362 * upper_bc | T = T_initial | no-slip | - | -
363 * -----------------------------------------------------------------------------
364 * evaporation boundary = false
365 * periodic boundary = true
366 * slip boundary = true
367 * | temperature | velocity | pressure | level set
368 * left_bc, right_bc | periodic | periodic | periodic | periodic
369 * lower_bc | T = T_initial | slip | fixed constant | -
370 * upper_bc | T = T_initial | slip | - | -
371 * -----------------------------------------------------------------------------
372 * evaporation boundary = true
373 * periodic boundary = false
374 * slip boundary = false
375 * | temperature | velocity | pressure | level set
376 * left_bc, right_bc | adiabatic | symmetry | - | -
377 * lower_bc | T = T_initial | no-slip | - | -
378 * upper_bc | T = T_initial | open | - | -
379 * -----------------------------------------------------------------------------
380 * evaporation boundary = true
381 * periodic boundary = false
382 * slip boundary = true
383 * | temperature | velocity | pressure | level set
384 * left_bc, right_bc | adiabatic | symmetry | - | -
385 * lower_bc | T = T_initial | slip | - | -
386 * upper_bc | T = T_initial | open | - | -
387 * -----------------------------------------------------------------------------
388 * evaporation boundary = true
389 * periodic boundary = true
390 * slip boundary = false
391 * | temperature | velocity | pressure | level set
392 * left_bc, right_bc | periodic | periodic | periodic | periodic
393 * lower_bc | T = T_initial | no-slip | - | -
394 * upper_bc | T = T_initial | open | - | -
395 * -----------------------------------------------------------------------------
396 * evaporation boundary = true
397 * periodic boundary = true
398 * slip boundary = true
399 * | temperature | velocity | pressure | level set
400 * left_bc, right_bc | periodic | periodic | periodic | periodic
401 * lower_bc | T = T_initial | slip | - | -
402 * upper_bc | T = T_initial | open | - | -
403 * -----------------------------------------------------------------------------
404 *
405 * Note: In the 3D recoil pressure simulation, the front and back boundaries are treated
406 * the same as the left and right boundaries.
407 *
408 * Note: For 1D we consider the constraints along the y-axis, i.e. lower_bc and upper_bc.
409 */
410
411 // face numbering according to the deal.II colorize flag
412 const auto [lower_bc, upper_bc, left_bc, right_bc, front_bc, back_bc] =
413 get_colorized_rectangle_boundary_ids<dim>();
414
416 {
417 if (dim >= 2)
418 this->attach_periodic_boundary_condition(left_bc, right_bc, 0 /*direction*/);
419 if (dim == 3)
420 this->attach_periodic_boundary_condition(front_bc, back_bc, 1 /*direction*/);
421 }
422
423 /*
424 * BC for two-phase flow
425 */
426 const auto add_slip_or_no_slip_boundary = [&](const dealii::types::boundary_id bc) {
427 if (slip_boundary)
428 this->attach_boundary_condition(bc, "symmetry", "navier_stokes_u");
429 else
430 this->attach_boundary_condition(bc, "no_slip", "navier_stokes_u");
431 };
432
433 add_slip_or_no_slip_boundary(lower_bc);
435 {
437 {upper_bc, std::make_shared<dealii::Functions::ConstantFunction<dim>>(outlet_pressure)},
438 "open",
439 "navier_stokes_u");
441 {
442 if (dim >= 2)
443 {
444 this->attach_boundary_condition(left_bc, "symmetry", "navier_stokes_u");
445 this->attach_boundary_condition(right_bc, "symmetry", "navier_stokes_u");
446 }
447 if (dim == 3)
448 {
449 this->attach_boundary_condition(front_bc, "symmetry", "navier_stokes_u");
450 this->attach_boundary_condition(back_bc, "symmetry", "navier_stokes_u");
451 }
452 }
453 }
454 else // no evaporation
455 {
456 // The fix pressure constant condition can be set on any boundary (that is not a
457 // periodic boundary).
458 this->attach_boundary_condition(lower_bc, "fix_pressure_constant", "navier_stokes_p");
459 add_slip_or_no_slip_boundary(upper_bc);
461 {
462 if (dim >= 2)
463 {
464 add_slip_or_no_slip_boundary(left_bc);
465 add_slip_or_no_slip_boundary(right_bc);
466 }
467 if (dim == 3)
468 {
469 add_slip_or_no_slip_boundary(front_bc);
470 add_slip_or_no_slip_boundary(back_bc);
471 }
472 }
473 }
474
475 /*
476 * BC for heat transfer
477 */
478 if (this->parameters.laser.model != Heat::LaserModelType::analytical_temperature)
479 {
480 if (evaporation_boundary && this->parameters.heat.convection.convection_coefficient > 0)
481 this->attach_boundary_condition(upper_bc, "convection", "heat_transfer");
482 else
483 {
484 std::shared_ptr<dealii::Function<dim>> T_1;
485 std::shared_ptr<dealii::Function<dim>> T_2;
486
487 if ((T_bc_top != "") && (T_bc_bottom != ""))
488 {
489 T_1 = std::make_shared<dealii::FunctionParser<dim>>(T_bc_top);
490 T_2 = std::make_shared<dealii::FunctionParser<dim>>(T_bc_bottom);
491 }
492 else
493 {
494 T_1 = std::make_shared<dealii::Functions::ConstantFunction<dim>>(T_initial_top);
495 T_2 =
496 std::make_shared<dealii::Functions::ConstantFunction<dim>>(T_initial_bottom);
497 }
498
499 this->attach_boundary_condition({upper_bc, T_1}, "dirichlet", "heat_transfer");
500 this->attach_boundary_condition({lower_bc, T_2}, "dirichlet", "heat_transfer");
501 }
502 }
503 // BC for RTE laser
504 if (this->parameters.laser.model == Heat::LaserModelType::RTE)
505 this->parameters.laser.rte_boundary_id = upper_bc;
506
507 if (this->parameters.base.fe.type != FiniteElementType::FE_SimplexP)
508 this->triangulation->refine_global(this->parameters.base.global_refinements);
509
510 /*
511 * locally refined region described by max. 2 bounding boxes
512 *
513 *
514 * +-------------------------+
515 * | |
516 * | +--------+ |
517 * | |refine 1| |
518 * | +--------+ |
519 * | |
520 * | |
521 * | +--------+ |
522 * | |refine 2| |
523 * | +--------+ |
524 * | |
525 * | |
526 * +-------------------------+
527 *
528 */
529 if (n_local_refinement > 0)
530 {
531 if constexpr (dim == 2)
532 {
533 // 1. region
534 const auto refinement_region = dealii::BoundingBox<dim>(
536
537 // 2. region
538 const auto refinement_region_2 = dealii::BoundingBox<dim>(
540
541 for (unsigned int j = 0; j < n_local_refinement; ++j)
542 {
543 for (auto &cell : this->triangulation->active_cell_iterators())
544 {
545 if (cell->is_locally_owned())
546 {
547 for (unsigned int i = 0; i < cell->n_vertices(); ++i)
548 if (refinement_region.point_inside(cell->vertex(i)) ||
549 refinement_region_2.point_inside(cell->vertex(i)))
550 {
551 cell->set_refine_flag();
552 break;
553 }
554 }
555 }
556 this->triangulation->execute_coarsening_and_refinement();
557 }
558 }
559 else
560 AssertThrow(false, dealii::ExcNotImplemented());
561 }
562 }
563
564 void
566 {
568 std::make_shared<dealii::Functions::SignedDistance::Plane<dim>>(
569 dealii::Point<dim>::unit_vector(dim - 1) *
570 this->parameters.laser.template get_starting_position<dim>()[dim - 1],
571 -dealii::Point<dim>::unit_vector(dim - 1)),
572 "signed_distance");
573 this->attach_initial_condition(std::make_shared<dealii::Functions::ZeroFunction<dim>>(dim),
574 "navier_stokes_u");
575 if (this->parameters.laser.model != Heat::LaserModelType::analytical_temperature)
577 std::make_shared<InitialConditionTemperature<dim>>(
579 "heat_transfer");
580
581 if (this->parameters.laser.model == Heat::LaserModelType::RTE)
582 this->attach_initial_condition(std::make_shared<dealii::Functions::ZeroFunction<dim>>(),
583 "intensity");
584 }
585
586 void
588 [[maybe_unused]] const GenericDataOut<dim, double> &generic_data_out) const final
589 {
590 if (this->parameters.output.do_user_defined_postprocessing == false || !slice_data.enable)
591 return;
592
593 // create slice
594 if constexpr (dim == 3)
595 {
596 if (!slice)
597 {
598 slice = std::make_shared<PostProcessingTools::SliceCreator<3, double>>(
599 generic_data_out, tria_slice, slice_data.output_variables, this->parameters.output);
600 }
601 // @todo: We need to reinit, since generic_data_out is currently created
602 // for every time step.
603 slice->reinit(generic_data_out);
604
607 }
608 }
609 };
610} // namespace MeltPoolDG::Simulation::RecoilPressure
A generic utility for managing simulation output data in the MeltPoolDG context.
Definition generic_data_out.hpp:32
Definition melt_pool_case.hpp:290
MeltPoolCaseParameters< number > parameters
Definition melt_pool_case.hpp:292
void attach_boundary_condition(std::pair< const dealii::types::boundary_id, const std::shared_ptr< dealii::Function< dim > > > id_and_function, const std::string &type, const std::string &operation_name)
Attach a boundary condition for a specific operation.
Definition simulation_case_base.hpp:345
std::shared_ptr< dealii::Triangulation< dim, spacedim > > triangulation
Definition simulation_case_base.hpp:49
const std::string parameter_file
Definition simulation_case_base.hpp:52
void attach_periodic_boundary_condition(const dealii::types::boundary_id id_in, const dealii::types::boundary_id id_out, const int direction)
Definition simulation_case_base.hpp:384
void attach_initial_condition(std::shared_ptr< dealii::Function< dim > > initial_function, const std::string &operation_name)
Definition simulation_case_base.hpp:327
const MPI_Comm mpi_communicator
Definition simulation_case_base.hpp:56
const double y_min
Definition recoil_pressure.hpp:66
InitialConditionTemperature(const double T_initial_bottom, const double T_initial_top, const double y_min, const double y_max)
Definition recoil_pressure.hpp:43
double value(const dealii::Point< dim > &p, const unsigned int) const override
Definition recoil_pressure.hpp:55
const double T_initial_top
Definition recoil_pressure.hpp:65
const double grad_T
Definition recoil_pressure.hpp:67
const double T_initial_bottom
Definition recoil_pressure.hpp:64
void set_boundary_conditions() override
Pure virtual function to set the boundary conditions.
Definition recoil_pressure.hpp:324
void do_postprocessing(const GenericDataOut< dim, double > &generic_data_out) const final
Definition recoil_pressure.hpp:587
void set_field_conditions() override
Pure virtual function to set the field conditions.
Definition recoil_pressure.hpp:565
struct MeltPoolDG::Simulation::RecoilPressure::SimulationRecoilPressure::SliceData slice_data
double domain_x_max
Definition recoil_pressure.hpp:75
std::vector< unsigned int > cell_repetitions
Definition recoil_pressure.hpp:78
void create_spatial_discretization() override
Pure virtual function to create the spatial discretization.
Definition recoil_pressure.hpp:215
double domain_x_min
Definition recoil_pressure.hpp:74
unsigned int n_written_time_step_slice
Definition recoil_pressure.hpp:96
bool add_case_specific_parameters(dealii::ParameterHandler &prm) override
Add simulation-specific parameters (can be overridden).
Definition recoil_pressure.hpp:122
dealii::Point< dim > local_refinement_1_top_right
Definition recoil_pressure.hpp:89
bool evaporation_boundary
Definition recoil_pressure.hpp:81
SimulationRecoilPressure(std::string parameter_file, const MPI_Comm mpi_communicator)
Definition recoil_pressure.hpp:115
dealii::parallel::distributed::Triangulation< 2, 3 > tria_slice
Definition recoil_pressure.hpp:94
double domain_y_min
Definition recoil_pressure.hpp:76
double outlet_pressure
Definition recoil_pressure.hpp:82
dealii::Point< dim > local_refinement_1_bottom_left
Definition recoil_pressure.hpp:88
double T_initial_bottom
Definition recoil_pressure.hpp:86
dealii::Point< dim > local_refinement_2_bottom_left
Definition recoil_pressure.hpp:90
unsigned int n_local_refinement
Definition recoil_pressure.hpp:84
std::shared_ptr< PostProcessingTools::SliceCreator< 3, double > > slice
Definition recoil_pressure.hpp:95
double T_initial_top
Definition recoil_pressure.hpp:85
double domain_y_max
Definition recoil_pressure.hpp:77
dealii::Point< dim > local_refinement_2_top_right
Definition recoil_pressure.hpp:91
Definition recoil_pressure.cpp:6
static std::string T_bc_bottom
Definition recoil_pressure.hpp:36
static std::string T_bc_top
Definition recoil_pressure.hpp:35
Definition dealii_tensor.hpp:10
struct MeltPoolDG::Simulation::RecoilPressure::SimulationRecoilPressure::SliceData::RefinedRegion refined_region
std::vector< std::string > output_variables
Definition recoil_pressure.hpp:103