README.md 6.3 KB
Newer Older
Dennis Gläser's avatar
Dennis Gläser committed
1
2
<!--- Example picture --->
<p align="center">
Dennis Gläser's avatar
Dennis Gläser committed
3
    <img src="../../doc/img/example2_network.png" alt="frackit example 2" width="800"/>
Dennis Gläser's avatar
Dennis Gläser committed
4
5
6
7
8
9
10
</p>

Example 2
=========

In this exemplary application, a network of quadrilaterals, following the same
distributions as the network of [example 1][0], is created. However, in this
11
example we want to confine the network to a cylindrical domain (see image above).
Dennis Gläser's avatar
Dennis Gläser committed
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
We represent the domain via an instance of the internal cylinder class:

```cpp
// In this example we consider a cylindrical domain
Cylinder<ctype> domain(/*radius*/0.5, /*height*/1.0);
```

This creates an axis-aligned cylinder where the x- and y- axis form the basis of
the bottom face of the cylinder, while the cylinder axis is aligned with the
z-axis. Note that there are other ways to construct arbitrarily-oriented cylinders,
and for details on this we refer to the [class documentation][2].

In addition to constraints among entities of the different orientations, we also
want to enforce constraints with respect to the boundary of the cylindrical domain.
In this example, we simply reuse the constraints of entities of the same orientation
and write

```cpp
auto constraintsOnBoundary = constraintsOnSelf;
```

33
34
35
to create a new constraints object. We create this copy here to improve readability
of the code when evaluating the constraints.
Within the loop in which the entities are created,
Dennis Gläser's avatar
Dennis Gläser committed
36
37
38
39
40
41
42
43
these constraints are enforced:

```cpp
// we want to enforce constraints also w.r.t. to the cylinder boundary
if (!constraintsOnBoundary.evaluate(domain.topFace(), quad))
{ status.increaseRejectedCounter(); continue; }
if (!constraintsOnBoundary.evaluate(domain.bottomFace(), quad))
{ status.increaseRejectedCounter(); continue; }
Dennis Gläser's avatar
Dennis Gläser committed
44
if (!constraintsOnBoundary.evaluate(OCCUtilities::getShape(domain.lateralFace()), quad))
Dennis Gläser's avatar
Dennis Gläser committed
45
46
47
48
49
50
{ status.increaseRejectedCounter(); continue; }
```

As you can see, the `Cylinder` class provides functions for obtaining the representations
of the top, bottom and lateral boundaries. The top and bottom boundaries are represented
by instances of the `Disk` class, while the lateral surface is described by the class
Dennis Gläser's avatar
Dennis Gläser committed
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
`CylinderSurface`. Please also note that for the lateral surface, we enforce the constraints
using its representation in OpenCascade, which we obtain by calling `OCCUtilities::getShape`.
We could also write `if (!constraintsOnBoundary.evaluate(domain.lateralFace(), quad)) {...}`,
but the behaviour is different. This is because in the OpenCascade representation of cylindrical
surfaces, there is an edge connecting the upper and lower circles. This has implications on the
constraint regarding the minimum allowed length of intersection edges, as these possibly
intersect with the edge of the cylindrical surface. The figure below illustrates the intersections
of a fracture quadrilateral with both the internal and the OpenCascade representations of cylindrical
surfaces.

<!--- Intersection with cylinder, nternal vs OCC representation --->
<p align="center">
    <img src="../../doc/img/example2_isection.png" alt="frackit example 2 - cylindrical surface intersection" width="800"/>
</p>

As you can see, when the internal representation of cylindrical surfaces is used, the result
is a single intersection edge, while this edge is split into two sub-edges in case the
OpenCascade representation is used. As a result, when evaluating the constraints against
the OpenCascade representation of the cylindrical surface, the constraint on the minimum
allowed length of intersection edges is checked for each sub-edge. Thus, this approach should
be preferred when using cylindrical domains in order to detect small length scales originating
from intersections with the auxiliary edge used by OpenCascade.

Moreover, we want to reject all those quadrilaterals of which only
Dennis Gläser's avatar
Dennis Gläser committed
75
76
77
78
79
80
81
82
83
84
85
86
87
88
a very small portion is inside the cylinder. This is done in the lines

```cpp
const auto containedArea = computeContainedMagnitude(quad, domain);

// reject if this is too small (< 0.01 m^2)
if (containedArea < 0.01)
{ status.increaseRejectedCounter(); continue; }
```

where `computeContainedMagnitude()` is a free function that returns the length/area/volume
of the part of a geometry that is contained inside of another geometry.

Finally, after the desired number of entities has been created, we cast the entities
Dennis Gläser's avatar
Dennis Gläser committed
89
into an instance of the class `ContainedEntityNetwork`, using the corresponding builder class:
Dennis Gläser's avatar
Dennis Gläser committed
90
91
92
93
94
95
96
97
98
99

```cpp
ContainedEntityNetworkBuilder builder;

// define the domain (single sub-domain) and give it a unique id
builder.addConfiningSubDomain(domain, Id(1));
```

The class `ContainedEntityNetworkBuilder` returns an instance of a `ContainedEntityNetwork`
when the `build()` function is called (see below). This network implementation contains information
100
on sub-domains, and which entities are embedded in which sub-domain. Each sub-domain
Dennis Gläser's avatar
Dennis Gläser committed
101
receives a unique identifier by means of the `Id` class. By calling
102
103
104
`builder.addConfiningSubDomain(domain, Id(1))`, we define the sub-domain to be
confining, i.e. entities that are added to this sub-domain will be confined to it
by cutting away all parts that lie outside the sub-domain. In contrast to that,
Dennis Gläser's avatar
Dennis Gläser committed
105
one could call `builder.addSubDomain(domain, Id(1))`, in which case embedded networks
106
will not be confined (see [example 3][2]). Entities are associated with the sub-
Dennis Gläser's avatar
Dennis Gläser committed
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
domain they are embedded in, and are added to the builder class by writing

```cpp
// define entities to be embedded in this domain
builder.addSubDomainEntities(entitySet1, Id(1));
builder.addSubDomainEntities(entitySet2, Id(1));

const auto network = builder.build();
```

The variable `network` now holds an instance of the `ContainedEntityNetwork`,
which we can also pass to the `GmshWriter`:

```cpp
GmshWriter writer(network);
writer.write("network", // filename of the .geo files (will add extension .geo automatically)
             0.1,       // element size to be used on the quadrilaterals
             0.2);      // element size to be used in the domain away from the quadrilaterals
```

As you can see, one can specify different mesh sizes to be used on the fracture
entities and in the rest of the domain.

130
131
[go to example 3][2]

Dennis Gläser's avatar
Dennis Gläser committed
132
133
134
[0]: https://git.iws.uni-stuttgart.de/DennisGlaeser/frackit/tree/master/appl/example1
[1]: https://git.iws.uni-stuttgart.de/DennisGlaeser/frackit/tree/master/geometry/cylinder.hh
[2]: https://git.iws.uni-stuttgart.de/DennisGlaeser/frackit/tree/master/appl/example3