Skip to content

Commit 22a8796

Browse files
authored
Merge pull request #192 from gridap/geometry
Improved geometry tutorial
2 parents 3adbf7d + 7e6f447 commit 22a8796

File tree

3 files changed

+110
-24
lines changed

3 files changed

+110
-24
lines changed

README.md

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,16 @@
22

33
*Start solving PDEs in Julia*
44

5-
65
| **Documentation** |
76
|:------------ |
87
| [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://gridap.github.io/Tutorials/stable) [![](https://img.shields.io/badge/docs-dev-blue.svg)](https://gridap.github.io/Tutorials/dev) |
98
|**Build Status** |
109
| [![Build Status](https://github.com/gridap/Tutorials/workflows/CI/badge.svg?branch=master)](https://github.com/gridap/Tutorials/actions?query=workflow%3ACI) |
1110
| **Community** |
12-
| [![Join the chat at https://gitter.im/Gridap-jl/community](https://badges.gitter.im/Gridap-jl/community.svg)](https://gitter.im/Gridap-jl/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) |
11+
| [![Join the chat at https://gitter.im/Gridap-jl/community](https://badges.gitter.im/Gridap-jl/community.svg)](https://gitter.im/Gridap-jl/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat in Slack](https://img.shields.io/badge/chat-on_slack-purple?style=flat&logo=slack&logoColor=white)(https://julialang.slack.com/archives/C02AK382QSG)]|
1312
| **Citation** |
1413
| [![DOI](https://joss.theoj.org/papers/10.21105/joss.02520/status.svg)](https://doi.org/10.21105/joss.02520) |
1514

16-
17-
18-
1915
## What
2016

2117
This repo contains a set of tutorials to learn how to solve partial differential equations (PDEs) in Julia with the Gridap ecosystem of packages. At the root of this ecosystem is the [Gridap.jl](https://github.com/gridap/Gridap.jl) library. The initial tutorials illustrate the usage of the tools in [Gridap.jl](https://github.com/gridap/Gridap.jl), and these are the tutorials new users should focus on.
@@ -35,7 +31,7 @@ Visit one of the following pages, depending of your needs, and start enjoying!
3531
- [**STABLE**](https://gridap.github.io/Tutorials/stable) — **Tutorials for the most recently tagged version of Gridap.jl.**
3632
- [**DEVEL**](https://gridap.github.io/Tutorials/dev) — *Tutorials for the in-development version of Gridap.jl.*
3733

38-
## Generating tutorials locally
34+
## Generating tutorials locally
3935

4036
Note: **only if you intend to contribute to the tutorials as an advanced user/developer**
4137

@@ -55,12 +51,11 @@ and then, each time that you perform a change on the tutorial sources, you have
5551
julia --project=docs docs/make.jl # From the Unix shell, located at the root of Tutorials repo
5652
```
5753

58-
to generate the tutorials. The files generated are available at `Tutorials/docs/build/`.
59-
54+
to generate the tutorials. The files generated are available at `Tutorials/docs/build/`.
6055

6156
## Gridap community
6257

63-
Join to our [gitter](https://gitter.im/Gridap-jl/community) chat to ask questions and interact with the Gridap community.
58+
Join to our [gitter](https://gitter.im/Gridap-jl/community) or [slack](https://julialang.slack.com/archives/C02AK382QSG) chats to ask questions and interact with the Gridap community.
6459

6560
## How to cite Gridap
6661

@@ -83,7 +78,4 @@ In order to give credit to the `Gridap` contributors, we simply ask you to cite
8378

8479
## Contact
8580

86-
8781
Please, contact the project administrators, [Santiago Badia](mailto:[email protected]) and [Francesc Verdugo](mailto:[email protected]), for further questions about licenses and terms of use.
88-
89-

src/geometry_dev.jl

Lines changed: 106 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# - How to extract geometrical information from a `Grid`.
77
# - How periodicity is handled in Gridap, and the difference between nodes and vertices.
88
# - How to create a periodic model from scratch, use the example of a Mobius strip.
9+
# - How to create and manipulate `FaceLabeling` objects, which are used to handle boundary conditions.
910
#
1011
# ## Required Packages
1112

@@ -21,19 +22,20 @@ using Plots
2122
# 4. Geometric Mappings
2223
# 5. High-order Grids
2324
# 6. Periodicity in Gridap
25+
# 7. FaceLabelings
2426
#
2527
# ## 1. Utility Functions
2628
# We begin by defining helper functions that will be essential throughout this tutorial.
2729
# These functions help us visualize and work with our mesh structures.
2830

29-
# Convert a CartesianDiscreteModel to an UnstructuredDiscreteModel for more generic handling
31+
# Convert a `CartesianDiscreteModel` to an `UnstructuredDiscreteModel` for more generic handling.
3032
function cartesian_model(args...; kwargs...)
3133
UnstructuredDiscreteModel(CartesianDiscreteModel(args...; kwargs...))
3234
end
3335

34-
# Visualization function to plot nodes with their IDs
35-
# Input: node_coords - Array of node coordinates
36-
# node_ids - Array of corresponding node IDs
36+
# Visualization function to plot nodes with their IDs. Input:
37+
# - node_coords: Array of node coordinates.
38+
# - node_ids: Array of corresponding node IDs.
3739
function plot_node_numbering(node_coords, node_ids)
3840
x = map(c -> c[1], node_coords)
3941
y = map(c -> c[2], node_coords)
@@ -43,8 +45,8 @@ function plot_node_numbering(node_coords, node_ids)
4345
vline!(unique(y), linestyle=:dash, color=:grey)
4446
end
4547

46-
# Overloaded method to plot node numbering directly from a model
47-
# This function extracts the necessary information from the model and calls the base plotting function
48+
# Overloaded method to plot node numbering directly from a model.
49+
# This function extracts the necessary information from the model and calls the base plotting function.
4850
function plot_node_numbering(model)
4951
D = num_cell_dims(model)
5052
topo = get_grid_topology(model)
@@ -83,15 +85,15 @@ end
8385
#
8486
# ### Key Concept: Nodes vs. Vertices
8587
#
86-
# One of the most important distinctions in Gridap is between nodes and vertices:
88+
# A very important distinction in Gridap is between nodes and vertices:
8789
#
8890
# - **Vertices** (Topological entities):
8991
# * 0-dimensional entities in the `GridTopology`
9092
# * Define the connectivity of the mesh
9193
# * Used for neighbor queries and mesh traversal
9294
# * Number of vertices depends only on topology
9395
#
94-
# - **Nodes** (Geometric entities):
96+
# - **Nodes** (Geometrical entities):
9597
# * Control points stored in the `Grid`
9698
# * Define the geometry of elements
9799
# * Used for interpolation and mapping
@@ -180,10 +182,10 @@ node_coordinates = get_node_coordinates(grid) # Physical coordinates of nodes
180182
#
181183
# There are two ways to get the coordinates of nodes for each cell:
182184
#
183-
# 1. Using standard Julia mapping:
185+
# A) Using standard Julia mapping:
184186
cell_to_node_coords = map(nodes -> node_coordinates[nodes], cell_to_nodes)
185187

186-
# 2. Using Gridap's lazy evaluation system (more efficient for large meshes):
188+
# B) Using Gridap's lazy evaluation system (more efficient for large meshes):
187189
cell_to_node_coords = lazy_map(Broadcasting(Reindex(node_coordinates)),cell_to_nodes)
188190

189191
# ### Geometric Mappings
@@ -230,7 +232,7 @@ writevtk(new_grid,"half_cylinder_linear")
230232
# our half-cylinder looks faceted. This is because we're still using linear elements
231233
# (straight edges) to approximate the curved geometry.
232234
#
233-
# ### Solution: High-order Elements
235+
# ### Example: High-order Elements
234236
#
235237
# To accurately represent curved geometries, we need high-order elements:
236238

@@ -389,3 +391,96 @@ mobius = UnstructuredDiscreteModel(grid,topo,labels)
389391
# Visualize the vertex numbering:
390392
plot_node_numbering(mobius)
391393
# ![](../assets/geometry/mobius.png)
394+
395+
# ## 7. FaceLabelings and boundary conditions
396+
#
397+
# The `FaceLabeling` component of a `DiscreteModel` is the way Gridap handles boundary conditions.
398+
# The basic idea is that, similar to Gmsh, we classify the d-faces (cells, faces, edges, nodes) of the mesh
399+
# into different entities (physical groups in Gmsh terminology) which in turn have one or more
400+
# tags/labels associated with them.
401+
# We can then query the `FaceLabeling` for the tags associated with a given d-face,
402+
# or the d-faces associated with a given tag.
403+
#
404+
# We will now explore ways to create and manipulate `Facelabeling` objects.
405+
#
406+
# ### Creating FaceLabelings
407+
#
408+
# The simplest way to create a blank `FaceLabeling` is to use your `GridTopology`:
409+
#
410+
411+
model = cartesian_model((0,1,0,1),(3,3))
412+
topo = get_grid_topology(model)
413+
414+
labels = FaceLabeling(topo)
415+
416+
# The above `FaceLabeling` is by default created with 2 entities and 2 tags, associated to
417+
# interior and boundary d-faces respectively. The boundary facets are chosen as the ones
418+
# with a single neighboring cell.
419+
#
420+
# We can extract the low-level information from the `FaceLabeling` object:
421+
422+
tag_names = get_tag_name(labels) # Each name is a string
423+
tag_entities = get_tag_entities(labels) # For each tag, a vector of entities
424+
cell_to_entity = get_face_entity(labels,2) # For each cell, its associated entity
425+
edge_to_entity = get_face_entity(labels,1) # For each edge, its associated entity
426+
node_to_entity = get_face_entity(labels,0) # For each node, its associated entity
427+
428+
# It is usually more convenient to visualise it in Paraview by exporting to vtk:
429+
430+
writevtk(model,"labels_basic",labels=labels)
431+
432+
# Another useful way to create a `FaceLabeling` is by providing a coloring for the mesh cells,
433+
# where each color corresponds to a different tag.
434+
# The d-faces of the mesh will have all the tags associated to the cells that share them.
435+
436+
cell_to_tag = [1,1,1,2,2,3,2,2,3]
437+
tag_to_name = ["A","B","C"]
438+
labels_cw = Geometry.face_labeling_from_cell_tags(topo,cell_to_tag,tag_to_name)
439+
writevtk(model,"labels_cellwise",labels=labels_cw)
440+
441+
# We can also create a `FaceLabeling` from a vertex filter. The resulting `FaceLabeling` will have
442+
# only one tag, gathering the d-faces whose vertices ALL fullfill `filter(x) == true`.
443+
444+
vfilter(x) = abs(x[1]- 1.0) < 1.e-5
445+
labels_vf = Geometry.face_labeling_from_vertex_filter(topo, "top", vfilter)
446+
writevtk(model,"labels_filter",labels=labels_vf)
447+
448+
# `FaceLabeling` objects can also be merged together. The resulting `FaceLabeling` will have
449+
# the union of the tags and entities of the original ones.
450+
# Note that this modifies the first `FaceLabeling` in place.
451+
452+
labels = merge!(labels, labels_cw, labels_vf)
453+
writevtk(model,"labels_merged",labels=labels)
454+
455+
# ### Creating new tags from existing ones
456+
#
457+
# Tags in a `FaceLabeling` support all the usual set operation, i.e union, intersection,
458+
# difference and complementary.
459+
460+
cell_to_tag = [1,1,1,2,2,3,2,2,3]
461+
tag_to_name = ["A","B","C"]
462+
labels = Geometry.face_labeling_from_cell_tags(topo,cell_to_tag,tag_to_name)
463+
464+
# Union: Takes as input a list of tags and creates a new tag that is the union of all of them.
465+
Geometry.add_tag_from_tags!(labels,"A∪B",["A","B"])
466+
467+
# Intersection: Takes as input a list of tags and creates a new tag that is the intersection of all of them.
468+
Geometry.add_tag_from_tags_intersection!(labels,"A∩B",["A","B"])
469+
470+
# Complementary: Takes as input a list of tags and creates a new tag that is the complementary of the union.
471+
Geometry.add_tag_from_tags_complementary!(labels,"!A",["A"])
472+
473+
# Set difference: Takes as input two lists of tags (tags_include - tags_exclude)
474+
# and creates a new tag that contains all the d-faces that are in the first list but not in the second.
475+
Geometry.add_tag_from_tags_setdiff!(labels,"A-B",["A"],["B"]) # set difference
476+
477+
writevtk(model,"labels_setops",labels=labels)
478+
479+
# ### FaceLabeling queries
480+
#
481+
# The most common way of query information from a `FaceLabeling` is to query a face mask for
482+
# a given tag and face dimension. If multiple tags are provided, the union of the tags is returned.
483+
484+
face_dim = 1
485+
mask = get_face_mask(labels,["A","C"],face_dim) # Boolean mask
486+
ids = findall(mask) # Edge IDs

src/stokes_blocks.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# # Incompressible Stokes equations in a 2D/3D cavity
21
#
32
# This example solves the incompressible Stokes equations, given by
43
#

0 commit comments

Comments
 (0)