simudo.mesh package

Submodules

simudo.mesh.construction_helper module

class simudo.mesh.construction_helper.BaseConstructionHelper[source]

Bases: object

boilerplate

allocate_subdomain_range(length)[source]
compute_facets()[source]
debug_cvs_to_mf(cvs)[source]
debug_fvs_to_mf(fvs, signed=True)[source]
debug_plot()[source]
dim
fix_facets_after_subdivision()[source]
classmethod from_existing_mesh_cf(mesh, cf, cell_regions, run=True, params=None, mesh_unit=None)[source]
gdim
generate_mesh()[source]

by default does nothing. override me

main(params, output_filename)[source]
mesh_data
p
refine_subdomains(subdomains, predicate)[source]
robjs
run()[source]
used_cell_values
user_extra_definitions()[source]

override me

user_mark_external_boundary_facets(mesh, boundary_facet_function)[source]

override me (maybe)

this function is allowed to add new definitions and cell values to self.cell_regions

by default this uses facet.facet2d_angle and defines new regions right/top/left/bottom

this function MUST add an ‘exterior’ key for all external boundary facets

user_modify_meta(meta)[source]

override me

user_refinement()[source]

override me

util_define_internal()[source]
util_init_cf_from_domains()[source]
class simudo.mesh.construction_helper.ConstructionHelperIntervalProduct2DMesh[source]

Bases: BaseConstructionHelper

Mesh built from tagged x-intervals.

By default (params['mesh_dimension'] == 1) a true 1D dolfin interval mesh is built: one cell per x-interval, and the exterior boundary marked exterior_left / exterior_right (exterior_top and exterior_bottom are defined but empty, so topology code written for the strip keeps working).

With params['mesh_dimension'] == 2 the same x coordinates are instead extruded into a 2D strip of triangles with vertices at product2d_Ys. That was the only route before the 1D one existed, and is kept for backward compatibility: it doubles the vertex count and roughly triples the degrees of freedom of a 1D device for no gain in accuracy, and its line cuts do not conserve current as exactly. Prefer the default unless you specifically need the extruded mesh.

If product2d_Ys has been customized (i.e. differs from the default (0.0, 1.0)), the mesh is extruded even without an explicit mesh_dimension: those Y coordinates mean nothing on an interval mesh, so a subclass that sets them is asking for a genuinely 2D mesh, and silently flattening it would be worse than ignoring the new default.

Everything downstream (element choice, zero vectors, output) detects the mesh dimension automatically; see element_hdiv().

class Interval1DTag(intervals)

Bases: Product2DMeshMixin, Interval1DMeshMixin, MinimumCoordinateDistanceMixin, BaseInterval1DTag

default_mesh_dimension = 1

Mesh dimension used when params does not specify one.

generate_mesh()[source]

by default does nothing. override me

interval_1d_tag
mesh_dimension
product2d_Ys = (0.0, 1.0)

Y coordinates of the extruded strip. Only used when the mesh is 2D.

user_define_interval_regions()[source]

override me

must return ((domain_x0, domain_x1), list_of_intervals) domain is overall domain

user_mark_external_boundary_facets(mesh, boundary_facet_function)[source]

override me (maybe)

this function is allowed to add new definitions and cell values to self.cell_regions

by default this uses facet.facet2d_angle and defines new regions right/top/left/bottom

this function MUST add an ‘exterior’ key for all external boundary facets

class simudo.mesh.construction_helper.ConstructionHelperLayeredStructure[source]

Bases: ConstructionHelperIntervalProduct2DMesh

Mesh-construction helper for 1-D layered device structures (optionally extruded to 2-D).

Layers are specified as a list of dicts, each containing at minimum 'name' (str), 'material' (str), and 'thickness' (float, in mesh units). Pass the list as params['layers']. Additional mesh refinement regions can be supplied as params['extra_regions'].

The mesh is a true 1D interval mesh by default. Set params['mesh_dimension'] = 2 for the 2D strip Simudo extruded these layer stacks into before the 1D route existed; see ConstructionHelperIntervalProduct2DMesh. The physics, boundary conditions and outputs are the same either way, but the strip has roughly three times the degrees of freedom and is correspondingly slower. Checkpoints are not portable between the two mesh dimensions.

