Solid Models
DeviceLayout.SolidModels.SolidModel
— Typestruct SolidModel{T} where {T <: SolidModelKernel}
name::String
groups::NTuple{4,Dict{String,AbstractPhysicalGroup}}
end
SolidModel(name::String, kernel=OpenCascade; overwrite=false)
A 3D geometry model.
Geometry rendering, boolean operations, and export are provided by the specified kernel
.
Physical groups can be accessed by name using indexing with a String
or Symbol
and a dimension: mymodel["mygroup", 3]
will return the PhysicalGroup
with dimension 3 called mygroup
.
Physical groups can also be assigned as mymodel["mygroup"] = dimtags
, where dimtags
is a list of NTuple{2, Int32}
of entities identified by (dim, tag)
in mymodel
. If dimtags
includes entities of multiple dimensions, then a group is created for each dimension.
If the constructor is called with overwrite=false
(the default), then an error will be thrown if a model with the same name already exists. If overwrite=true
, then any existing model with the same name will be deleted and a new model will be created.
A SolidModel
can be saved to a file with FileIO.save(filename, sm)
. Supported filetypes for OpenCASCADE geometries are .brep
and .stp
. Meshes can be exported as .msh2
(compatible with Palace) or .msh
(most recent Gmsh format) files.
DeviceLayout.SolidModels.SolidModelKernel
— Typeabstract type SolidModelKernel
Supertype for solid geometry kernels. Subtypes are OpenCascade
and GmshNative
.
Note that GmshNative
does not support Boolean geometry operations.
Physical groups
DeviceLayout.SolidModels.PhysicalGroup
— Typestruct PhysicalGroup
name::String
model::SolidModel
dim::Int32
grouptag::Int32
end
A named group of entities of dimension dim
in a SolidModel
.
DeviceLayout.SolidModels.dimtags
— Functiondimtags(pg::AbstractPhysicalGroup)
Return the (dimension, integer tag)
tuples for SolidModel
entities in pg
.
DeviceLayout.SolidModels.entitytags
— Functionentitytags(pg::AbstractPhysicalGroup)
Return the integer tags for SolidModel
entities in pg
.
Rendering to a SolidModel
DeviceLayout.render!
— Methodrender!(sm::SolidModel, cs::AbstractCoordinateSystem{T}; map_meta=layer, postrender_ops=[], zmap=(_) -> zero(T), kwargs...) where {T}
Render cs
to sm
.
Keywords
map_meta
: Function (m::SemanticMeta) -> name ofPhysicalGroup
(asString
orSymbol
; may also returnnothing
to skip renderingm
)postrender_ops
: Vector of Tuples(destination, op, args, op_kwargs...)
specifying "postrendering" ofPhysicalGroup
s executed after entities have been rendered to tosm
. Each operationop
creates a newPhysicalGroup
defined assm[destination] = op(sm, args...; op_kwargs...)
. That is,args
are the arguments toop
(following the first argument, which is always the modelsm
being rendered to). For most operations, these arguments include the names and dimensions of groups being operated on, andop_kwargs
are the keyword arguments passed toop
. For example,("base", difference_geom!, ("writeable_area", "base_negative"), :remove_object => true, :remove_tool => true)
defines a postrendering step that subtracts thePhysicalGroup
named"base_negative"
from"writeable_area"
(by default using dimension 2 for each group) to define a new group called"base"
. The keyword pairs:remove_object=>true
and:remove_tool=>true
mean that the "object" (first argument) group"writeable_area"
and the "tool" (second argument) group"base_negative"
are both removed when"base"
is created.zmap
: Function (m::SemanticMeta) ->z
coordinate of corresponding elements. Default: Map all metadata to zero.meshing_parameters
:MeshingParameters
allows customization of the top level meshing parameters when calling Gmsh.
Available postrendering operations are translate!
, extrude_z!
, revolve!
, union_geom!
, intersect_geom!
, difference_geom!
, fragment_geom!
, and box_selection
. (The geometric Boolean operations are only available for models using the OpenCASCADE kernel.)
Additional keyword arguments are passed to SolidModels.to_primitives
(which falls back to to_polygons
) and may be used for certain entity types to control how entities of cs
are converted to primitives and added to sm
.
DeviceLayout.SolidModels.to_primitives
— Functionto_primitives(::SolidModel, ent::GeometryEntity; kwargs...)
Return a GeometryEntity
or a vector of entities equivalent to ent
.
Called inside render!
before adding entities to the SolidModel
. Each resulting entity corresponds to a single entity in that SolidModel
's geometry kernel.
If there is no special handling for ent
in the kernel, then the result will be to_polygons(ent; kwargs...)
.
Postrendering operations
After adding the elements of a CoordinateSystem
to a SolidModel
("rendering"), we can perform additional "postrendering" operations including boolean operations, extrusions, and selections, to create new PhysicalGroup
s.
The recommended pattern is to provide all postrendering operations to the postrender_ops
keyword argument in render!
, because render!
performs important cleanup at the very end. Specifically, it removes duplicate elements using the fragment
operation; because this can also change the labeling of elements, it then reassigns the resulting elements to their corresponding groups.
Boolean operations and infix equivalents:
DeviceLayout.SolidModels.difference_geom!
— Functiondifference_geom!(
object::Union{PhysicalGroup, AbstractArray{PhysicalGroup}},
tool::Union{PhysicalGroup, AbstractArray{PhysicalGroup}};
tag=-1,
remove_object=false,
remove_tool=false
)
Create the geometric difference of the groups object
and tool
.
Return the resulting entities as a vector of (dimension, entity_tag)
Tuple
s.
If tag
is positive, try to set the tag explicitly (only valid if the boolean operation results in a single entity). Remove the object if remove_object
is set. Remove the tool if remove_tool
is set.
The operator -
can be used as a synonymous infix operator.
difference_geom!(sm::SolidModel, object::Union{String, Symbol}, tool::Union{String, Symbol}, d1=2, d2=2;
tag=-1,
remove_object=false,
remove_tool=false)
Create the geometric difference of groups with Symbol
or String
names object, tool
in sm
.
Return the resulting entities as a vector of (dimension, entity_tag)
Tuple
s.
The dimensions of the object and tool groups can be specified as d1
and d2
, respectively. The dimension defaults to 2 (surfaces).
If the tag
is positive, try to set the tag explicitly (only valid if the boolean operation results in a single entity). Remove the object if remove_object
is set. Remove the tool if remove_tool
is set.
If object
is not a physical group in sm
, will error and return an empty dimtag array. If tool
is not a physical group in sm
, will return dimtags of object
.
difference_geom!(sm::SolidModel, object, tool, d1=2, d2=2; remove_tool=false,
remove_object=false, kwargs...)
Create the geometric difference of groups object
and tool
which can be collections of Union{String, Symbol}
.
DeviceLayout.SolidModels.fragment_geom!
— Functionfragment_geom!(
object::Union{PhysicalGroup, AbstractArray{PhysicalGroup}},
tool::Union{PhysicalGroup, AbstractArray{PhysicalGroup}};
tag=-1,
remove_object=false,
remove_tool=false
)
Create the Boolean fragments (general fuse) of the groups object
and tool
, making all interfaces conformal.
When applied to entities of different dimensions, the lower dimensional entities will be automatically embedded in the higher dimensional entities if they are not on their boundary.
Return the resulting entities as a vector of (dimension, entity_tag)
Tuple
s.
If tag
is positive, try to set the tag explicitly (only valid if the boolean operation results in a single entity). Remove the object if remove_object
is set. Remove the tool if remove_tool
is set.
fragment_geom!(sm::SolidModel, object::Union{String, Symbol}, tool::Union{String, Symbol}, d1=2, d2=2;
tag=-1,
remove_object=false,
remove_tool=false)
Create the Boolean fragments (general fuse) of groups with Symbol
or String
names object, tool
in sm
, making all interfaces conformal.
When applied to entities of different dimensions, the lower dimensional entities will be automatically embedded in the higher dimensional entities if they are not on their boundary.
Return the resulting entities as a vector of (dimension, entity_tag)
Tuple
s.
The dimensions of the object and tool groups can be specified as d1
and d2
, respectively. The dimension defaults to 2 (surfaces).
If the tag
is positive, try to set the tag explicitly (only valid if the boolean operation results in a single entity). Remove the object if remove_object
is set. Remove the tool if remove_tool
is set.
If only one of object
or tool
is a physical group in sm
, will perform union of physical group with itself, if neither are present will return an empty array.
DeviceLayout.SolidModels.intersect_geom!
— Functionintersect_geom!(
object::Union{PhysicalGroup, AbstractArray{PhysicalGroup}},
tool::Union{PhysicalGroup, AbstractArray{PhysicalGroup}};
tag=-1,
remove_object=false,
remove_tool=false
)
Create the geometric intersection (the common parts) of the groups object
and tool
.
Return the resulting entities as a vector of (dimension, entity_tag)
Tuple
s.
If tag
is positive, try to set the tag explicitly (only valid if the boolean operation results in a single entity). Remove the object if remove_object
is set. Remove the tool if remove_tool
is set.
The operators *
and ∩
can be used as synonymous infix operators.
intersect_geom!(sm::SolidModel, object::Union{String, Symbol}, tool::Union{String, Symbol}, d1=2, d2=2;
tag=-1,
remove_object=false,
remove_tool=false)
Create the geometric intersection (the common parts) of groups with Symbol
or String
names object, tool
in sm
.
Return the resulting entities as a vector of (dimension, entity_tag)
Tuple
s.
The dimensions of the object and tool groups can be specified as d1
and d2
, respectively. The dimension defaults to 2 (surfaces).
If the tag
is positive, try to set the tag explicitly (only valid if the boolean operation results in a single entity). Remove the object if remove_object
is set. Remove the tool if remove_tool
is set.
If tool
or object
are not physical groups in sm
, will error and return an empty dimtag array.
DeviceLayout.SolidModels.union_geom!
— Functionunion_geom!(
object::Union{PhysicalGroup, AbstractArray{PhysicalGroup}},
tool::Union{PhysicalGroup, AbstractArray{PhysicalGroup}};
tag=-1,
remove_object=false,
remove_tool=false
)
Create the geometric union (the fusion) of the groups object
and tool
.
Return the resulting entities as a vector of (dimension, entity_tag)
Tuple
s.
If tag
is positive, try to set the tag explicitly (only valid if the boolean operation results in a single entity). Remove the object if remove_object
is set. Remove the tool if remove_tool
is set.
The operators +
and ∪
can be used as synonymous infix operators.
union_geom!(sm::SolidModel, object::Union{String, Symbol}, tool::Union{String, Symbol}, d1=2, d2=2;
tag=-1,
remove_object=false,
remove_tool=false)
Create the geometric union of groups with Symbol
or String
names object, tool
in sm
.
Return the resulting entities as a vector of (dimension, entity_tag)
Tuple
s.
The dimensions of the object and tool groups can be specified as d1
and d2
, respectively. The dimension defaults to 2 (surfaces).
If tag
is positive, try to set the tag explicitly (only valid if the boolean operation results in a single entity). Remove the object if remove_object
is set. Remove the tool if remove_tool
is set.
If only one of object
or tool
is a physical group in sm
, will perform union of physical group with itself, if neither are present will return an empty array.
Base.:+
— Method+(object::AbstractPhysicalGroup, tool::AbstractPhysicalGroup)
Equivalent to union_geom!(object, tool)
. Can be used as an infix (object + tool
).
Base.:∪
— Method∪(object::AbstractPhysicalGroup, tool::AbstractPhysicalGroup)
Equivalent to union_geom!(object, tool)
. Can be used as an infix (object ∪ tool
).
Base.:-
— Method-(object::AbstractPhysicalGroup, tool::AbstractPhysicalGroup)
Equivalent to difference_geom!(object, tool)
. Can be used as an infix (object - tool
).
Base.:*
— Method*(object::AbstractPhysicalGroup, tool::AbstractPhysicalGroup)
Equivalent to intersect_geom!(object, tool)
. Can be used as an infix (object * tool
).
Base.:∩
— Method∩(object::AbstractPhysicalGroup, tool::AbstractPhysicalGroup)
Equivalent to intersect_geom!(object, tool)
. Can be used as an infix (object ∩ tool
).
Selections:
DeviceLayout.SolidModels.box_selection
— Functionbox_selection(x1, y1, z1, x2, y2, z2; dim=-1, delta=zero(x1))
box_selection(::SolidModel, x1, y1, z1, x2, y2, z2; dim=-1, delta=zero(x1))
Get the model entities in the bounding box defined by the two points (xmin
, ymin
, zmin
) and (xmax
, ymax
, zmax
). If dim
is >= 0, return only the entities of the specified dimension (e.g. points if dim
== 0).
Return the selected entities as a vector of (dimension, entity_tag)
Tuple
s.
DeviceLayout.SolidModels.get_boundary
— Functionget_boundary(group::AbstractPhysicalGroup; combined=true, oriented=true, recursive=false)
get_boundary(sm::SolidModel, groupname, dim=2; combined=true, oriented=true, recursive=false)
Get the boundary of the model entities in group
, given as a vector of (dim, tag) tuples.
Return the boundary of the individual entities (if combined
is false) or the boundary of the combined geometrical shape formed by all input entities (if combined
is true).
Return tags multiplied by the sign of the boundary entity if oriented
is true.
Apply the boundary operator recursively down to dimension 0 (i.e. to points) if recursive
is true.
Other operations:
DeviceLayout.SolidModels.extrude_z!
— Functionextrude_z!(g::PhysicalGroup, dz; num_elements=[], heights=[], recombine=false)
extrude_z!(sm::SolidModel, groupname, dz, groupdim=2; num_elements=[], heights=[], recombine=false)
Extrude the entities in g
in the z
direction by dz
.
If the numElements
vector is not empty, also extrude the mesh: the entries in numElements
give the number of elements in each layer. If the height
vector is not empty, it provides the (cumulative) height of the different layers, normalized to 1. If recombine
is set, recombine the mesh in the layers.
Return the resulting entities as a vector of (dimension, entity_tag)
Tuple
s.
DeviceLayout.SolidModels.remove_group!
— Functionremove_group!(sm::SolidModel, group::Union{String, Symbol}, dim; recursive=true, remove_entities=false)
remove_group!(group::AbstractPhysicalGroup; recursive=true, remove_entities=false)
Remove entities in group
from the model, unless they are boundaries of higher-dimensional entities.
If recursive
is true, remove all entities on their boundaries, down to dimension zero (points).
Also removes the (now-empty) physical group.
DeviceLayout.SolidModels.restrict_to_volume!
— Functionrestrict_to_volume(sm::SolidModel, volume)
Replace all entities and groups with their intersection with sm[volume, 3]
.
Embeds entities if they are on the boundary of higher-dimensional entities and removes duplicate entities.
Preserves the meaning of existing groups by assigning to them the (possibly new) entities corresponding to that group's intersection with the volume.
DeviceLayout.SolidModels.revolve!
— Functionrevolve!(g::PhysicalGroup, x, y, z, ax, ay, az, θ; num_elements=[], heights=[], recombine=false)
revolve!(sm::SolidModel, groupname, groupdim, x, y, z, ax, ay, az, θ; num_elements=[], heights=[], recombine=false)
Extrude the entities in g
using a rotation of θ
radians around the axis of revolution through (x, y, z)
in the direction (ax, ay, az)
.
If the numElements
vector is not empty, also extrude the mesh: the entries in numElements
give the number of elements in each layer. If the height
vector is not empty, it provides the (cumulative) height of the different layers, normalized to 1. If recombine
is set, recombine the mesh in the layers. When the mesh is extruded the angle should be strictly smaller than 2π.
Return the resulting entities as a vector of (dimension, entity_tag)
Tuple
s.
DeviceLayout.SolidModels.translate!
— Functiontranslate!(group, dx, dy, dz; copy=true)
translate!(sm::SolidModel, groupname, dx, dy, dz, groupdim=2; copy=true)
Translate the entities in physical group group
by (dx, dy, dz)
.
If copy=true
, then a copy of the entities in group
are translated instead.
Return the resulting entities as a vector of (dimension, entity_tag)
Tuple
s.
Meshing
Entities can carry mesh sizing information with them when rendered to a SolidModel
. Many entities will default to a maximal size to reasonably resolve the geometry. This is particularly useful together with adaptive mesh refinement to efficiently refine your mesh to minimize estimated error with as few elements as possible. You can also style entities with MeshSized
to manually control mesh sizing, and provide MeshingParameters
to render!
using the meshing_parameters
keyword argument.
DeviceLayout.SolidModels.MeshingParameters
— TypeBase.@kwdef struct MeshingParameters
mesh_scale::Float64 = 1.0
mesh_order::Int = 1
α_default::Float64 = 0.9
apply_size_to_surfaces::Bool = false
high_order_optimize::Int = 1
surface_mesh_algorithm::Int = 6
volume_mesh_algorithm::Int = 1
options::Dict{String, Float64} = Dict{String, Float64}()
end
MeshingParameters contains high level parameters to specify mesh sizing fields throughout the domain.
mesh_scale
applies multiplicatively to the smallest size specified by any size field function, comparing to the formula in theMeshSized
style, this results in all mesh size fields being rescaled whereh
←mesh_scale
*h
.mesh_order
specifies the order of polynomials to use in representing the geometry, this is important if curved geometric features are present,mesh_order == 1
will represent the geometry with linear polynomials, whilstmesh_order == 2
will represent it with quadratic polynomials, andmesh_order == 3
with cubic polynomials. Increasing the value ofmesh_order
results in greater geometric fidelity, whilst making meshing more difficult (and prone to errors).α_default
specifies the default value ofα
to use forMeshSized
entities whereα
is set to less than 0,α_default ∈ (0, 1]
is particularly used for the default grading ofPath
entities. A value closer to 1 can result in an unstable meshing algorithm in gmsh, particularly for complex geometries.apply_size_to_surfaces=true
will cause the mesh sizing field to specify the size within any sized entities, as opposed to only along the perimeter of the entity ifapply_size_to_surfaces=false
. Settingapply_size_to_surfaces=true
will result in a larger number of elements.high_order_optimize=0
flag to pass to gmsh if optimization of a higher order mesh is to be performed. (0: none, 1: optimization, 2: elastic+optimization, 3: elastic, 4: fast curving). Refer to the gmsh documentation for more details.surface_mesh_algorithm
specifies the algorithm gmsh should use when performing the surface mesh generation. Refer to the gmsh documentation for more details.volume_mesh_algorithm
specifies the algorithm gmsh should use when performing the volume mesh generation. Refer to the gmsh documentation for more details.options
used to specify any additional options provided to gmsh, which will be set withgmsh.options.set_number(key, value)
for eachkey => value
pair. Refer to the gmsh documentation for a list of available options. Will override any other options as is called last.
Example
Below, we create a 3D model of a meandered CPW on a chip, restricting the model to a small volume (for example, for the purposes of simulation).
using DeviceLayout
using FileIO
cs = CoordinateSystem("test", nm)
# Create a CPW meander
pa = Path(-0.5mm, 0nm)
straight!(pa, 900μm, Paths.SimpleCPW(10μm, 6μm))
turn!(pa, 180°, 50μm)
straight!(pa, 900μm)
turn!(pa, -180°, 50μm)
straight!(pa, 900μm)
turn!(pa, 180°, 50μm)
straight!(pa, 900μm)
terminate!(pa)
render!(cs, pa, SemanticMeta(:base_negative))
render!(cs, centered(Rectangle(10mm, 10mm)), SemanticMeta(:chip_outline))
render!(cs, centered(Rectangle(9mm, 9mm)), SemanticMeta(:writeable_area))
render!(cs, centered(Rectangle(2mm, 2mm)), SemanticMeta(:simulated_area))
# Define z heights and thickness (where nonzero)
layer_z = Dict(:chip_outline => -525μm, :simulated_area => -1mm)
layer_thickness = Dict(:chip_outline => 525μm, :simulated_area => 2mm)
# Define postrendering operations:
# Extrusions, geometric Boolean operations, and other transformations
postrender_ops = vcat(
[ # Extrude layers with nonzero thickness
(string(layer) * "_extrusion", SolidModels.extrude_z!, (layer, thickness)) for
(layer, thickness) in pairs(layer_thickness)
],
[ # sm["chip_sim"] = intersect_geom!(sm, "simulated_area_extrusion", ...)
( # Intersect chip volume with simulation volume
"chip_sim", # New physical group name
SolidModels.intersect_geom!, # Operation
# Arguments: Object, tool, object dimension, tool dimension
("simulated_area_extrusion", "chip_outline_extrusion", 3, 3), # Vol ∩ Vol
# Keyword arguments
:remove_tool => true # Remove the "chip_outline_extrusion" group
),
( # Intersect writeable area with simulation volume
"writeable_sim",
SolidModels.intersect_geom!,
("simulated_area_extrusion", "writeable_area", 3, 2), # Volume ∩ Area
:remove_tool => true # Remove "writeable_area" group
),
( # Create group for non-chip volumes (vacuum)
"vac_sim",
SolidModels.difference_geom!, # Subtract "tool" from "object"
("simulated_area_extrusion", "chip_sim", 3, 3),
:remove_object => true # Remove "simulated_area_extrusion" group
),
( # Subtract negative from writeable area to get metal area
"base_metal",
SolidModels.difference_geom!,
("writeable_sim", "base_negative"), # Uses default dimension 2
:remove_object => true # Remove "writeable_sim" group
)
]
)
sm = SolidModel("model"; overwrite=true)
SolidModels.render!(
sm,
cs,
zmap=(m) -> get(layer_z, layer(m), 0μm),
postrender_ops=postrender_ops
)
SolidModels.gmsh.model.mesh.generate() # Generate default mesh (low quality)
save("model.msh2", sm) # Use older MSH v2 format (Gmsh format compatible with Palace)
# save("model.stp", sm) # Use standard STEP format
SolidModels.gmsh.finalize() # Finalize the Gmsh API when done using Gmsh