Skip to content

Commit bdb6d05

Browse files
Merge pull request #285 from arcaneframework/dev/mab-hex-quad-support-elasticity
Dev/mab hex quad support elasticity
2 parents e89bc7d + 130665e commit bdb6d05

21 files changed

+1278
-106
lines changed

femutils/FemUtils.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,18 +374,34 @@ class RealVector
374374

375375
public:
376376

377+
//! Add operator()
377378
ARCCORE_HOST_DEVICE Arcane::Real& operator()(Arcane::Int32 i)
378379
{
379380
ARCANE_CHECK_AT(i, N);
380381
return m_values[i];
381382
}
382383

384+
//! Add operator()
383385
ARCCORE_HOST_DEVICE Arcane::Real operator()(Arcane::Int32 i) const
384386
{
385387
ARCANE_CHECK_AT(i, N);
386388
return m_values[i];
387389
}
388390

391+
//! Add operator[]
392+
ARCCORE_HOST_DEVICE Arcane::Real& operator[](Arcane::Int32 i)
393+
{
394+
ARCANE_CHECK_AT(i, N);
395+
return m_values[i];
396+
}
397+
398+
//! Add operator[]
399+
ARCCORE_HOST_DEVICE Arcane::Real operator[](Arcane::Int32 i) const
400+
{
401+
ARCANE_CHECK_AT(i, N);
402+
return m_values[i];
403+
}
404+
389405
public:
390406

391407
//! Multiply all the components by \a v

meshes/msh/five_quads.msh

1.98 KB
Binary file not shown.