See ConstructionHelperIntervalProduct2DMesh for the underlying mesh-generation machinery, and ProblemData for the solver object that consumes the resulting mesh.

Variables:
  • material_to_region (dict) – Mapping from material name (str) to the union CellRegion covering all layers with that material.

  • layers (list of dict) – The layer definitions as supplied in params['layers'].

  • extra_regions (list) – Extra refinement regions, from params['extra_regions'] (formerly params['simple_overmesh_regions']).

extra_regions
layers
material_to_region
user_define_interval_regions()[source]

override me

must return ((domain_x0, domain_x1), list_of_intervals) domain is overall domain

user_layer_extra_intervals(intervals, name_interval)[source]

override if necessary

class simudo.mesh.construction_helper.ConstructionHelperManualCellTagging[source]

Bases: BaseConstructionHelper

generate_mesh()[source]

by default does nothing. override me

user_just_generate_mesh()[source]
user_tag_cell(cell)[source]
user_tag_cells(cell_function)[source]
class simudo.mesh.construction_helper.ConstructionHelperMshr[source]

Bases: BaseConstructionHelper

generate_mesh()[source]

by default does nothing. override me

user_define_mshr_regions()[source]

override me

must return {region_name: mshr_domain} regions[‘domain’] is overall domain

class simudo.mesh.construction_helper.ConstructionHelperPygmsh2[source]

Bases: BaseConstructionHelper

Example:

from simudo.mesh import ConstructionHelperPygmsh2
from simudo.mesh.gmsh import AnisotropicPygmshGeneratorHelper

class MyMeshConstructor(ConstructionHelperPygmsh2):
    my_custom_r2_height = 1.5

    class GeneratorHelper(AnisotropicPygmshGeneratorHelper):
        def user_generate(self):
            geo = self.geometry
            tt = self.tag_tracker

            # yuo can reference attributes of the ConstructionHelper
            constructor = self.user_data
            r2h = constructor.my_custom_r2_height

            # construct three overlapping rectangles
            r0 = tt(geo.add_rectangle([0.0, 0.0, 0.0], 1.0, 1.0))
            r1 = tt(geo.add_rectangle([0.5, 0.5, 0.0], 1.0, 1.0))
            r2 = tt(geo.add_rectangle([0.7, 0.2, 0.0], 0.1, r2h))

            # no need to wait until the end to define physical tags!
            self.regions["r0"] = r0
            self.regions["core"] = r0 & r1 & r2

            # merge the shapes together
            tt.merge(r0, r1, r2)

            # finish defining regions
            self.regions["r1"] = r1
            self.regions["r2"] = r2

            # poke a hole in the mesh!
            tt.remove((r2 & r0) - r1)

    def user_density_function(self, mesh, cell_function, tag_values):
        cf = cell_function
        r = tag_values
        dx = dolfin.dx()

        element = dolfin.VectorElement("DG", mesh.ufl_cell(), 1, 9)
        space = dolfin.FunctionSpace(mesh, element)
        u = dolfin.Function(space)
        v = dolfin.TestFunction(space)
        expr = -dolfin.inner(v, u) * dx

        a = r["r0"] - r["r1"] - r["r2"]
        b = r["r1"] - r["r0"] - r["r2"]
        c = (r["r0"] | r["r1"] | r["r2"]) - a - b

        A = 2000
        B = 20
        for cvs, vec in [
            [a, [A, 0.0, 0.0, 0.0, B, 0.0, 0.0, 0.0, 1.0]],
            [b, [B, 0.0, 0.0, 0.0, A, 0.0, 0.0, 0.0, 1.0]],
            [c, [B,   A, 0.0,   A, B, 0.0, 0.0, 0.0, 1.0]],
        ]:
            dx1 = dolfin.dx(subdomain_data=cf, subdomain_id=tuple(cvs))
            expr += dolfin.inner(v, dolfin.Constant(vec)) * dx1

        solver = NewtonSolver(F=expr, u_=u, bcs=[])
        solver.solve()
        return u
