Mod: improved mesh and shape classes

Mod: exception handling
This commit is contained in:
L-Nafaryus 2022-01-19 23:02:10 +05:00
parent d724b45e85
commit 7dce03e97a
No known key found for this signature in database
GPG Key ID: C76D8DCD2727DBB7
9 changed files with 285 additions and 243 deletions

View File

@ -396,11 +396,5 @@ def show(params, path, printlist, export, fields, output):
# CLI entry # CLI entry
## ##
if __name__ == "__main__": if __name__ == "__main__":
#try: anisotropy()
anisotropy()
#except KeyboardInterrupt:
# click.echo("Interrupted!")
#finally:
# sys.exit(0)

View File

@ -4,14 +4,15 @@
from datetime import datetime from datetime import datetime
import os import os
from os import path from os import path, PathLike
from pathlib import Path
from anisotropy.core.config import DefaultConfig from anisotropy.core.config import DefaultConfig
import logging import logging
from anisotropy.core.postProcess import PostProcess from anisotropy.core.postProcess import PostProcess
from anisotropy.core.utils import Timer from anisotropy.core.utils import Timer, ErrorHandler
from anisotropy.core.parallel import ParallelRunner from anisotropy.core.parallel import ParallelRunner
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -22,6 +23,7 @@ from anisotropy.shaping import Simple, BodyCentered, FaceCentered, Shape
from anisotropy.meshing import Mesh from anisotropy.meshing import Mesh
from anisotropy.solving import OnePhaseFlow from anisotropy.solving import OnePhaseFlow
class UltimateRunner(object): class UltimateRunner(object):
def __init__(self, config = None, exec_id: int = None, typo: str = "master"): def __init__(self, config = None, exec_id: int = None, typo: str = "master"):
# Configuration file # Configuration file
@ -46,18 +48,9 @@ class UltimateRunner(object):
self.exec_id = T.Execution.create(date = datetime.now()) self.exec_id = T.Execution.create(date = datetime.now())
# Parameters # Parameters
self.shape = None
self.mesh = None
self.flow = None
self.queue = [] self.queue = []
def dispose(self):
self.shape = None
self.mesh = None
self.flow = None
def createRow(self): def createRow(self):
# create a row in each table for the current case # create a row in each table for the current case
with self.database: with self.database:
@ -81,6 +74,7 @@ class UltimateRunner(object):
flow = T.FlowOnephase(mesh_id = mesh.mesh_id, **self.config.params) flow = T.FlowOnephase(mesh_id = mesh.mesh_id, **self.config.params)
self.database.csave(mesh) self.database.csave(mesh)
def fill(self): def fill(self):
self.config.expand() self.config.expand()
logger.info(f"Preparing queue: { len(self.config.cases) }") logger.info(f"Preparing queue: { len(self.config.cases) }")
@ -96,7 +90,7 @@ class UltimateRunner(object):
} }
self.queue.append(kwargs) self.queue.append(kwargs)
def start(self, queue: list = None, nprocs: int = None): def start(self, queue: list = None, nprocs: int = None):
nprocs = nprocs or self.config["nprocs"] nprocs = nprocs or self.config["nprocs"]
@ -109,17 +103,22 @@ class UltimateRunner(object):
parallel.wait() parallel.wait()
def casepath(self):
@property
def casepath(self) -> PathLike:
params = self.config.params params = self.config.params
path = Path(os.environ["ANISOTROPY_CWD"], os.environ["ANISOTROPY_BUILD_DIR"])
path /= "execution-{}".format(self.exec_id)
path /= "{}-[{},{},{}]-{}".format(
params["label"],
*[ str(d) for d in params["direction"] ],
params["alpha"]
)
execution = "execution-{}".format(self.exec_id) return path.resolve()
case = "{}-[{},{},{}]-{}".format(params["label"], *[ str(d) for d in params["direction"] ], params["alpha"])
dirpath = path.join(os.environ["ANISOTROPY_CWD"], self.config["build"], execution, case)
return path.abspath(dirpath)
def computeShape(self): def computeShape(self):
out, err, returncode = "", "", 0
params = self.config.params params = self.config.params
shapeParams = self.database.getShape( shapeParams = self.database.getShape(
params["label"], params["label"],
@ -131,54 +130,48 @@ class UltimateRunner(object):
logger.info("Computing shape for {} with direction = {} and alpha = {}".format( logger.info("Computing shape for {} with direction = {} and alpha = {}".format(
params["label"], params["direction"], params["alpha"] params["label"], params["direction"], params["alpha"]
)) ))
filename = "shape.step" shapeFile = self.casepath / "shape.step"
shapepath = path.join(self.casepath(), filename)
timer = Timer() timer = Timer()
if path.exists(shapepath) and shapeParams.shapeStatus == "done" and not self.config["overwrite"]: if shapeFile.exists() and shapeParams.shapeStatus == "done" and not self.config["overwrite"]:
logger.info("Shape exists. Skipping ...") logger.info("Shape exists. Skipping ...")
return return
shape = { shapeSelected = {
"simple": Simple, "simple": Simple,
"bodyCentered": BodyCentered, "bodyCentered": BodyCentered,
"faceCentered": FaceCentered "faceCentered": FaceCentered
}[shapeParams.label] }[shapeParams.label]
self.shape = shape( shape = shapeSelected(
direction = shapeParams.direction, direction = shapeParams.direction,
alpha = shapeParams.alpha, alpha = shapeParams.alpha,
r0 = shapeParams.r0, r0 = shapeParams.r0,
filletsEnabled = shapeParams.filletsEnabled filletsEnabled = shapeParams.filletsEnabled
) )
try: with ErrorHandler() as (eh, handler):
self.shape.build() handler(shape.build)()
except Exception as e: if not eh.returncode:
err = e self.casepath.mkdir(exist_ok = True)
returncode = 1
if not returncode: with ErrorHandler() as (eh, handler):
os.makedirs(self.casepath(), exist_ok = True) handler(shape.write)(shapeFile)
out, err, returncode = self.shape.export(path.join(self.casepath(), filename))
if not returncode: if not eh.returncode:
shapeParams.shapeStatus = "done" shapeParams.shapeStatus = "done"
shapeParams.volume = shape.shape.volume
shapeParams.volume = self.shape.shape.volume shapeParams.volumeCell = shape.cell.volume
shapeParams.volumeCell = self.shape.cell.volume
shapeParams.porosity = shapeParams.volume / shapeParams.volumeCell shapeParams.porosity = shapeParams.volume / shapeParams.volumeCell
else: else:
logger.error(err)
shapeParams.shapeStatus = "failed" shapeParams.shapeStatus = "failed"
logger.error(eh.error)
#with self.database:
shapeParams.shapeExecutionTime = timer.elapsed() shapeParams.shapeExecutionTime = timer.elapsed()
#shapeParams.save()
self.database.csave(shapeParams) self.database.csave(shapeParams)
self.dispose()
def computeMesh(self): def computeMesh(self):
out, err, returncode = "", "", 0 out, err, returncode = "", "", 0
@ -193,40 +186,45 @@ class UltimateRunner(object):
logger.info("Computing mesh for {} with direction = {} and alpha = {}".format( logger.info("Computing mesh for {} with direction = {} and alpha = {}".format(
params["label"], params["direction"], params["alpha"] params["label"], params["direction"], params["alpha"]
)) ))
filename = "mesh.mesh" meshFile = self.casepath / "mesh.mesh"
meshpath = path.join(self.casepath(), filename)
timer = Timer() timer = Timer()
if path.exists(meshpath) and meshParams.meshStatus == "done" and not self.config["overwrite"]: if meshFile.exists() and meshParams.meshStatus == "done" and not self.config["overwrite"]:
logger.info("Mesh exists. Skipping ...") logger.info("Mesh exists. Skipping ...")
return return
if not self.shape: # Shape
shapefile = "shape.step" shape = None
filepath = path.join(self.casepath(), shapefile) shapeFile = self.casepath / "shape.step"
if not path.exists(filepath) and not path.isfile(filepath): if not shapeFile.exists() and not shapeFile.is_file():
err = f"File not found: { filepath }" err = f"File not found: { shapeFile }"
returncode = 2 returncode = 2
if not returncode:
self.shape = Shape()
self.shape.load(filepath)
if not returncode: if not returncode:
self.mesh = Mesh(self.shape.shape) shape = Shape().read(shapeFile)
# Mesh
if not returncode:
mesh = Mesh(shape.shape)
try: try:
self.mesh.build() mesh.generate()
except Exception as e: except Exception as e:
err = e err = e
returncode = 1 returncode = 1
if not returncode: if not returncode:
os.makedirs(self.casepath(), exist_ok = True) self.casepath.mkdir(exist_ok = True)
out, err, returncode = self.mesh.export(path.join(self.casepath(), filename))
out, err, returncode = self.mesh.export(path.join(self.casepath(), "mesh.msh")) try:
mesh.write(meshFile)
mesh.write(self.casepath / "mesh.msh")
except Exception as e:
err = e
returncode = 1
if not returncode: if not returncode:
meshParams.meshStatus = "done" meshParams.meshStatus = "done"
@ -241,7 +239,7 @@ class UltimateRunner(object):
with self.database: with self.database:
meshParams.meshExecutionTime = timer.elapsed() meshParams.meshExecutionTime = timer.elapsed()
meshParams.save() meshParams.save()
self.dispose()
def computeFlow(self): def computeFlow(self):
params = self.config.params params = self.config.params
@ -261,37 +259,33 @@ class UltimateRunner(object):
flowParams.viscosityKinematic = flowParams.viscosity / flowParams.density flowParams.viscosityKinematic = flowParams.viscosity / flowParams.density
with self.database: with self.database:
flowParams.save() flowParams.save()
with self.database: with self.database:
self.flow = OnePhaseFlow( flow = OnePhaseFlow(
direction = params["direction"], direction = params["direction"],
**self.database.getFlowOnephase(*query, to_dict = True), **self.database.getFlowOnephase(*query, to_dict = True),
path = self.casepath() path = self.casepath
) )
if not self.shape: # Shape
filename = "shape.step" shapeFile = self.casepath / "shape.step"
filepath = path.join(self.casepath(), filename)
if not path.exists(filepath) and not path.isfile(filepath): if not shapeFile.exists() and not shapeFile.is_file():
err = f"File not found: { filepath }" err = f"File not found: { shapeFile }"
returncode = 2 returncode = 2
if not returncode: if not returncode:
self.shape = Shape() shape = Shape().read(shapeFile)
self.shape.load(filepath)
faces = [ (n, face.name) for n, face in enumerate(self.shape.shape.faces) ] # Patches from occ to openfoam
createPatchDict = OnePhaseFlow.facesToPatches(faces) patches = shape.patches(group = True, shiftIndex = True, prefix = "patch")
flow.createPatches(patches)
self.flow.append(createPatchDict) flow.write()
self.flow.write()
# Build a flow # Build a flow
try: try:
out, err, returncode = self.flow.build() out, err, returncode = flow.build()
except Exception as e: except Exception as e:
out, err, returncode = "", e, 1 out, err, returncode = "", e, 1
@ -308,6 +302,7 @@ class UltimateRunner(object):
flowParams.flowExecutionTime = timer.elapsed() flowParams.flowExecutionTime = timer.elapsed()
flowParams.save() flowParams.save()
def computePostProcess(self): def computePostProcess(self):
params = self.config.params params = self.config.params
flowParams = self.database.getFlowOnephase( flowParams = self.database.getFlowOnephase(
@ -321,7 +316,7 @@ class UltimateRunner(object):
params["label"], params["direction"], params["alpha"] params["label"], params["direction"], params["alpha"]
)) ))
postProcess = PostProcess(self.casepath()) postProcess = PostProcess(self.casepath)
if flowParams.flowStatus == "done": if flowParams.flowStatus == "done":
flowParams.flowRate = postProcess.flowRate("outlet") flowParams.flowRate = postProcess.flowRate("outlet")

