def test_square_mesh(corner_x, corner_y, width, height, _): assume(width > 1e-3) assume(height > 1e-3) # todo limit aspect ratio bg = Rectangle.from_center([0, 0], 2e6, 2e6) r = Rectangle([corner_x, corner_y], width, height) mg = ModelGeometry(allow_overlaps=True) mg.add_domain("bg", bg) mg.add_domain("r", r) points = [ (-1e6, -1e6), (1e-6, -1e6), (1e6, 1e6), (-1e6, 1e6), (corner_x, corner_y), (corner_x + width, corner_y), (corner_x + width, corner_y + height), (corner_x, corner_y + height), ] mesh = create_mesh(mg) coordinates = mesh.coordinates() for p in points: err = coordinates - p assert np.any(np.isclose(err, 0, atol=1e-6))
def compile(self, n_refine: int = 0, refine_domains: List[str] = None, recompute_mesh=True, **model_parameters) -> None: """Create model mesh, label domains/boundaries and build model equations. Needs to be called before solving the models :param n_refine: Number of times to refine the mesh :param refine_domains: Name of domains to refine :param model_parameters: Model parameter dictionary. :param recompute_mesh: kwargs catch all for model parameters """ # forces the geometry to update. If the mesh doesnt need to be recomputed the non-geometric parameters # (i.e. e.g. sigma) will update. The "geometry" will be recreated but since the physical parts haven't changed # the mesh can remain the same. self.model_geometry.clear() self.create_geometry(**model_parameters) # remove existing geometry and recreate if no mesh or needs recompute if recompute_mesh or not self.mesh: self.mesh = create_mesh( self.model_geometry, verbose=self.verboseness >= self._VERBOSE_GMSH ) self.structural_compilation() for _ in range(n_refine): # TODO: good test for this self.refine(refine_domains) # do n refinements self.build_equations(**model_parameters)
def test_domain_single(): mg = ModelGeometry() bg = Rectangle.from_center([0, 0], 1) mg.add_domain("bg", bg) mesh = create_mesh(mg) domains = mark_domains(mesh, mg).array() assert np.all(domains == mg.domain_names["bg"])
def test_domains_polygon(): mg = ModelGeometry() bg = Rectangle.from_center([0, 0], 1) r = Polygon([-0.25, 0.25, 0.25, -0.25], [-0.25, -0.25, 0.25, 0.25]) mg.add_domain("bg", bg) mg.add_domain("r", r) mesh = create_mesh(mg) domains = mark_domains(mesh, mg).array() checker = r.expand(1e-3)._shapely_representation xy = mesh.coordinates() tri_f = tri.Triangulation(xy[:, 0], xy[:, 1], mesh.cells()) triangles = tri_f.get_masked_triangles() verts = np.stack((tri_f.x[triangles], tri_f.y[triangles]), axis=-1) for ix, (v1, v2, v3) in enumerate(verts): if (checker.contains(shp.Point(v1)) and checker.contains(shp.Point(v2)) and checker.contains(shp.Point(v3))): assert domains[ix] == mg.domain_names["r"] else: assert domains[ix] == mg.domain_names["bg"]
def make_square_in_square_in_square(complex=False): """Make a complex nested square structure. Default behaviour is a nested square Complex behaviour will nest two other squares inside the center square :param complex: If the complex regime will be used :return: Model geometry of the nested squares """ sq1 = Rectangle.from_center([0, 0], 6) sq2 = Rectangle.from_center([0, 0], 4) mg = ModelGeometry(allow_overlaps=True) mg.add_domain("bg", sq1) mg.add_domain("fg", sq2) if complex: sq3 = Rectangle.from_center([0, 0], 2) sq4 = Rectangle.from_center([0, 0], 0.5) # not labeled mg.add_domain("fg2", sq3) mg.add_domain("fake", sq4) mesh = create_mesh(mg) domains = mark_domains(mesh, mg) return domains, mg