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

Developer Documentation: applications/mp-melt-pool/cases/thermo_capillary_droplet/thermo_capillary_droplet.hpp Source File
Developer Documentation
thermo_capillary_droplet.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <deal.II/base/conditional_ostream.h>
4#include <deal.II/base/exceptions.h>
5#include <deal.II/base/function.h>
6#include <deal.II/base/function_signed_distance.h>
7#include <deal.II/base/mpi.h>
8#include <deal.II/base/mpi_remote_point_evaluation.h>
9#include <deal.II/base/parameter_handler.h>
10#include <deal.II/base/patterns.h>
11#include <deal.II/base/point.h>
12#include <deal.II/base/quadrature_lib.h>
13#include <deal.II/base/tensor.h>
14#include <deal.II/base/types.h>
15#include <deal.II/base/utilities.h>
16
17#include <deal.II/distributed/shared_tria.h>
18#include <deal.II/distributed/tria.h>
19
20#include <deal.II/dofs/dof_handler.h>
21
22#include <deal.II/fe/fe_update_flags.h>
23#include <deal.II/fe/fe_values.h>
24#include <deal.II/fe/fe_values_extractors.h>
25
26#include <deal.II/grid/grid_generator.h>
27#include <deal.II/grid/grid_tools_geometry.h>
28#include <deal.II/grid/tria.h>
29
30#include <deal.II/numerics/vector_tools_evaluate.h>
31
37
38#include <cmath>
39#include <fstream>
40#include <iostream>
41#include <memory>
42#include <vector>
43
44#include "../../melt_pool_case.hpp"
45
94{
95 using namespace MeltPoolDG::Simulation;
96
97
98 static constexpr double a = 1.44e-3;
99 static constexpr double grad_T = 200;
100
101 template <int dim>
102 class InitialValuesLS : public dealii::Function<dim>
103 {
104 public:
105 InitialValuesLS(const double eps, const bool liquid_phase_outside)
106 : dealii::Function<dim>()
107 , distance_sphere(dim == 2 ? dealii::Point<dim>(0, 0) : dealii::Point<dim>(0, 0, 0), a)
108 , eps(eps)
109 , factor(liquid_phase_outside ? 1.0 : -1.0)
110 {}
111
112 double
113 value(const dealii::Point<dim> &p, const unsigned int /*component*/) const override
114 {
116 distance_sphere.value(p),
117 eps);
118 }
119
120 private:
121 const dealii::Functions::SignedDistance::Sphere<dim> distance_sphere;
122 const double eps;
123 const double factor;
124 };
125
126
127 template <int dim>
128 class InitialValuesTemperature : public dealii::Function<dim>
129 {
130 public:
132 : dealii::Function<dim>()
133 {}
134
135 double
136 value(const dealii::Point<dim> &p, const unsigned int /*component*/) const override
137 {
138 return 290 + grad_T * (p[dim - 1] + 2 * a);
139 }
140 };
141 /*
142 * This class collects all relevant input data for the level set simulation
143 */
144
145 template <int dim, typename number>
147 {
148 public:
151 {
152 if (this->parameters.output.do_user_defined_postprocessing and
153 dealii::Utilities::MPI::this_mpi_process(mpi_communicator) == 0)
154 file.open(this->parameters.output.directory + "/" +
155 this->parameters.output.paraview.filename +
156 "_droplet_velocity_over_time_normalized.csv");
158 this->parameters.flow.surface_tension.temperature_dependent_surface_tension_coefficient *
159 grad_T * a / this->parameters.material.gas.dynamic_viscosity;
161
162 const auto characteristic_numbers =
164 reynolds_number = characteristic_numbers.Reynolds(velocity_reference, a);
165 mach_number = characteristic_numbers.Mach(velocity_reference, a);
166 capillary_number = characteristic_numbers.capillary(
167 velocity_reference, this->parameters.flow.surface_tension.surface_tension_coefficient);
168 }
169
170 bool
171 add_case_specific_parameters(dealii::ParameterHandler &prm) override
172 {
173 prm.add_parameter(
174 "liquid phase outside",
176 "set this parameter to true to flip the level set and have the \"liquid\" phase outside the droplet.",
177 dealii::Patterns::Bool());
178
179 return this->parameters.base.do_print_parameters;
180 }
181
182 void
184 {
185 if (this->parameters.base.fe.type == FiniteElementType::FE_SimplexP)
186 {
187#ifdef DEAL_II_WITH_METIS
188 this->triangulation = std::make_shared<dealii::parallel::shared::Triangulation<dim>>(
189 this->mpi_communicator,
190 dealii::Triangulation<dim>::none,
191 false,
192 dealii::parallel::shared::Triangulation<dim>::Settings::partition_metis);
193#else
194 AssertThrow(
195 false,
196 dealii::ExcMessage(
197 "Missing Metis support of the deal.II installation. "
198 "Configure deal.II with -D DEAL_II_WITH_METIS='ON' to execute this example."));
199#endif
200 }
201 else
202 {
203 this->triangulation = std::make_shared<dealii::parallel::distributed::Triangulation<dim>>(
204 this->mpi_communicator);
205 }
206
207 if constexpr (dim == 2 or dim == 3)
208 {
209 // create mesh
210 const dealii::Point<dim> bottom_left =
211 dim == 2 ? dealii::Point<dim>(x_min, x_min) : dealii::Point<dim>(x_min, x_min, x_min);
212 const dealii::Point<dim> top_right =
213 dim == 2 ? dealii::Point<dim>(x_max, x_max) : dealii::Point<dim>(x_max, x_max, x_max);
214
215 if (this->parameters.base.fe.type == FiniteElementType::FE_SimplexP)
216 {
217 // create mesh
218 std::vector<unsigned int> subdivisions(
219 dim, 5 * dealii::Utilities::pow(2, this->parameters.base.global_refinements));
220 subdivisions[dim - 1] *= 2;
221
222 dealii::GridGenerator::subdivided_hyper_rectangle_with_simplices(*this->triangulation,
223 subdivisions,
224 bottom_left,
225 top_right);
226 }
227 else
228 {
229 dealii::GridGenerator::hyper_rectangle(*this->triangulation, bottom_left, top_right);
230 this->triangulation->refine_global(this->parameters.base.global_refinements);
231 }
232 }
233 else
234 {
235 AssertThrow(false, dealii::ExcNotImplemented());
236 }
237 }
238
239 void
241 {
242 /*
243 * create a pair of (boundary_id, dirichlet_function)
244 */
245
246 const dealii::types::boundary_id lower_bc = 1;
247 const dealii::types::boundary_id upper_bc = 2;
248 const dealii::types::boundary_id left_bc = 3;
249 const dealii::types::boundary_id right_bc = 4;
250
251 this->attach_boundary_condition(lower_bc, "no_slip", "navier_stokes_u");
252 this->attach_boundary_condition(upper_bc, "no_slip", "navier_stokes_u");
253
254 this->attach_boundary_condition(left_bc, "symmetry", "navier_stokes_u");
255 this->attach_boundary_condition(right_bc, "symmetry", "navier_stokes_u");
256
257 this->attach_boundary_condition({lower_bc, std::make_shared<InitialValuesTemperature<dim>>()},
258 "dirichlet",
259 "heat_transfer");
260 this->attach_boundary_condition({upper_bc, std::make_shared<InitialValuesTemperature<dim>>()},
261 "dirichlet",
262 "heat_transfer");
263
264 if constexpr (dim == 2)
265 {
266 for (const auto &cell : this->triangulation->cell_iterators())
267 for (const auto &face : cell->face_iterators())
268 {
269 if (not face->at_boundary())
270 continue;
271 if (face->center()[1] == x_min)
272 face->set_boundary_id(lower_bc);
273 else if (face->center()[1] == x_max)
274 face->set_boundary_id(upper_bc);
275 else if (face->center()[0] == x_min)
276 face->set_boundary_id(left_bc);
277 else if (face->center()[0] == x_max)
278 face->set_boundary_id(right_bc);
279 }
280 }
281 else if constexpr (dim == 3)
282 {
283 const dealii::types::boundary_id front_bc = 5;
284 const dealii::types::boundary_id back_bc = 6;
285 this->attach_boundary_condition(front_bc, "symmetry", "navier_stokes_u");
286 this->attach_boundary_condition(back_bc, "symmetry", "navier_stokes_u");
287 for (const auto &cell : this->triangulation->cell_iterators())
288 for (const auto &face : cell->face_iterators())
289 {
290 if (not face->at_boundary())
291 continue;
292 if (face->center()[1] == x_min)
293 face->set_boundary_id(lower_bc);
294 else if (face->center()[1] == x_max)
295 face->set_boundary_id(upper_bc);
296 else if (face->center()[0] == x_min)
297 face->set_boundary_id(left_bc);
298 else if (face->center()[0] == x_max)
299 face->set_boundary_id(right_bc);
300 else if (face->center()[2] == x_min)
301 face->set_boundary_id(back_bc);
302 else if (face->center()[2] == x_max)
303 face->set_boundary_id(front_bc);
304 }
305 }
306 else
307 {
308 AssertThrow(false, dealii::ExcNotImplemented());
309 }
310 }
311
312 void
314 {
315 const double eps = this->parameters.ls.reinit.compute_interface_thickness_parameter_epsilon(
316 dealii::GridTools::minimal_cell_diameter(*this->triangulation) /
317 this->parameters.ls.get_n_subdivisions() / std::sqrt(dim));
318
319 this->attach_initial_condition(std::make_shared<InitialValuesLS<dim>>(eps,
321 "level_set");
322 this->attach_initial_condition(std::make_shared<dealii::Functions::ZeroFunction<dim>>(dim),
323 "navier_stokes_u");
325 "heat_transfer");
326 }
327
328 void
329 do_postprocessing(const GenericDataOut<dim, double> &generic_data_out) const final
330 {
331 if (not this->parameters.output.do_user_defined_postprocessing)
332 return;
333
334 if constexpr (dim > 1)
335 {
336 dealii::ConditionalOStream pcout(std::cout,
337 dealii::Utilities::MPI::this_mpi_process(
338 this->mpi_communicator) == 0 and
339 this->parameters.base.verbosity_level > 0);
340
341 const auto &level_set = generic_data_out.get_vector("level_set");
342 const auto &velocity = generic_data_out.get_vector("velocity");
343 if (not level_set.has_ghost_elements())
344 level_set.update_ghost_values();
345 if (not velocity.has_ghost_elements())
346 velocity.update_ghost_values();
347
348 const auto &level_set_dof_handler = generic_data_out.get_dof_handler("level_set");
349 const auto &velocity_dof_handler = generic_data_out.get_dof_handler("velocity");
350
351 dealii::Point<dim> center_of_mass;
352
353 double average_velocity = 0.0;
354 double area_of_phase = 0.0;
355
356 dealii::FEValues<dim> level_set_eval(
357 generic_data_out.get_mapping(),
358 level_set_dof_handler.get_fe(),
359 dealii::QGauss<dim>(level_set_dof_handler.get_fe().tensor_degree() + 1),
360 dealii::update_quadrature_points | dealii::update_JxW_values | dealii::update_values);
361
362 const dealii::FEValuesExtractors::Vector velocities(0);
363 dealii::FEValues<dim> vel_eval(generic_data_out.get_mapping(),
364 velocity_dof_handler.get_fe(),
365 dealii::QGauss<dim>(
366 level_set_dof_handler.get_fe().tensor_degree() + 1),
367 dealii::update_values);
368
369 std::vector<double> ls_at_q(level_set_eval.n_quadrature_points);
370 std::vector<dealii::Tensor<1, dim>> vel_at_q(level_set_eval.n_quadrature_points,
371 dealii::Tensor<1, dim>());
372
373 typename dealii::DoFHandler<dim>::active_cell_iterator vel_cell =
374 velocity_dof_handler.begin_active();
375
376 for (const auto &cell : level_set_dof_handler.active_cell_iterators())
377 {
378 if (cell->is_locally_owned())
379 {
380 level_set_eval.reinit(cell);
381 level_set_eval.get_function_values(level_set, ls_at_q);
382
383 vel_eval.reinit(vel_cell);
384 vel_eval[velocities].get_function_values(velocity, vel_at_q);
385
386 for (const auto q : level_set_eval.quadrature_point_indices())
387 {
388 if (ls_at_q[q] <= 0.0)
389 continue;
390 area_of_phase += level_set_eval.JxW(q);
391 average_velocity += vel_at_q[q][dim - 1] * level_set_eval.JxW(q);
392 for (unsigned int d = 0; d < dim; ++d)
393 center_of_mass[d] +=
394 level_set_eval.quadrature_point(q)[d] * level_set_eval.JxW(q);
395 }
396 }
397 ++vel_cell;
398 }
399
400 /*
401 * area of the phase
402 */
403 double global_area = dealii::Utilities::MPI::sum(area_of_phase, this->mpi_communicator);
404
405 /*
406 * centroid position
407 */
408 dealii::Point<dim> global_center_of_mass;
409 for (unsigned int d = 0; d < dim; ++d)
410 global_center_of_mass[d] =
411 dealii::Utilities::MPI::sum(center_of_mass[d], this->mpi_communicator);
412
413 global_center_of_mass /= global_area;
414
415 /*
416 * average velocity
417 */
418 double global_average_velocity =
419 dealii::Utilities::MPI::sum(average_velocity, this->mpi_communicator);
420 global_average_velocity /= global_area;
421
422 /*
423 * velocity measured at centroid
424 */
425 dealii::Utilities::MPI::RemotePointEvaluation<dim, dim> cache;
426 std::vector<dealii::Tensor<1, dim>> velocity_of_center =
427 dealii::VectorTools::point_values<dim>(generic_data_out.get_mapping(),
428 velocity_dof_handler,
429 velocity,
430 {global_center_of_mass},
431 cache);
432
433 pcout << "---------------------------------------------" << std::endl;
434 pcout << " user defined postprocessing" << std::endl;
435 pcout << "---------------------------------------------" << std::endl;
436 if (print_once)
437 {
438 pcout << "reference velocity: " << velocity_reference << std::endl;
439 pcout << "reference time: " << time_reference << std::endl;
440 pcout << "Reynolds number: " << reynolds_number << std::endl;
441 pcout << "Mach number: " << mach_number << std::endl;
442 pcout << "Capillary number: " << capillary_number << std::endl;
443 }
444
445 const auto max_vel = velocity.linfty_norm();
446 if (file.is_open())
447 {
448 pcout << "centroid: " << global_center_of_mass << std::endl;
449 pcout << "vel: " << velocity_of_center[0][dim - 1] << std::endl;
450 if (print_once)
451 file << "time,y_center,t/tr,u/ur,u_max/ur,u_avg/ur" << std::endl;
452
453 file << generic_data_out.get_time() << ", " << global_center_of_mass[dim - 1] << ", "
454 << generic_data_out.get_time() / time_reference << ", "
455 << velocity_of_center[0][dim - 1] / velocity_reference << ", "
456 << max_vel / velocity_reference << ", "
457 << global_average_velocity / velocity_reference << std::endl;
458 }
459 pcout << "---------------------------------------------" << std::endl;
460 pcout << "---------------------------------------------" << std::endl;
461 }
462 print_once = false;
463 }
464
465 private:
466 const double x_min = -2 * a;
467 const double x_max = 2 * a;
474 // postprocessing
475 mutable std::ofstream file;
476 mutable bool print_once = true;
477 };
478} // namespace MeltPoolDG::Simulation::ThermoCapillaryDroplet
Computes dimensionless characteristic numbers for fluid flow.
Definition characteristic_numbers.hpp:15
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
Definition thermo_capillary_droplet.hpp:103
InitialValuesLS(const double eps, const bool liquid_phase_outside)
Definition thermo_capillary_droplet.hpp:105
const double eps
Definition thermo_capillary_droplet.hpp:122
const double factor
Definition thermo_capillary_droplet.hpp:123
const dealii::Functions::SignedDistance::Sphere< dim > distance_sphere
Definition thermo_capillary_droplet.hpp:121
double value(const dealii::Point< dim > &p, const unsigned int) const override
Definition thermo_capillary_droplet.hpp:113
InitialValuesTemperature()
Definition thermo_capillary_droplet.hpp:131
double value(const dealii::Point< dim > &p, const unsigned int) const override
Definition thermo_capillary_droplet.hpp:136
const double x_min
Definition thermo_capillary_droplet.hpp:466
const double x_max
Definition thermo_capillary_droplet.hpp:467
double reynolds_number
Definition thermo_capillary_droplet.hpp:470
double velocity_reference
Definition thermo_capillary_droplet.hpp:468
void create_spatial_discretization() override
Pure virtual function to create the spatial discretization.
Definition thermo_capillary_droplet.hpp:183
bool add_case_specific_parameters(dealii::ParameterHandler &prm) override
Add simulation-specific parameters (can be overridden).
Definition thermo_capillary_droplet.hpp:171
double time_reference
Definition thermo_capillary_droplet.hpp:469
double capillary_number
Definition thermo_capillary_droplet.hpp:472
std::ofstream file
Definition thermo_capillary_droplet.hpp:475
void set_field_conditions() final
Pure virtual function to set the field conditions.
Definition thermo_capillary_droplet.hpp:313
void do_postprocessing(const GenericDataOut< dim, double > &generic_data_out) const final
Definition thermo_capillary_droplet.hpp:329
bool liquid_phase_outside
Definition thermo_capillary_droplet.hpp:473
SimulationThermoCapillaryDroplet(std::string parameter_file, const MPI_Comm mpi_communicator)
Definition thermo_capillary_droplet.hpp:149
void set_boundary_conditions() final
Pure virtual function to set the boundary conditions.
Definition thermo_capillary_droplet.hpp:240
number tanh_characteristic_function(const number &distance, const number &eps)
Definition characteristic_functions.hpp:12
Definition thermo_capillary_droplet.cpp:6
static constexpr double grad_T
Definition thermo_capillary_droplet.hpp:99
static constexpr double a
Definition thermo_capillary_droplet.hpp:98
Definition advection_diffusion.cpp:6
Definition dealii_tensor.hpp:10