Mod: cli in dev
Mod: some new tests Mod: some new db models in dev for flow Mod: default configuration file (flow) Move: merge genmesh with cli
This commit is contained in:
parent
513fd1be52
commit
85383f4cbc
@ -1,20 +1,85 @@
|
|||||||
import click
|
import click
|
||||||
from anisotropy.anisotropy import Anisotropy
|
|
||||||
|
|
||||||
pass_anisotropy = click.make_pass_decorator(Anisotropy)
|
#pass_anisotropy = click.make_pass_decorator(Anisotropy)
|
||||||
|
def version():
|
||||||
|
msg = "Missed package anisotropy"
|
||||||
|
|
||||||
|
try:
|
||||||
|
from anisotropy import Anisotropy
|
||||||
|
msg = Anisotropy.version()
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return msg
|
||||||
|
|
||||||
@click.group()
|
@click.group()
|
||||||
@click.version_option(version = "", message = Anisotropy.version())
|
@click.version_option(version = "", message = version())
|
||||||
@click.pass_context
|
def anisotropy():
|
||||||
def anisotropy(ctx):
|
pass
|
||||||
ctx.obj = Anisotropy()
|
|
||||||
|
|
||||||
|
|
||||||
@anisotropy.command()
|
@anisotropy.command()
|
||||||
@click.option("-s", "--stage", "stage", type = click.Choice(["all", "mesh", "flow"]), default = "all")
|
@click.option("-s", "--stage", "stage", type = click.Choice(["all", "mesh", "flow"]), default = "all")
|
||||||
@click.option("-p", "--param", "params", metavar = "key=value", multiple = True)
|
@click.option("-p", "--param", "params", metavar = "key=value", multiple = True)
|
||||||
@pass_anisotropy
|
def compute(stage, params):
|
||||||
def compute(anisotropy, stage, params):
|
from anisotropy import Anisotropy
|
||||||
pass
|
|
||||||
|
|
||||||
|
model = Anisotropy()
|
||||||
|
model.setupDB()
|
||||||
|
|
||||||
|
if model.isEmptyDB():
|
||||||
|
paramsAll = model.loadFromScratch()
|
||||||
|
|
||||||
|
for entry in paramsAll:
|
||||||
|
model.updateDB(entry)
|
||||||
|
|
||||||
|
model.loadDB(type, direction, theta)
|
||||||
|
# TODO: merge cli params with db params here
|
||||||
|
model.evalParams()
|
||||||
|
model.updateDB()
|
||||||
|
|
||||||
|
# TODO: do smth with output
|
||||||
|
if stage == "all" or stage == "mesh":
|
||||||
|
((out, err, code), elapsed) = model.computeMesh(type, direction, theta)
|
||||||
|
|
||||||
|
if stage == "all" or stage == "flow":
|
||||||
|
((out, err, code), elapsed) = model.computeFlow(type, direction, theta)
|
||||||
|
|
||||||
|
|
||||||
|
@anisotropy.command()
|
||||||
|
@click.argument("root")
|
||||||
|
@click.argument("name")
|
||||||
|
@click.argument("direction")
|
||||||
|
@click.argument("theta", type = click.FLOAT)
|
||||||
|
def _compute_mesh(root, name, direction, theta):
|
||||||
|
# [Salome Environment]
|
||||||
|
|
||||||
|
###
|
||||||
|
# Args
|
||||||
|
##
|
||||||
|
direction = list(map(lambda num: float(num), direction[1:-1].split(",")))
|
||||||
|
|
||||||
|
###
|
||||||
|
# Modules
|
||||||
|
##
|
||||||
|
import salome
|
||||||
|
|
||||||
|
sys.path.extend([
|
||||||
|
root,
|
||||||
|
os.path.join(root, "env/lib/python3.9/site-packages")
|
||||||
|
])
|
||||||
|
|
||||||
|
from anisotropy import Anisotropy
|
||||||
|
|
||||||
|
###
|
||||||
|
model = Anisotropy()
|
||||||
|
model.setupDB()
|
||||||
|
model.loadDB(type, direction, theta)
|
||||||
|
|
||||||
|
model.genmesh()
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# CLI entry
|
||||||
|
##
|
||||||
anisotropy()
|
anisotropy()
|
||||||
|
@ -54,7 +54,7 @@ env.update(dict(
|
|||||||
CONFIG = os.path.join(env["ROOT"], "conf/config.toml")
|
CONFIG = os.path.join(env["ROOT"], "conf/config.toml")
|
||||||
))
|
))
|
||||||
env["db_path"] = env["BUILD"]
|
env["db_path"] = env["BUILD"]
|
||||||
|
env["salome_port"] = 2810
|
||||||
|
|
||||||
#if os.path.exists(env["CONFIG"]):
|
#if os.path.exists(env["CONFIG"]):
|
||||||
# config = toml.load(env["CONFIG"])
|
# config = toml.load(env["CONFIG"])
|
||||||
@ -157,7 +157,7 @@ class Anisotropy(object):
|
|||||||
return "\n".join([ f"{ k }: { v }" for k, v in versions.items() ])
|
return "\n".join([ f"{ k }: { v }" for k, v in versions.items() ])
|
||||||
|
|
||||||
|
|
||||||
def loadScratch(self):
|
def loadFromScratch(self):
|
||||||
if not os.path.exists(self.env["DEFAULT_CONFIG"]):
|
if not os.path.exists(self.env["DEFAULT_CONFIG"]):
|
||||||
logger.error("Missed default configuration file")
|
logger.error("Missed default configuration file")
|
||||||
return
|
return
|
||||||
@ -200,6 +200,7 @@ class Anisotropy(object):
|
|||||||
|
|
||||||
paramsAll.append(entryNew)
|
paramsAll.append(entryNew)
|
||||||
|
|
||||||
|
return paramsAll
|
||||||
self.setupDB()
|
self.setupDB()
|
||||||
|
|
||||||
for entry in paramsAll:
|
for entry in paramsAll:
|
||||||
@ -499,14 +500,260 @@ class Anisotropy(object):
|
|||||||
self.params = sorted(self.params, key = lambda entry: f"{ entry['name'] } { entry['geometry']['direction'] } { entry['geometry']['theta'] }")
|
self.params = sorted(self.params, key = lambda entry: f"{ entry['name'] } { entry['geometry']['direction'] } { entry['geometry']['theta'] }")
|
||||||
|
|
||||||
@timer
|
@timer
|
||||||
def computeMesh(self, name, direction, theta):
|
def computeMesh(self, type, direction, theta):
|
||||||
scriptpath = os.path.join(self.env["ROOT"], "anisotropy/genmesh.py")
|
scriptpath = os.path.join(self.env["ROOT"], "anisotropy/__main__.py")
|
||||||
port = 2900
|
port = 2900
|
||||||
|
|
||||||
return salomepl.utils.runSalome(port, scriptpath, self.env["ROOT"], name, direction, theta)
|
return salomepl.utils.runSalome(port, scriptpath, self.env["ROOT"], "_compute_mesh", type, direction, theta)
|
||||||
|
|
||||||
|
def genmesh(self):
|
||||||
|
import salome
|
||||||
|
|
||||||
|
p = self.params
|
||||||
|
|
||||||
|
logger.info("\n".join([
|
||||||
|
"genmesh:",
|
||||||
|
f"structure type:\t{ p['structure']['type'] }",
|
||||||
|
f"coefficient:\t{ p['structure']['theta'] }",
|
||||||
|
f"fillet:\t{ p['structure']['fillets'] }",
|
||||||
|
f"flow direction:\t{ p['structure']['direction'] }"
|
||||||
|
]))
|
||||||
|
|
||||||
|
salome.salome_init()
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# Shape
|
||||||
|
##
|
||||||
|
geompy = salomepl.geometry.getGeom()
|
||||||
|
structure = dict(
|
||||||
|
simple = Simple,
|
||||||
|
bodyCentered = BodyCentered,
|
||||||
|
faceCentered = FaceCentered
|
||||||
|
)[p["structure"]["type"]]
|
||||||
|
shape, groups = structure(**p["structure"]).build()
|
||||||
|
|
||||||
|
[length, surfaceArea, volume] = geompy.BasicProperties(shape, theTolerance = 1e-06)
|
||||||
|
|
||||||
|
logger.info("\n".join([
|
||||||
|
"shape:",
|
||||||
|
f"edges length:\t{ length }",
|
||||||
|
f"surface area:\t{ surfaceArea }",
|
||||||
|
f"volume:\t{ volume }"
|
||||||
|
]))
|
||||||
|
|
||||||
|
|
||||||
|
###
|
||||||
|
# Mesh
|
||||||
|
##
|
||||||
|
mp = p["mesh"]
|
||||||
|
|
||||||
|
lengths = [
|
||||||
|
geompy.BasicProperties(edge)[0] for edge in geompy.SubShapeAll(shape, geompy.ShapeType["EDGE"])
|
||||||
|
]
|
||||||
|
meanSize = sum(lengths) / len(lengths)
|
||||||
|
mp["maxSize"] = meanSize
|
||||||
|
mp["minSize"] = meanSize * 1e-1
|
||||||
|
mp["chordalError"] = mp["maxSize"] / 2
|
||||||
|
|
||||||
|
faces = []
|
||||||
|
for group in groups:
|
||||||
|
if group.GetName() in mp["facesToIgnore"]:
|
||||||
|
faces.append(group)
|
||||||
|
|
||||||
|
|
||||||
|
mesh = salomepl.mesh.Mesh(shape)
|
||||||
|
mesh.Tetrahedron(**mp)
|
||||||
|
|
||||||
|
if mp["viscousLayers"]:
|
||||||
|
mesh.ViscousLayers(**mp, faces = faces)
|
||||||
|
|
||||||
|
smp = p["submesh"]
|
||||||
|
|
||||||
|
for submesh in smp:
|
||||||
|
for group in groups:
|
||||||
|
if submesh["name"] == group.GetName():
|
||||||
|
subshape = group
|
||||||
|
|
||||||
|
submesh["maxSize"] = meanSize * 1e-1
|
||||||
|
submesh["minSize"] = meanSize * 1e-3
|
||||||
|
submesh["chordalError"] = submesh["minSize"] * 1e+1
|
||||||
|
|
||||||
|
mesh.Triangle(subshape, **submesh)
|
||||||
|
|
||||||
|
|
||||||
|
model.updateDB()
|
||||||
|
returncode, errors = mesh.compute()
|
||||||
|
|
||||||
|
if not returncode:
|
||||||
|
mesh.removePyramids()
|
||||||
|
mesh.assignGroups()
|
||||||
|
|
||||||
|
casePath = model.getCasePath()
|
||||||
|
os.makedirs(casePath, exist_ok = True)
|
||||||
|
mesh.exportUNV(os.path.join(casePath, "mesh.unv"))
|
||||||
|
|
||||||
|
meshStats = mesh.stats()
|
||||||
|
p["meshresults"] = dict(
|
||||||
|
surfaceArea = surfaceArea,
|
||||||
|
volume = volume,
|
||||||
|
**meshStats
|
||||||
|
)
|
||||||
|
model.updateDB()
|
||||||
|
|
||||||
|
logger.info("mesh stats:\n{}".format(
|
||||||
|
"\n".join(map(lambda v: f"{ v[0] }:\t{ v[1] }", meshStats.items()))
|
||||||
|
))
|
||||||
|
|
||||||
|
else:
|
||||||
|
logger.error(errors)
|
||||||
|
|
||||||
|
p["meshresults"] = dict(
|
||||||
|
surfaceArea = surfaceArea,
|
||||||
|
volume = volume
|
||||||
|
)
|
||||||
|
model.updateDB()
|
||||||
|
|
||||||
|
salome.salome_close()
|
||||||
|
|
||||||
|
@timer
|
||||||
|
def computeFlow(self, type, direction, theta):
|
||||||
|
###
|
||||||
|
# Case preparation
|
||||||
|
##
|
||||||
|
foamCase = [ "0", "constant", "system" ]
|
||||||
|
|
||||||
|
# ISSUE: ideasUnvToFoam cannot import mesh with '-case' flag so 'os.chdir' for that
|
||||||
|
os.chdir(self.getCasePath())
|
||||||
|
openfoam.foamClean()
|
||||||
|
|
||||||
|
for d in foamCase:
|
||||||
|
shutil.copytree(
|
||||||
|
os.path.join(ROOT, "openfoam/template", d),
|
||||||
|
os.path.join(case, d)
|
||||||
|
)
|
||||||
|
|
||||||
|
###
|
||||||
|
# Mesh manipulations
|
||||||
|
##
|
||||||
|
if not os.path.exists("mesh.unv"):
|
||||||
|
logger.error(f"missed 'mesh.unv'")
|
||||||
|
os.chdir(self.env["ROOT"])
|
||||||
|
return 1
|
||||||
|
|
||||||
|
_, returncode = openfoam.ideasUnvToFoam("mesh.unv")
|
||||||
|
|
||||||
|
if returncode:
|
||||||
|
os.chdir(self.env["ROOT"])
|
||||||
|
return returncode
|
||||||
|
|
||||||
|
openfoam.createPatch(dictfile = "system/createPatchDict")
|
||||||
|
|
||||||
|
openfoam.foamDictionary(
|
||||||
|
"constant/polyMesh/boundary",
|
||||||
|
"entry0.defaultFaces.type",
|
||||||
|
"wall"
|
||||||
|
)
|
||||||
|
openfoam.foamDictionary(
|
||||||
|
"constant/polyMesh/boundary",
|
||||||
|
"entry0.defaultFaces.inGroups",
|
||||||
|
"1 (wall)"
|
||||||
|
)
|
||||||
|
|
||||||
|
out = openfoam.checkMesh()
|
||||||
|
|
||||||
|
if out:
|
||||||
|
logger.info(out)
|
||||||
|
# TODO: replace all task variables
|
||||||
|
openfoam.transformPoints(task.flow.scale)
|
||||||
|
|
||||||
|
###
|
||||||
|
# Decomposition and initial approximation
|
||||||
|
##
|
||||||
|
openfoam.foamDictionary(
|
||||||
|
"constant/transportProperties",
|
||||||
|
"nu",
|
||||||
|
str(task.flow.constant.nu)
|
||||||
|
)
|
||||||
|
|
||||||
|
openfoam.decomposePar()
|
||||||
|
|
||||||
|
openfoam.renumberMesh()
|
||||||
|
|
||||||
|
pressureBF = task.flow.approx.pressure.boundaryField
|
||||||
|
velocityBF = task.flow.approx.velocity.boundaryField
|
||||||
|
direction = {
|
||||||
|
"[1, 0, 0]": 0,
|
||||||
|
"[0, 0, 1]": 1,
|
||||||
|
"[1, 1, 1]": 2
|
||||||
|
}[str(task.geometry.direction)]
|
||||||
|
|
||||||
|
openfoam.foamDictionary(
|
||||||
|
"0/p",
|
||||||
|
"boundaryField.inlet.value",
|
||||||
|
openfoam.uniform(pressureBF.inlet.value)
|
||||||
|
)
|
||||||
|
openfoam.foamDictionary(
|
||||||
|
"0/p",
|
||||||
|
"boundaryField.outlet.value",
|
||||||
|
openfoam.uniform(pressureBF.outlet.value)
|
||||||
|
)
|
||||||
|
|
||||||
|
openfoam.foamDictionary(
|
||||||
|
"0/U",
|
||||||
|
"boundaryField.inlet.value",
|
||||||
|
openfoam.uniform(velocityBF.inlet.value[direction])
|
||||||
|
)
|
||||||
|
|
||||||
|
openfoam.potentialFoam()
|
||||||
|
|
||||||
|
###
|
||||||
|
# Main computation
|
||||||
|
##
|
||||||
|
pressureBF = task.flow.main.pressure.boundaryField
|
||||||
|
velocityBF = task.flow.main.velocity.boundaryField
|
||||||
|
|
||||||
|
for n in range(os.cpu_count()):
|
||||||
|
openfoam.foamDictionary(
|
||||||
|
f"processor{n}/0/U",
|
||||||
|
"boundaryField.inlet.type",
|
||||||
|
velocityBF.inlet.type
|
||||||
|
)
|
||||||
|
openfoam.foamDictionary(
|
||||||
|
f"processor{n}/0/U",
|
||||||
|
"boundaryField.inlet.value",
|
||||||
|
openfoam.uniform(velocityBF.inlet.value[direction])
|
||||||
|
)
|
||||||
|
|
||||||
|
returncode, out = openfoam.simpleFoam()
|
||||||
|
if out:
|
||||||
|
logger.info(out)
|
||||||
|
|
||||||
|
###
|
||||||
|
# Check results
|
||||||
|
##
|
||||||
|
elapsed = time.monotonic() - stime
|
||||||
|
logger.info("computeFlow: elapsed time: {}".format(timedelta(seconds = elapsed)))
|
||||||
|
|
||||||
|
if returncode == 0:
|
||||||
|
task.status.flow = True
|
||||||
|
task.statistics.flowTime = elapsed
|
||||||
|
|
||||||
|
postProcessing = "postProcessing/flowRatePatch(name=outlet)/0/surfaceFieldValue.dat"
|
||||||
|
|
||||||
|
with open(postProcessing, "r") as io:
|
||||||
|
lastLine = io.readlines()[-1]
|
||||||
|
flowRate = float(lastLine.replace(" ", "").replace("\n", "").split("\t")[1])
|
||||||
|
|
||||||
|
task.statistics.flowRate = flowRate
|
||||||
|
|
||||||
|
with open(os.path.join(case, "task.toml"), "w") as io:
|
||||||
|
toml.dump(dict(task), io)
|
||||||
|
|
||||||
|
os.chdir(ROOT)
|
||||||
|
|
||||||
|
return returncode
|
||||||
|
|
||||||
def computeFlow(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def _queue(self):
|
def _queue(self):
|
||||||
pass
|
pass
|
||||||
|
@ -74,6 +74,24 @@ faceCentered = true
|
|||||||
fuseEdges = true
|
fuseEdges = true
|
||||||
checkChartBoundary = false
|
checkChartBoundary = false
|
||||||
|
|
||||||
|
[flow]
|
||||||
|
scale = [ 1e-5, 1e-5, 1e-5 ]
|
||||||
|
|
||||||
|
constant.nu = 1e-6
|
||||||
|
|
||||||
|
approx.pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 }
|
||||||
|
approx.pressure.boundaryField.outlet = { type = "fixedValue", value = 0 }
|
||||||
|
|
||||||
|
# multiplication velocity value with direction vector
|
||||||
|
approx.velocity.boundaryField.inlet = { type = "fixedValue", value = 6e-5 }
|
||||||
|
approx.velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" }
|
||||||
|
|
||||||
|
pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 }
|
||||||
|
pressure.boundaryField.outlet = { type = "fixedValue", value = 0 }
|
||||||
|
|
||||||
|
velocity.boundaryField.inlet = { type = "fixedValue", value = 0.0 }
|
||||||
|
velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" }
|
||||||
|
|
||||||
[[structures]]
|
[[structures]]
|
||||||
[structures.structure]
|
[structures.structure]
|
||||||
type = "bodyCentered"
|
type = "bodyCentered"
|
||||||
@ -141,6 +159,24 @@ faceCentered = true
|
|||||||
fuseEdges = true
|
fuseEdges = true
|
||||||
checkChartBoundary = false
|
checkChartBoundary = false
|
||||||
|
|
||||||
|
[flow]
|
||||||
|
scale = [ 1e-5, 1e-5, 1e-5 ]
|
||||||
|
|
||||||
|
constant.nu = 1e-6
|
||||||
|
|
||||||
|
approx.pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 }
|
||||||
|
approx.pressure.boundaryField.outlet = { type = "fixedValue", value = 0 }
|
||||||
|
|
||||||
|
# multiplication velocity value with direction vector
|
||||||
|
approx.velocity.boundaryField.inlet = { type = "fixedValue", value = 6e-5 }
|
||||||
|
approx.velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" }
|
||||||
|
|
||||||
|
pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 }
|
||||||
|
pressure.boundaryField.outlet = { type = "fixedValue", value = 0 }
|
||||||
|
|
||||||
|
velocity.boundaryField.inlet = { type = "fixedValue", value = 0.0 }
|
||||||
|
velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" }
|
||||||
|
|
||||||
[[structures]]
|
[[structures]]
|
||||||
[structures.structure]
|
[structures.structure]
|
||||||
type = "faceCentered"
|
type = "faceCentered"
|
||||||
@ -208,4 +244,21 @@ faceCentered = true
|
|||||||
fuseEdges = true
|
fuseEdges = true
|
||||||
checkChartBoundary = false
|
checkChartBoundary = false
|
||||||
|
|
||||||
|
[flow]
|
||||||
|
scale = [ 1e-5, 1e-5, 1e-5 ]
|
||||||
|
|
||||||
|
constant.nu = 1e-6
|
||||||
|
|
||||||
|
approx.pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 }
|
||||||
|
approx.pressure.boundaryField.outlet = { type = "fixedValue", value = 0 }
|
||||||
|
|
||||||
|
# multiplication velocity value with direction vector
|
||||||
|
approx.velocity.boundaryField.inlet = { type = "fixedValue", value = 6e-5 }
|
||||||
|
approx.velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" }
|
||||||
|
|
||||||
|
pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 }
|
||||||
|
pressure.boundaryField.outlet = { type = "fixedValue", value = 0 }
|
||||||
|
|
||||||
|
velocity.boundaryField.inlet = { type = "fixedValue", value = 0.0 }
|
||||||
|
velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" }
|
||||||
|
|
||||||
|
@ -1,164 +0,0 @@
|
|||||||
###
|
|
||||||
# This file executes inside salome environment
|
|
||||||
#
|
|
||||||
# salome starts at user home directory
|
|
||||||
##
|
|
||||||
import os, sys
|
|
||||||
import math
|
|
||||||
import logging
|
|
||||||
import salome
|
|
||||||
import click
|
|
||||||
|
|
||||||
@click.command()
|
|
||||||
@click.argument("root")
|
|
||||||
@click.argument("name")
|
|
||||||
@click.argument("direction")
|
|
||||||
@click.argument("theta", type = click.FLOAT)
|
|
||||||
def genmesh(root, name, direction, theta):
|
|
||||||
print(root)
|
|
||||||
print(name)
|
|
||||||
print(direction)
|
|
||||||
print(theta)
|
|
||||||
###
|
|
||||||
# Args
|
|
||||||
##
|
|
||||||
direction = list(map(lambda num: float(num), direction[1:-1].split(",")))
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
# Modules
|
|
||||||
##
|
|
||||||
sys.path.extend([
|
|
||||||
root,
|
|
||||||
os.path.join(root, "env/lib/python3.9/site-packages")
|
|
||||||
])
|
|
||||||
|
|
||||||
from anisotropy import (
|
|
||||||
Anisotropy,
|
|
||||||
logger,
|
|
||||||
Simple,
|
|
||||||
BodyCentered,
|
|
||||||
FaceCentered
|
|
||||||
)
|
|
||||||
|
|
||||||
import salomepl
|
|
||||||
|
|
||||||
###
|
|
||||||
# Model
|
|
||||||
##
|
|
||||||
model = Anisotropy()
|
|
||||||
model.setupDB()
|
|
||||||
model.loadDB(name, direction, theta)
|
|
||||||
model.evalParams()
|
|
||||||
|
|
||||||
p = model.params
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
# Entry
|
|
||||||
##
|
|
||||||
logger.info("\n".join([
|
|
||||||
"genmesh:",
|
|
||||||
f"structure type:\t{ p['structure']['type'] }",
|
|
||||||
f"coefficient:\t{ p['structure']['theta'] }",
|
|
||||||
f"fillet:\t{ p['structure']['fillets'] }",
|
|
||||||
f"flow direction:\t{ p['structure']['direction'] }"
|
|
||||||
]))
|
|
||||||
|
|
||||||
salome.salome_init()
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
# Shape
|
|
||||||
##
|
|
||||||
geompy = salomepl.geometry.getGeom()
|
|
||||||
structure = dict(
|
|
||||||
simple = Simple,
|
|
||||||
bodyCentered = BodyCentered,
|
|
||||||
faceCentered = FaceCentered
|
|
||||||
)[p["structure"]["type"]]
|
|
||||||
shape, groups = structure(**p["structure"]).build()
|
|
||||||
|
|
||||||
[length, surfaceArea, volume] = geompy.BasicProperties(shape, theTolerance = 1e-06)
|
|
||||||
|
|
||||||
logger.info("\n".join([
|
|
||||||
"shape:",
|
|
||||||
f"edges length:\t{ length }",
|
|
||||||
f"surface area:\t{ surfaceArea }",
|
|
||||||
f"volume:\t{ volume }"
|
|
||||||
]))
|
|
||||||
|
|
||||||
|
|
||||||
###
|
|
||||||
# Mesh
|
|
||||||
##
|
|
||||||
mp = p["mesh"]
|
|
||||||
|
|
||||||
lengths = [
|
|
||||||
geompy.BasicProperties(edge)[0] for edge in geompy.SubShapeAll(shape, geompy.ShapeType["EDGE"])
|
|
||||||
]
|
|
||||||
meanSize = sum(lengths) / len(lengths)
|
|
||||||
mp["maxSize"] = meanSize
|
|
||||||
mp["minSize"] = meanSize * 1e-1
|
|
||||||
mp["chordalError"] = mp["maxSize"] / 2
|
|
||||||
|
|
||||||
faces = []
|
|
||||||
for group in groups:
|
|
||||||
if group.GetName() in mp["facesToIgnore"]:
|
|
||||||
faces.append(group)
|
|
||||||
|
|
||||||
|
|
||||||
mesh = salomepl.mesh.Mesh(shape)
|
|
||||||
mesh.Tetrahedron(**mp)
|
|
||||||
|
|
||||||
if mp["viscousLayers"]:
|
|
||||||
mesh.ViscousLayers(**mp, faces = faces)
|
|
||||||
|
|
||||||
smp = p["submesh"]
|
|
||||||
|
|
||||||
for submesh in smp:
|
|
||||||
for group in groups:
|
|
||||||
if submesh["name"] == group.GetName():
|
|
||||||
subshape = group
|
|
||||||
|
|
||||||
submesh["maxSize"] = meanSize * 1e-1
|
|
||||||
submesh["minSize"] = meanSize * 1e-3
|
|
||||||
submesh["chordalError"] = submesh["minSize"] * 1e+1
|
|
||||||
|
|
||||||
mesh.Triangle(subshape, **submesh)
|
|
||||||
|
|
||||||
|
|
||||||
model.updateDB()
|
|
||||||
returncode, errors = mesh.compute()
|
|
||||||
|
|
||||||
if not returncode:
|
|
||||||
# TODO: MeshResult
|
|
||||||
pass
|
|
||||||
|
|
||||||
else:
|
|
||||||
logger.error(errors)
|
|
||||||
|
|
||||||
|
|
||||||
mesh.removePyramids()
|
|
||||||
mesh.assignGroups()
|
|
||||||
|
|
||||||
casePath = model.getCasePath()
|
|
||||||
os.makedirs(casePath, exist_ok = True)
|
|
||||||
mesh.exportUNV(os.path.join(casePath, "mesh.unv"))
|
|
||||||
|
|
||||||
meshStats = mesh.stats()
|
|
||||||
p["meshresults"] = dict(
|
|
||||||
#mesh_id = p["mesh"]["mesh_id"],
|
|
||||||
surfaceArea = surfaceArea,
|
|
||||||
volume = volume,
|
|
||||||
**meshStats
|
|
||||||
)
|
|
||||||
model.updateDB()
|
|
||||||
|
|
||||||
logger.info("mesh stats:\n{}".format(
|
|
||||||
"\n".join(map(lambda v: f"{ v[0] }:\t{ v[1] }", meshStats.items()))
|
|
||||||
))
|
|
||||||
|
|
||||||
salome.salome_close()
|
|
||||||
|
|
||||||
genmesh()
|
|
@ -118,3 +118,9 @@ class MeshResult(BaseModel):
|
|||||||
|
|
||||||
calculationTime = TimeField(null = True)
|
calculationTime = TimeField(null = True)
|
||||||
|
|
||||||
|
class Flow(BaseModel):
|
||||||
|
# TODO: flow model
|
||||||
|
pass
|
||||||
|
|
||||||
|
class FlowResults(BaseModel):
|
||||||
|
pass
|
||||||
|
@ -7,7 +7,7 @@ try:
|
|||||||
from salome.smesh import smeshBuilder
|
from salome.smesh import smeshBuilder
|
||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
logger.warning("[Warning] Trying to get SALOME mesh modules outside SALOME environment. Modules won't be imported.")
|
logger.warning("Trying to get SALOME mesh modules outside SALOME environment. Modules won't be imported.")
|
||||||
|
|
||||||
if globals().get("smeshBuilder"):
|
if globals().get("smeshBuilder"):
|
||||||
smesh = smeshBuilder.New()
|
smesh = smeshBuilder.New()
|
||||||
|
@ -1,17 +1,38 @@
|
|||||||
import os
|
import os
|
||||||
|
import unittest
|
||||||
|
|
||||||
class TestAnisotropy:
|
unittest.TestLoader.sortTestMethodsUsing = None
|
||||||
def test_import(self):
|
|
||||||
|
class TestAnisotropy(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
import anisotropy
|
import anisotropy
|
||||||
|
self.model = anisotropy.Anisotropy()
|
||||||
|
|
||||||
def test_db(self):
|
def test_01_create_db(self):
|
||||||
import anisotropy
|
self.model.setupDB()
|
||||||
|
path = os.path.join(self.model.env["db_path"], "anisotropy.db")
|
||||||
|
|
||||||
a = anisotropy.Anisotropy()
|
self.assertTrue(os.path.exists(path))
|
||||||
a.setupDB()
|
|
||||||
a.evalEnvParameters()
|
|
||||||
a.updateDB()
|
|
||||||
|
|
||||||
if os.path.exists("build/anisotropy.db"):
|
def test_02_load_scratch(self):
|
||||||
os.remove("build/anisotropy.db")
|
passed = True
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.model.loadScratch()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
passed = False
|
||||||
|
|
||||||
|
self.assertTrue(passed)
|
||||||
|
|
||||||
|
def test_03_load_db(self):
|
||||||
|
self.model.setupDB()
|
||||||
|
self.model.loadDB("simple", [1.0, 0.0, 0.0], 0.01)
|
||||||
|
|
||||||
|
self.assertEqual(self.model.params["structure"]["type"], "simple")
|
||||||
|
|
||||||
|
def test_04_updateDB(self):
|
||||||
|
self.model.updateDB()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user