View File

@ -6,6 +6,7 @@ import logging
import copy import copy
import time import time
from types import FunctionType from types import FunctionType
import contextlib
class CustomFormatter(logging.Formatter): class CustomFormatter(logging.Formatter):
@ -206,3 +207,33 @@ class Timer(object):
def elapsed(self): def elapsed(self):
return time.monotonic() - self.start return time.monotonic() - self.start
class ErrorHandler(contextlib.AbstractContextManager):
def __init__(self):
self.error = ""
self.returncode = 0
self.traceback = None
def __enter__(self):
return self, self.handler
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
self.error = exc_value.args
self.returncode = 1
self.traceback = traceback
def handle(self, obj):
def inner(*args, **kwargs):
try:
output = obj(*args, **kwargs)
except Exception as e:
self.error = e.args
self.returncode = 1
else:
return output
return inner

View File

@ -269,7 +269,7 @@ def plotDraw(clicks, execution, structure, direction, data):
) )
if not direction == "all": if not direction == "all":
query = qeury.where(models.Shape.direction == json.loads(direction)) query = query.where(models.Shape.direction == json.loads(direction))
with db: with db:
if query.exists(): if query.exists():

View File

@ -4,9 +4,11 @@
from netgen.occ import OCCGeometry from netgen.occ import OCCGeometry
from netgen import meshing from netgen import meshing
from numpy import array import numpy
from numpy import array, ndarray, linalg
import os import os
from .utils import extractPoints, extractCells from .utils import extractNetgenPoints, extractNetgenCells
from . import metrics
import meshio import meshio
@ -19,154 +21,130 @@ class NotSupportedMeshFormat(Exception):
def __init__(self, msg): def __init__(self, msg):
super().__init__(self, msg) super().__init__(self, msg)
class MeshingParameters(object):
def __init__(self, **kwargs):
self.preset(2, **kwargs)
def preset(self, key: int, **kwargs):
"""Apply predefined parameters.
:param key:
0: very_coarse
1: coarse
2: moderate
3: fine
4: very_fine
"""
self.maxh = kwargs.get("maxh", 0.2)
self.curvaturesafety = kwargs.get("curvaturesafety", [1, 1.5, 2, 3, 5][key])
self.segmentsperedge = kwargs.get("segmentsperedge", [0.3, 0.5, 1, 2, 3][key])
self.grading = kwargs.get("grading", [0.7, 0.5, 0.3, 0.2, 0.1][key])
self.chartdistfac = kwargs.get("chartdistfac", [0.8, 1, 1.5, 2, 5][key])
self.linelengthfac = kwargs.get("linelengthfac", [0.2, 0.35, 0.5, 1.5, 3][key])
self.closeedgefac = kwargs.get("closeedgefac", [0.5, 1, 2, 3.5, 5][key])
self.minedgelen = kwargs.get("minedgelen", [0.002, 0.02, 0.2, 1.0, 2.0][key])
self.surfmeshcurvfac = kwargs.get("surfmeshcurvfac", [1, 1.5, 2, 3, 5.0][key])
self.optsteps2d = kwargs.get("optsteps2d", 5)
self.optsteps3d = kwargs.get("optsetps3d", 5)
return self
def get(self) -> meshing.MeshingParameters:
return meshing.MeshingParameters(**self.__dict__)
def __repr__(self):
return str(self.__dict__)
class Mesh(object): class Mesh(object):
def __init__(self, shape: OCCGeometry = None): def __init__(self, shape = None):
self.geometry = OCCGeometry(shape) if shape else None self.shape = shape
self.mesh = None self.mesh = None
# Parameters self.points = []
self.maxh = 0.2 self.cells = []
self.curvaturesafety = 5 self.boundary = []
self.segmentsperedge = 3
self.grading = 0.1
self.chartdistfac = 5
self.linelengthfac = 3
self.closeedgefac = 5
self.minedgelen = 2.0
self.surfmeshcurvfac = 5.0
self.optsteps2d = 5
self.optsteps3d = 5
@property @property
def parameters(self): def geometry(self):
return meshing.MeshingParameters( return OCCGeometry(self.shape)
maxh = self.maxh,
curvaturesafety = self.curvaturesafety,
segmentsperedge = self.segmentsperedge,
grading = self.grading,
chartdistfac = self.chartdistfac,
linelengthfac = self.linelengthfac,
closeedgefac = self.closeedgefac,
minedgelen = self.minedgelen,
surfmeshcurvfac = self.surfmeshcurvfac,
optsteps2d = self.optsteps2d,
optsteps3d = self.optsteps3d
)
def build(self): def generate(self, parameters: MeshingParameters = None, refineSteps: int = 0, scale: float = 0):
if self.geometry: if not self.geometry:
self.mesh = self.geometry.GenerateMesh(self.parameters) raise NoGeometrySpecified("Cannot build mesh without geometry")
parameters = parameters or MeshingParameters()
mesh = self.geometry.GenerateMesh(parameters.get())
else: if refineSteps > 0:
raise NoGeometrySpecified("Specify a geometry to build a mesh") for n in range(refineSteps):
mesh.Refine()
mesh.OptimizeMesh2d(parameters)
mesh.OptimizeVolumeMesh(parameters)
if scale > 0:
mesh.Scale(scale)
self.points = extractNetgenPoints(mesh)
self.cells = []
formats = { for dim in range(4):
"vol": "Netgen Format", self.cells.extend(extractNetgenCells(dim, mesh))
"mesh": "Neutral Format",
"msh": "Gmsh2 Format"
}
def load(self, filename: str): return self
def read(self, filename: str):
"""Import a mesh. """Import a mesh.
Use `Mesh.formats` to see supported formats.
:param filename: :param filename:
Name of the file to store the given mesh in. Name of the mesh file.
""" """
ext = os.path.splitext(filename)[1][1: ] mesh = meshio.read(filename)
if ext in self.formats.keys(): self.points = mesh.points
self.mesh = meshing.Mesh() self.cells = mesh.cells
self.mesh.Load(filename)
else:
raise NotSupportedMeshFormat(f"Mesh format '{ ext }' is not supported")
return self return self
def export(self, filename: str): def write(self, filename: str):
"""Export a mesh. """Export a mesh.
Use `Mesh.formats` to see supported formats.
:param filename: :param filename:
Name of the file to store the given mesh in. Name of the file to store the given mesh in.
"""
mesh = meshio.Mesh(self.points, self.cells)
mesh.write(filename)
@property
def volumes(self) -> list[ndarray]:
points = []
for cellBlock in self.cells:
if cellBlock.dim == 3:
points.extend([ *self.points[cellBlock.data] ])
return points
@property
def volume(self) -> float:
"""Volume of whole mesh.
:return: :return:
Output, error messages and returncode Volume.
""" """
out, err, returncode = "", "", 0 return sum([ metrics.volume(cell) for cell in self.volumes ])
ext = os.path.splitext(filename)[1][1: ]
try:
if ext == "vol":
self.mesh.Save(filename)
elif ext in self.formats.keys():
self.mesh.Export(filename, self.formats[ext])
else:
raise NotSupportedMeshFormat(f"Mesh format '{ ext }' is not supported")
except (NotSupportedMeshFormat, Exception) as e:
err = e
returncode = 1
return out, err, returncode
def to_meshio(self):
points = extractPoints(self.mesh.Points())
cells = []
if len(self.mesh.Elements1D()) > 0:
cells.extend([ cells_ for cells_ in extractCells(1, self.mesh.Elements1D()).items() ])
if len(self.mesh.Elements2D()) > 0:
cells.extend([ cells_ for cells_ in extractCells(2, self.mesh.Elements2D()).items() ])
if len(self.mesh.Elements3D()) > 0:
cells.extend([ cells_ for cells_ in extractCells(3, self.mesh.Elements3D()).items() ])
return meshio.Mesh(points, cells)
@staticmethod
def volumeTetra(points: array) -> float:
return 1 / 6 * linalg.det(numpy.append(points.transpose(), numpy.array([[1, 1, 1, 1]]), axis = 0))
@property @property
def volumes(self) -> array: def faces(self) -> list[ndarray]:
points = [] points = []
for cells in self.cells: for cellBlock in self.cells:
if cells.dim == 3: if cellBlock.dim == 2:
points.extend([ self.mesh.points[cell] for cell in cells.data ]) points.extend([ *self.points[cellBlock.data] ])
return array(points) return points
@property
def faces(self) -> array:
points = []
for cells in self.cells:
if cells.dim == 2:
points.extend([ self.mesh.points[cell] for cell in cells.data ])
return array(points)
@property
def edges(self) -> array:
points = []
for cells in self.cells:
if cells.dim == 1:
points.extend([ self.mesh.points[cell] for cell in cells.data ])
return array(points)
# tetras = numpy.array([ [ [ vertex for vertex in mesh[index] ] for index in element.vertices ] for element in self.mesh.Elements3D() ])
# volumes = numpy.array([ 1 / 6 * linalg.det(numpy.append(tetra.transpose(), numpy.array([[1, 1, 1, 1]]), axis = 0)) for tetra in tetras ])

