# Copyright (c) 2012-2024, OpenGeoSys Community (http://www.opengeosys.org)
#            Distributed under a Modified BSD License.
#            See accompanying file LICENSE.txt or
#            http://www.opengeosys.org/project/license
#
from pathlib import Path
from typing import Union
import gmsh
def _geo_square(
    geo: gmsh.model.geo,
    lengths: Union[float, list[float]],
    n_edge_cells: Union[int, list[int]],
    structured: bool,
) -> None:
    _lengths = lengths if isinstance(lengths, list) else [lengths] * 2
    _n = n_edge_cells if isinstance(n_edge_cells, list) else [n_edge_cells] * 2
    geo.addPoint(0, 0, 0, tag=1)
    geo.addPoint(_lengths[0], 0, 0, tag=2)
    geo.addPoint(_lengths[0], _lengths[1], 0, tag=3)
    geo.addPoint(0, _lengths[1], 0, tag=4)
    geo.addLine(1, 2, tag=1)
    geo.addLine(2, 3, tag=2)
    geo.addLine(3, 4, tag=3)
    geo.addLine(4, 1, tag=4)
    geo.addCurveLoop([1, 2, 3, 4], tag=1)
    geo.addPlaneSurface([1], tag=1)
    geo.mesh.setTransfiniteCurve(1, _n[0] + 1)
    geo.mesh.setTransfiniteCurve(2, _n[1] + 1)
    geo.mesh.setTransfiniteCurve(3, _n[0] + 1)
    geo.mesh.setTransfiniteCurve(4, _n[1] + 1)
    if structured:
        geo.mesh.setTransfiniteSurface(1)
        geo.mesh.setRecombine(dim=2, tag=1)
[docs]
def rect(
    lengths: Union[float, list[float]] = 1.0,
    n_edge_cells: Union[int, list[int]] = 1,
    structured_grid: bool = True,
    order: int = 1,
    out_name: Path = Path("unit_square.msh"),
) -> None:
    gmsh.initialize()
    gmsh.option.set_number("General.Verbosity", 0)
    gmsh.model.add("unit_square")
    _geo_square(gmsh.model.geo, lengths, n_edge_cells, structured_grid)
    rectangle = gmsh.model.addPhysicalGroup(dim=2, tags=[1], tag=0)
    bottom = gmsh.model.addPhysicalGroup(dim=1, tags=[1])
    right = gmsh.model.addPhysicalGroup(dim=1, tags=[2])
    top = gmsh.model.addPhysicalGroup(dim=1, tags=[3])
    left = gmsh.model.addPhysicalGroup(dim=1, tags=[4])
    gmsh.model.setPhysicalName(dim=2, tag=rectangle, name="unit_square")
    gmsh.model.setPhysicalName(dim=1, tag=bottom, name="bottom")
    gmsh.model.setPhysicalName(dim=1, tag=right, name="right")
    gmsh.model.setPhysicalName(dim=1, tag=top, name="top")
    gmsh.model.setPhysicalName(dim=1, tag=left, name="left")
    gmsh.model.geo.synchronize()
    gmsh.model.mesh.generate(dim=2)
    gmsh.option.setNumber("Mesh.SecondOrderIncomplete", 1)
    gmsh.model.mesh.setOrder(order)
    gmsh.write(str(out_name))
    gmsh.finalize() 