GeneratorHelper: type = Ellipsis
generate_mesh()[source]

by default does nothing. override me

user_density_function(mesh, cell_function, tag_values)[source]

override me

Parameters:
  • mesh (FEM mesh) – Initial generated mesh.

  • cell_function – Cell function with region information.

  • tag_values – Dictionary mapping region names to sets of cell values.

Returns:

Vector 9-component FEM function representing a 3x3 anisotropic metric matrix.

Return type:

function

xdmf_output: str = None
class simudo.mesh.construction_helper.InvertibleTransform[source]

Bases: object

FIXME: make PlazaRefinementND use alternate definition of longest_edge

This hack is instead used to temporarily modify the mesh coordinates temporarily to alter PlazaRefinementND’s length metric

v[i, j] is vertex i’s jth coordinate

after_modification(mesh)[source]
transform(mesh)[source]
transform_coordinates(v)[source]
untransform(mesh)[source]
untransform_coordinates(v)[source]

v[i, j] is vertex i’s jth coordinate

class simudo.mesh.construction_helper.LinearTransform(matrix)[source]

Bases: InvertibleTransform

transform_coordinates(v)[source]
untransform_coordinates(v)[source]

v[i, j] is vertex i’s jth coordinate

simudo.mesh.construction_helper.inplace_dict_map(mapping, func)[source]

simudo.mesh.construction_helper_example module

class simudo.mesh.construction_helper_example.Bob[source]

Bases: ConstructionHelperMshr

user_define_mshr_regions()[source]

must return {region_name: mshr_domain} regions[‘domain’] is overall domain

user_extra_definitions()[source]

override me

user_refinement()[source]

override me

simudo.mesh.construction_helper_example.main()[source]

simudo.mesh.domaintag_mshr module

class simudo.mesh.domaintag_mshr.DomainTag[source]

Bases: object

domain_relationship(A, B)[source]

must return one of {REL_DISJOINT, REL_OVERLAPPING, …}

domain_relationship_tabulate(items)[source]
first_cell_value = 1
generate_intersection_regions(tagitems)[source]

returns frozenset of tagset

region described by tagset is intersection(tagset) - union(all_tags - tagset)

make_subdomains(tags)[source]

dict must be {tag_name: region}

returns (tag_to_cv_dict, subdomains)

tag_to_cv_dict will be {tag_name: cell_values} where all cell_values >= start_value

subdomains is list of (subdomain, cell_value) where subdomain is as returned by the self.region_to_subdomain method

region_to_subdomain(tags, included, excluded)[source]
class simudo.mesh.domaintag_mshr.DomainTagTest(methodName='runTest')[source]

Bases: TestCase

assert_gen_reg(answer, tags)[source]
assert_rel(answer, A, B)[source]
rect(x0, y0, x1, y1)[source]
test_domain_relationship()[source]
test_generate_possibilities()[source]
class simudo.mesh.domaintag_mshr.MshrDomainTag[source]

Bases: DomainTag

domain_relationship(A, B)[source]

must return one of {REL_DISJOINT, REL_OVERLAPPING, …}

mshr_make_subdomains(domain, tags)[source]
simudo.mesh.domaintag_mshr.powerset(iterable)[source]

simudo.mesh.facet module

class simudo.mesh.facet.FacetsManager(mesh, cell_function, boundary_facet_function)[source]

Bases: object

Keep track of boundaries between subdomains (cell function values).

boundary(X, Y, intersection=None)[source]

Get signed boundary between X and Y.

If the intersection between X and Y is nonempty, you must pass the intersection argument. This function will pretend that the intersection is actually part of X or Y (depending on the value of intersection). In other words,

  • boundary(X, Y, 0) == boundary(X, Y-X), and

  • boundary(X, Y, 1) == boundary(X-Y, Y).

Parameters:
  • X (set) – X and Y must be sets of cell marker values (representing subdomains). X and Y must be disjoint unless the intersection argument is used.

  • Y (set) – See X.

  • intersection (int, optional) – Must be 0 or 1, if specified.

Returns:

fvs – Set of tuples (facet_value, sign) representing facets between X and Y.