View File

@ -2,4 +2,18 @@
# This file is part of anisotropy. # This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details. # License: GNU GPL version 3, see the file "LICENSE" for details.
import numpy
from numpy import ndarray
from numpy import linalg
from .utils import detectCellType
def volume(points: ndarray) -> ndarray:
cellType = detectCellType(3, len(points))
if cellType == "tetra":
return 1 / 6 * linalg.det(numpy.append(points.transpose(), numpy.array([[1, 1, 1, 1]]), axis = 0))
else:
raise Exception(f"Not supported cell type '{ cellType }'")

View File

@ -1,31 +1,68 @@
from __future__ import annotations
from netgen import meshing
from meshio._mesh import topological_dimension from meshio._mesh import topological_dimension
from meshio._common import num_nodes_per_cell from meshio._common import num_nodes_per_cell
from numpy import array from numpy import array, asarray, ndarray
def detectCellType(dimension: int, num_nodes: int):
def detectTopology(dimension: dict, num_nodes: dict):
for dim in topological_dimension.keys(): for dim in topological_dimension.keys():
for num in num_nodes_per_cell.keys(): for num in num_nodes_per_cell.keys():
if topological_dimension[dim] == dimension and num_nodes_per_cell[num] == num_nodes and dim == num: if topological_dimension[dim] == dimension and num_nodes_per_cell[num] == num_nodes and dim == num:
return dim return dim
class CellBlock:
def __init__(self, cellType: str, data: list | ndarray, tags: list[str] | None = None):
self.type = cellType
self.data = data
def extractPoints(points): if cellType.startswith("polyhedron"):
return array([ point.p for point in points ], dtype = float) self.dim = 3
else:
self.data = asarray(self.data)
self.dim = topological_dimension[cellType]
self.tags = [] if tags is None else tags
def __repr__(self):
items = [
"CellBlock",
f"type: { self.type }",
f"num cells: { len(self.data) }",
f"tags: { self.tags }",
]
return "<" + ", ".join(items) + ">"
def __len__(self):
return len(self.data)
def extractNetgenPoints(mesh: meshing.Mesh) -> ndarray:
return array([ point.p for point in mesh.Points() ], dtype = float)
def extractCells(dimension: int, elements): def extractNetgenCells(dim: int, mesh: meshing.Mesh) -> list[CellBlock]:
cellsNew = {} cellsDict = {}
elements = {
0: mesh.Elements0D(),
1: mesh.Elements1D(),
2: mesh.Elements2D(),
3: mesh.Elements3D()
}[dim]
if len(elements) == 0:
return []
for cell in elements: for cell in elements:
cellTopo = detectTopology(dimension, len(cell.points)) cellType = detectCellType(dim, len(cell.points))
# shift indicies, they should starts from zero # shift indicies, they should start from zero
cellNew = array([ pointId.nr for pointId in cell.points ], dtype = int) - 1 cellNew = array([ pointId.nr for pointId in cell.points ], dtype = int) - 1
if cellsNew.get(cellTopo): if cellsDict.get(cellType):
cellsNew[cellTopo].append(cellNew) cellsDict[cellType].append(cellNew)
else: else:
cellsNew[cellTopo] = [ cellNew ] cellsDict[cellType] = [ cellNew ]
return cellsNew cells = [ CellBlock(key, value) for key, value in cellsDict.items() ]
return cells

