applications/mp-reinit/cases/wall_wetting_zahedi_2009_comparison/wall_wetting.hpp Source File

Developer Documentation: applications/mp-reinit/cases/wall_wetting_zahedi_2009_comparison/wall_wetting.hpp Source File
Developer Documentation
wall_wetting.hpp
Go to the documentation of this file.
1#pragma once
2#include <deal.II/base/function.h>
3#include <deal.II/base/function_signed_distance.h>
4#include <deal.II/base/point.h>
5#include <deal.II/base/table_handler.h>
6
7#include <deal.II/distributed/tria.h>
8
9#include <deal.II/dofs/dof_handler.h>
10
11#include <deal.II/fe/fe_q.h>
12
13#include <deal.II/grid/grid_generator.h>
14
15#include <deal.II/numerics/vector_tools.h>
16
22
23#include <cmath>
24#include <filesystem>
25#include <fstream>
26#include <iostream>
27
28#include "../../reinitialization_case.hpp"
29
31{
38 template <int dim, typename number>
39 class InitialLevelSet : public dealii::Function<dim>
40 {
41 public:
49 InitialLevelSet(const number p_x_interface, const number p_epsilon)
50 : dealii::Function<dim>()
51 , x_interface(p_x_interface)
52 , epsilon(p_epsilon)
53 {}
54
62 double
63 value(const dealii::Point<dim> &p, const unsigned int /*component*/) const final
64 {
66 }
67
68 private:
72 number epsilon;
73 };
74
82 template <int dim, typename number>
83 class BottomBoundaryNormalPerComponent : public dealii::Function<dim>
84 {
85 public:
93 BottomBoundaryNormalPerComponent(const number p_vector_component, const number p_contact_angle)
94 : dealii::Function<dim>()
95 , vector_component(p_vector_component)
96 , contact_angle(p_contact_angle)
97 {}
98
104 double
105 value(const dealii::Point<dim> & /*p*/, const unsigned int /*component*/) const final
106 {
107 if (vector_component == 0)
108 return std::sin(contact_angle);
109 else /*component == 1*/
110 return std::cos(contact_angle);
111 }
112
113 private:
115 const number vector_component;
117 const number contact_angle;
118 };
119
128 template <int dim, typename number>
130 {
131 public:
140 : LevelSet::ReinitializationCase<dim, number>(parameter_file, mpi_communicator)
141 {}
142
150 bool
151 add_case_specific_parameters(dealii::ParameterHandler &prm) final
152 {
153 prm.add_parameter("contact angle",
155 "contact angle at the bottom wall",
156 dealii::Patterns::Double(0, 180));
157 prm.add_parameter(
158 "gamma factor",
160 "factor multiplying epsilon_n in the computation of the normal vector filter parameter as defined by Zahedi et al. (2009)",
161 dealii::Patterns::Double());
162 prm.add_parameter(
163 "time-step factor",
165 "time-step scaling factor; it is used to conduct a time-step sensitivity analysis",
166 dealii::Patterns::Double());
167 prm.add_parameter(
168 "output contact angle evolution",
170 "if set to 'true', it outputs the contact angle evolution in a .txt file in the output directory",
171 dealii::Patterns::Bool());
172 return this->parameters.base.do_print_parameters;
173 }
174
178 void
180 {
181 // Check that the simulation is run in 2D
182 AssertDimension(dim, 2);
183
184 // Generate triangulation
185 this->triangulation =
186 std::make_shared<dealii::parallel::distributed::Triangulation<dim>>(this->mpi_communicator);
187
188 // Create mesh
189 std::vector<unsigned> refinements(2, 25);
190 const dealii::Point<2> bottom_left(x_min, y_min);
191 const dealii::Point<2> top_right(x_max, y_max);
192 dealii::GridGenerator::subdivided_hyper_rectangle(
193 *this->triangulation, refinements, bottom_left, top_right, true);
194 this->triangulation->refine_global(this->parameters.base.global_refinements);
195 }
196
200 void
202 {
203 // Face numbering according to the deal.II colorize flag
204 const auto [bottom_bc, upper_bc, left_bc, right_bc, front_bc, back_bc] =
205 get_colorized_rectangle_boundary_ids<dim>();
206
207 // Wetting boundary condition
208 const number contact_angle_rad =
210
211
212 // Component-wise definition of AffineConstraints objects is required. Therefore, one
213 // function per component has to be instantiated.
215 {bottom_bc,
216 std::make_shared<BottomBoundaryNormalPerComponent<dim, number>>(0, contact_angle_rad)},
217 "nx",
218 "normal_vector");
220 {bottom_bc,
221 std::make_shared<BottomBoundaryNormalPerComponent<dim, number>>(1, contact_angle_rad)},
222 "ny",
223 "normal_vector");
224 }
225
229 void
231 {
232 // Compute normal diffusion factor (we consider a static mesh)
234 dealii::GridTools::minimal_cell_diameter(*this->triangulation) / std::sqrt(dim);
235 epsilon = this->parameters.reinit.compute_interface_thickness_parameter_epsilon(
236 cell_size_min / this->parameters.reinit.fe.get_n_subdivisions());
237
238 // Compute time-step and change data value
239 /* dt = h^2 / [2 * (epsilon_n + epsilon_t)] * time_step_factor */
240 number time_step =
241 time_step_factor * 0.5 * dealii::Utilities::fixed_power<2>(cell_size_min) /
242 (epsilon * (1 + this->parameters.reinit.hyperbolic.cg.tangential_diffusion_factor));
243 this->parameters.time_stepping.time_step_size = time_step;
244
245 // Compute normal vector filtering factor and change data value
246 gamma = dealii::Utilities::fixed_power<2>(
247 gamma_factor * this->parameters.reinit.interface_thickness_parameter.value);
248 this->parameters.normal_vec.filter_parameter = gamma;
249
250 // Initial level-set condition
252 epsilon),
253 "level_set");
254 }
255
262 void
264 [[maybe_unused]] const GenericDataOut<dim, double> &generic_data_out) const final
265 {
266 // Do nothing if output is not requested
267 if (not this->parameters.output.do_user_defined_postprocessing)
268 return;
269
270 // Compute contact angle
271 number contact_angle;
272 compute_contact_angle_at_boundary(contact_angle, generic_data_out);
273
274 if (dealii::Utilities::MPI::this_mpi_process(this->mpi_communicator) == 0)
275 {
276 std::cout << "| Static contact angle: " << this->contact_angle_deg << std::endl;
277 std::cout << "| Computed contact angle: " << contact_angle << std::endl;
278
280 {
281 // Add values to table
282 postprocess_table.add_value("time", generic_data_out.get_time());
283 postprocess_table.set_scientific("time", true);
284 postprocess_table.set_scientific("time", 5);
285 postprocess_table.add_value("contact_angle", contact_angle);
286
287 // Write in output file
288 namespace fs = std::filesystem;
289 std::ofstream output(fs::path(this->parameters.output.directory) /
290 fs::path(this->parameters.output.paraview.filename + ".txt"));
291 postprocess_table.write_text(output);
292 }
293 } // End rank 0 scope
294 }
295
312 void
314 const GenericDataOut<dim, double> &generic_data_out) const
315 {
316 const auto &dof_handler = generic_data_out.get_dof_handler("psi");
317 const auto &mapping = generic_data_out.get_mapping();
318 const auto &level_set_vector = generic_data_out.get_vector("psi");
319
320 number contact_angle_sum = 0.0;
321 number total_weight = 0.0;
322
323 const unsigned int n_subdivisions = 2;
324 const number tolerance = 3 * epsilon;
325 const number contour_value = 0.0;
326
327 // Bottom wall normal
328 dealii::Tensor<1, dim> wall_normal;
329 wall_normal[1] = 1.0; // unit normal in +y direction
330
331 // Tolerance identifying value at the bottom wall
332 const number tolerance_bottom_wall = 0.25 * cell_size_min;
333
334 // Evaluate the contact angle
335 LevelSet::Tools::evaluate_at_interface<dim, number>(
336 dof_handler,
337 mapping,
338 level_set_vector,
339 [&](const auto &cell,
340 const auto &interface_points,
341 const auto &reference_points,
342 const auto & /*JxW*/) {
343 const auto &fe = dof_handler.get_fe();
344 dealii::FEValues<dim> fe_values(mapping,
345 fe,
346 dealii::Quadrature<dim>(reference_points),
347 dealii::update_gradients);
348 fe_values.reinit(cell);
349 std::vector<dealii::Tensor<1, dim>> grad_phi(reference_points.size());
350 fe_values.get_function_gradients(level_set_vector, grad_phi);
351
352 for (unsigned int i = 0; i < reference_points.size(); ++i)
353 {
354 // Extract real points and level-set indicator gradient values
355 const auto &point_i = interface_points[i];
356 const auto &grad_phi_i = grad_phi[i];
357
358 // Check if point is at the bottom wall
359 const number distance_to_wall = std::abs(point_i[dim - 1] - y_min);
360 if (distance_to_wall < tolerance_bottom_wall)
361 {
362 // Compute contact angle with normal vector and grad_phi scalar product
363 const number cos_alpha = grad_phi_i * wall_normal / (grad_phi_i.norm() + 1e-16);
364 const number alpha_rad = std::acos(cos_alpha);
365
366 // Sum weighted contributions, so that if multiple points are considered, the
367 // closest to the bottom wall have more weight
368 const number weight = (tolerance - distance_to_wall) / tolerance;
369 contact_angle_sum += weight * alpha_rad * 180.0 / dealii::numbers::PI;
370 total_weight += weight;
371 }
372 }
373 },
374 contour_value,
375 n_subdivisions,
376 tolerance,
377 true /*use_mca=*/);
378
379 // Sum results from all processes
380 const number global_contact_angle_sum =
381 dealii::Utilities::MPI::sum(contact_angle_sum, MPI_COMM_WORLD);
382 const number global_total_weight = dealii::Utilities::MPI::sum(total_weight, MPI_COMM_WORLD);
383 contact_angle = (global_total_weight > 0) ? global_contact_angle_sum / global_total_weight :
384 std::numeric_limits<number>::quiet_NaN();
385 }
386
387 private:
388 /* Domain dimensions */
390 number x_min = 0.0;
392 number x_max = 2.0;
394 number y_min = x_min;
396 number y_max = x_max;
397
399 number x_interface = 1.0;
400
402 number contact_angle_deg = 45.0;
403
406 number gamma_factor = 1.0;
407
409 number gamma;
410
412 number epsilon;
413
416
418 number time_step_factor = 1.0;
419
421 mutable dealii::TableHandler postprocess_table;
422
425 };
426
427} // namespace MeltPoolDG::Simulation::WallWetting
A generic utility for managing simulation output data in the MeltPoolDG context.
Definition generic_data_out.hpp:32
const VectorType & get_vector(const std::string &name) const
Definition generic_data_out.cpp:105
const dealii::DoFHandler< dim > & get_dof_handler(const std::string &name) const
Retrieve the DoFHandler associated with a named distributed vector.
Definition generic_data_out.cpp:158
const dealii::Mapping< dim > & get_mapping() const
Access the stored Mapping used in the constructor.
Definition generic_data_out.cpp:195
Definition reinitialization_case.hpp:79
ReinitializationCase(const std::string &parameter_file_in, MPI_Comm mpi_communicator_in)
Definition reinitialization_case.hpp:83
ReinitializationCaseParameters< number > parameters
Definition reinitialization_case.hpp:81
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
Function that imposes the bottom wall wetting boundary condition component-wise for component-wise Af...
Definition wall_wetting.hpp:84
double value(const dealii::Point< dim > &, const unsigned int) const final
Evaluate the value of the normal vector component at a given point of the boundary.
Definition wall_wetting.hpp:105
const number contact_angle
Imposed static contact angle in radians.
Definition wall_wetting.hpp:117
const number vector_component
Component of the normal vector currently evaluated.
Definition wall_wetting.hpp:115
BottomBoundaryNormalPerComponent(const number p_vector_component, const number p_contact_angle)
Function used to compute the normal vector at the bottom boundary considering wetting.
Definition wall_wetting.hpp:93
Initial condition of the level-set field.
Definition wall_wetting.hpp:40
number epsilon
Interface thickness parameter.
Definition wall_wetting.hpp:72
number x_interface
Position of the vertical interface.
Definition wall_wetting.hpp:70
double value(const dealii::Point< dim > &p, const unsigned int) const final
Evaluate the value of the level-set indicator ( ) at a given point p.
Definition wall_wetting.hpp:63
InitialLevelSet(const number p_x_interface, const number p_epsilon)
Function describing the initial state of the level-set field. The function computes a field with the ...
Definition wall_wetting.hpp:49
Simulation of wetting at the bottom wall. This simulates the modelling problem described in "A conser...
Definition wall_wetting.hpp:130
void set_field_conditions() final
Set initial level-set field condition.
Definition wall_wetting.hpp:230
number gamma_factor
Definition wall_wetting.hpp:406
dealii::TableHandler postprocess_table
Contact angle post-processing table.
Definition wall_wetting.hpp:421
number epsilon
Interface thickness parameter.
Definition wall_wetting.hpp:412
void do_postprocessing(const GenericDataOut< dim, double > &generic_data_out) const final
Post-process the solution to extract the contact angle at the boundary for the current time-step and ...
Definition wall_wetting.hpp:263
number gamma
Normal vector filter parameter.
Definition wall_wetting.hpp:409
void compute_contact_angle_at_boundary(number &contact_angle, const GenericDataOut< dim, double > &generic_data_out) const
Computes the position-weighted contact angle at the bottom boundary.
Definition wall_wetting.hpp:313
number y_max
Maximal y value of the domain.
Definition wall_wetting.hpp:396
number contact_angle_deg
Contact angle on bottom wall.
Definition wall_wetting.hpp:402
number time_step_factor
Time-step scaling factor (for sensitivity analysis on the time-step)
Definition wall_wetting.hpp:418
number cell_size_min
Minimum cell size.
Definition wall_wetting.hpp:415
SimulationWallWetting(std::string parameter_file, const MPI_Comm mpi_communicator)
Constructor of the wall wetting simulation using wetting boundary condition.
Definition wall_wetting.hpp:139
number x_min
Minimal x value of the domain.
Definition wall_wetting.hpp:390
number y_min
Minimal y value of the domain.
Definition wall_wetting.hpp:394
void create_spatial_discretization() final
Create the spatial discretization of the problem.
Definition wall_wetting.hpp:179
void set_boundary_conditions() final
Set boundary conditions.
Definition wall_wetting.hpp:201
bool output_contact_angle_evolution
Bool output contact-angle evolution in a .txt file.
Definition wall_wetting.hpp:424
bool add_case_specific_parameters(dealii::ParameterHandler &prm) final
Add parameters that are specific to the simulation.
Definition wall_wetting.hpp:151
number x_max
Maximal x value of the domain.
Definition wall_wetting.hpp:392
number x_interface
Interface location.
Definition wall_wetting.hpp:399
number tanh_characteristic_function(const number &distance, const number &eps)
Definition characteristic_functions.hpp:12
Definition wall_wetting.cpp:6
number compute_angle_in_radians(const number angle_deg)
Convert an angle from degrees to radians.
Definition numbers.hpp:34
Definition dealii_tensor.hpp:10