Skip to content

Commit 81ff754

Browse files
Merge pull request #225 from arcaneframework/dev/mab-fourier-3D
fourier 3D with tests
2 parents 671c720 + bb218a8 commit 81ff754

File tree

5 files changed

+270
-21
lines changed

5 files changed

+270
-21
lines changed

femutils/ArcaneFemFunctions.h

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,29 @@ class ArcaneFemFunctions
241241
return { Center_x, Center_y, 0 };
242242
}
243243

244+
/*---------------------------------------------------------------------------*/
245+
/**
246+
* @brief Computes the barycenter (centroid) of a tetrahedron.
247+
*
248+
* This method calculates the barycenter of a tetrahedron defined by its nodes.
249+
* The barycenter is computed as the average of the vertices' coordinates.
250+
*/
251+
/*---------------------------------------------------------------------------*/
252+
253+
static inline Real3 computeBaryCenterTetra4(Cell cell, const VariableNodeReal3& node_coord)
254+
{
255+
Real3 vertex0 = node_coord[cell.nodeId(0)];
256+
Real3 vertex1 = node_coord[cell.nodeId(1)];
257+
Real3 vertex2 = node_coord[cell.nodeId(2)];
258+
Real3 vertex3 = node_coord[cell.nodeId(3)];
259+
260+
Real Center_x = (vertex0.x + vertex1.x + vertex2.x + vertex3.x) / 4.;
261+
Real Center_y = (vertex0.y + vertex1.y + vertex2.y + vertex3.x) / 4.;
262+
Real Center_z = (vertex0.z + vertex1.z + vertex2.z + vertex3.z) / 4.;
263+
264+
return { Center_x, Center_y, Center_z };
265+
}
266+
244267
/*---------------------------------------------------------------------------*/
245268
/**
246269
* @brief Computes the length of the edge defined by a given face.
@@ -864,6 +887,36 @@ class ArcaneFemFunctions
864887
}
865888
}
866889

890+
/*---------------------------------------------------------------------------*/
891+
/**
892+
* @brief Applies a manufactured source term to the RHS vector.
893+
*
894+
* This method adds a manufactured source term to the RHS vector for each
895+
* node in the mesh. The contribution to each node is weighted by the area of
896+
* the cell and evenly distributed among the nodes of the cell.
897+
*
898+
* @param [IN] qdot : The constant source term.
899+
* @param [IN] mesh : The mesh containing all cells.
900+
* @param [IN] node_dof : DOF connectivity view.
901+
* @param [IN] node_coord : The coordinates of the nodes.
902+
* @param [OUT] rhs_values : The RHS values to update.
903+
*/
904+
/*---------------------------------------------------------------------------*/
905+
906+
static inline void applyManufacturedSourceToRhs(IBinaryMathFunctor<Real, Real3, Real>* manufactured_source, IMesh* mesh, const IndexedNodeDoFConnectivityView& node_dof, const VariableNodeReal3& node_coord, VariableDoFReal& rhs_values)
907+
{
908+
ENUMERATE_ (Cell, icell, mesh->allCells()) {
909+
Cell cell = *icell;
910+
Real volume = ArcaneFemFunctions::MeshOperation::computeVolumeTetra4(cell, node_coord);
911+
Real3 bcenter = ArcaneFemFunctions::MeshOperation::computeBaryCenterTetra4(cell, node_coord);
912+
913+
for (Node node : cell.nodes()) {
914+
if (node.isOwn())
915+
rhs_values[node_dof.dofId(node, 0)] += manufactured_source->apply(volume / cell.nbNode(), bcenter);
916+
}
917+
}
918+
}
919+
867920
/*---------------------------------------------------------------------------*/
868921
/**
869922
* @brief Applies Dirichlet boundary conditions to RHS and LHS.
@@ -993,6 +1046,40 @@ class ArcaneFemFunctions
9931046
}
9941047
}
9951048
}
1049+
1050+
/*---------------------------------------------------------------------------*/
1051+
/**
1052+
* @brief Applies Manufactured Dirichlet boundary conditions to RHS and LHS.
1053+
*
1054+
* Updates the LHS matrix and RHS vector to enforce the Dirichlet.
1055+
*
1056+
* - For LHS matrix `A`, the diagonal term for the Dirichlet DOF is set to `P`.
1057+
* - For RHS vector `b`, the Dirichlet DOF term is scaled by `P`.
1058+
*
1059+
* @param [IN] manufactured_dirichlet : External function for Dirichlet.
1060+
* @param [IN] group : Group of all external faces.
1061+
* @param [IN] bs : Boundary condition values.
1062+
* @param [IN] node_dof : DOF connectivity view.
1063+
* @param [IN] node_coord : Node coordinates.
1064+
* @param [OUT] m_linear_system : Linear system for LHS.
1065+
* @param [OUT] rhs_values RHS : RHS values to update.
1066+
*/
1067+
/*---------------------------------------------------------------------------*/
1068+
static inline void applyManufacturedDirichletToLhsAndRhs(IBinaryMathFunctor<Real, Real3, Real>* manufactured_dirichlet, Real /*lambda*/, const FaceGroup& group, BC::IManufacturedSolution* bs, const IndexedNodeDoFConnectivityView& node_dof, const VariableNodeReal3& node_coord, DoFLinearSystem& m_linear_system, VariableDoFReal& rhs_values)
1069+
{
1070+
Real Penalty = bs->getPenalty();
1071+
1072+
ENUMERATE_ (Face, iface, group) {
1073+
for (Node node : iface->nodes()) {
1074+
if (node.isOwn()) {
1075+
m_linear_system.matrixSetValue(node_dof.dofId(node, 0), node_dof.dofId(node, 0), Penalty);
1076+
double tt = 1.;
1077+
Real u_g = Penalty * manufactured_dirichlet->apply(tt, node_coord[node]);
1078+
rhs_values[node_dof.dofId(node, 0)] = u_g;
1079+
}
1080+
}
1081+
}
1082+
}
9961083
};
9971084