modules/elasticity/BodyForce.h

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2+
//-----------------------------------------------------------------------------
3+
// Copyright 2000-2025 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4+
// See the top-level COPYRIGHT file for details.
5+
// SPDX-License-Identifier: Apache-2.0
6+
//-----------------------------------------------------------------------------
7+
/*---------------------------------------------------------------------------*/
8+
/* BodyForce.h (C) 2022-2025 */
9+
/* */
10+
/* Contains functions to compute and assemble body force contribution to RHS */
11+
/*---------------------------------------------------------------------------*/
12+
/*---------------------------------------------------------------------------*/
13+
14+
/*---------------------------------------------------------------------------*/
15+
/**
16+
* @brief Applies body force to the RHS vector of the linear system.
17+
*
18+
* This function computes the contribution of body forces to the RHS vector
19+
* of the linear system. It iterates over all cells in the mesh, calculates
20+
* the appropriate force contributions based on the element type and mesh
21+
* dimension, and updates the RHS vector accordingly.
22+
*
23+
* body force ∫∫∫ (𝐟.𝐯) with 𝐟 = (𝑓𝑥, 𝑓𝑦, 𝑓𝑧) = (f[0], f[1], f[2])
24+
*
25+
* @param rhs_values The variable representing the RHS vector to be updated.
26+
* @param node_dof The connectivity view mapping nodes to their corresponding
27+
* degrees of freedom (DoFs).
28+
*
29+
/*---------------------------------------------------------------------------*/
30+
31+
inline void FemModule::
32+
_applyBodyForceToRHS(VariableDoFReal& rhs_values, const IndexedNodeDoFConnectivityView& node_dof)
33+
{
34+
35+
// get bodyforce vector
36+
bool applyBodyForce = false;
37+
const UniqueArray<String> f_string = options()->f();
38+
info() << "[ArcaneFem-Info] Applying Bodyforce " << f_string;
39+
for (Int32 i = 0; i < f_string.size(); ++i) {
40+
f[i] = 0.0;
41+
if (f_string[i] != "NULL") {
42+
applyBodyForce = true;
43+
f[i] = std::stod(f_string[i].localstr());
44+
}
45+
}
46+
47+
// no bodyforce to apply hence return
48+
if (!applyBodyForce)
49+
return;
50+
51+
// apply bodyforce based on dimension and mesh type
52+
if (mesh()->dimension() == 2) {
53+
if (m_hex_quad_mesh) {
54+
ENUMERATE_ (Cell, icell, allCells()) {
55+
Cell cell = *icell;
56+
57+
constexpr Real gp[2] = { -M_SQRT1_3, M_SQRT1_3 }; //(ξ,η)
58+
constexpr Real weights[2] = { 1.0, 1.0 };
59+
60+
for (Int32 ixi = 0; ixi < 2; ++ixi) {
61+
for (Int32 ieta = 0; ieta < 2; ++ieta) {
62+
63+
// set the coordinates of the Gauss point
64+
Real xi = gp[ixi]; // Get the ξ coordinate of the Gauss point
65+
Real eta = gp[ieta]; // Get the η coordinate of the Gauss point
66+
67+
// set the weight of the Gauss point
68+
Real weight = weights[ixi] * weights[ieta];
69+
70+
// get shape functions 𝐍 for Quad4: 𝐍(ξ,η) = [𝑁₁ 𝑁₂ 𝑁₃ 𝑁₄]
71+
RealVector<4> N = ArcaneFemFunctions::FeOperation2D::computeShapeFunctionsQuad4(xi, eta);
72+
73+
// get determinant of Jacobian
74+
const auto gp_info = ArcaneFemFunctions::FeOperation2D::computeGradientsAndJacobianQuad4(cell, m_node_coord, xi, eta);
75+
const Real detJ = gp_info.det_j;
76+
77+
// compute integration weight
78+
Real integration_weight = weight * detJ;
79+
80+
// Assemble RHS
81+
for (Int32 i = 0; i < 4; ++i) {
82+
Node node = cell.node(i);
83+
if (node.isOwn()) {
84+
rhs_values[node_dof.dofId(node, 0)] += N[i] * f[0] * integration_weight;
85+
rhs_values[node_dof.dofId(node, 1)] += N[i] * f[1] * integration_weight;
86+
}
87+
}
88+
}
89+
}
90+
}
91+
}
92+
else {
93+
ENUMERATE_ (Cell, icell, allCells()) {
94+
Cell cell = *icell;
95+
Real area = ArcaneFemFunctions::MeshOperation::computeAreaTria3(cell, m_node_coord);
96+
for (Node node : cell.nodes()) {
97+
if (node.isOwn()) {
98+
rhs_values[node_dof.dofId(node, 0)] += f[0] * area / 3;
99+
rhs_values[node_dof.dofId(node, 1)] += f[1] * area / 3;
100+
}
101+
}
102+
}
103+
}
104+
}
105+
if (mesh()->dimension() == 3) {
106+
if (m_hex_quad_mesh) {
107+
ENUMERATE_ (Cell, icell, allCells()) {
108+
Cell cell = *icell;
109+
110+
constexpr Real gp[2] = { -M_SQRT1_3, M_SQRT1_3 }; // [-1/sqrt(3), 1/sqrt(3)]
111+
constexpr Real weights[2] = { 1.0, 1.0 };
112+
113+
for (Int32 ixi = 0; ixi < 2; ++ixi) {
114+
for (Int32 ieta = 0; ieta < 2; ++ieta) {
115+
for (Int32 izeta = 0; izeta < 2; ++izeta) {
116+
117+
// set the coordinates of the Gauss point
118+
Real xi = gp[ixi];
119+
Real eta = gp[ieta];
120+
Real zeta = gp[izeta];
121+
122+
// set the weight of the Gauss point
123+
Real weight = weights[ixi] * weights[ieta] * weights[izeta];
124+
125+
// Get shape functions for Hexa8: 𝐍(ξ,η,ζ) = [𝑁₁ 𝑁₂ 𝑁₃ 𝑁₄ 𝑁₅ 𝑁₆ 𝑁₇ 𝑁₈]
126+
RealVector<8> N = ArcaneFemFunctions::FeOperation3D::computeShapeFunctionsHexa8(xi, eta, zeta);
127+
128+
// get determinant of Jacobian
129+
const auto gp_info = ArcaneFemFunctions::FeOperation3D::computeGradientsAndJacobianHexa8(cell, m_node_coord, xi, eta, zeta);
130+
const Real detJ = gp_info.det_j;
131+
132+
// compute integration weight
133+
Real integration_weight = detJ * weight;
134+
135+
// Assemble RHS
136+
for (Int32 i = 0; i < 8; ++i) {
137+
Node node = cell.node(i);
138+
if (node.isOwn()) {
139+
rhs_values[node_dof.dofId(node, 0)] += N[i] * f[0] * integration_weight;
140+
rhs_values[node_dof.dofId(node, 1)] += N[i] * f[1] * integration_weight;
141+
rhs_values[node_dof.dofId(node, 2)] += N[i] * f[2] * integration_weight;
142+
}
143+
}
144+
}
145+
}
146+
}
147+
}
148+
}
149+
else {
150+
ENUMERATE_ (Cell, icell, allCells()) {
151+
Cell cell = *icell;
152+
Real volume = ArcaneFemFunctions::MeshOperation::computeVolumeTetra4(cell, m_node_coord);
153+
for (Node node : cell.nodes()) {
154+
if (node.isOwn()) {
155+
rhs_values[node_dof.dofId(node, 0)] += f[0] * volume / 4;
156+
rhs_values[node_dof.dofId(node, 1)] += f[1] * volume / 4;
157+
rhs_values[node_dof.dofId(node, 2)] += f[2] * volume / 4;
158+
}
159+
}
160+
}
161+
}
162+
}
163+
}

modules/elasticity/CMakeLists.txt

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ file(COPY "inputs" DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
2828
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/meshes)
2929
set(MESH_FILES
3030
bar.msh
31+
plate.quad.msh
32+
five_quads.msh
3133
bar_dynamic_3D.msh
34+
truncated_cube.hexa.msh
3235
sphere_cut.msh
3336
)
3437
foreach(MESH_FILE IN LISTS MESH_FILES)
@@ -44,6 +47,9 @@ if(FEMUTILS_HAS_SOLVER_BACKEND_PETSC)
4447
add_test(NAME [elasticity]Dirichlet COMMAND Elasticity
4548
inputs/bar.2D.arc)
4649