[docs]
def cuboid(
    lengths: Union[float, list[float]] = 1.0,
    n_edge_cells: Union[int, list[int]] = 1,
    structured_grid: bool = True,
    order: int = 1,
    out_name: Path = Path("unit_cube.msh"),
) -> None:
    gmsh.initialize()
    gmsh.option.set_number("General.Verbosity", 0)
    gmsh.model.add("unit_cube")
    _geo_square(gmsh.model.geo, lengths, n_edge_cells, structured_grid)
    dz = lengths if isinstance(lengths, float) else lengths[2]
    nz = n_edge_cells if isinstance(n_edge_cells, int) else n_edge_cells[2]
    newEntities = gmsh.model.geo.extrude(
        dimTags=[(2, 1)], dx=0, dy=0, dz=dz,
        numElements=[nz], recombine=structured_grid  # fmt: skip
    )
    top_tag = newEntities[0][1]
    vol_tag = newEntities[1][1]
    side_tags = [nE[1] for nE in newEntities[2:]]
    surf_tags = [1, top_tag] + side_tags
    surf_names = ["bottom", "top", "front", "right", "back", "left"]
    for surf_tag, surf_name in zip(surf_tags, surf_names):
        side_name = gmsh.model.addPhysicalGroup(dim=2, tags=[surf_tag])
        gmsh.model.setPhysicalName(dim=2, tag=side_name, name=surf_name)
    vol = gmsh.model.addPhysicalGroup(dim=3, tags=[vol_tag], tag=0)
    gmsh.model.setPhysicalName(dim=3, tag=vol, name="volume")
    gmsh.model.geo.synchronize()
    gmsh.model.mesh.generate(dim=3)
    gmsh.option.setNumber("Mesh.SecondOrderIncomplete", 1)
    gmsh.model.mesh.setOrder(order)
    gmsh.write(str(out_name))
    gmsh.finalize() 
[docs]
def bhe_mesh(
    width: float = 10.0,
    length: float = 10.0,
    depth: float = 30.0,
    x_BHE: float = 5,
    y_BHE: float = 5,
    bhe_depth: float = 20,
    order: int = 1,
    out_name: Path = Path("bhe_mesh.msh"),
) -> None:
    gmsh.initialize()
    model, geo = (gmsh.model, gmsh.model.geo)
    model.add(Path(out_name).stem)
    geo.addPoint(0.0, 0.0, 0.0)
    geo.addPoint(width, 0.0, 0.0)
    geo.addPoint(width, length, 0.0)
    geo.addPoint(0.0, length, 0.0)
    geo.addLine(1, 2)
    geo.addLine(2, 3)
    geo.addLine(3, 4)
    geo.addLine(4, 1)
    geo.addCurveLoop([1, 2, 3, 4], 1)
    geo.addPlaneSurface([1], tag=1)
    alpha = 6.134  # valid only for 6 surronding points
    bhe_radius = 0.076
    delta = alpha * bhe_radius
    delta_2 = 0.866 * delta
    delta_3 = 0.5 * delta
    d1 = geo.addPoint(x_BHE, y_BHE, 0, delta)
    d2 = geo.addPoint(x_BHE, y_BHE - delta, 0, delta)
    d3 = geo.addPoint(x_BHE, y_BHE + delta, 0, delta)
    d4 = geo.addPoint(x_BHE + delta_2, y_BHE + delta_3, 0, delta)
    d5 = geo.addPoint(x_BHE - delta_2, y_BHE + delta_3, 0, delta)
    d6 = geo.addPoint(x_BHE + delta_2, y_BHE - delta_3, 0, delta)
    d7 = geo.addPoint(x_BHE - delta_2, y_BHE - delta_3, 0, delta)
    geo.synchronize()
    model.mesh.embed(0, [d1, d2, d3, d4, d5, d6, d7], 2, 1)
    soil_1 = geo.extrude([(2, 1)], 0, 0, -depth / 2, [4], [1], True)
    soil_2 = geo.extrude([soil_1[0]], 0, 0, -depth / 2, [4], [1], True)
    bhe = geo.extrude([(0, 5)], 0, 0, -bhe_depth, [5], [1], True)
    top_soil_tag = model.addPhysicalGroup(dim=3, tags=[soil_1[1][1]], tag=0)
    bottom_soil_tag = model.addPhysicalGroup(dim=3, tags=[soil_2[1][1]], tag=1)
    bhe_tag = model.addPhysicalGroup(dim=1, tags=[bhe[1][1]])
    model.setPhysicalName(dim=3, tag=top_soil_tag, name="top")
    model.setPhysicalName(dim=3, tag=bottom_soil_tag, name="bottom")
    model.setPhysicalName(dim=1, tag=bhe_tag, name="bhe")
    geo.synchronize()
    model.mesh.generate(3)
    gmsh.option.setNumber("Mesh.SecondOrderIncomplete", 1)
    model.mesh.setOrder(order)
    model.mesh.removeDuplicateNodes()
    gmsh.write(str(out_name))
    gmsh.finalize()