Skip to content

Commit e9f3e77

Browse files
Larry AagesenLarry Aagesen
authored andcommitted
Clean up code and comments, add test for InterfaceNormalCurvatures. Closes #32436
1 parent e752ec0 commit e9f3e77

6 files changed

Lines changed: 133 additions & 80 deletions

File tree

modules/phase_field/doc/content/source/materials/InterfaceNormalCurvatures.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
`InterfaceNormalCurvatures` is a `Material` object that computes the two **normal curvatures** of a diffuse interface defined by an order parameter $\eta$. The interface geometry is encoded entirely in the gradient and Hessian of $\eta$; no explicit surface mesh is required.
88

9-
The two normal curvatures characterise how the interface bends in two orthogonal tangent directions:
9+
The two normal curvatures characterize how the interface bends in two orthogonal tangent directions:
1010

1111
| Property | Symbol | Direction |
1212
|---|---|---|
@@ -121,9 +121,6 @@ The mean curvature $\kappa = \nabla \cdot \hat{n}$ is also declared as a materia
121121
| `kappa1` | `Real` | Normal curvature $\kappa_1$ along the in-plane tangent $\hat{t}_1$ |
122122
| `kappa2` | `Real` | Normal curvature $\kappa_2$ along the out-of-plane tangent $\hat{t}_2$ |
123123
| `kappa_mean` | `Real` | Mean curvature $\kappa = \kappa_1 + \kappa_2 = \nabla\cdot\hat{n}$ |
124-
| `interface_normal` | `RealVectorValue` | Unit interface normal $\hat{n}$ |
125-
| `tangent1` | `RealVectorValue` | First tangent vector $\hat{t}_1$ (in-plane) |
126-
| `tangent2` | `RealVectorValue` | Second tangent vector $\hat{t}_2$ (binormal) |
127124

128125
All property names can be prefixed by setting `base_name`.
129126

modules/phase_field/include/materials/InterfaceNormalCurvatures.h

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,25 @@
1313

1414
/**
1515
* Computes the two normal curvatures of a diffuse interface defined
16-
* by an order parameter η using = ∇η / |∇η|.
16+
* by an order parameter eta using n = grad(eta) / | grad(eta) |.
1717
*
1818
* At every quadrature point the local frame is:
1919
*
20-
* — unit interface normal (= ∇η / |∇η|)
21-
* t̂₁ — tangent in the xy-plane (= ẑ × n̂, normalised)
22-
* t̂₂ — binormal (= n̂ × t̂₁)
20+
* n — unit interface normal (grad(eta) / | grad(eta) |)
21+
* t_1 — tangent in the xy-plane (= z x n, normalized)
22+
* t_2 — binormal (= n x t_1)
2323
*
2424
* The normal curvatures are then:
2525
*
26-
* κ₁ = t̂₁ · S · t̂₁ (curvature along t̂₁, the in-plane tangent)
27-
* κ₂ = t̂₂ · S · t̂₂ (curvature along t̂₂, the out-of-plane tangent)
26+
* kappa_1 = t_1 · S · t_1 (curvature along t_1, the in-plane tangent)
27+
* kappa_2 = t_2 · S · t_2 (curvature along t_2, the out-of-plane tangent)
2828
*
29-
* where S = −∇n̂ is the shape operator (Weingarten map).
29+
* where S is the shape operator (Weingarten map).
3030
*
31-
* Note: κ₁ + κ₂ = mean curvature κ = ∇·n̂ (as a consistency check).
31+
* Note: kappa_1 + kappa_2 = mean curvature kappa = div(n) (as a consistency check).
3232
*
3333
* Requires second-order Lagrange (or higher) elements so that the
34-
* second derivatives of η are available.
34+
* second derivatives of eta are available.
3535
*/
3636
class InterfaceNormalCurvatures : public Material
3737
{
@@ -44,20 +44,17 @@ class InterfaceNormalCurvatures : public Material
4444

4545
private:
4646
// ── order parameter ────────────────────────────────────────
47-
const VariableValue & _eta; ///< η
48-
const VariableGradient & _grad_eta; ///< ∇η
49-
const VariableSecond & _second_eta; ///< ∇∇η (Hessian)
47+
const VariableValue & _eta;
48+
const VariableGradient & _grad_eta;
49+
const VariableSecond & _second_eta;
5050

5151
// ── user parameters ────────────────────────────────────────
52-
const Real _eps; ///< regularisation floor for |∇η| (avoids /0)
52+
const Real _eps; /// regularization floor for grad(eta) (avoids /0)
5353

5454
// ── material properties produced ───────────────────────────
55-
MaterialProperty<Real> & _kappa1; ///< normal curvature along t̂₁
56-
MaterialProperty<Real> & _kappa2; ///< normal curvature along t̂₂
55+
MaterialProperty<Real> & _kappa1; /// normal curvature along t_1
56+
MaterialProperty<Real> & _kappa2; /// normal curvature along t_2
5757

5858
// ── optional diagnostics ───────────────────────────────────
59-
MaterialProperty<Real> & _kappa_mean; ///< κ₁+κ₂ (= ∇·n̂)
60-
MaterialProperty<RealVectorValue> & _normal; ///< n̂
61-
MaterialProperty<RealVectorValue> & _tangent1; ///< t̂₁
62-
MaterialProperty<RealVectorValue> & _tangent2; ///< t̂₂
59+
MaterialProperty<Real> & _kappa_mean;
6360
};