View File

@ -6,6 +6,8 @@ from netgen.occ import *
import numpy import numpy
from numpy import linalg from numpy import linalg
import os import os
from os import PathLike
from pathlib import Path
class ShapeError(Exception): class ShapeError(Exception):
@ -17,7 +19,7 @@ class Shape(object):
self.groups = {} self.groups = {}
self.shape = None self.shape = None
def export(self, filename: str): def write(self, filename: PathLike):
"""Export a shape. """Export a shape.
Supported formats: step. Supported formats: step.
@ -29,11 +31,12 @@ class Shape(object):
Output, error messages and returncode Output, error messages and returncode
""" """
out, err, returncode = "", "", 0 out, err, returncode = "", "", 0
ext = os.path.splitext(filename)[1][1: ] path = Path(filename).resolve()
ext = path.suffix[1: ]
try: try:
if ext == "step": if ext == "step":
self.shape.WriteStep(filename) self.shape.WriteStep(path)
else: else:
raise NotImplementedError(f"{ ext } is not supported") raise NotImplementedError(f"{ ext } is not supported")
@ -48,11 +51,12 @@ class Shape(object):
return out, err, returncode return out, err, returncode
def load(self, filename: str): def read(self, filename: PathLike):
ext = os.path.splitext(filename)[1][1:] path = Path(filename).resolve()
ext = path.suffix[1: ]
if ext in ["step", "iges", "brep"]: if ext in ["step", "iges", "brep"]:
self.shape = OCCGeometry(filename).shape self.shape = OCCGeometry(path).shape
else: else:
raise NotImplementedError(f"Shape format '{ext}' is not supported") raise NotImplementedError(f"Shape format '{ext}' is not supported")