50+
add_test(NAME [elasticity]Dirichlet_quad COMMAND Elasticity
51+
inputs/bar.2D.quad.arc)
52+
4753
add_test(NAME [elasticity]Dirichlet_traction COMMAND Elasticity
4854
inputs/bar.2D.traction.arc)
4955

@@ -68,23 +74,38 @@ if(FEMUTILS_HAS_SOLVER_BACKEND_PETSC)
6874
-A,//fem/enforce-Dirichlet-method=RowColumnElimination
6975
inputs/bar.2D.arc)
7076

77+
add_test(NAME [elasticity]Dirichlet_bodyforce_quad COMMAND Elasticity
78+
inputs/2D.dirichlet.bodyforce.quad.arc)
79+
80+
add_test(NAME [elasticity]Dirichlet_traction_bodyforce_quad COMMAND Elasticity
81+
inputs/2D.dirichlet.traction.bodyforce.quad.arc)
82+
7183
add_test(NAME [elasticity]Dirichlet_traction_bodyforce COMMAND Elasticity
7284
inputs/bar.2D.traction.bodyforce.arc)
7385

86+
add_test(NAME [elasticity]2D_Dirichlet_traction_bodyforce_quad COMMAND Elasticity
87+
inputs/bar.2D.traction.bodyforce.quad.arc)
88+
7489
add_test(NAME [elasticity]bar_parse_and_exit COMMAND Elasticity
7590
-A,//fem/assemble-linear-system=false
7691
-A,//fem/solve-linear-system=false
7792
-A,//fem/cross-validation=false
7893
inputs/bar.2D.arc)
7994

80-
add_test(NAME [elasticity]3D_Dirichlet_bodyforce_dok COMMAND Elasticity
95+
add_test(NAME [elasticity]2D_Dirichlet_bodyforce_dok COMMAND Elasticity
8196
-A,//fem/matrix-format=DOK
8297
inputs/bar.2D.PointDirichlet.arc)
8398

99+
add_test(NAME [elasticity]3D_Dirichlet_bodyforce_hexa COMMAND Elasticity
100+
inputs/3D.dirichlet.bodyforce.hexa.arc)
101+
102+
add_test(NAME [elasticity]3D_Dirichlet_traction_bodyforce_hexa COMMAND Elasticity
103+
inputs/3D.dirichlet.traction.bodyforce.hexa.arc)
104+
84105
add_test(NAME [elasticity]3D_Dirichlet_bodyforce_subdivider COMMAND Elasticity ARGS
85-
-A,//fem/cross-validation=false
86-
-A,//meshes/mesh/subdivider/nb-subdivision=2
87-
inputs/bar.3D.Dirichlet.bodyForce.arc)
106+
-A,//fem/cross-validation=false
107+
-A,//meshes/mesh/subdivider/nb-subdivision=2
108+
inputs/bar.3D.Dirichlet.bodyForce.arc)
88109

89110
arcanefem_add_gpu_test(NAME [elasticity]Dirichlet_pointBC_bsr COMMAND ./Elasticity ARGS
90111
-A,//fem/matrix-format=BSR
@@ -113,10 +134,19 @@ if(FEMUTILS_HAS_SOLVER_BACKEND_PETSC)
113134
if(FEMUTILS_HAS_PARALLEL_SOLVER)
114135
add_test(NAME [elasticity]Dirichlet_2p COMMAND ${MPIEXEC_EXECUTABLE} -n 2 ./Elasticity
115136
inputs/bar.2D.arc)
137+
138+
add_test(NAME [elasticity]Dirichlet_quad_2p COMMAND ${MPIEXEC_EXECUTABLE} -n 2 ./Elasticity
139+
inputs/bar.2D.quad.arc)
140+
116141
add_test(NAME [elasticity]Dirichlet_via_RowElimination_2p COMMAND ${MPIEXEC_EXECUTABLE} -n 2 ./Elasticity
117142
-A,//fem/enforce-Dirichlet-method=RowElimination
118143
${SOLVER_PETSC_GMRES}
119144
inputs/bar.2D.arc)
145+
146+
add_test(NAME [elasticity]Dirichlet_RowColumnElim_quad_2p COMMAND ${MPIEXEC_EXECUTABLE} -n 2 ./Elasticity
147+
-A,//fem/enforce-Dirichlet-method=RowColumnElimination
148+
inputs/bar.2D.quad.arc)
149+
120150
add_test(NAME [elasticity]Dirichlet_via_RowColElimination_2p COMMAND ${MPIEXEC_EXECUTABLE} -n 2 ./Elasticity
121151
-A,//fem/enforce-Dirichlet-method=RowColumnElimination
122152
inputs/bar.2D.arc)

0 commit comments

Comments
 (0)