modules/phase_field/src/materials/InterfaceNormalCurvatures.C

Lines changed: 24 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,14 @@ InterfaceNormalCurvatures::validParams()
1717
{
1818
InputParameters params = Material::validParams();
1919
params.addClassDescription(
20-
"Computes the two normal curvatures κ₁ and κ₂ of a diffuse interface "
21-
"from an order parameter η via n̂ = ∇η/|∇η| and the shape operator "
22-
"S = −∇n̂. t̂₁ lies in the xy-plane (ẑ×n̂); t̂₂ = n̂×t̂₁.");
23-
24-
params.addRequiredCoupledVar("eta", "Order parameter η that defines the interface");
25-
26-
params.addParam<Real>("regularization", 1e-8,
27-
"Floor added to |∇η| before division to prevent singularities in "
28-
"bulk regions where ∇η ≈ 0");
29-
30-
params.addParam<std::string>("base_name", "",
31-
"Optional prefix for all material property names");
32-
20+
"Computes the two normal curvatures kappa_1 and kappa_2 of a diffuse interface "
21+
"from an order parameter eta.");
22+
params.addRequiredCoupledVar("eta", "Order parameter that defines the interface");
23+
params.addParam<Real>("regularization",
24+
1e-8,
25+
"Floor added to |grad(eta)| before division to prevent singularities in "
26+
"bulk regions");
27+
params.addParam<std::string>("base_name", "", "Optional prefix for all material property names");
3328
return params;
3429
}
3530

