Skip to content

Commit bde5030

Browse files
author
zeptodoctor
committed
build based on 22a8796
1 parent 3031e33 commit bde5030

32 files changed

Lines changed: 311 additions & 52 deletions

File tree

dev/index.html

Lines changed: 2 additions & 2 deletions
Large diffs are not rendered by default.

dev/notebooks/t024_stokes_blocks.ipynb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
{
1111
"cell_type": "markdown",
1212
"source": [
13-
"# Incompressible Stokes equations in a 2D/3D cavity\n",
14-
"\n",
1513
"This example solves the incompressible Stokes equations, given by\n",
1614
"\n",
1715
"$$\n",

dev/notebooks/t027_geometry_dev.ipynb

Lines changed: 253 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
" - How to extract geometrical information from a `Grid`.\n",
1818
" - How periodicity is handled in Gridap, and the difference between nodes and vertices.\n",
1919
" - How to create a periodic model from scratch, use the example of a Mobius strip.\n",
20+
" - How to create and manipulate `FaceLabeling` objects, which are used to handle boundary conditions.\n",
2021
"\n",
2122
"## Required Packages"
2223
],
@@ -43,6 +44,7 @@
4344
"4. Geometric Mappings\n",
4445
"5. High-order Grids\n",
4546
"6. Periodicity in Gridap\n",
47+
"7. FaceLabelings\n",
4648
"\n",
4749
"## 1. Utility Functions\n",
4850
"We begin by defining helper functions that will be essential throughout this tutorial.\n",
@@ -53,7 +55,7 @@
5355
{
5456
"cell_type": "markdown",
5557
"source": [
56-
"Convert a CartesianDiscreteModel to an UnstructuredDiscreteModel for more generic handling"
58+
"Convert a `CartesianDiscreteModel` to an `UnstructuredDiscreteModel` for more generic handling."
5759
],
5860
"metadata": {}
5961
},
@@ -71,9 +73,9 @@
7173
{
7274
"cell_type": "markdown",
7375
"source": [
74-
"Visualization function to plot nodes with their IDs\n",
75-
"Input: node_coords - Array of node coordinates\n",
76-
" node_ids - Array of corresponding node IDs"
76+
"Visualization function to plot nodes with their IDs. Input:\n",
77+
"- node_coords: Array of node coordinates.\n",
78+
"- node_ids: Array of corresponding node IDs."
7779
],
7880
"metadata": {}
7981
},
@@ -96,8 +98,8 @@
9698
{
9799
"cell_type": "markdown",
98100
"source": [
99-
"Overloaded method to plot node numbering directly from a model\n",
100-
"This function extracts the necessary information from the model and calls the base plotting function"
101+
"Overloaded method to plot node numbering directly from a model.\n",
102+
"This function extracts the necessary information from the model and calls the base plotting function."
101103
],
102104
"metadata": {}
103105
},
@@ -148,15 +150,15 @@
148150
"\n",
149151
"### Key Concept: Nodes vs. Vertices\n",
150152
"\n",
151-
"One of the most important distinctions in Gridap is between nodes and vertices:\n",
153+
"A very important distinction in Gridap is between nodes and vertices:\n",
152154
"\n",
153155
" - **Vertices** (Topological entities):\n",
154156
" * 0-dimensional entities in the `GridTopology`\n",
155157
" * Define the connectivity of the mesh\n",
156158
" * Used for neighbor queries and mesh traversal\n",
157159
" * Number of vertices depends only on topology\n",
158160
"\n",
159-
" - **Nodes** (Geometric entities):\n",
161+
" - **Nodes** (Geometrical entities):\n",
160162
" * Control points stored in the `Grid`\n",
161163
" * Define the geometry of elements\n",
162164
" * Used for interpolation and mapping\n",
@@ -387,7 +389,7 @@
387389
"\n",
388390
"There are two ways to get the coordinates of nodes for each cell:\n",
389391
"\n",
390-
"1. Using standard Julia mapping:"
392+
"A) Using standard Julia mapping:"
391393
],
392394
"metadata": {}
393395
},
@@ -403,7 +405,7 @@
403405
{
404406
"cell_type": "markdown",
405407
"source": [
406-
"2. Using Gridap's lazy evaluation system (more efficient for large meshes):"
408+
"B) Using Gridap's lazy evaluation system (more efficient for large meshes):"
407409
],
408410
"metadata": {}
409411
},
@@ -538,7 +540,7 @@
538540
"our half-cylinder looks faceted. This is because we're still using linear elements\n",
539541
"(straight edges) to approximate the curved geometry.\n",
540542
"\n",
541-
"### Solution: High-order Elements\n",
543+
"### Example: High-order Elements\n",
542544
"\n",
543545
"To accurately represent curved geometries, we need high-order elements:"
544546
],
@@ -1059,6 +1061,246 @@
10591061
],
10601062
"metadata": {}
10611063
},
1064+
{
1065+
"cell_type": "markdown",
1066+
"source": [
1067+
"## 7. FaceLabelings and boundary conditions\n",
1068+
"\n",
1069+
"The `FaceLabeling` component of a `DiscreteModel` is the way Gridap handles boundary conditions.\n",
1070+
"The basic idea is that, similar to Gmsh, we classify the d-faces (cells, faces, edges, nodes) of the mesh\n",
1071+
"into different entities (physical groups in Gmsh terminology) which in turn have one or more\n",
1072+
"tags/labels associated with them.\n",
1073+
"We can then query the `FaceLabeling` for the tags associated with a given d-face,\n",
1074+
"or the d-faces associated with a given tag.\n",
1075+
"\n",
1076+
"We will now explore ways to create and manipulate `Facelabeling` objects.\n",
1077+
"\n",
1078+
"### Creating FaceLabelings\n",
1079+
"\n",
1080+
"The simplest way to create a blank `FaceLabeling` is to use your `GridTopology`:"
1081+
],
1082+
"metadata": {}
1083+
},
1084+
{
1085+
"outputs": [],
1086+
"cell_type": "code",
1087+
"source": [
1088+
"model = cartesian_model((0,1,0,1),(3,3))\n",
1089+
"topo = get_grid_topology(model)\n",
1090+
"\n",
1091+
"labels = FaceLabeling(topo)"
1092+
],
1093+
"metadata": {},
1094+
"execution_count": null
1095+
},
1096+
{
1097+
"cell_type": "markdown",
1098+
"source": [
1099+
"The above `FaceLabeling` is by default created with 2 entities and 2 tags, associated to\n",
1100+
"interior and boundary d-faces respectively. The boundary facets are chosen as the ones\n",
1101+
"with a single neighboring cell.\n",
1102+
"\n",
1103+
"We can extract the low-level information from the `FaceLabeling` object:"
1104+
],
1105+
"metadata": {}
1106+
},
1107+
{
1108+
"outputs": [],
1109+
"cell_type": "code",
1110+
"source": [
1111+
"tag_names = get_tag_name(labels) # Each name is a string\n",
1112+
"tag_entities = get_tag_entities(labels) # For each tag, a vector of entities\n",
1113+
"cell_to_entity = get_face_entity(labels,2) # For each cell, its associated entity\n",
1114+
"edge_to_entity = get_face_entity(labels,1) # For each edge, its associated entity\n",
1115+
"node_to_entity = get_face_entity(labels,0) # For each node, its associated entity"
1116+
],
1117+
"metadata": {},
1118+
"execution_count": null
1119+
},
1120+
{
1121+
"cell_type": "markdown",
1122+
"source": [
1123+
"It is usually more convenient to visualise it in Paraview by exporting to vtk:"
1124+
],
1125+
"metadata": {}
1126+
},
1127+
{
1128+
"outputs": [],
1129+
"cell_type": "code",
1130+
"source": [
1131+
"writevtk(model,\"labels_basic\",labels=labels)"
1132+
],
1133+
"metadata": {},
1134+
"execution_count": null
1135+
},
1136+
{
1137+
"cell_type": "markdown",
1138+
"source": [
1139+
"Another useful way to create a `FaceLabeling` is by providing a coloring for the mesh cells,\n",
1140+
"where each color corresponds to a different tag.\n",
1141+
"The d-faces of the mesh will have all the tags associated to the cells that share them."
1142+
],
1143+
"metadata": {}
1144+
},
1145+
{
1146+
"outputs": [],
1147+
"cell_type": "code",
1148+
"source": [
1149+
"cell_to_tag = [1,1,1,2,2,3,2,2,3]\n",
1150+
"tag_to_name = [\"A\",\"B\",\"C\"]\n",
1151+
"labels_cw = Geometry.face_labeling_from_cell_tags(topo,cell_to_tag,tag_to_name)\n",
1152+
"writevtk(model,\"labels_cellwise\",labels=labels_cw)"
1153+
],
1154+
"metadata": {},
1155+
"execution_count": null
1156+
},
1157+
{
1158+
"cell_type": "markdown",
1159+
"source": [
1160+
"We can also create a `FaceLabeling` from a vertex filter. The resulting `FaceLabeling` will have\n",
1161+
"only one tag, gathering the d-faces whose vertices ALL fullfill `filter(x) == true`."
1162+
],
1163+
"metadata": {}
1164+
},
1165+
{
1166+
"outputs": [],
1167+
"cell_type": "code",
1168+
"source": [
1169+
"vfilter(x) = abs(x[1]- 1.0) < 1.e-5\n",
1170+
"labels_vf = Geometry.face_labeling_from_vertex_filter(topo, \"top\", vfilter)\n",
1171+
"writevtk(model,\"labels_filter\",labels=labels_vf)"
1172+
],
1173+
"metadata": {},
1174+
"execution_count": null
1175+
},
1176+
{
1177+
"cell_type": "markdown",
1178+
"source": [
1179+
"`FaceLabeling` objects can also be merged together. The resulting `FaceLabeling` will have\n",
1180+
"the union of the tags and entities of the original ones.\n",
1181+
"Note that this modifies the first `FaceLabeling` in place."
1182+
],
1183+
"metadata": {}
1184+
},
1185+
{
1186+
"outputs": [],
1187+
"cell_type": "code",
1188+
"source": [
1189+
"labels = merge!(labels, labels_cw, labels_vf)\n",
1190+
"writevtk(model,\"labels_merged\",labels=labels)"
1191+
],
1192+
"metadata": {},
1193+
"execution_count": null
1194+
},
1195+
{
1196+
"cell_type": "markdown",
1197+
"source": [
1198+
"### Creating new tags from existing ones\n",
1199+
"\n",
1200+
"Tags in a `FaceLabeling` support all the usual set operation, i.e union, intersection,\n",
1201+
"difference and complementary."
1202+
],
1203+
"metadata": {}
1204+
},
1205+
{
1206+
"outputs": [],
1207+
"cell_type": "code",
1208+
"source": [
1209+
"cell_to_tag = [1,1,1,2,2,3,2,2,3]\n",
1210+
"tag_to_name = [\"A\",\"B\",\"C\"]\n",
1211+
"labels = Geometry.face_labeling_from_cell_tags(topo,cell_to_tag,tag_to_name)"
1212+
],
1213+
"metadata": {},
1214+
"execution_count": null
1215+
},
1216+
{
1217+
"cell_type": "markdown",
1218+
"source": [
1219+
"Union: Takes as input a list of tags and creates a new tag that is the union of all of them."
1220+
],
1221+
"metadata": {}
1222+
},
1223+
{
1224+
"outputs": [],
1225+
"cell_type": "code",
1226+
"source": [
1227+
"Geometry.add_tag_from_tags!(labels,\"A∪B\",[\"A\",\"B\"])"
1228+
],
1229+
"metadata": {},
1230+
"execution_count": null
1231+
},
1232+
{
1233+
"cell_type": "markdown",
1234+
"source": [
1235+
"Intersection: Takes as input a list of tags and creates a new tag that is the intersection of all of them."
1236+
],
1237+
"metadata": {}
1238+
},
1239+
{
1240+
"outputs": [],
1241+
"cell_type": "code",
1242+
"source": [
1243+
"Geometry.add_tag_from_tags_intersection!(labels,\"A∩B\",[\"A\",\"B\"])"
1244+
],
1245+
"metadata": {},
1246+
"execution_count": null
1247+
},
1248+
{
1249+
"cell_type": "markdown",
1250+
"source": [
1251+
"Complementary: Takes as input a list of tags and creates a new tag that is the complementary of the union."
1252+
],
1253+
"metadata": {}
1254+
},
1255+
{
1256+
"outputs": [],
1257+
"cell_type": "code",
1258+
"source": [
1259+
"Geometry.add_tag_from_tags_complementary!(labels,\"!A\",[\"A\"])"
1260+
],
1261+
"metadata": {},
1262+
"execution_count": null
1263+
},
1264+
{
1265+
"cell_type": "markdown",
1266+
"source": [
1267+
"Set difference: Takes as input two lists of tags (tags_include - tags_exclude)\n",
1268+
"and creates a new tag that contains all the d-faces that are in the first list but not in the second."
1269+
],
1270+
"metadata": {}
1271+
},
1272+
{
1273+
"outputs": [],
1274+
"cell_type": "code",
1275+
"source": [
1276+
"Geometry.add_tag_from_tags_setdiff!(labels,\"A-B\",[\"A\"],[\"B\"]) # set difference\n",
1277+
"\n",
1278+
"writevtk(model,\"labels_setops\",labels=labels)"
1279+
],
1280+
"metadata": {},
1281+
"execution_count": null
1282+
},
1283+
{
1284+
"cell_type": "markdown",
1285+
"source": [
1286+
"### FaceLabeling queries\n",
1287+
"\n",
1288+
"The most common way of query information from a `FaceLabeling` is to query a face mask for\n",
1289+
"a given tag and face dimension. If multiple tags are provided, the union of the tags is returned."
1290+
],
1291+
"metadata": {}
1292+
},
1293+
{
1294+
"outputs": [],
1295+
"cell_type": "code",
1296+
"source": [
1297+
"face_dim = 1\n",
1298+
"mask = get_face_mask(labels,[\"A\",\"C\"],face_dim) # Boolean mask\n",
1299+
"ids = findall(mask) # Edge IDs"
1300+
],
1301+
"metadata": {},
1302+
"execution_count": null
1303+
},
10621304
{
10631305
"cell_type": "markdown",
10641306
"source": [

dev/pages/t001_poisson/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
h(x) = 3.0
1717
a(u,v) = ∫( ∇(v)⋅∇(u) )*dΩ
1818
b(v) = ∫( v*f )*dΩ + ∫( v*h )*dΓ</code></pre><p>Note that by using the integral function <code></code>, the Lebesgue measures <code></code>, <code></code>, and the gradient function <code></code>, the weak form is written with an obvious relation with the corresponding mathematical notation.</p><h2 id="FE-Problem-1"><a class="docs-heading-anchor" href="#FE-Problem-1">FE Problem</a><a class="docs-heading-anchor-permalink" href="#FE-Problem-1" title="Permalink"></a></h2><p>At this point, we can build the FE problem that, once solved, will provide the numerical solution we are looking for. A FE problem is represented in Gridap by types inheriting from the abstract type <code>FEOperator</code> (both for linear and nonlinear cases). Since we want to solve a linear problem, we use the concrete type <code>AffineFEOperator</code>, i.e., a problem represented by a matrix and a right hand side vector.</p><pre><code class="language-julia">op = AffineFEOperator(a,b,Ug,V0)</code></pre><p>Note that the <code>AffineFEOperator</code> object representing our FE problem is built from the function <code>a</code> and <code>b</code> representing the weak form and test and trial FE spaces <code>V0</code> and <code>Ug</code>.</p><h2 id="Solver-phase-1"><a class="docs-heading-anchor" href="#Solver-phase-1">Solver phase</a><a class="docs-heading-anchor-permalink" href="#Solver-phase-1" title="Permalink"></a></h2><p>We have constructed a FE problem, the last step is to solve it. In Gridap, FE problems are solved with types inheriting from the abstract type <code>FESolver</code>. Since this is a linear problem, we use a <code>LinearFESolver</code>:</p><pre><code class="language-julia">ls = LUSolver()
19-
solver = LinearFESolver(ls)</code></pre><p><code>LinearFESolver</code> objects are built from a given algebraic linear solver. In this case, we use a LU factorization. Now we are ready to solve the FE problem with the FE solver as follows:</p><pre><code class="language-julia">uh = solve(solver,op)</code></pre><p>The <code>solve</code> function returns the computed numerical solution <code>uh</code>. This object is an instance of <code>FEFunction</code>, the type used to represent a function in a FE space. We can inspect the result by writing it into a <code>vtk</code> file:</p><pre><code class="language-julia">writevtk(Ω,&quot;results&quot;,cellfields=[&quot;uh&quot;=&gt;uh])</code></pre><p>which will generate a file named <code>results.vtu</code> having a nodal field named <code>&quot;uh&quot;</code> containing the solution of our problem (see next figure).</p><p><img src="../../assets/poisson/fig_uh.png" alt/></p><h2 id="References-1"><a class="docs-heading-anchor" href="#References-1">References</a><a class="docs-heading-anchor-permalink" href="#References-1" title="Permalink"></a></h2><p>[1] C. Johnson. <em>Numerical Solution of Partial Differential Equations by the Finite Element Method</em>. Dover Publications, 2009.</p><hr/><p><em>This page was generated using <a href="https://github.com/fredrikekre/Literate.jl">Literate.jl</a>.</em></p></article><nav class="docs-footer"><a class="docs-footer-prevpage" href="../../">« Introduction</a><a class="docs-footer-nextpage" href="../t002_validation/">2 Code validation »</a></nav></div><div class="modal" id="documenter-settings"><div class="modal-background"></div><div class="modal-card"><header class="modal-card-head"><p class="modal-card-title">Settings</p><button class="delete"></button></header><section class="modal-card-body"><p><label class="label">Theme</label><div class="select"><select id="documenter-themepicker"><option value="documenter-light">documenter-light</option><option value="documenter-dark">documenter-dark</option></select></div></p><hr/><p>This document was generated with <a href="https://github.com/JuliaDocs/Documenter.jl">Documenter.jl</a> on <span class="colophon-date" title="Monday 16 June 2025 04:46">Monday 16 June 2025</span>. Using Julia version 1.10.9.</p></section><footer class="modal-card-foot"></footer></div></div></div></body></html>
19+
solver = LinearFESolver(ls)</code></pre><p><code>LinearFESolver</code> objects are built from a given algebraic linear solver. In this case, we use a LU factorization. Now we are ready to solve the FE problem with the FE solver as follows:</p><pre><code class="language-julia">uh = solve(solver,op)</code></pre><p>The <code>solve</code> function returns the computed numerical solution <code>uh</code>. This object is an instance of <code>FEFunction</code>, the type used to represent a function in a FE space. We can inspect the result by writing it into a <code>vtk</code> file:</p><pre><code class="language-julia">writevtk(Ω,&quot;results&quot;,cellfields=[&quot;uh&quot;=&gt;uh])</code></pre><p>which will generate a file named <code>results.vtu</code> having a nodal field named <code>&quot;uh&quot;</code> containing the solution of our problem (see next figure).</p><p><img src="../../assets/poisson/fig_uh.png" alt/></p><h2 id="References-1"><a class="docs-heading-anchor" href="#References-1">References</a><a class="docs-heading-anchor-permalink" href="#References-1" title="Permalink"></a></h2><p>[1] C. Johnson. <em>Numerical Solution of Partial Differential Equations by the Finite Element Method</em>. Dover Publications, 2009.</p><hr/><p><em>This page was generated using <a href="https://github.com/fredrikekre/Literate.jl">Literate.jl</a>.</em></p></article><nav class="docs-footer"><a class="docs-footer-prevpage" href="../../">« Introduction</a><a class="docs-footer-nextpage" href="../t002_validation/">2 Code validation »</a></nav></div><div class="modal" id="documenter-settings"><div class="modal-background"></div><div class="modal-card"><header class="modal-card-head"><p class="modal-card-title">Settings</p><button class="delete"></button></header><section class="modal-card-body"><p><label class="label">Theme</label><div class="select"><select id="documenter-themepicker"><option value="documenter-light">documenter-light</option><option value="documenter-dark">documenter-dark</option></select></div></p><hr/><p>This document was generated with <a href="https://github.com/JuliaDocs/Documenter.jl">Documenter.jl</a> on <span class="colophon-date" title="Wednesday 18 June 2025 23:39">Wednesday 18 June 2025</span>. Using Julia version 1.10.9.</p></section><footer class="modal-card-foot"></footer></div></div></div></body></html>

0 commit comments

Comments
 (0)