Mod: mesh oop style

New: submeshes
Fix: salome current version
Mod: default values for mesh parameters - less values in main config
Fix: smesh_* style for boundary groups
Move: notes to real notes, reserve docs for docs
This commit is contained in:
L-Nafaryus 2021-07-09 23:07:53 +05:00
parent a7adc59b70
commit 7f75e9c790
No known key found for this signature in database
GPG Key ID: C76D8DCD2727DBB7
9 changed files with 274 additions and 291 deletions

View File

@ -112,7 +112,7 @@ def createQueue():
for structure in config.base.__dict__.keys():
theta = getattr(config, structure).parameters.theta
theta = getattr(config, structure).geometry.theta
parameters_theta[structure] = [ n * theta[2] for n in range(int(theta[0] / theta[2]), int(theta[1] / theta[2]) + 1) ]
thickness = getattr(config, structure).mesh.thickness
@ -156,10 +156,8 @@ def createQueue():
"meshTime": 0,
"flowTime": 0
},
"parameters": {
"theta": theta
},
"geometry": {
"theta": theta,
"direction": direction,
"fillet": getattr(config, structure).geometry.fillet
},

View File

@ -11,17 +11,15 @@ name = "anisotropy"
format = "%(levelname)s: %(message)s"
[base]
simple = false
simple = true
bodyCentered = true
faceCentered = false
faceCentered = true
###
# Simple
##
[simple.parameters]
theta = [0.01, 0.28, 0.01]
[simple.geometry]
theta = [0.01, 0.28, 0.01]
directions = [
[1, 0, 0],
[0, 0, 1],
@ -30,37 +28,20 @@ directions = [
fillet = true
[simple.mesh]
fineness = 3
minSize = 0.05
maxSize = 0.1
growthRate = 0.5
nbSegPerEdge = 0.5
nbSegPerRadius = 0.5
chordalErrorEnabled = false
chordalError = -1
secondOrder = false
optimize = true
quadAllowed = false
useSurfaceCurvature = true
fuseEdges = true
checkChartBoundary = false
localSizeOnShape.strips = 0.01
viscousLayers = false
viscousLayers = true
thickness = [0.01, 0.005]
numberOfLayers = 1
stretchFactor = 1.2
isFacesToIgnore = true
[simple.mesh.submesh.strips]
growthRate = 0.2
nbSegPerEdge = 2
nbSegPerRadius = 3
###
# Body-centered
##
[bodyCentered.parameters]
# TODO: 0.18
theta = [0.01, 0.17, 0.01]
[bodyCentered.geometry]
theta = [0.01, 0.17, 0.01]
directions = [
[1, 0, 0],
[0, 0, 1],
@ -69,36 +50,19 @@ directions = [
fillet = true
[bodyCentered.mesh]
fineness = 3
minSize = 0.05
maxSize = 0.5
growthRate = 0.5
nbSegPerEdge = 0.5
nbSegPerRadius = 0.5
chordalErrorEnabled = false
chordalError = -1
secondOrder = false
optimize = true
quadAllowed = false
useSurfaceCurvature = true
fuseEdges = true
checkChartBoundary = false
localSizeOnShape.strips = 0.01
viscousLayers = false
thickness = [0.005, 0.0005]
numberOfLayers = 1
stretchFactor = 1.2
isFacesToIgnore = true
[bodyCentered.mesh.submesh.strips]
growthRate = 0.2
nbSegPerEdge = 2
nbSegPerRadius = 3
###
# Face-centered
##
[faceCentered.parameters]
theta = [0.01, 0.13, 0.01]
[faceCentered.geometry]
theta = [0.01, 0.13, 0.01]
directions = [
[1, 0, 0],
[0, 0, 1],
@ -107,28 +71,13 @@ directions = [
fillet = true
[faceCentered.mesh]
fineness = 3
minSize = 0.01
maxSize = 0.5
growthRate = 0.5
nbSegPerEdge = 0.5
nbSegPerRadius = 0.5
chordalErrorEnabled = false
chordalError = -1
secondOrder = false
optimize = true
quadAllowed = false
useSurfaceCurvature = true
fuseEdges = true
checkChartBoundary = false
localSizeOnShape.strips = 0.01
viscousLayers = false
thickness = [0.001, 0.0005]
numberOfLayers = 1
stretchFactor = 1.2
isFacesToIgnore = true
[faceCentered.mesh.submesh.strips]
growthRate = 0.2
nbSegPerEdge = 2
nbSegPerRadius = 3
###
# Flow

View File

@ -41,7 +41,7 @@ patches
}
constructFrom patches;
patches (inlet_);
patches (smesh_inlet);
}
{
@ -55,7 +55,7 @@ patches
}
constructFrom patches;
patches (outlet_);
patches (smesh_outlet);
}
{
@ -68,7 +68,7 @@ patches
}
constructFrom patches;
patches (wall_);
patches (smesh_wall);
}
{
@ -81,7 +81,7 @@ patches
}
constructFrom patches;
patches (symetry0_);
patches (smesh_symetry0);
}
{
@ -94,7 +94,7 @@ patches
}
constructFrom patches;
patches (symetry1_);
patches (smesh_symetry1);
}
{
@ -107,7 +107,7 @@ patches
}
constructFrom patches;
patches (symetry2_);
patches (smesh_symetry2);
}
{
@ -120,7 +120,7 @@ patches
}
constructFrom patches;
patches (symetry3_);
patches (smesh_symetry3);
}
{
@ -133,7 +133,7 @@ patches
}
constructFrom patches;
patches (symetry4_);
patches (smesh_symetry4);
}
{
@ -146,7 +146,7 @@ patches
}
constructFrom patches;
patches (symetry5_);
patches (smesh_symetry5);
}
{
@ -159,7 +159,7 @@ patches
}
constructFrom patches;
patches (strips_);
patches (smesh_strips);
}