Return type:

set

cell_value_internal(X)[source]

Get internal facets excluding boundaries across cell values (subdomains).

Parameters:

X (set) – Set of cell values (representing subdomains).

Returns:

fvs – Set of (facet_value, sign) representing facets contained within X and not on the boundary between two cell values.

Return type:

set

fix_undefined_facets_after_subdivision(mesh, cell_function, facet_function)[source]

Assign markers to facets created by mesh subdivision.

Upon subdivision, cells get split and new facets are created to separate them. The subdivision algorithm cannot know what facet value to assign to these new facets, so it leaves them with a large undefined value.

These facets must be fully internal to a subdomain, so the cells on either side must have the same cell value. That cell value corresponds to a facet value for internal facets, which is precisely the information stored in the internal_facets_dict attribute.

Parameters:
  • mesh (dolfin.Mesh) – Mesh on which to operate.

  • cell_function (dolfin.CellFunction) – Cell function on mesh representing subdomains.

  • facet_function (dolfin.FacetFunction) – Facet function to fix up after subdivision. This will be modified in place.

internal(X)[source]

Get all internal facets.

Parameters:

X (set) – Set of cell values (representing subdomains).

Returns:

fvs – Set of (facet_value, sign) representing facets contained within X and not on its boundary.

Return type:

set

simudo.mesh.facet.facet2d_angle(facet)[source]

right_value=0, up_value=1, left_value=2, down_value=3

simudo.mesh.facet.mark_boundary_facets(mesh, boundary_facet_function, facet_closure, offset=0)[source]
simudo.mesh.facet.mesh_function_map(mesh_function, func, out_type='size_t')[source]

simudo.mesh.interval1dtag module

class simudo.mesh.interval1dtag.BaseInterval1DTag(intervals)[source]

Bases: object

Class that turns a bunch of arbitrary overlapping intervals into a mesh.

coordinates
first_cell_value = 1
intervals_to_subdomains(intervals)[source]
make_coordinates(subdomain_to_intervals, endpoints)[source]
make_interval_coordinates(x0, x1, local_edge_length_function)[source]

Note: this excludes second endpoint

subdomains
tag_to_cell_values

Mapping from a tag to a set of cell values (e.g. values inside self.product2d_mesh.cell_function).

class simudo.mesh.interval1dtag.CInterval(x0, x1, tags=(), edge_length=inf)[source]

Bases: Interval

Represents an interval with constant edge length (in the x direction).

Note: you do not need to derive from this class to implement a custom edge length. Instead, you can subclass from Interval and implement a custom local_edge_length method.

local_edge_length(x)[source]
class simudo.mesh.interval1dtag.GeometricallyExpandingMeshInterval(*, edge_length_start, edge_length_expansion_factor, **kw)[source]

Bases: Interval

Interval of 1D mesh where the edge lengths start at start and increase geometrically away from the region bounds.

See doc/mesh.lyx for more information.

(Local edge length: minimum distance between two mesh vertices.)

Parameters:
  • bounds (tuple) – Tuple defining the region.

  • edge_length_start (float or tuple) – The initial edge length at the bounds. To have different initial edge lengths at the two ends of the region, pass in a tuple.

  • edge_length_expansion_factor (float or tuple) – Geometric expansion factor. Pass in a tuple to use different factors on the two ends of the region.

local_edge_length(x)[source]
class simudo.mesh.interval1dtag.Interval(x0, x1, tags=())[source]

Bases: object

Represents a single interval, possibly with tags.

class simudo.mesh.interval1dtag.Interval1DMesh(Xs)[source]

Bases: object

A true-1D (interval) dolfin mesh built from sorted x coordinates, with a cell function attached. Counterpart of Product2DMesh for the true-1D route; cell ix spans Xs[ix] to Xs[ix+1].

Created by Claude Fable 5.1 (Anthropic), 2026-09-04.

cells_at_ix(ix)[source]
mesh
nX
class simudo.mesh.interval1dtag.Interval1DMeshMixin[source]

Bases: object

