applications/mp-melt-pool/cases/evaporating_droplet/evaporating_shell.hpp Source File

Developer Documentation: applications/mp-melt-pool/cases/evaporating_droplet/evaporating_shell.hpp Source File
Developer Documentation
evaporating_shell.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <deal.II/base/function.h>
4#include <deal.II/base/function_signed_distance.h>
5#include <deal.II/base/mpi_remote_point_evaluation.h>
6#include <deal.II/base/point.h>
7#include <deal.II/base/table_handler.h>
8#include <deal.II/base/tensor_function.h>
9
10#include <deal.II/distributed/shared_tria.h>
11#include <deal.II/distributed/tria.h>
12
13#include <deal.II/grid/grid_generator.h>
14#include <deal.II/grid/manifold_lib.h>
15
16#include <deal.II/numerics/vector_tools.h>
17
19#include <meltpooldg/utilities/better_enum.hpp>
20
21#include <iostream>
22
23#include "../../melt_pool_case.hpp"
24
36{
37 BETTER_ENUM(ShellType, char, full, half, quarter)
38
39 // velocity prescribed at the interior edge
40 static double velocity = 0.0;
41 // inner radius of the circular shell
42 static double inner_radius = 0.5;
43 // outer radius of the circular shell
44 static double outer_radius = 2.0;
45
46 static ShellType shell_type = ShellType::full;
47
48 static bool two_phase = false;
49
50 template <int dim>
51 class SignedDistanceSphereFlipped : public dealii::Function<dim>
52 {
53 public:
54 SignedDistanceSphereFlipped(const double radius)
55 : dealii::Function<dim>()
56 , distance_sphere(dealii::Point<dim>(), radius)
57 {}
58
59 double
60 value(const dealii::Point<dim> &p, const unsigned int /*component*/) const override
61 {
62 return -distance_sphere.value(p);
63 }
64
65 private:
66 const dealii::Functions::SignedDistance::Sphere<dim> distance_sphere;
67 };
68
69 template <int dim>
70 class RadialBoundaryVelocity : public dealii::Function<dim>
71 {
72 public:
73 RadialBoundaryVelocity(const dealii::Point<dim> &center)
74 : dealii::Function<dim>(dim)
75 , center(center)
76 {}
77
78 double
79 value(const dealii::Point<dim> &p, const unsigned int comp) const override
80 {
81 const double v = velocity;
82
83 const double radius = p.distance(center);
84
85 // if point is not at boundary face
86 if (std::abs(radius - inner_radius) > 1e-6)
87 return 0.0;
88
89 if constexpr (dim == 1)
90 return v;
91
92 const auto n = p - center;
93
94 if (dim == 2)
95 {
96 if (comp == 0)
97 return v * n[0] / radius;
98 else //(comp == 1)
99 return v * n[1] / radius;
100 }
101 else if (dim == 3)
102 {
103 const double phi = std::acos(n[2] / radius);
104 const double theta = std::atan2(n[1], n[0]);
105
106 if (comp == 0)
107 return v * std::cos(theta) * std::sin(phi);
108 else if (comp == 1)
109 return v * std::sin(theta) * std::sin(phi);
110 else // if (comp == 2)
111 return v * std::cos(phi);
112 }
113 else
114 {
115 AssertThrow(false, dealii::ExcNotImplemented());
116 return 0;
117 }
118 }
119
120 private:
121 const dealii::Point<dim> center;
122 };
123
124 template <int dim, typename number>
125 class SimulationEvaporatingShell : public MeltPoolCase<dim, number>
126 {
127 public:
131
132 bool
133 add_case_specific_parameters(dealii::ParameterHandler &prm) override
134 {
135 prm.add_parameter("velocity", velocity, "Radial velocity on the interior edge of the shell.");
136 prm.add_parameter("inner radius", inner_radius, "inner radius");
137 prm.add_parameter("outer radius", outer_radius, "outer radius");
138 prm.add_parameter("shell type",
140 "Geometry type of the shell: quarter, half, full.");
141 prm.add_parameter("two phase", two_phase, "two phase");
142
143 return this->parameters.base.do_print_parameters;
144 }
145
146 void
148 {
149 if (this->parameters.base.fe.type == FiniteElementType::FE_SimplexP)
150 {
151 this->triangulation =
152 std::make_shared<dealii::parallel::shared::Triangulation<dim>>(this->mpi_communicator);
153 }
154 else
155 {
156 this->triangulation = std::make_shared<dealii::parallel::distributed::Triangulation<dim>>(
157 this->mpi_communicator);
158 }
159
160 if (shell_type == ShellType::full)
161 {
162 dealii::GridGenerator::hyper_shell(
163 *this->triangulation, center, inner_radius, outer_radius, 0, true /*colorize*/);
164 }
165 else if (shell_type == ShellType::half)
166 {
167 dealii::GridGenerator::half_hyper_shell(
168 *this->triangulation, center, inner_radius, outer_radius, 0, true /*colorize*/);
169 }
170 else if (shell_type == ShellType::quarter)
171 {
172 dealii::GridGenerator::quarter_hyper_shell(
173 *this->triangulation, center, inner_radius, outer_radius, 0, true /*colorize*/);
174 }
175 else
176 AssertThrow(false, dealii::ExcNotImplemented());
177
178 if (this->parameters.base.fe.type != FiniteElementType::FE_SimplexP)
179 this->triangulation->refine_global(this->parameters.base.global_refinements);
180 }
181
182 void
184 {
185 // outer boundary
186 this->attach_boundary_condition({1, std::make_shared<dealii::Functions::ZeroFunction<dim>>()},
187 "open",
188 "navier_stokes_u");
189
190 // inner boundary
191 const auto dirichlet = std::make_shared<RadialBoundaryVelocity<dim>>(center);
192 this->attach_boundary_condition({0, dirichlet}, "dirichlet", "navier_stokes_u");
193
194 if (shell_type != ShellType::full)
195 {
196 this->attach_boundary_condition(2, "symmetry", "navier_stokes_u");
197
198 if ((shell_type == ShellType::half && dim == 2) || shell_type == ShellType::quarter)
199 this->attach_boundary_condition(3, "symmetry", "navier_stokes_u");
200
201 if (shell_type == ShellType::quarter && dim == 3)
202 this->attach_boundary_condition(4, "symmetry", "navier_stokes_u");
203 }
204 }
205
206 void
208 {
209 if (two_phase)
211 (inner_radius + outer_radius) * 0.5),
212 "signed_distance");
213 else
215 std::make_shared<dealii::Functions::ConstantFunction<dim>>(-1), "level_set");
216
218 "navier_stokes_u");
219 }
220
221 void
222 do_postprocessing(const GenericDataOut<dim, double> &generic_data_out) const final
223 {
224 // Compare numerical vs. analytical solution based on the last computed time-step.
225 // This is sufficient since the test case is stationary.
226 if ((n_time_step == this->parameters.time_stepping.max_n_steps) ||
227 generic_data_out.get_time() == this->parameters.time_stepping.end_time)
228 {
229 std::cout.precision(3);
230 generic_data_out.get_vector("velocity").update_ghost_values();
231 generic_data_out.get_vector("pressure").update_ghost_values();
232
233 const auto analytical_velocity = [&](const double &r) -> double {
234 return velocity * inner_radius / r;
235 };
236
237 const auto analytical_pressure = [&](const double &r) -> double {
238 const double rho = this->parameters.material.gas.density;
239 const double mu = this->parameters.material.gas.dynamic_viscosity;
240 const double u0 = velocity;
241 return rho * u0 * u0 * inner_radius * inner_radius * 0.5 *
242 (1. / std::pow(outer_radius, 2) - 1 / (r * r)) -
243 2. * mu * u0 * inner_radius / std::pow(outer_radius, 2);
244 };
245
246 // generate number of request points and calculate analytical solution
247 std::vector<dealii::Point<dim>> req_points;
248 dealii::TableHandler table;
249 if (dealii::Utilities::MPI::this_mpi_process(this->mpi_communicator) == 0)
250 {
251 const std::vector<double> req_radii = {inner_radius,
252 (inner_radius + outer_radius) * 0.5,
254
255 for (const auto r : req_radii)
256 {
257 auto p = dealii::Point<dim>();
258 p[0] = r;
259 req_points.emplace_back(p);
260 table.add_value("analytical pressure", analytical_pressure(r));
261 table.add_value("analytical radial velocity", analytical_velocity(r));
262 }
263 }
264
265 // read numerical results at request points
266 dealii::Utilities::MPI::RemotePointEvaluation<dim, dim> remote_point_evaluation;
267 remote_point_evaluation.reinit(req_points,
268 *this->triangulation,
269 generic_data_out.get_mapping());
270
271 const auto pressure_vals =
272 dealii::VectorTools::point_values<1>(remote_point_evaluation,
273 generic_data_out.get_dof_handler("pressure"),
274 generic_data_out.get_vector("pressure"));
275
276 const auto vel_vals =
277 dealii::VectorTools::point_values<dim>(remote_point_evaluation,
278 generic_data_out.get_dof_handler("velocity"),
279 generic_data_out.get_vector("velocity"));
280 if (dealii::Utilities::MPI::this_mpi_process(this->mpi_communicator) == 0)
281 {
282 for (unsigned int i = 0; i < vel_vals.size(); ++i)
283 {
284 table.add_value("pressure", pressure_vals[i]);
285 if constexpr (dim == 1)
286 table.add_value("radial velocity", vel_vals[i]);
287 else
288 table.add_value("radial velocity", vel_vals[i][0]);
289 }
290
291 table.set_scientific("analytical radial velocity", true);
292 table.set_scientific("analytical pressure", true);
293 table.set_scientific("radial velocity", true);
294 table.set_scientific("pressure", true);
295 std::cout << std::endl;
296 table.write_text(std::cout);
297 std::cout << std::endl;
298 }
299
300 generic_data_out.get_vector("velocity").zero_out_ghost_values();
301 generic_data_out.get_vector("pressure").zero_out_ghost_values();
302 }
303 n_time_step += 1;
304 }
305
306 const dealii::Point<dim> center;
307
308 // needed for postprocessing
309 mutable unsigned int n_time_step = 0.0;
310 };
311
312} // namespace MeltPoolDG::Simulation::EvaporatingShell
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_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
RadialBoundaryVelocity(const dealii::Point< dim > &center)
Definition evaporating_shell.hpp:73
const dealii::Point< dim > center
Definition evaporating_shell.hpp:121
double value(const dealii::Point< dim > &p, const unsigned int comp) const override
Definition evaporating_shell.hpp:79
SignedDistanceSphereFlipped(const double radius)
Definition evaporating_shell.hpp:54
double value(const dealii::Point< dim > &p, const unsigned int) const override
Definition evaporating_shell.hpp:60
const dealii::Functions::SignedDistance::Sphere< dim > distance_sphere
Definition evaporating_shell.hpp:66
bool add_case_specific_parameters(dealii::ParameterHandler &prm) override
Add simulation-specific parameters (can be overridden).
Definition evaporating_shell.hpp:133
SimulationEvaporatingShell(std::string parameter_file, const MPI_Comm mpi_communicator)
Definition evaporating_shell.hpp:128
unsigned int n_time_step
Definition evaporating_shell.hpp:309
void set_field_conditions() override
Pure virtual function to set the field conditions.
Definition evaporating_shell.hpp:207
void set_boundary_conditions() override
Pure virtual function to set the boundary conditions.
Definition evaporating_shell.hpp:183
const dealii::Point< dim > center
Definition evaporating_shell.hpp:306
void do_postprocessing(const GenericDataOut< dim, double > &generic_data_out) const final
Definition evaporating_shell.hpp:222
void create_spatial_discretization() override
Pure virtual function to create the spatial discretization.
Definition evaporating_shell.hpp:147
Definition evaporating_shell.cpp:6
static double inner_radius
Definition evaporating_shell.hpp:42
static double outer_radius
Definition evaporating_shell.hpp:44
static double velocity
Definition evaporating_shell.hpp:40
static ShellType shell_type
Definition evaporating_shell.hpp:46
static bool two_phase
Definition evaporating_shell.hpp:48
BETTER_ENUM(MaterialTemplate, char, none, stainless_steel, Ti64, Ti64Benchmark) BETTER_ENUM(SolidLiquidPropertiesTransitionType
Definition dealii_tensor.hpp:10