Source code for src.mesh
# -*- coding: utf-8 -*-
# noinspection PyUnresolvedReferences
r"""
.. _docs-mesh:
Mesh
====
We define an abstract mesh based on an abstract manifold by calling ``ph.mesh`` method,
.. autofunction:: src.mesh.mesh
As an example,
>>> mesh = ph.mesh(manifold)
The output, ``mesh``, is an instance of :class:`Mesh`. And similarly, it is abstract at this stage.
.. autoclass:: src.mesh.Mesh
:members: m, n, manifold
You can print a list of defined meshes by
>>> ph.list_meshes() # doctest: +ELLIPSIS
Existing meshes:...
"""
from tools.frozen import Frozen
from src.config import _mesh_default_sym_repr
from src.config import _check_sym_repr
from src.config import _parse_lin_repr
from src.config import _mesh_default_lin_repr
from src.spaces.main import set_mesh
from src.config import _mesh_partition_sym_repr, _mesh_partition_lin_repr
_global_meshes = dict() # all meshes are cached, and all sym_repr and lin_repr are different.
[docs]
def mesh(manifold, sym_repr=None, lin_repr=None):
"""Generate an abstract mesh over an abstract manifold.
It is actually a wrapper of the ``__init__`` method of :class:`Mesh`.
Parameters
----------
manifold : :class:`Manifold`
The abstract manifold this mesh is built on.
sym_repr : {None, str}, optional
The symbolic representation of the mesh. If it is ``None``, we will use a pre-set symbolic
representation. The default is ``None``.
lin_repr : {None, str}, optional
The linguistic representation of the mesh. If it is ``None``, we will use a pre-set linguistic
representation. The default is ``None``.
Returns
-------
mesh : :class:`Mesh`
The abstract mesh instance.
"""
return Mesh(
manifold,
sym_repr=sym_repr,
lin_repr=lin_repr,
)
def _list_meshes():
""""""
from src.config import RANK, MASTER_RANK
if RANK != MASTER_RANK:
return
else:
pass
print('Existing meshes:')
print('{:>25} - {}'.format('---------------- symbolic', '<manifold> -------------------------'))
for rp in _global_meshes:
print('{:>25} | {}'.format(rp, _global_meshes[rp].manifold))
[docs]
class Mesh(Frozen): # Mesh -
def __init__(self, manifold, sym_repr=None, lin_repr=None):
self._objective = None
# when initializing, it has no objective instance. And when we generate an objective of this
# abstract mesh, we store the last objective one with this attribute.
assert manifold.__class__.__name__ == 'Manifold', f"I need a manifold."
self._manifold = manifold
assert manifold._covered_by_mesh is None, f"we already made an abstract mesh for this manifold."
manifold._covered_by_mesh = self
if sym_repr is None:
number_existing_meshes = len(_global_meshes)
base_repr = _mesh_default_sym_repr
if number_existing_meshes == 0:
sym_repr = base_repr
else:
sym_repr = base_repr + r'_{' + str(number_existing_meshes) + '}'
else:
pass
sym_repr = _check_sym_repr(sym_repr)
if lin_repr is None:
base_repr = _mesh_default_lin_repr
number_existing_meshes = len(_global_meshes)
if number_existing_meshes == 0:
lin_repr = base_repr
else:
lin_repr = base_repr + str(number_existing_meshes)
assert sym_repr not in _global_meshes, \
f"Manifold symbolic representation is illegal, pls specify a symbolic representation other than " \
f"{set(_global_meshes.keys())}"
for _ in _global_meshes:
_m = _global_meshes[_]
assert lin_repr != _m._lin_repr
lin_repr, pure_lin_repr = _parse_lin_repr('mesh', lin_repr)
self._sym_repr = sym_repr
self._lin_repr = lin_repr
self._pure_lin_repr = pure_lin_repr
_global_meshes[sym_repr] = self
if len(_global_meshes) == 1: # we just initialize the first mesh
set_mesh(self) # we set it as the default mesh
self._boundary = None
self._interface = None
self._inclusion = None
self._freeze()
@property
def ndim(self):
""""""
return self._manifold.ndim
@property
def n(self):
"""The dimensions of the manifold."""
return self.ndim
@property
def m(self):
"""The dimensions of the embedding space."""
return self._manifold.m
def __repr__(self):
""""""
super_repr = super().__repr__().split('object')[-1]
return '<Mesh ' + self._sym_repr + super_repr # this will be unique.
@property
def manifold(self):
"""The manifold this mesh is built on."""
return self._manifold
# it is regarded as an operator, so do not use @property
def boundary(self):
"""Give a mesh of dimensions (n-1) on the boundary manifold."""
if self._boundary is None:
manifold_boundary = self.manifold.boundary()
if manifold_boundary.__class__.__name__ == 'Manifold':
self._boundary = Mesh(
manifold_boundary,
sym_repr=r'\eth' + self._sym_repr,
lin_repr=r'boundary-of-' + self._pure_lin_repr
)
self._boundary._inclusion = self
elif manifold_boundary.__class__.__name__ == 'NullManifold':
self._boundary = NullMesh(manifold_boundary)
else:
raise NotImplementedError()
return self._boundary
def inclusion(self):
"""Give the mesh of dimensions (n+1) on the inclusion manifold."""
return self._inclusion
def boundary_partition(self, *sym_reprs, config_name=None):
"""Define boundary sections by partition the mesh boundary into sections defined by `*sym_reprs`."""
if self._boundary is None:
_ = self.boundary()
else:
pass
_boundary = self.manifold.boundary()
sub_manifolds = _boundary.partition(*sym_reprs, config_name=config_name)
for sub_manifold in sub_manifolds:
sr0, sr1 = _mesh_partition_sym_repr
if sub_manifold._covered_by_mesh is None:
self.__class__(
sub_manifold,
sym_repr=sr0 + sub_manifold._sym_repr + sr1,
lin_repr=_mesh_partition_lin_repr + sub_manifold._pure_lin_repr,
) # it will be automatically saved to _global_meshes.
else:
pass
class NullMesh(Frozen):
"""A mesh that is constructed upon a null manifold."""
def __init__(self, null_manifold):
self._null_manifold = null_manifold
self._freeze()
@property
def ndim(self):
return self._null_manifold.ndim