Build a true-1D interval mesh from the tagged intervals, tagging each cell with the cell value of the subdomain it lies in (same convention as Product2DMeshMixin).

class Interval1DMesh(Xs)

Bases: object

A true-1D (interval) dolfin mesh built from sorted x coordinates, with a cell function attached. Counterpart of Product2DMesh for the true-1D route; cell ix spans Xs[ix] to Xs[ix+1].

Created by Claude Fable 5.1 (Anthropic), 2026-09-04.

cells_at_ix(ix)
mesh
nX
interval_1d_mesh

Use this to get a readily-constructed Interval1DMesh object. Note that an attribute cell_function has been added to it.

make_interval_1d_mesh(coordinates, subdomain_to_coordinate_range, subdomain_to_cell_value)[source]
class simudo.mesh.interval1dtag.Interval1DTag(intervals)[source]

Bases: Product2DMeshMixin, Interval1DMeshMixin, MinimumCoordinateDistanceMixin, BaseInterval1DTag

class simudo.mesh.interval1dtag.MinimumCoordinateDistanceMixin[source]

Bases: object

make_interval_coordinates(x0, x1, *args, **kwargs)[source]
minimum_coordinate_distance = 1e-10
class simudo.mesh.interval1dtag.Product2DMeshMixin[source]

Bases: object

class Product2DMesh(Xs, Ys=None)

Bases: object

cells_at_ix(ix)
copy()

note: does not deepcopy Xs and Ys

create_function_from_x_values(values)
element
ix_from_vertex(v)
iy_from_vertex(v)
mesh
nX
nY
space
vertices_at_ix(ix)
vertices_at_iy(iy)
make_product2d_mesh(coordinates, subdomain_to_coordinate_range, subdomain_to_cell_value, Ys)[source]
product2d_Ys = (0.0, 1.0)
product2d_mesh

Use this to get a readily-constructed Product2D object. Note that an attribute cell_function has been added to it.

simudo.mesh.interval1dtag.clip_intervals(x0, x1, intervals)[source]

in-place modifies intervals

simudo.mesh.mesh1d module

simudo.mesh.mesh1d.make_1d_mesh_from_points(Xs)[source]

simudo.mesh.mesh_entity_predicate module

class simudo.mesh.mesh_entity_predicate.AlwaysTruePredicate(dim)[source]

Bases: BaseMeshEntityPredicate

class simudo.mesh.mesh_entity_predicate.AndMeshEntityPredicate(*predicates)[source]

Bases: CombiningMeshEntityPredicate

class simudo.mesh.mesh_entity_predicate.BaseMeshEntityPredicate[source]

Bases: object

classmethod assert_compatible_predicates(predicates)[source]
dim = None
prepare(dictionary)[source]
class simudo.mesh.mesh_entity_predicate.CombiningMeshEntityPredicate(*predicates)[source]

Bases: BaseMeshEntityPredicate

prepare(dictionary)[source]
class simudo.mesh.mesh_entity_predicate.DimensionAdapterPredicate(predicate, dim)[source]

Bases: BaseMeshEntityPredicate

prepare(dictionary)[source]
class simudo.mesh.mesh_entity_predicate.DirectionalEdgeLengthPredicate(direction, threshold=None)[source]

Bases: BaseMeshEntityPredicate

dim = 1
prepare(dictionary)[source]
class simudo.mesh.mesh_entity_predicate.InRadiusCellPredicate(threshold, dim)[source]

Bases: BaseMeshEntityPredicate

class simudo.mesh.mesh_entity_predicate.MaxEdgeLengthCellPredicate(threshold, dim)[source]

Bases: BaseMeshEntityPredicate

class simudo.mesh.mesh_entity_predicate.NandMeshEntityPredicate(*predicates)[source]

Bases: CombiningMeshEntityPredicate

class simudo.mesh.mesh_entity_predicate.OrMeshEntityPredicate(*predicates)[source]

Bases: CombiningMeshEntityPredicate

class simudo.mesh.mesh_entity_predicate.SubdomainCellPredicate(cell_function, subdomains)[source]

Bases: BaseMeshEntityPredicate

simudo.mesh.product2d module