View File

@ -22,34 +22,64 @@ import toml
import logging
from anisotropy.utils import struct
CONFIG = os.path.join(CASE, "task.toml")
config = struct(toml.load(CONFIG))
LOG = os.path.join(ROOT, "logs")
logging.basicConfig(
level = logging.INFO,
format = config.logger.format,
handlers = [
logging.StreamHandler(),
logging.FileHandler(f"{ LOG }/{ config.logger.name }.log")
]
)
logger = logging.getLogger(config.logger.name)
from salomepl.simple import simple
from salomepl.faceCentered import faceCentered
from salomepl.bodyCentered import bodyCentered
from salomepl.geometry import getGeom
from salomepl.mesh import smeshBuilder, meshCreate, meshCompute, meshStats, meshExport
from salomepl.mesh import Mesh, Fineness, ExtrusionMethod
def defaultParameters(**configParameters):
maxSize = 0.5
minSize = 0.05
fineness = Fineness.Custom.value
growthRate = 0.7
nbSegPerEdge = 0.3
nbSegPerRadius = 1
chordalErrorEnabled = True
chordalError = 0.25
secondOrder = False
optimize = True
quadAllowed = False
useSurfaceCurvature = True
fuseEdges = True
checkChartBoundary = False
viscousLayers = False
thickness = 0.005
numberOfLayers = 1
stretchFactor = 1
isFacesToIgnore = True
facesToIgnore = ["inlet", "outlet"]
faces = []
extrusionMethod = ExtrusionMethod.SURF_OFFSET_SMOOTH
p = locals()
del p["configParameters"]
if configParameters:
for k, v in p.items():
if configParameters.get(k) is not None:
p[k] = configParameters[k]
# Overwrite special values
if k == "fineness":
p["fineness"] = Fineness.__dict__[p["fineness"]].value
if k == "extrusionMethod":
p["extrusionMethod"] = ExtrusionMethod.__dict__[p["extrusionMethod"]]
return p
def genmesh():
def genmesh(config):
logger.info(f"""genmesh:
structure type:\t{ config.structure }
coefficient:\t{ config.parameters.theta }
coefficient:\t{ config.geometry.theta }
fillet:\t{ config.geometry.fillet }
flow direction:\t{ config.geometry.direction }""")
@ -60,7 +90,7 @@ def genmesh():
##
geompy = getGeom()
structure = globals().get(config.structure)
shape, groups = structure(config.parameters.theta, config.geometry.fillet, config.geometry.direction)
shape, groups = structure(config.geometry.theta, config.geometry.fillet, config.geometry.direction)
[length, surfaceArea, volume] = geompy.BasicProperties(shape, theTolerance = 1e-06)
logger.info(f"""shape:
@ -71,31 +101,87 @@ def genmesh():
###
# Mesh
##
facesToIgnore = []
config = dict(config)
mconfig = defaultParameters(**config["mesh"])
lengths = [ geompy.BasicProperties(edge)[0] for edge in geompy.SubShapeAll(shape, geompy.ShapeType["EDGE"]) ]
meanSize = sum(lengths) / len(lengths)
mconfig["maxSize"] = meanSize
mconfig["minSize"] = meanSize * 1e-1
mconfig["chordalError"] = mconfig["maxSize"] / 2
faces = []
for group in groups:
if group.GetName() in ["inlet", "outlet"]:
facesToIgnore.append(group)
if group.GetName() in mconfig["facesToIgnore"]:
faces.append(group)
meshParameters = config.mesh
meshParameters.facesToIgnore = facesToIgnore
meshParameters.extrusionMethod = smeshBuilder.SURF_OFFSET_SMOOTH
mconfig["faces"] = faces
mesh = meshCreate(shape, meshParameters, groups)
returncode = meshCompute(mesh, groups)
mesh = Mesh(shape)
mesh.Tetrahedron(**mconfig)
if returncode == 0:
config.status.mesh = True
if mconfig["viscousLayers"]:
mesh.ViscousLayers(**mconfig)
config["mesh"].update(mconfig)
smconfigs = config["mesh"]["submesh"]
for name in smconfigs.keys():
for group in groups:
if group.GetName() == name:
subshape = group
smconfig = defaultParameters(**smconfigs[name])
smconfig["maxSize"] = meanSize * 1e-1
smconfig["minSize"] = meanSize * 1e-3
smconfig["chordalError"] = smconfig["minSize"] * 1e+1
mesh.Triangle(subshape, **smconfig)
config["mesh"]["submesh"][name].update(smconfig)
returncode, errors = mesh.compute()
if not returncode:
config["status"]["mesh"] = True
else:
logger.error(errors)
with open(CONFIG, "w") as io:
toml.dump(dict(config), io)
toml.dump(config, io)
meshStats(mesh)
meshExport(mesh, os.path.join(CASE, "mesh.unv"))
mesh.removePyramids()
mesh.assignGroups()
mesh.exportUNV(os.path.join(CASE, "mesh.unv"))
stats = ""
for k, v in mesh.stats().items():
stats += f"{ k }:\t\t{ v }\n"
logger.info(f"mesh stats:\n{ stats[ :-1] }")
salome.salome_close()
if __name__ == "__main__":
genmesh()
CONFIG = os.path.join(CASE, "task.toml")
config = struct(toml.load(CONFIG))
LOG = os.path.join(ROOT, "logs")
logging.basicConfig(
level = logging.INFO,
format = config.logger.format,
handlers = [
logging.StreamHandler(),
logging.FileHandler(f"{ LOG }/{ config.logger.name }.log")
]
)
logger = logging.getLogger(config.logger.name)
genmesh(config)

View File

@ -2,201 +2,151 @@ import SMESH
from salome.smesh import smeshBuilder
smesh = smeshBuilder.New()
import logging
logger = logging.getLogger("anisotropy")
import enum
class Fineness(enum.Enum):
VeryCoarse = 0
Coarse = 1
Moderate = 2
Fine = 3
VeryFine = 4
Custom = 5
class ExtrusionMethod(object):
SURF_OFFSET_SMOOTH = smeshBuilder.SURF_OFFSET_SMOOTH
FACE_OFFSET = smeshBuilder.FACE_OFFSET
NODE_OFFSET = smeshBuilder.NODE_OFFSET
def getSmesh():
return smesh
def updateParams(old, new: dict):
old.SetMaxSize(new.get("maxSize") if new.get("maxSize") else old.GetMaxSize())
old.SetMinSize(new.get("minSize") if new.get("minSize") else old.GetMinSize())
def meshCreate(shape, parameters, groups): #fineness, parameters, viscousLayers = None):
"""
Creates a mesh from a geometry.
old.SetFineness(new.get("fineness") if new.get("fineness") else old.GetFineness())
old.SetGrowthRate(new.get("growthRate") if new.get("growthRate") else old.GetGrowthRate())
old.SetNbSegPerEdge(new.get("nbSegPerEdge") if new.get("nbSegPerEdge") else old.GetNbSegPerEdge())
old.SetNbSegPerRadius(new.get("nbSegPerRadius") if new.get("nbSegPerRadius") else old.GetNbSegPerRadius())
Parameters:
fineness (int): Fineness of mesh.
old.SetChordalErrorEnabled(new.get("chordalErrorEnabled") if new.get("chordalErrorEnabled") else old.GetChordalErrorEnabled())
old.SetChordalError(new.get("chordalError") if new.get("chordalError") else old.GetChordalError())
0 - Very coarse,
1 - Coarse,
2 - Moderate,
3 - Fine,
4 - Very fine.
Returns:
Configured instance of class <SMESH.SMESH_Mesh>, containig the parameters and boundary groups.
"""
###
# Netgen
##
Fineness = {
0: "Very coarse",
1: "Coarse",
2: "Moderate",
3: "Fine",
4: "Very fine",
5: "Custom"
}[parameters.fineness]
# Mesh
mesh = smesh.Mesh(shape)
netgen = mesh.Tetrahedron(algo=smeshBuilder.NETGEN_1D2D3D)
# Parameters
param = netgen.Parameters()
param.SetMinSize(parameters.minSize)
param.SetMaxSize(parameters.maxSize)
param.SetFineness(parameters.fineness)
if parameters.fineness == 5:
param.SetGrowthRate(parameters.growthRate)
param.SetNbSegPerEdge(parameters.nbSegPerEdge)
param.SetNbSegPerRadius(parameters.nbSegPerRadius)
old.SetSecondOrder(new.get("secondOrder") if new.get("secondOrder") else old.GetSecondOrder())
old.SetOptimize(new.get("optimize") if new.get("optimize") else old.GetOptimize())
old.SetQuadAllowed(new.get("quadAllowed") if new.get("quadAllowed") else old.GetQuadAllowed())
old.SetUseSurfaceCurvature(new.get("useSurfaceCurvature") if new.get("useSurfaceCurvature") else old.GetUseSurfaceCurvature())
old.SetFuseEdges(new.get("fuseEdges") if new.get("fuseEdges") else old.GetFuseEdges())
old.SetCheckChartBoundary(new.get("checkChartBoundary") if new.get("checkChartBoundary") else old.GetCheckChartBoundary())
param.SetChordalErrorEnabled(parameters.chordalErrorEnabled)
param.SetChordalError(parameters.chordalError)
class Mesh(object):
def __init__(self, shape, name = ""):
self.name = name if name else shape.GetName()
self.mesh = smesh.Mesh(shape, self.name)
self.geom = shape
self.algo = None
self.params = None
self.viscousLayers = None
param.SetSecondOrder(parameters.secondOrder)
param.SetOptimize(parameters.optimize)
param.SetQuadAllowed(parameters.quadAllowed)
self.submeshes = []
param.SetUseSurfaceCurvature(parameters.useSurfaceCurvature)
param.SetFuseEdges(parameters.fuseEdges)
param.SetCheckChartBoundary(parameters.checkChartBoundary)
def Tetrahedron(self, **kwargs):
self.algo = self.mesh.Tetrahedron(algo = smeshBuilder.NETGEN_1D2D3D)
self.params = self.algo.Parameters()
self.params = updateParams(self.params, kwargs)
logger.info("""meshCreate:
fineness:\t{}
min size:\t{}
max size:\t{}
growth rate:\t{}
nb segs per edge:\t{}
nb segs per radius:\t{}
limit size by surface curvature:\t{}
quad-dominated:\t{}
second order:\t{}
optimize:\t{}""".format(
Fineness, param.GetMinSize(), param.GetMaxSize(),
param.GetGrowthRate(), param.GetNbSegPerEdge(), param.GetNbSegPerRadius(),
True if param.GetUseSurfaceCurvature() else False,
True if param.GetQuadAllowed() else False,
True if param.GetSecondOrder() else False,
True if param.GetOptimize() else False))
def ViscousLayers(self,
thickness = 1,
numberOfLayers = 1,
stretchFactor = 0,
faces = [],
isFacesToIgnore = True,
extrMethod = ExtrusionMethod.SURF_OFFSET_SMOOTH,
**kwargs
):
###
# Local sizes
##
for group in groups:
localSize = parameters.localSizeOnShape.__dict__.get(group)
if localSize:
param.SetLocalSizeOnShape(group, localSize)
###
# Viscous layers
##
if parameters.viscousLayers:
vlayer = netgen.ViscousLayers(
parameters.thickness,
parameters.numberOfLayers,
parameters.stretchFactor,
parameters.facesToIgnore,
parameters.isFacesToIgnore,
parameters.extrusionMethod
self.viscousLayers = self.algo.ViscousLayers(
thickness,
numberOfLayers,
stretchFactor,
faces,
isFacesToIgnore,
extrMethod
)
logger.info("""meshCreate:
viscous layers:
thickness:\t{}
number:\t{}
stretch factor:\t{}""".format(
parameters.thickness,
parameters.numberOfLayers,
parameters.stretchFactor))
def Triangle(self, subshape, **kwargs):
submesh = Submesh(self.mesh, subshape)
submesh.algo = self.mesh.Triangle(algo = smeshBuilder.NETGEN_1D2D, geom = subshape)
submesh.mesh = submesh.algo.subm
submesh.params = submesh.algo.Parameters()
else:
logger.info("""meshCreate:
viscous layers: false""")
submesh.params = updateParams(submesh.params, kwargs)
return mesh
self.submeshes.append(submesh)
def assignGroups(self, withPrefix = True):
prefix = "smesh_" if withPrefix else ""
def meshCompute(mobj, groups):
"""Compute the mesh."""
status = mobj.Compute()
for group in self.mesh.geompyD.GetGroups(self.geom):
if group.GetName():
self.mesh.GroupOnGeom(group, f"{ prefix }{ group.GetName() }", SMESH.FACE)
if status:
logger.info("meshCompute: computed")
def compute(self):
isDone = self.mesh.Compute()
returncode = int(not isDone)
errors = self.mesh.GetComputeErrors()
###
# Post computing
##
if mobj.NbPyramids() > 0:
logger.info(f"meshCompute: detected {mobj.NbPyramids()} pyramids: splitting volumes into tetrahedrons")
return returncode, errors
def stats(self):
return {
"elements": self.mesh.NbElements(),
"edges": self.mesh.NbEdges(),
"faces": self.mesh.NbFaces(),
"volumes": self.mesh.NbVolumes(),
"tetrahedrons": self.mesh.NbTetras(),
"prisms": self.mesh.NbPrisms(),
"pyramids": self.mesh.NbPyramids()
}
def exportUNV(self, path):
returncode = 0
error = ""
try:
self.mesh.ExportUNV(path)
except Exception as e:
error = e.details.text
returncode = 1
return returncode, error
def removePyramids(self):
if self.mesh.NbPyramids() > 0:
pyramidCriterion = smesh.GetCriterion(
SMESH.VOLUME,
SMESH.FT_ElemGeomType,
SMESH.FT_Undefined,
SMESH.Geom_PYRAMID
)
pyramidGroup = mobj.MakeGroupByCriterion("pyramids", pyramidCriterion)
pyramidVolumes = mobj.GetIDSource(pyramidGroup.GetIDs(), SMESH.VOLUME)
pyramidGroup = self.mesh.MakeGroupByCriterion("pyramids", pyramidCriterion)
pyramidVolumes = self.mesh.GetIDSource(pyramidGroup.GetIDs(), SMESH.VOLUME)
mobj.SplitVolumesIntoTetra(pyramidVolumes, smesh.Hex_5Tet)
self.mesh.SplitVolumesIntoTetra(pyramidVolumes, smesh.Hex_5Tet)
mobj.RemoveGroup(pyramidGroup)
mobj.RenumberElements()
###
# Groups
##
for group in groups:
mobj.GroupOnGeom(group, f"{ group.GetName() }_", SMESH.FACE)
else:
logger.warning("meshCompute: not computed")
return not status
self.mesh.RemoveGroup(pyramidGroup)
self.mesh.RenumberElements()
def meshStats(mobj):
"""
Print mesh information.
"""
stats = {
"Elements": mobj.NbElements(),
"Edges": mobj.NbEdges(),
"Faces": mobj.NbFaces(),
"Volumes": mobj.NbVolumes(),
"Tetrahedrons": mobj.NbTetras(),
"Prisms": mobj.NbPrisms(),
"Pyramids": mobj.NbPyramids()
}
info = "meshStats:\n"
for key in stats:
info += f"\t{key}:\t{stats[key]}\n"
logger.info(info)
def meshExport(mobj, path):
"""
Export the mesh in a file in UNV format.
Parameters:
path (string): full path to the expected directory.
"""
try:
mobj.ExportUNV(path)
logger.info("""meshExport:
format:\t{}""".format("unv"))
except:
logger.error("""meshExport: Cannot export.""")
class Submesh(object):
def __init__(self, father, subshape, name = ""):
self.name = name if name else subshape.GetName()
self.mesh = None
self.geom = subshape
self.algo = None
self.params = None

View File

@ -20,11 +20,11 @@ def startServer(port):
return p
def salomeVersion() -> str:
return "Salome 9.6.0"
return "Salome 9.7.0 MPI"
def runExecute(port: int, scriptpath: str, *args) -> int:
cmd = ["salome", "start", "--shutdown-servers=1", "--port", str(port), "-t",
cmd = ["salome-9.7.0-mpi", "start", "--shutdown-servers=1", "--port", str(port), "-t",
scriptpath, "args:{}".format(", ".join([str(arg) for arg in args]))]
logger.info("salome: {}".format(cmd[1 : 6]))