Transformations, extrusions and other operations#
Geometrical transformations#
XLiFE++ allows you to apply geometrical transformations on Mesh
, Geometry
and Geometry
children objects.
The main type is Transformation
. It can be a canonical transformation or a composition of transformations.
Canonical transformations#
In the following, we will consider straight lines and planes. A straight line is fully defined by a point and a direction. The latter is a vector of components (2 or 3). This is a reason why we will write a straight line as follows : \(\left(\Omega, \vec{d}\right)\). A plane is fully defined by a point and a normal vector. This is a reason why we will write a plane as follows : \(\left[\Omega, \vec{n}\right]\).
All canonical transformations are related to classes inheriting from the Transformation
class and the way to define them is based on a key-value system.
Translations#
Point P is the image of point M by a translation of vector \(\vec{u}\) if and only if
A translation can be defined by a vector (size 1, 2 or 3) or by its components, thanks to the key _direction
:
Reals u;
Real ux, uy, uz;
Translation t1(_direction=u), t2(_direction={ux, uy, uz});
Important
Default value for _direction
is the 3D zero vector. In the second syntax, uy
and uz
can be omitted too. If so, their default value is 0.
2D rotations#
Point P is the image of point M by the 2D rotation of center \(\Omega\) and of angle \(\theta\) if and only if
A 2D rotation is defined by a point and an angle (in radians), thanks to keys _center
and _angle
:
Point omega;
Real angle;
Rotation2d r(_center=omega, _angle=angle);
Important
Default value for _center
is the 2D zero vector. Default value for _angle
is 0.
3D rotations#
Point P is the image of point M by the 3D rotation of axis \(\left(\Omega, \vec{d}\right)\) and of angle \(\theta\) (in radians) if and only if
where \(\displaystyle \vec{n}=\dfrac{\vec{d}}{||\vec{d}||}\) (the unitary direction).
A 3D rotation is defined by a point, a direction vector and an angle (in radians), thanks to keys _center
, _axis
and _angle
:
Point omega;
Reals d;
Real dx, dy, dz;
Real theta;
Rotation3D r1(_center=omega, _axis=d, _angle=theta), r2(_center=omega, _axis={dx, dy, dz}, _angle=theta);
Important
Default value for _center
and _axis
is the 3D zero vector. Default value for _angle
is 0. In the second syntax, dz
can be omitted. If so, its default value is 0.
Homotheties#
Point P is the image of point M by the homothety of center \(\Omega\) and of factor \(k\) if and only if
A homothety is defined by a point and a scale factor, thanks to keys _center
and _scale
:
Point omega(1.,2.,3.);
Real k=2.;
Homothety h(_center=omega, _scale=k);
Important
Default value for _scale
is 1. Default value for _center
is the 3D zero vector.
Point reflections#
Point P is the image of point M by the point reflection of center \(\Omega\) if and only if
It is a homothety of factor -1 and same center.
Point omega(1.,2.,3.);
PointReflection h(_center=omega); // omega can still be omitted, as for homothety
2D reflections#
Point P is the image of point M by the 2D reflection of axis \(\left(\Omega,\vec{d}\right)\) if and only if
where \(H\) is the orthogonal projection of \(M\) on \(\left(\Omega,\vec{d}\right)\)
A 2D reflection is then defined by a Point and a vector defining an axis, thanks to keys _center
and _direction
:
Point omega(1.,2.,3.);
Vector<Real> d(1.,0.,0.);
Real dx=1., dy=0.;
Reflection2d r1(_center=omega, _direction=d), r2(_center=omega, _direction={dx, dy});
Important
Default value for _direction
is the 2D zero vector. Default value for _center
is the 2D zero point.
3D reflections#
Point P is the image of point M by the 3D reflection of plane \(\left[\Omega,\vec{n}\right]\) if and only if
where \(H\) is the orthogonal projection of \(M\) on plane \(\left[\Omega,\vec{n}\right]\).
A 3D reflection is then defined by a Point and a normal vector defining a plane, thanks to keys _center
and _normal
:
Point omega(1.,2.,3.);
Vector<Real> n;
Real nx, ny, nz;
Reflection3d r1(_center=omega, _normal=n), r2(_center=omega, _normal={nx, ny, nz});
Important
Default value for _normal
is the 3D zero vector. Default value for _center
is the 3D zero point.
Linear transformations#
Any linear transformation can be set from its matrix-vector (\(x\rightarrow \mathbb{A}x+b\)) using the following Transformation
constructors:
Transformation(const Matrix<Real>& A, const Vector<Real>& b = Vector<Real>(3,0.))
Transformation(Real a11, Real a12, Real a13, Real a21, Real a22, Real a23,
Real a31, Real a32, Real a33, Real b1=0, Real b2=0, Real b3=0);
Note
The matrix representation of a transformation can be accessed using the member functions mat()
and vec()
. Matrix representations are also available for canonical geometries.
Composition of transformations#
To define a composition of transformations, use the operator * between canonical transformations, an is the following example:
Rotation2d r1(_center=Point(0.,0.), _angle=120.);
Reflection2d r2(_center=Point(1.,-1.), _axis={1.,2.5, -3.});
Translation t1(_direction={-1.,4.});
Homothety h (_center=Point(-1.,0.), _scale=-3.2);
Transformation t = r1*h*r2*t1;
Composition * has to be understood as usual composition operator \(\circ\) : \(t(P)=r1(h(r2(t1(P))))\).
Note
The matrix representation (mat()
and vec()
member functions) is available for composition of transformations.
Transformations on Point, geometries and Mesh#
How to apply a transformation ?#
On Point and geometries#
Transformations can be applied on every canonical geometry, composite geometry or loop geometry. The only exceptions are Rotation2d
and Reflection2d
for 3D geometries, as they are meaning less in theses cases.
In the following, to illustrate application of transformations, we will use Segment
.
The general case is to use transform()
:
-
either as a member function, to modify the object on which the transformation is applied
Segment s; s.transform(Translation(_direction={0.,0.,1.}));
Warning
This is only available for geometries, not for
Point
-
or as an external function, to build a new object next to the one on which the transformation is applied
Segment s; Segment s2 = transform(s, Translation(_direction={0.,0.,1.}));
Shortcuts are naturally available in both contexts (only the external functions for Point
) with routines translate()
, rotate2d()
, rotate3d()
, homothetize()
, pointReflect()
, reflect2d()
and reflect3d()
.
These routines also work with a key-value system, the same as the corresponding transformation object:
Segment s;
Segment s2 = translate(s, _direction={0.,0.,1.});
s.translate(_direction={0.,0.,1.});
On meshes#
On Mesh
objects, transformations apply in the same way as geometries and points (See above).
Mesh m;
Mesh m2 = translate(m, _direction={0.,0.,1.});
m.translate(_direction={0.,0.,1.});
There is a little difference concerning the external shortcuts, in so are as additional keys can be used: _name
to set the Mesh
name (as in every Mesh
constructor), and _suffix
to add a suffix to every domain name. In the following code sample, plain domain in Mesh
m2 will be S_prime and side domains will be Sigma_prime and Gamma_prime:
Mesh m(Segment(_v1=Point(0.,0.), _v2=Point(1.,2.), _domain_name="S"), _nnodes=10, _side_names={"Sigma, "Gamma"});
Mesh m2 = translate(m, _direction={0.,1.}, _name="Translation of m", _suffix="prime");
What does a transformation really do ?#
Applying a transformation to an object means computing the image of each point defining the object.
It also calls the transformation routine on some underlying objects, such as the Geometry
pointer in a Mesh
, or the BoundingBox
and the MinimalBox
in a Geometry
.
Extrusions of geometries and meshes#
This is another way to define geometries: by extrusion of geometries of lesser dimension. Extruded geometries can be surfaces or volumes, defined by a geometry (the section of the extruded geometry) and a geometrical transformation. This feature can be used to generate meshes with the GMSH interface with some restrictions about the transformation : only translations or rotations are authorized. There is also another parameter : the number of layers. Let’s see the following figures:
On the left, extrusion of a disk by a translation, with 3 layers. On the right, extrusion of a circular arc by rotation, with 4 layers
Extrusion of geometries#
It is possible to extrude a 1D or a 2D geometry, applying a Transformation
(Translation, Rotation, …) using the routine extrude()
. More precisely, you can extrude:
-
a canonical geometry (1D or 2D). Here, a
CircArc
:Point b(1.5,-4.,0.); Point c(2.,-3.5,0.); CircArc g(_center=Point(1.5,-3.5,0.), _v1=b, _v2=c, _nnodes=5, _domain_name="BC"); Geometry e2D=extrude(g, Translation(_direction={0.,0.,4.}), _layers=5, _domain_name="Omega");
-
a loop geometry (1D or 2D). Here, a rounded rectangle defines as in Definition of a geometry from its boundary:
Point a(-1.5,-4.,0.); Point b(1.5,-4.,0.); Point c(2.,-3.5,0.); Point d(2.,3.5,0.); Point e(1.5,4.,0.); Point f(-1.5,4.,0.); Point g(-2.,3.5,0.); Point h(-2.,-3.5,0.); Segment s1(_v1=a, _v2=b, _nnodes=21, _domain_name="AB"); CircArc c1(_center=Point(3.5,0.5,0.), _v1=b, _v2=c, _nnodes=5, _domain_name="BC"); Segment s2(_v1=c, _v2=d, _nnodes=11, _domain_name="CD"); CircArc c2(_center=Point(3.5,1.5,0.), _v1=d, _v2=e, _nnodes=5, _domain_name="DE"); Segment s3(_v1=e, _v2=f, _nnodes=21, _domain_name="EF"); CircArc c3(_center=Point(0.5,1.5,0.), _v1=f, _v2=g, _nnodes=5, _domain_name="FG"); Segment s4(_v1=g, _v2=h, _nnodes=11, _domain_name="GH"); CircArc c4(_center=Point(0.5,0.5,0.), _v1=h, _v2=a, _nnodes=5, _domain_name="HA"); Geometry g=planeSurfaceFrom(s1+c1+s2+c2+s3+c3+s4+c4,"Omega"); Geometry e3d=extrude(g, Translation(_direction={0.,0.,4.}), _layers=10, _domain_name="Omega");
-
Every composite geometry composed exclusively of a geometry and its holes (1D or 2D). That is to say only operator- or operator-= is used to define the geometry:
Ellipse e1(_center=Point(0.,0.,0.), _v1=Point(4,0.,0.), _v2=Point(0.,5.,0.), _nnodes=12, _domain_name="Omega1", _side_names=Strings("Gamma_1","Gamma_2","Gamma_3","Gamma_4")); Ellipse e2(_center=Point(1.,2.,0.), _v1=Point(1.5,2.,0.), _v2=Point(1.,3.,0.), _nnodes=12, _domain_name="Omega3", _side_names=Strings("Gamma_9","Gamma_10","Gamma_11","Gamma_12")); Geometry e3d2=extrude(e1-e2, Rotation3d(_center=Point(5.,0.,0.), _axis={0.,5.,0.}, _angle=pi_/2.), _layers10, _domain_name="Omega", _side_names="Gamma");
How to define names of lateral domains of an extrusion ?#
Instead of giving the same name to every lateral surface of an extrusion, it is possible to name each of them, but what about sides numbering ?
First example, let’s take the extrusion of a CircArc
:
Point b(1.5,-4.,0.);
Point c(2.,-3.5,0.);
CircArc g(_center=Point(1.5,-3.5,0.), _v1=b, _v2=c, _nnodes=5, _domain_name="BC");
Geometry e2D=extrude(g, Translation(_direction={0.,0.,4.}), _layers=5, _domain_name="Omega", _side_names=Strings("Gamma1", "Gamma2"));
Point b is the front below left corner and point c is the front top right corner of the circular arc g. As g is defined from b to c, the first lateral side, corresponding to domain Gamma1, will be the edge below, starting from b. If g was defined from c to b, Gamma1 would have corresponded to the edge above, starting from c.
Second example, let’s take the extrusion of an ellipse with an elliptical hole:
Ellipse e1(_center=Point(0.,0.,0.), _v1=Point(4,0.,0.), _v2=Point(0.,5.,0.), _nnodes=12, _domain_name="Omega1");
Ellipse e2(_center=Point(1.,2.,0.), _v1=Point(1.5,2.,0.), _v2=Point(1.,3.,0.), _nnodes=12, _domain_name="Omega3");
Geometry e3d3=extrude(e1-e2, Rotation3d(_center=Point(5.,0.,0.), _axis={0.,5.,0.}, _angle=pi_/2.), _layers=10, _domain_nae="Omega", _side_names={"Gamma1", "Gamma2", "Gamma3", "Gamma4", "Gamma5", "Gamma6", "Gamma7", "Gamma8});
This time, lateral surfaces are ordered as follows:
Lateral surfaces from the outer ellipse are ordered the same way as borders of the ellipse. They will become Gamma1, Gamma2, Gamma3 and Gamma4.
Lateral surfaces from the inner ellipse (and every hole in general) are ordered in the reverse order of borders of the ellipse. They will become Gamma5, Gamma6, Gamma7 and Gamma8.
Tip
Contrary to Gmsh, extrusion of a geometry by rotation of angle greater than \(\pi\) is available, by splitting extrusion in 2 half extrusions when angle is not \(2\pi\) or in 4 quarter extrusions when angle is \(2\pi\). As a result, the number of lateral surfaces is multiplied by 2 or 4.
Extrusion of a mesh#
As an alternative to mesh an extruded geometry, it is possible to extrude a 1D or a 2D mesh, applying a Transformation
(Translation, Rotation, …) using the routine extrude()
:
Mesh mdi(Disk(_center=Point(0.,0.),_radius=1.,_nnodes=8),_shape=_triangle);
Mesh m=extrude(mdi, Rotation3d(_center=Point(3.,0.,0.), _axis={0.,1.,0.}, _angle=2*pi_/40), _layers=40);
Here a 3D rotation of angle \(\frac{\pi}{20}\) is applied to each section and _layers
key-value specifies the number of layers (40). Note that in that case, a full turn is done and the last section coincides with the first section, the nodes being not duplicated.
The transformation may be a basic transformation (translation, rotation, …) or a combination of transformations (see Geometrical transformations for more details):
Mesh mr(Rectangle(_xmin=0, _xmax=1, _ymin=1, _ymax=3, _nnodes=Numbers(6, 10)), _shape=_triangle, _order=1, _generator=_structured);
Mesh m=extrude(mr, Translation(0.,0.1,0.)*Rotation3d(Point(3.,0.,0.), Reals(0.,1.,0.), 2.5*pi_/100), _layers=100);
The extruded mesh is a mesh of:
quadrangles if the section mesh is 1D,
prisms if the section mesh is made of triangles,
hexahedra if the section mesh is made of quadrangles.
Instead of specifying a transformation, it is possible to specify the list of transformations to apply to the sections.
Mesh mr(Rectangle(_xmin=0, _xmax=1, _ymin=1, _ymax=3, _nnodes=Numbers(6, 10)), _shape=_triangle, _order=1, _generator=_structured);
Translation tran(_direction={0.2,0.,0.});
Rotation3d rot1(_center=Point(3.,0.,0.), _axis={0.,1.,0.}, _angle=pi_/40);
Rotation3d rot2(_center=Point(5.,0.,6.), _axis={0.,1.,0.}, _angle=-pi_/40);
std::vector<Transformation*> trs(50);
for (number_t i=0;i<20;i++) { trs[i]=&rot1; trs[i+30]=&rot2; }
for (number_t i=0;i<10;i++) { trs[i+20]=&tran; }
Mesh m=extrude(mesh2DP1, trs, _naming_domain=1);
To deal with more general extrusions, a C++ function giving the parametrization of the extrusion path: \(t\in[0,1]\rightarrow \gamma(t)\in \mathbb R^d\) can be given. Be caution, the parametrization has to statisfy \(\gamma(0)=0\) and \(\gamma'(0)=n_s\) where \(n_s\) is the normal vector to the section to be extruded. The extrusion works as following:
the nodes \(M_0\) of section \(S_0\) are translated: \(M_k=M_0+\gamma(\frac{k}{n})\)
then, a rotation defined from the center \(C_k=C_0+\gamma(\frac{k}{n})\) and the two vectors \(n_0,\ \gamma'(\frac{k}{n})\) is applied to the nodes \(M_k\)
By default, the rotation center \(C_0\) is the barycenter of all nodes of the section \(S_0\), but it can be changed using the key-value _center
. Note that this process guarantees that all sections are orthogonal to the extrusion curve.
Reals gamma(const Point& P, Parameters& par, DiffOpType dop)
{
real_t t=P(1);
if (dop==_dt) return Reals{16*pi_*std::sin(4*pi_*t), 0., 40.};
return Reals{2*(1-std::cos(4*pi_*t)), 0., 40*t};
}
Mesh mdi(Disk(_center=Point(0.,0.), _radius=1., _nnodes=8), _shape=_triangle, _generator=subdiv);
Mesh m=extrude(mdi, gamma, _layers=100);
Tip
The orientation of normal vector to the section to be extruded is not predictable. But using the routine setNormalOrientation()
it can be set:
Mesh mdi(Disk(_center=Point(0.,0.),_radius=1.,_nnodes=8),_shape=_triangle);
mdi.domain(0).setNormalOrientation(_towardsInfinite,Point(0.,0.,-1.));
where the given point (here (0.,0.,-1.)) specifies an ‘interior’ point.
Danger
If curvature radius is too small compared to the section size, the extrusion process may lead to incoherent domain!
extrude()
manages the following key-values:
_layers
to give the number of layers (mandatory)_center
to give the center of rotation when using a curve parametrization (computed by default)_init_transformation
to specify a transformation to apply to the reference section before extruding it (none by default)_naming_domain
to control the naming of domains (0,1 or 2)_naming_section
to control the naming of sections (0,1 or 2)_naming_side
to control the naming of boundaries (0,1 or 2)
The meaning of the naming level is
0: domains/sections/boundaries are not created
1: one extruded domain/section/boundary is created for any domain/section/boundary of the original section
2: for each layer, one extruded domain/section/boundary is created for any domain/section/boundary of the original section
Be cautious, the side domains of extruded domain are created from the side domains of the given section. Thus, if the given section has no side domains, the extruded domains will have no side domain! The naming convention is the following:
Domains and side domains keep their name with the extension “_e” or “_e1”, “_e2”, …, “_en”
Section domains have the name of original domains with the extension “_0”, …, “_n”
When
_naming_domain=0
, the full domain is always created and named “Omega”.
The following figure illustrates the naming rules of domains.
For instance, to mesh a tubular domain using the mesh extrusion of a crown:
Disk dext(_center=Point(0.,0.), _radius=1., _nnodes=20, _domain_name="Omega", _side_names="Sigma");
Disk dint(_center=Point(0.,0.), _radius=0.5, _nnodes=10, _side_names="Gamma");
Mesh crown(dext-dint, _generator=gmsh);
Mesh tube(crown, Translation(_direction={0,0,.1}), _layers=10, _naming_domain=1, _naming_section=1, _naming_side=1);
Example: definition of a conesphere#
To define geometries based on cones, extrusions have to be used. It is the case for the conesphere:
Real rb=1., hc=3.;
Real hs=rb*rb/hc;etrahedra
Real rs=sqrt(rb*rb + hs*hs);
Point origin(0.,0.,0.), apex(0.,0.,hc), p1(rb,0.,0.), p2(0.,0.,-hs-rs);
Segment s1(_v1=p1, _v2=apex, _hsteps=0.05);
Segment s2(_v1=apex, _v2=origin, _hsteps=0.05);
Segment s3(_v1=origin, _v2=p2, _hsteps=0.05);
CircArc c1(_center=Point(0.,0.,-cssphereheight), _v1=p2, _v2=p1, _hsteps=0.05);
Disk d1(_center=0.5*p1, _v1=0.5*p1+Point(0.2*rb,0.,0.), _v2=0.5*p1+Point(0.,0.,0.2*rb), _domain_name="Sigma", _hsteps=0.05);
Geometry base=planeSurfaceFrom(s2+s3+c1+s1, "Gamma");
Geometry g=extrude(base, Rotation3d(_center=Point(0.,0.,0.), _axis={0.,0.,1.}, _angle=2.*pi_), _domain_name="Omega1", _side_names={"Gamma1", "Gamma2", "Gamma3", "Gamma4", "Gamma5", "Gamma6", "Gamma7", "Gamma8"});
Other Mesh operations#
Mesh refinement#
It is possible to refine an existing mesh of order 1: a new mesh is created using the subdivision generator mentioned above. It is a uniform refinement, say, all the elements are subdivided in a same way. The corresponding constructor is defined as follows:
Disk d(_center=Point(0.,0.),_radius=1.,_nnodes=5);
Mesh md(d,_generator=gmsh,_shape=triangle);
Mesh md1(md,_refinement_depth=1);
Mesh md2(md,_refinement_depth=2);
This builds the meshes md2
and md2
which are obtained by subdividing, respectively, once and twice the mesh md
:
The optional keys are:
_refinement_depth
: the refinement depth of the subdivision generator. 0 means no refinement (the default value).
_order
: by using it, it possible to increase the order of the refined mesh (defaut value is 1).
Note
Up to now, there is no adaptative refinement tool!
Splitting mesh element#
Sometimes it may be useful to split elements into elements of another type, for instance to produce mesh of pyramids that are not provided by standard meshing software products. To do this, the routine split()
is available:
Cuboid c(_xmin=0,_xmax=1,_ymin=1,_ymax=3,_zmin=1,_zmax=5,_nnodes={3, 5, 9});
Mesh meshQ1(c, _shape=hexahedron, _generator=structured, _name="Q1 mesh");
Mesh meshPyramid=split(meshQ1, pyramid, "Py1 mesh");
Note
Up to now, only one splitting process is available: hexahedron of order 1 into six pyramids of order 1, based on the hexahedron faces and the centroid of the hexahedron as tip.
Merging meshes#
It is possible to merge some meshes of same dimension. They can share common parts or common boundaries but with same elements/nodes. If elements or nodes on common parts do not coincide, the resulting mesh would not be conform to do finite element approximations. The merging process combines the elements and nodes of the meshes, eliminating duplicate elements or duplicate nodes. Domains with same name are also merged, names being preserved. The new whole domain is created with default name #Omega or one given and shared boundary domains are merged on demand (default).
Mesh m1(...);
Mesh m2(...);
Mesh m3(...);
m1.merge(m2,[mergeSharedBoundary=true],[name="#Omega"]);//merging m2 with m1
m1.merge(m3,[mergeSharedBoundary=true],[name="#Omega"]);//merging m2, m3 with m1
Mesh m = merge(m1,m2,m3,[mergeSharedBoundary = true],[name = "#Omega"]);
// alternate syntax merging m1,m2 and m3 in a new mesh m (up to 5 meshes)
As an exemple:
Rectangle R1(_xmin=0, _xmax=1, _ymin=1, _ymax=3, _nnodes={6,10});
Rectangle R2(_xmin=1, _xmax=2, _ymin=1, _ymax=3, _nnodes={3, 5});
Mesh mP1(R1, _shape=triangle, _generator=structured, _name="P1 mesh");
Mesh mQ1(R2, _shape=quadrangle, _generator=structured, _name="Q1 mesh");
Mesh mP1Q1 = merge(mP1,mQ1);
Rectangle R3(_xmin=1, _xmax=2, _ymin=1, _ymax=3, _nnodes={6,10});
Mesh mQ1a(R3, _shape=quadrangle, _generator=structured, _name="Q1 mesh a");
mP1Q1 = merge(mP1,mQ1a);
In merging process, the following rules are applied:
all named domains of original meshes are preserved, with the same names,
if two different domains have the same name, say domname, they are merged together
-
if two side domains define an interface and do not have the same name, say domname1 and domname2:
if
mergeSharedBoundary
is true, a new domain named domname1_domname2 is created and the original ones are deletedif
mergeSharedBoundary
is false, the original domains domname1 and domname2 are retained
if two side domains define an interface and have the same name, say domname, only one domain remains, again named domname and regarded as an interface.
Attention
To be merged, two side domains must have exactly the same nodes.
The following example shows the merging of two rectangles with different side names (mergeSharedBoundary
set to true by default):
Rectangle R1(_xmin=0, _xmax=1, _ymin=0, _ymax=1, _nnodes={3,3}, _side_names={"g1","g2","g3","g4"});
Rectangle R2(_xmin=1, _xmax=2, _ymin=0, _ymax=1, _nnodes={3,3}, _side_names={"s1","s2","s3","s4"});
Mesh mR1P1(R1, _shape=_triangle, _order=1, _generator=_structured);
Mesh mR2Q1(R2, _shape=_quadrangle, _order=1, _generator=_structured);
Mesh mR1R2=merge(mR1P1,mR2Q1);
producing the domains:
Domain 'g1' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 13: side 3 of element 1
geometric side element 14: side 3 of element 3
Domain 'g3' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 17: side 3 of element 6
geometric side element 18: side 3 of element 8
Domain 'g4' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 19: side 2 of element 1
geometric side element 20: side 2 of element 5
Domain 's1' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 21: side 1 of element 9
geometric side element 22: side 1 of element 10
Domain 's2' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 23: side 2 of element 10
geometric side element 24: side 2 of element 12
Domain 's3' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 25: side 3 of element 11
geometric side element 26: side 3 of element 12
Domain 'g2_s4' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 29: side 2 of element 4, side 4 of element 9
geometric side element 30: side 2 of element 8, side 4 of element 11
Domain '#Omega' of dimension 2 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 12 elements
geometric element 1 (material 0, color 0, twin 0): triangle_Lagrange_1
geometric element 2 (material 0, color 0, twin 0): triangle_Lagrange_1
...
geometric element 12 (material 0, color 0, twin 0): quadrangle_Lagrange_1
This is the same example but with mergeSharedBoundary
set to false:
Mesh mR1R2=merge(mR1P1,mR2Q1, false);
producing the domains:
Domain 'g1' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 13: side 3 of element 1
geometric side element 14: side 3 of element 3
Domain 'g2' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 15: side 2 of element 4
geometric side element 16: side 2 of element 8
Domain 'g3' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 17: side 3 of element 6
geometric side element 18: side 3 of element 8
Domain 'g4' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 19: side 2 of element 1
geometric side element 20: side 2 of element 5
Domain 's1' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 21: side 1 of element 9
geometric side element 22: side 1 of element 10
Domain 's2' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 23: side 2 of element 10
geometric side element 24: side 2 of element 12
Domain 's3' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 25: side 3 of element 11
geometric side element 26: side 3 of element 12
Domain 's4' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 27: side 4 of element 9
geometric side element 28: side 4 of element 11
Domain '#Omega' of dimension 2 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 12 elements
geometric element 1 (material 0, color 0, twin 0): triangle_Lagrange_1
geometric element 2 (material 0, color 0, twin 0): triangle_Lagrange_1
...
geometric element 12 (material 0, color 0, twin 0): quadrangle_Lagrange_1
Finally, the case when the side domains defining the interface have the same name (here g2):
Rectangle R1(_xmin=0, _xmax=1, _ymin=0, _ymax=1, _nnodes={3,3}, _side_names={"g1","g2","g3","g4"});
Rectangle R2(_xmin=1, _xmax=2, _ymin=0, _ymax=1, _nnodes={3,3}, _side_names={"s1","s2","s3","g2"});
Mesh mR1P1(R1, _shape=_triangle, _order=1, _generator=_structured);
Mesh mR2Q1(R2, _shape=_quadrangle, _order=1, _generator=_structured);
Mesh mR1R2=merge(mR1P1,mR2Q1);
provides the following domains:
Domain 'g1' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 13: side 3 of element 1
geometric side element 14: side 3 of element 3
Domain 'g3' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 17: side 3 of element 6
geometric side element 18: side 3 of element 8
Domain 'g4' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 19: side 2 of element 1
geometric side element 20: side 2 of element 5
Domain 's1' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 21: side 1 of element 9
geometric side element 22: side 1 of element 10
Domain 's2' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 23: side 2 of element 10
geometric side element 24: side 2 of element 12
Domain 's3' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 25: side 3 of element 11
geometric side element 26: side 3 of element 12
Domain 'g2' of dimension 1 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 2 elements
geometric side element 29: side 2 of element 4, side 4 of element 9
geometric side element 30: side 2 of element 8, side 4 of element 11
Domain '#Omega' of dimension 2 from mesh 'P1 mesh of [0,1]x[0,1] + Q1 mesh of [1,2]x[0,1]', orientation not computed, 12 elements
geometric element 1 (material 0, color 0, twin 0): triangle_Lagrange_1
geometric element 2 (material 0, color 0, twin 0): triangle_Lagrange_1
...
geometric element 12 (material 0, color 0, twin 0): quadrangle_Lagrange_1, orientation +0
Note
As it can be seen in previous examples, an element of an interface domain handles two parent elements whereas an element of a side domain handles only one parent element. For continuous-FE computations, both types of domain can be used but sometimes it may
be important to work with the interface domain. Note that the member function updateParentOfSideElements()
transforms a side domain into an interface domain.
Cracking mesh#
Cracking a mesh means defining an interface between two domains as a crack; the nodes located on the crack are duplicated, one belonging to a domain and the second to the other domain (see ?).