class simudo.mesh.product2d.Product2DMesh(Xs, Ys=None)[source]

Bases: object

cells_at_ix(ix)[source]
copy()[source]

note: does not deepcopy Xs and Ys

create_function_from_x_values(values)[source]
element
ix_from_vertex(v)[source]
iy_from_vertex(v)[source]
mesh
nX
nY
space
vertices_at_ix(ix)[source]
vertices_at_iy(iy)[source]

simudo.mesh.pygmsh module

class simudo.mesh.pygmsh.PygmshMakeRegions[source]

Bases: object

We want overlapping regions. gmsh and pygmsh make that difficult. gmsh supports overlapping physical surfaces/volumes, but it returns duplicate mesh cells (see meshio issue 175). We can fix this by postprocessing pygmsh’s output, which thankfully contains all the necessarily info. At least for now.

process(cells, cell_data, field_data, dim)[source]

Note: In-place modifies cells and cell_data.

unduplicate_msh3_cells(cells, cell_data)[source]

simudo.mesh.refine module

simudo.mesh.refine.adapt(obj, *args, **kwargs)[source]
simudo.mesh.refine.adapt_mf(mf, new_mesh)[source]
simudo.mesh.refine.cell_predicate_expr_threshold(mesh, function, threshold)[source]

function must be a dolfin.FunctionSpace or pint wrapper around one

simudo.mesh.refine.mark_using_predicate(mf, mesh, predicate)[source]
simudo.mesh.refine.predicate_to_meshfunction(mesh, predicate, dim)[source]
simudo.mesh.refine.refine_forever(refinement_objs, make_predicate)[source]

simudo.mesh.topology module

class simudo.mesh.topology.CellRegion(*args, **kwargs)[source]

Abstract cell region.

Can be evaluated down to a set of subdomain markers using MeshData.evaluate_topology().

To access a cell region predefined (named) in the mesh generator, instantiate this class directly with a name argument.

__and__(x)[source]

Return the intersection of this cell region and another.

static __new__(cls, *args, **kwargs)[source]
__or__(x)[source]

Return the union of this cell region and another.

__sub__(x)[source]

Return the subtraction of the other cell region from this one.

__xor__(x)[source]

Return the symmetric difference of this cell region and another.

boundary(x)[source]

Signed boundary between self and x.

internal_facets()[source]

Get all internal facets.

static null()[source]

Get null cell region that matches nothing.

subdomain_internal_facets()[source]

Get internal facets excluding boundaries across cell values (subdomains).

class simudo.mesh.topology.FacetRegion(*args, **kwargs)[source]

Abstract facet region.

Can be evaluated down to a set of (facet_marker_value, facet_sign) using MeshData.evaluate_topology().

To access a facet region predefined (named) in the mesh generator, instantiate this class directly with a name argument.

__and__(x)[source]

Return the intersection of this facet region and another.

static __new__(cls, *args, **kwargs)[source]
__or__(x)[source]

Return the union of this facet region and another.

__sub__(x)[source]

Return the subtraction of the other facet region from this one.

__xor__(x)[source]

Return the symmetric difference of this facet region and another.

both()[source]

Both facet sides, i.e.

f.both() == (f | f.flip())

flip()[source]

Invert facet signedness. For example,

X.boundary(Y) == Y.boundary(X).flip()

static null()[source]

Get null facet region that matches nothing.

unsigned()[source]

Erase facet signedness information by setting sign = 1 for every (facet_value, sign) pair.

class simudo.mesh.topology.CellRegions(mapping=None)[source]

Convenient container for cell region objects.

Variables:

_mapping_ (dict) – Dictionary of cell regions.

\_\_getitem\_\_(name)

I.e. obj[name]. If name is already in _mapping_, it is retrieved from there; otherwise a CellRegion is created with that name, stored inside _mapping_, and returned.

If name is a set, then a subset of the _mapping_ dictionary is returned with those keys.

\_\_getattr\_\_(name)

I.e. obj.$name. Redirected to obj[name].

class simudo.mesh.topology.FacetRegions(mapping=None)[source]

Convenient container for facet region objects.

See CellRegions.

Module contents