9981085
/*---------------------------------------------------------------------------*/

modules/fourier/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ set(MESH_FILES
3434
multi-material.msh
3535
plancher.quad4.msh
3636
square_-2pi_to_2pi.msh
37+
bar_dynamic_3D.msh
3738
)
3839
foreach(MESH_FILE IN LISTS MESH_FILES)
3940
file(COPY ${MSH_DIR}/${MESH_FILE} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/meshes)
@@ -73,6 +74,13 @@ if(FEMUTILS_HAS_SOLVER_BACKEND_PETSC)
7374
add_test(NAME [Fourier]manufacture_solution COMMAND Fourier
7475
-A,UsingDotNet=1
7576
inputs/manufacture.solution.arc)
77+
add_test(NAME [Fourier]conduction_3D COMMAND Fourier
78+
inputs/conduction.3D.arc)
79+
add_test(NAME [Fourier]manufacture_solution_3D COMMAND Fourier
80+
-A,UsingDotNet=1
81+
-A,//meshes/mesh/filename=meshes/bar_dynamic_3D.msh
82+
-A,//fem/mesh-type=TETRA4
83+
inputs/manufacture.solution.arc)
7684

7785
if(FEMUTILS_HAS_PARALLEL_SOLVER AND MPIEXEC_EXECUTABLE)
7886
add_test(NAME [Fourier]conduction_2p COMMAND ${MPIEXEC_EXECUTABLE} -n 2 ./Fourier
@@ -82,6 +90,11 @@ if(FEMUTILS_HAS_SOLVER_BACKEND_PETSC)
8290
add_test(NAME [Fourier]manufacture_solution_2p COMMAND ${MPIEXEC_EXECUTABLE} -n 2 ./Fourier
8391
-A,UsingDotNet=1
8492
inputs/manufacture.solution.arc)
93+
add_test(NAME [Fourier]manufacture_solution_3D_2p COMMAND ${MPIEXEC_EXECUTABLE} -n 2 ./Fourier
94+
-A,UsingDotNet=1
95+
-A,//meshes/mesh/filename=meshes/bar_dynamic_3D.msh
96+
-A,//fem/mesh-type=TETRA4
97+
inputs/manufacture.solution.arc)
8598
if(FEMTEST_HAS_GMSH_TEST)
8699
add_test(NAME [Fourier]conduction_10k_2p COMMAND ${MPIEXEC_EXECUTABLE} -n 2 ./Fourier
87100
-A,//meshes/mesh/filename=meshes/plancher.10k.msh

modules/fourier/FemModule.cc

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -202,31 +202,39 @@ _assembleLinearOperator()
202202

203203
auto node_dof(m_dofs_on_nodes.nodeDoFConnectivityView());
204204

205-
if (options()->qdot.isPresent())
206-
ArcaneFemFunctions::BoundaryConditions2D::applyConstantSourceToRhs(qdot, mesh(), node_dof, m_node_coord, rhs_values);
207-
208205
BC::IArcaneFemBC* bc = options()->boundaryConditions();
209206

210207
if (bc) {
211-
for (BC::INeumannBoundaryCondition* bs : bc->neumannBoundaryConditions())
212-
ArcaneFemFunctions::BoundaryConditions2D::applyNeumannToRhs(bs, node_dof, m_node_coord, rhs_values);
213-
214-
for (BC::IDirichletBoundaryCondition* bs : bc->dirichletBoundaryConditions())
215-
ArcaneFemFunctions::BoundaryConditions2D::applyDirichletToLhsAndRhs(bs, node_dof, m_node_coord, m_linear_system, rhs_values);
216-
217-
for (BC::IManufacturedSolution* bs : bc->manufacturedSolutions()) {
218-
if (bs->getManufacturedSource()) {
219-
ARCANE_CHECK_POINTER(m_manufactured_source);
220-
info() << "Apply manufactured Source condition to all cells";
221-
ArcaneFemFunctions::BoundaryConditions2D::applyManufacturedSourceToRhs(m_manufactured_source, mesh(), node_dof, m_node_coord, rhs_values);
222-
}
223-
if (bs->getManufacturedDirichlet()) {
224-
ARCANE_CHECK_POINTER(m_manufactured_dirichlet);
225-
info() << "Apply manufactured dirichlet condition to all borders";
226-
FaceGroup group = mesh()->outerFaces();
227-
ArcaneFemFunctions::BoundaryConditions2D::applyManufacturedDirichletToLhsAndRhs(m_manufactured_dirichlet, lambda, group, bs, node_dof, m_node_coord, m_linear_system, rhs_values);
208+
auto applyBoundaryConditions = [&](auto BCFunctions) {
209+
if (options()->qdot.isPresent())
210+
BCFunctions.applyConstantSourceToRhs(qdot, mesh(), node_dof, m_node_coord, rhs_values);
211+
212+
BC::IArcaneFemBC* bc = options()->boundaryConditions();
213+
for (BC::INeumannBoundaryCondition* bs : bc->neumannBoundaryConditions())
214+
BCFunctions.applyNeumannToRhs(bs, node_dof, m_node_coord, rhs_values);
215+
216+
for (BC::IDirichletBoundaryCondition* bs : bc->dirichletBoundaryConditions())
217+
BCFunctions.applyDirichletToLhsAndRhs(bs, node_dof, m_node_coord, m_linear_system, rhs_values);
218+
219+
for (BC::IManufacturedSolution* bs : bc->manufacturedSolutions()) {
220+
if (bs->getManufacturedSource()) {
221+
ARCANE_CHECK_POINTER(m_manufactured_source);
222+
info() << "Apply manufactured Source condition to all cells";
223+
BCFunctions.applyManufacturedSourceToRhs(m_manufactured_source, mesh(), node_dof, m_node_coord, rhs_values);
224+
}
225+
if (bs->getManufacturedDirichlet()) {
226+
ARCANE_CHECK_POINTER(m_manufactured_dirichlet);
227+
info() << "Apply manufactured dirichlet condition to all borders";
228+
FaceGroup group = mesh()->outerFaces();
229+
BCFunctions.applyManufacturedDirichletToLhsAndRhs(m_manufactured_dirichlet, lambda, group, bs, node_dof, m_node_coord, m_linear_system, rhs_values);
230+
}
228231
}
229-
}
232+
};
233+
234+
if (mesh()->dimension() == 3)
235+
applyBoundaryConditions(ArcaneFemFunctions::BoundaryConditions3D());
236+
else
237+
applyBoundaryConditions(ArcaneFemFunctions::BoundaryConditions2D());
230238
}
231239

232240
elapsedTime = platform::getRealTime() - elapsedTime;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
1 12
2+
2 55
3+
3 55
4+
4 55
5+
5 55
6+
6 12
7+
7 12
8+
8 12
9+
9 50.7216511903551
10+
10 46.4387425490711
11+
11 42.1509493047928
12+
12 37.8582773154181
13+
13 33.5608291716414
14+
14 29.2581845749637
15+
15 24.950861190741
16+
16 20.6388656181528
17+
17 16.3220581180551
18+
18 16.3219078995032
19+
19 20.6387256401124
20+
20 24.9509397115797
21+
21 29.2582772718981
22+
22 33.5608291616598
23+
23 37.8581842921888
24+
24 42.1508586952028
25+
25 46.4386526503503
26+
26 50.7215780969766
27+
27 50.7216511903551
28+
28 46.4387425490711
29+
29 42.1509493047928
30+
30 37.858277315418
31+
31 33.5608291716414
32+
32 29.2581845749637
33+
33 24.9508714701844
34+
34 20.638744473218
35+
35 16.3220014135257
36+
36 16.321953690758
37+
37 20.6388647258524
38+
38 24.950956569867
39+
39 29.2582772718981
40+
40 33.5608291616598
41+
41 37.8581842921888
42+
42 42.1508586952028
43+
43 46.4386526503503
44+
44 50.7215780969766
45+
45 31.4101765280069
46+
46 48.5809477492477
47+
47 35.7102611938306
48+
48 40.0053634820613
49+
49 44.2955976300534
50+
50 52.8613623960177
51+
51 18.480906619199
52+
52 14.1613710092729
53+
53 27.1053100470222
54+
54 22.7955731592032
55+
55 35.7101764872987
56+
56 14.1614036258102
57+
57 18.4809848361747
58+
58 31.4102611531306
59+
59 27.1053624167412
60+
60 22.7955960075257
61+
61 48.5808986275508
62+
62 40.0053089816822
63+
63 44.2955443989129
64+
64 52.8614231112239
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
Case configuration for a Fourier analysis simulation.
4+
This file includes settings for:
5+
- General simulation parameters
6+
- Mesh configuration details
7+
- Finite Element Method (FEM) configurations
8+
- Post-processing options
9+
-->
10+
<case codename="Fourier" xml:lang="en" codeversion="1.0">
11+
12+
<!--
13+
Arcane-specific settings:
14+
- title: Descriptive name for the simulation case.
15+
- timeloop: Specifies the time-stepping loop used in this Fourier simulation.
16+
-->
17+
<arcane>
18+
<title>Fouriers equation FEM code</title>
19+
<timeloop>FourierLoop</timeloop>
20+
</arcane>
21+
22+
<!--
23+
Mesh configuration:
24+
- filename: The path to the mesh file used in the simulation.
25+
-->
26+
<meshes>
27+
<mesh>
28+
<filename>meshes/bar_dynamic_3D.msh</filename>
29+
</mesh>
30+
</meshes>
31+
32+
<!--
33+
FEM (Finite Element Method) settings:
34+
- lambda: Thermal conductivity or diffusivity coefficient.
35+
- qdot: Heat source term or volumetric heat generation.
36+
- result-file: File where simulation results will be saved.
37+
- boundary-conditions: Defines the boundary conditions for the simulation.
38+
- dirichlet: Fixed value boundary condition with penalty enforcement for specified surfaces.
39+
- neumann: Flux or gradient boundary condition for specified surfaces.
40+
-->
41+
<fem>
42+
<lambda>0.023</lambda>
43+
<qdot>1.123e-2</qdot>
44+
<mesh-type>TETRA4</mesh-type>
45+
<result-file>check/test_conduction_3D.txt</result-file>
46+
<boundary-conditions>
47+
<dirichlet>
48+
<enforce-Dirichlet-method>Penalty</enforce-Dirichlet-method>
49+
<surface>surfaceleft</surface>
50+
<value>55.0</value>
51+
</dirichlet>
52+
<dirichlet>
53+
<enforce-Dirichlet-method>Penalty</enforce-Dirichlet-method>
54+
<surface>surfaceright</surface>
55+
<value>12.0</value>
56+
</dirichlet>
57+
<neumann>
58+
<surface>sidesurfaces</surface>
59+
<value>0.0</value>
60+
</neumann>
61+
</boundary-conditions>
62+
</fem>
63+
64+
<!--
65+
Post-processing settings:
66+
- output-period: Defines how often (in simulation steps) the output is generated.
67+
- format: Specifies the post-processing format, here using VtkHdfV2.
68+
- output: Defines the variables to be included in the post-processing output.
69+
-->
70+
<arcane-post-processing>
71+
<output-period>1</output-period>
72+
<output>
73+
<variable>U</variable>
74+
</output>
75+
</arcane-post-processing>
76+
77+
</case>

0 commit comments

Comments
 (0)