View File

@ -135,25 +135,14 @@ class OnePhaseFlow(FoamCase):
u u
]) ])
@staticmethod
def facesToPatches(faces: tuple[int, str]): def createPatches(self, patches: dict):
# initial 43 unnamed patches -> # initial 43 unnamed patches ->
# 6 named patches (inlet, outlet, wall, symetry0 - 3/5) -> # 6 named patches (inlet, outlet, wall, symetry0 - 3/5) ->
# 4 inGroups (inlet, outlet, wall, symetry) # 4 inGroups (inlet, outlet, wall, symetry)
createPatchDict = F.CreatePatchDict() createPatchDict = F.CreatePatchDict()
createPatchDict["patches"] = [] createPatchDict["patches"] = []
patches = {}
for n, name in faces:
# shifted index
n += 1
if patches.get(name):
patches[name].append(f"patch{n}")
else:
patches[name] = [f"patch{n}"]
for name in patches.keys(): for name in patches.keys():
if name == "inlet": if name == "inlet":
@ -182,7 +171,7 @@ class OnePhaseFlow(FoamCase):
"patches": patches[name] "patches": patches[name]
}) })
return createPatchDict self.append(createPatchDict)
def build(self) -> tuple[str, str, int]: def build(self) -> tuple[str, str, int]:
# TODO: configure working directory (FoamCase) # TODO: configure working directory (FoamCase)