https://mooseframework.inl.gov
Loading...
Searching...
No Matches
ObtainAvgContactAngle.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://www.mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
11
12#include "libmesh/quadrature.h"
13
14#include <algorithm>
15
17
20{
22 params.addClassDescription("Obtain contact angle");
23 params.addRequiredCoupledVar("pf", "phase field variable");
24 return params;
25}
26
28 : SidePostprocessor(parameters),
29 _pf(coupledValue("pf")),
30 _grad_pf(coupledGradient("pf")),
31 _contact_angle(0.0),
32 _cos_theta_val(0.0),
33 _total_weight(0.0)
34{
35}
36
37void
43
44void
46{
47 // The pointwise angle cos(theta) = grad(pf).n/|grad(pf)| is only defined where the interface
48 // meets the boundary; in the bulk phases grad(pf) vanishes and the interface normal with it.
49 // Weighting by |grad(pf)| removes the pointwise division, and the double well factor (1 - pf^2)
50 // -- the same interface localization the contact angle boundary condition uses -- suppresses the
51 // bulk, whose share of the boundary otherwise biases the average toward 90 degrees. Both factors
52 // are smooth in pf, so the reported angle varies smoothly with the solution.
53 for (const auto qp : make_range(_qrule->n_points()))
54 {
55 // pf can overshoot |pf| = 1 slightly; holding the weight at zero there keeps it non-negative,
56 // which is what bounds the averaged cosine below by -1 and above by 1.
57 const Real localization = std::max(0.0, 1.0 - _pf[qp] * _pf[qp]);
58 const Real w = _JxW[qp] * _coord[qp] * localization;
59 _cos_theta_val += w * (_grad_pf[qp] * _normals[qp]);
60 _total_weight += w * _grad_pf[qp].norm();
61 }
62}
63
64Real
69
70void
72{
73 const ObtainAvgContactAngle & pps = cast_ref<const ObtainAvgContactAngle &>(y);
76}
77
78void
80{
83
84 // With the interface fully detached from the boundary there is no angle to report; error rather
85 // than silently holding the last computed value, which would misrepresent the current state.
86 if (_total_weight == 0.0)
87 mooseError("'",
88 name(),
89 "' found no interface intersecting boundary '",
91 "', so no contact angle can be computed.");
92
93 // |grad(pf).n| <= |grad(pf)| holds pointwise, so the ratio of the integrals lies in [-1, 1] up
94 // to roundoff; clamp it so that a ratio a few epsilon outside the range cannot produce a NaN.
95 const Real cos_theta = std::clamp(_cos_theta_val / _total_weight, -1.0, 1.0);
96 _contact_angle = std::acos(cos_theta) * 180 / libMesh::pi;
97}
const std::vector< double > y
registerMooseObject("PhaseFieldApp", ObtainAvgContactAngle)
const std::vector< BoundaryName > & boundaryNames() const
void addRequiredCoupledVar(const std::string &name, const std::string &doc_string)
void addClassDescription(const std::string &doc_string)
const std::string & name() const
void mooseError(Args &&... args) const
Computes the average contact angle that the phase field interface makes with a boundary.
virtual void execute() override
Real _total_weight
Boundary integral of (1 - pf^2) * |grad(pf)|, the normalization of _cos_theta_val.
virtual void initialize() override
virtual void finalize() override
const VariableValue & _pf
Value of the phase field variable, used to localize the average to the interface.
const VariableGradient & _grad_pf
Gradient of the phase field variable.
Real _contact_angle
Average contact angle, in degrees.
Real _cos_theta_val
Boundary integral of (1 - pf^2) * grad(pf).n, the numerator of the averaged cos(theta)
virtual Real getValue() const override
static InputParameters validParams()
virtual void threadJoin(const UserObject &y) override
ObtainAvgContactAngle(const InputParameters &parameters)
static InputParameters validParams()
const MooseArray< Real > & _coord
const QBase *const & _qrule
const MooseArray< Real > & _JxW
const MooseArray< Point > & _normals
void gatherSum(T &value)
std::string stringify(const T &t)
const Real pi