@@ -39,13 +34,9 @@ InterfaceNormalCurvatures::InterfaceNormalCurvatures(const InputParameters & par
3934
_grad_eta(coupledGradient("eta")),
4035
_second_eta(coupledSecond("eta")),
4136
_eps(getParam<Real>("regularization")),
42-
43-
_kappa1 (declareProperty<Real> (getParam<std::string>("base_name") + "kappa1")),
44-
_kappa2 (declareProperty<Real> (getParam<std::string>("base_name") + "kappa2")),
45-
_kappa_mean(declareProperty<Real> (getParam<std::string>("base_name") + "kappa_mean")),
46-
_normal (declareProperty<RealVectorValue> (getParam<std::string>("base_name") + "interface_normal")),
47-
_tangent1 (declareProperty<RealVectorValue> (getParam<std::string>("base_name") + "tangent1")),
48-
_tangent2 (declareProperty<RealVectorValue> (getParam<std::string>("base_name") + "tangent2"))
37+
_kappa1(declareProperty<Real>(getParam<std::string>("base_name") + "kappa1")),
38+
_kappa2(declareProperty<Real>(getParam<std::string>("base_name") + "kappa2")),
39+
_kappa_mean(declareProperty<Real>(getParam<std::string>("base_name") + "kappa_mean"))
4940
{
5041
}
5142

@@ -54,58 +45,34 @@ InterfaceNormalCurvatures::computeQpProperties()
5445
{
5546
// ── 1. Interface normal ─────────────────────────────────────────────────
5647
const RealVectorValue & g = _grad_eta[_qp];
57-
const Real g_mag = g.norm();
58-
const Real g_reg = g_mag + _eps;
48+
const Real g_mag = g.norm();
49+
const Real g_reg = g_mag + _eps;
5950

60-
const RealVectorValue nhat = g / g_reg; // n̂ (unit normal)
61-
_normal[_qp] = nhat;
51+
const RealVectorValue nhat = g / g_reg; // n (unit normal)
6252

6353
// ── 2. Tangent frame ────────────────────────────────────────────────────
64-
// t̂₁ = ẑ × n̂ projected into the xy-plane.
65-
// For a normal that is purely along ẑ the cross product vanishes;
66-
// in that case we fall back to x̂ so the frame is always well-defined.
6754
static const RealVectorValue ZHAT(0., 0., 1.);
6855
static const RealVectorValue XHAT(1., 0., 0.);
6956

7057
RealVectorValue t1 = ZHAT.cross(nhat);
7158
const Real t1_mag = t1.norm();
7259
if (t1_mag < 1e-12)
73-
t1 = XHAT; // ±ẑ: choose as in-plane tangent
60+
t1 = XHAT; // n+/- z: choose x as in-plane tangent
7461
else
7562
t1 /= t1_mag;
7663

77-
const RealVectorValue t2 = nhat.cross(t1); // already unit length
78-
79-
_tangent1[_qp] = t1;
80-
_tangent2[_qp] = t2;
64+
const RealVectorValue t2 = nhat.cross(t1); // already unit length
8165

82-
// ── 3. Shape operator S = −∇n̂ ─────────────────────────────────────────
83-
//
84-
// n̂ = ∇η / |∇η|, so its Jacobian is:
85-
//
86-
// ∂n̂ᵢ/∂xⱼ = ( Hᵢⱼ − nᵢ (∇η · ∇∂η/∂xⱼ) / |∇η| ) / |∇η|
87-
//
88-
// where H = ∇∇η is the Hessian of η.
89-
// Written compactly: ∇n̂ = (H − n̂ ⊗ (H·n̂)) / |∇η|
90-
// and the shape operator S = −∇n̂.
91-
//
92-
// The normal curvature in direction v̂ is κ(v̂) = v̂ · S · v̂.
66+
// ── 3. Shape operator S ─────────────────────────────────────────
9367

94-
const RankTwoTensor & H = _second_eta[_qp]; // Hessian ∇∇η (3×3)
68+
const RankTwoTensor & H = _second_eta[_qp]; // Hessian (3×3)
9569

96-
// H·n̂ (matrix-vector product)
9770
RealVectorValue Hn;
9871
for (unsigned i = 0; i < 3; ++i)
9972
for (unsigned j = 0; j < 3; ++j)
10073
Hn(i) += H(i, j) * nhat(j);
10174

102-
// Normal curvature along a unit tangent v̂:
103-
// κ(v̂) = v̂ · S · v̂
104-
// = −v̂ · (∇n̂) · v̂
105-
// = −[ (v̂·H·v̂) − (v̂·n̂)(n̂·H·n̂) ] / |∇η|
106-
// but since v̂ ⊥ n̂ → v̂·n̂ = 0, this simplifies to:
107-
// κ(v̂) = −(v̂·H·v̂) / |∇η| (*)
108-
75+
// Normal curvature along a unit tangent v:
10976
auto vHv = [&](const RealVectorValue & v) -> Real
11077
{
11178
Real val = 0.;
@@ -115,11 +82,11 @@ InterfaceNormalCurvatures::computeQpProperties()
11582
return val;
11683
};
11784

118-
_kappa1[_qp] = -vHv(t1) / g_reg; // κ₁ (in-plane tangent)
119-
_kappa2[_qp] = -vHv(t2) / g_reg; // κ₂ (out-of-plane tangent)
85+
_kappa1[_qp] = -vHv(t1) / g_reg; // in-plane tangent
86+
_kappa2[_qp] = -vHv(t2) / g_reg; // out-of-plane tangent
87+
88+
// ── 4. Mean curvature ───────────────────────────────────────────
12089

121-
// ── 4. Mean curvature (diagnostic) κ = κ₁ + κ₂ = ∇·n̂ ─────────────────
122-
// Trace of shape operator = H.trace()/|∇η| − (n̂·H·n̂)/|∇η|
123-
const Real nHn = nhat * Hn; // n̂·H·n̂
90+
const Real nHn = nhat * Hn;
12491
_kappa_mean[_qp] = -(H.tr() - nHn) / g_reg;
12592
}
Binary file not shown.
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#
2+
# Test calculation of normal curvatures of an interface defined by order parameter c
3+
#
4+
[Mesh]
5+
type = GeneratedMesh
6+
dim = 3
7+
nx = 8
8+
ny = 8
9+
nz = 8
10+
xmin = 0
11+
xmax = 20
12+
ymin = -10
13+
ymax = 10
14+
zmin = 0
15+
zmax = 20
16+
[]
17+
18+
[Modules]
19+
[PhaseField]
20+
[Conserved]
21+
[./c]
22+
solve_type = direct
23+
free_energy = F
24+
kappa = 2.0
25+
mobility = 1.0
26+
[]
27+
[]
28+
[]
29+
[]
30+
31+
[ICs]
32+
[InitialCondition]
33+
type = FunctionIC
34+
function = ic_func_c
35+
variable = c
36+
[]
37+
[]
38+
39+
[Functions]
40+
[ic_func_c]
41+
type = ParsedFunction
42+
symbol_names = ' A lambda '
43+
symbol_values = '0.5 40 '
44+
expression = '0.5*(1.0-tanh((y - A * sin(2*pi*x/lambda) * sin(2*pi*z/lambda)) / 2))'
45+
[]
46+
[]
47+
48+
[Materials]
49+
[free_energy]
50+
type = DerivativeParsedMaterial
51+
property_name = F
52+
coupled_variables = 'c'
53+
expression = 'c^2 * (1 - c)^2'
54+
[]
55+
[curvatures]
56+
type = InterfaceNormalCurvatures
57+
eta = c
58+
outputs = 'exodus'
59+
[]
60+
[]
61+
62+
[Executioner]
63+
type = Transient
64+
scheme = 'bdf2'
65+
66+
solve_type = 'NEWTON'
67+
68+
l_max_its = 30
69+
l_tol = 1.0e-4
70+
nl_max_its = 10
71+
nl_rel_tol = 1.0e-9
72+
nl_abs_tol = 1.0e-11
73+
74+
start_time = 0.0
75+
end_time = 0.001
76+
dt = 0.001
77+
[]
78+
79+
[Outputs]
80+
exodus = true
81+
[]

modules/phase_field/test/tests/misc/tests

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,15 @@
5656
'the value of a function evaluated over a set of up to four coupled variables'
5757
design = 'CoupledValueFunctionIC.md'
5858
[]
59+
60+
[interface_normal_curvatures]
61+
type = 'Exodiff'
62+
input = 'interface_normal_curvatures.i'
63+
exodiff = 'interface_normal_curvatures_out.e'
64+
issues = '32436'
65+
requirement = 'An Material shall be implemented that can calculate the normal curvatures of'
66+
'an interface defined by an order parameter'
67+
design = 'InterfaceNormalCurvatures.md'
68+
[]
69+
5970
[]

0 commit comments

Comments
 (0)