Massive improvement

New: few control args
Mod: struct to dict conversion
New: configuration for flow
Fix: missed logs from openfoam package (checkMesh, etc)
This commit is contained in:
L-Nafaryus 2021-06-07 17:09:32 +05:00
parent 2532e20c53
commit 3d4e7abb66
9 changed files with 254 additions and 71 deletions

View File

@ -10,7 +10,26 @@ from utils import struct
import toml import toml
import logging import logging
CONFIG = os.path.join(ROOT, "conf/config.toml") ###
# Shell args
##
configPath = "conf/config.toml"
mode = "safe"
for n, arg in enumerate(sys.argv):
if arg == "-c" or arg == "--config":
configPath = sys.args[n + 1]
if arg == "-s" or arg == "--safe":
mode = "safe"
elif arg == "-a" or arg == "--all":
mode = "all"
###
# Load configuration and tools
##
CONFIG = os.path.join(ROOT, configPath)
config = struct(toml.load(CONFIG)) config = struct(toml.load(CONFIG))
LOG = os.path.join(ROOT, "logs") LOG = os.path.join(ROOT, "logs")
@ -31,26 +50,38 @@ logging.basicConfig(
) )
logger = logging.getLogger(config.logger.name) logger = logging.getLogger(config.logger.name)
###
# Main
##
def main(): def main():
if checkEnv(): if checkEnv():
return return
tasks = createTasks() logger.info(f"args:\n\tconfig:\t{ configPath }\n\tmode:\t{ mode }")
for n, case in enumerate(tasks): queue = createQueue()
for n, case in enumerate(queue):
logger.info("-" * 80) logger.info("-" * 80)
logger.info(f"""main: logger.info(f"""main:
task:\t{ n + 1 } / { len(tasks) } task:\t{ n + 1 } / { len(queue) }
cpu count:\t{ os.cpu_count() } cpu count:\t{ os.cpu_count() }
case:\t{ case }""") case:\t{ case }""")
### ###
# Compute mesh # Compute mesh
## ##
computeMesh(case) taskPath = os.path.join(case, "task.toml")
task = struct(toml.load(taskPath))
if not task.status.mesh or mode == "all":
computeMesh(case)
else:
logger.info("computeMesh: mesh already computed")
task = struct(toml.load(os.path.join(case, "task.toml"))) task = struct(toml.load(taskPath))
if not task.status.mesh: if not task.status.mesh:
logger.critical("mesh not computed: Skipping flow computation") logger.critical("mesh not computed: Skipping flow computation")
@ -59,30 +90,41 @@ def main():
### ###
# Compute flow # Compute flow
## ##
computeFlow(case)
if not task.status.flow or mode == "all":
computeFlow(case)
else:
logger.info("computeFlow: flow already computed")
def createTasks(): def createQueue():
tasks = [] queue = []
for structure in config.base.__dict__.keys():
###
# Special values
##
_theta = getattr(config, structure).parameters.theta
getattr(config, structure).parameters.theta = [ n * _theta[2] for n in range(int(_theta[0] / _theta[2]), int(_theta[1] / _theta[2]) + 1) ]
_thickness = getattr(config, structure).mesh.thickness
_count = len(getattr(config, structure).parameters.theta)
getattr(config, structure).mesh.thickness = [ _thickness[0] + n * (_thickness[1] - _thickness[0]) / (_count - 1) for n in range(0, _count) ]
### ###
# structure type / flow direction / coefficient theta # Special values
##
parameters_theta = {}
mesh_thickness = {}
for structure in config.base.__dict__.keys():
theta = getattr(config, structure).parameters.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
count = len(parameters_theta[structure])
mesh_thickness[structure] = [ thickness[0] + n * (thickness[1] - thickness[0]) / (count - 1) for n in range(0, count) ]
###
# structure type > flow direction > coefficient theta
## ##
for structure in config.base.__dict__.keys(): for structure in config.base.__dict__.keys():
if getattr(config.base, structure): if getattr(config.base, structure):
for direction in getattr(config, structure).geometry.directions: for direction in getattr(config, structure).geometry.directions:
for n, theta in enumerate(getattr(config, structure).parameters.theta): for n, theta in enumerate(parameters_theta[structure]):
# create dirs for case path
case = os.path.join( case = os.path.join(
f"{ BUILD }", f"{ BUILD }",
f"{ structure }", f"{ structure }",
@ -90,16 +132,27 @@ def createTasks():
f"theta-{ theta }" f"theta-{ theta }"
) )
taskPath = os.path.join(case, "task.toml")
if os.path.exists(taskPath) and mode == "safe":
queue.append(case)
continue
if not os.path.exists(case): if not os.path.exists(case):
os.makedirs(case) os.makedirs(case)
# prepare configuration for task
task = { task = {
"logger": config.logger.__dict__, "logger": dict(config.logger),
"structure": structure, "structure": structure,
"status": { "status": {
"mesh": False, "mesh": False,
"flow": False "flow": False
}, },
"statistics": {
"meshTime": 0,
"flowTime": 0
},
"parameters": { "parameters": {
"theta": theta "theta": theta
}, },
@ -107,18 +160,21 @@ def createTasks():
"direction": direction, "direction": direction,
"fillet": getattr(config, structure).geometry.fillet "fillet": getattr(config, structure).geometry.fillet
}, },
"mesh": getattr(config, structure).mesh.__dict__ "mesh": dict(getattr(config, structure).mesh),
"flow": dict(config.flow)
} }
#task["mesh"]["thickness"] = task["mesh"]["thickness"][int(n)] # reassign special values
task["mesh"]["thickness"] = mesh_thickness[structure][n]
##
with open(os.path.join(case, "task.toml"), "w") as io: with open(os.path.join(case, "task.toml"), "w") as io:
toml.dump(task, io) toml.dump(task, io)
##
tasks.append(case) queue.append(case)
return tasks return queue
from salomepl.utils import runExecute, salomeVersion from salomepl.utils import runExecute, salomeVersion
@ -130,13 +186,24 @@ def computeMesh(case):
returncode = runExecute(port, scriptpath, ROOT, case) returncode = runExecute(port, scriptpath, ROOT, case)
etime = time.monotonic() task = struct(toml.load(os.path.join(case, "task.toml")))
logger.info("computeMesh: elapsed time: {}".format(timedelta(seconds = etime - stime))) elapsed = time.monotonic() - stime
logger.info("computeMesh: elapsed time: {}".format(timedelta(seconds = elapsed)))
if returncode == 0:
task.statistics.meshTime = elapsed
with open(os.path.join(case, "task.toml"), "w") as io:
toml.dump(dict(task), io)
import openfoam import openfoam
def computeFlow(case): def computeFlow(case):
###
# Case preparation
##
foamCase = [ "0", "constant", "system" ] foamCase = [ "0", "constant", "system" ]
os.chdir(case) os.chdir(case)
@ -151,6 +218,9 @@ def computeFlow(case):
stime = time.monotonic() stime = time.monotonic()
###
# Mesh manipulations
##
if not os.path.exists("mesh.unv"): if not os.path.exists("mesh.unv"):
logger.critical(f"computeFlow: missed 'mesh.unv'") logger.critical(f"computeFlow: missed 'mesh.unv'")
return return
@ -164,48 +234,104 @@ def computeFlow(case):
openfoam.createPatch(dictfile = "system/createPatchDict.symetry") openfoam.createPatch(dictfile = "system/createPatchDict.symetry")
openfoam.foamDictionary("constant/polyMesh/boundary", "entry0.defaultFaces.type", "wall") openfoam.foamDictionary(
openfoam.foamDictionary("constant/polyMesh/boundary", "entry0.defaultFaces.inGroups", "1 (wall)") "constant/polyMesh/boundary",
"entry0.defaultFaces.type",
"wall"
)
openfoam.foamDictionary(
"constant/polyMesh/boundary",
"entry0.defaultFaces.inGroups",
"1 (wall)"
)
openfoam.checkMesh() out = openfoam.checkMesh()
if out:
logger.info(out)
scale = (1e-5, 1e-5, 1e-5) openfoam.transformPoints(task.flow.scale)
openfoam.transformPoints(scale)
###
# Decomposition and initial approximation
##
openfoam.foamDictionary(
"constant/transportProperties",
"nu",
str(task.flow.constant.nu)
)
openfoam.decomposePar() openfoam.decomposePar()
openfoam.renumberMesh() 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() openfoam.potentialFoam()
###
# Main computation
##
pressureBF = task.flow.main.pressure.boundaryField
velocityBF = task.flow.main.velocity.boundaryField
for n in range(os.cpu_count()): for n in range(os.cpu_count()):
openfoam.foamDictionary(f"processor{n}/0/U", "boundaryField.inlet.type", "pressureInletVelocity") openfoam.foamDictionary(
openfoam.foamDictionary(f"processor{n}/0/U", "boundaryField.inlet.value", "uniform (0 0 0)") 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() returncode, out = openfoam.simpleFoam()
if out: if out:
logger.info(out) logger.info(out)
###
# Check results
##
elapsed = time.monotonic() - stime
logger.info("computeFlow: elapsed time: {}".format(timedelta(seconds = elapsed)))
if returncode == 0: if returncode == 0:
task.status.flow = True task.status.flow = True
task.statistics.flowTime = elapsed
with open(os.path.join(case, "task.toml"), "w") as io: with open(os.path.join(case, "task.toml"), "w") as io:
toml.dump({ toml.dump(dict(task), io)
"structure": task.structure,
"logger": task.logger.__dict__,
"status": task.status.__dict__,
"parameters": task.parameters.__dict__,
"geometry": task.geometry.__dict__,
"mesh": task.mesh.__dict__
}, io)
os.chdir(ROOT) os.chdir(ROOT)
etime = time.monotonic()
logger.info("computeFlow: elapsed time: {}".format(timedelta(seconds = etime - stime)))
return returncode return returncode
def checkEnv(): def checkEnv():
missed = False missed = False

View File

@ -11,11 +11,19 @@ class struct:
for (k, v) in args[0].items(): for (k, v) in args[0].items():
if type(v) == dict: if type(v) == dict:
setattr(self, k, struct(v)) setattr(self, k, struct(v))
else: else:
setattr(self, k, v) setattr(self, k, v)
else: else:
for (k, v) in kwargs.items(): self.__dict__.update(kwargs)
setattr(self, k, v)
def __iter__(self):
for k in self.__dict__:
if type(getattr(self, k)) == struct:
yield k, dict(getattr(self, k))
else:
yield k, getattr(self, k)
def __str__(self): def __str__(self):
members = [] members = []

View File

@ -15,6 +15,8 @@ anisotropy-help()
echo "" echo ""
echo "Options:" echo "Options:"
echo " -c, --config <path-to-file> Use custom configuration file." echo " -c, --config <path-to-file> Use custom configuration file."
echo " -s, --safe Safe mode (skip successfuly computed mesh/flow)"
echo " -a, --all All mode (overwrites everything)"
} }
case $1 in case $1 in
@ -33,7 +35,7 @@ case $1 in
run) run)
source ${OPENFOAM} source ${OPENFOAM}
source env/bin/activate source env/bin/activate
python ${DIR}/anisotropy/anisotropy.py python ${DIR}/anisotropy/anisotropy.py ${@:2}
deactivate deactivate
;; ;;

View File

@ -43,7 +43,7 @@ useSurfaceCurvature = true
fuseEdges = true fuseEdges = true
checkChartBoundary = false checkChartBoundary = false
thickness = [0.005, 0.005] thickness = [0.01, 0.005]
numberOfLayers = 2 numberOfLayers = 2
stretchFactor = 1.2 stretchFactor = 1.2
isFacesToIgnore = true isFacesToIgnore = true
@ -78,7 +78,7 @@ useSurfaceCurvature = true
fuseEdges = true fuseEdges = true
checkChartBoundary = false checkChartBoundary = false
thickness = [0.005, 0.005] thickness = [0.005, 0.001]
numberOfLayers = 2 numberOfLayers = 2
stretchFactor = 1.2 stretchFactor = 1.2
isFacesToIgnore = true isFacesToIgnore = true
@ -113,8 +113,50 @@ useSurfaceCurvature = true
fuseEdges = true fuseEdges = true
checkChartBoundary = false checkChartBoundary = false
thickness = [0.001, 0.001] thickness = [0.001, 0.0005]
numberOfLayers = 2 numberOfLayers = 2
stretchFactor = 1.2 stretchFactor = 1.2
isFacesToIgnore = true isFacesToIgnore = true
###
# Flow
##
[flow]
scale = [1e-5, 1e-5, 1e-5]
[flow.constant]
nu = 1e-6
[flow.approx.pressure.boundaryField]
inlet.type = "fixedValue"
inlet.value = 1e-3
outlet.type = "fixedValue"
outlet.value = 0
[flow.approx.velocity.boundaryField]
inlet.type = "fixedValue"
inlet.value = [
[ 6e-5, 6e-5, 0.0 ],
[ 0.0, 0.0, 6e-5 ],
[ 6e-5, 6e-5, 6e-5 ]
]
outlet.type = "zeroGradient"
outlet.value = "None"
[flow.main.pressure.boundaryField]
inlet.type = "fixedValue"
inlet.value = 1e-3
outlet.type = "fixedValue"
outlet.value = 0
[flow.main.velocity.boundaryField]
inlet.type = "pressureInletVelocity"
inlet.value = [
[ 0, 0, 0 ],
[ 0, 0, 0 ],
[ 0, 0, 0 ]
]
outlet.type = "zeroGradient"
outlet.value = "None"

View File

@ -4,7 +4,7 @@ from .meshManipulation import createPatch, transformPoints, checkMesh, renumberM
from .miscellaneous import foamDictionary from .miscellaneous import foamDictionary
from .parallelProcessing import decomposePar from .parallelProcessing import decomposePar
from .solvers import potentialFoam, simpleFoam from .solvers import potentialFoam, simpleFoam
from .utils import foamVersion, foamClean from .utils import foamVersion, foamClean, uniform
__all__ = [ __all__ = [
# meshConversion # meshConversion
@ -28,5 +28,6 @@ __all__ = [
# utils # utils
"foamVersion", "foamVersion",
"foamClean" "foamClean",
"uniform"
] ]

View File

@ -11,13 +11,13 @@ def createPatch(dictfile: str = None, case: str = None):
application("createPatch", *args, case = case, stderr = True) application("createPatch", *args, case = case, stderr = True)
def transformPoints(scale: tuple, case: str = None): def transformPoints(scale, case: str = None):
scale_ = "{}".format(scale).replace(",", "") _scale = f"({ scale[0] } { scale[1] } { scale[2] })"
application("transformPoints", "-scale", scale_, case = case, stderr = True) application("transformPoints", "-scale", _scale, case = case, stderr = True)
def checkMesh(case: str = None): def checkMesh(case: str = None) -> str:
application("checkMesh", "-allGeometry", "-allTopology", case = case, stderr = True) application("checkMesh", "-allGeometry", "-allTopology", case = case, stderr = True)
out = "" out = ""

View File

@ -14,3 +14,13 @@ def foamClean(case: str = None):
if os.path.exists(os.path.join(path, d)): if os.path.exists(os.path.join(path, d)):
shutil.rmtree(os.path.join(path, d)) shutil.rmtree(os.path.join(path, d))
def uniform(value) -> str:
if type(value) == list or type(value) == tuple:
return f"uniform ({ value[0] } { value[1] } { value[2] })"
elif type(value) == int or type(value) == float:
return f"uniform { value }"
else:
return ""

View File

@ -87,14 +87,7 @@ def genmesh():
config.status.mesh = True config.status.mesh = True
with open(CONFIG, "w") as io: with open(CONFIG, "w") as io:
toml.dump({ toml.dump(dict(config), io)
"structure": config.structure,
"logger": config.logger.__dict__,
"status": config.status.__dict__,
"parameters": config.parameters.__dict__,
"geometry": config.geometry.__dict__,
"mesh": config.mesh.__dict__
}, io)
meshStats(mesh) meshStats(mesh)
meshExport(mesh, os.path.join(CASE, "mesh.unv")) meshExport(mesh, os.path.join(CASE, "mesh.unv"))

View File

@ -28,7 +28,8 @@ def runExecute(port: int, scriptpath: str, *args) -> int:
scriptpath, "args:{}".format(", ".join([str(arg) for arg in args]))] scriptpath, "args:{}".format(", ".join([str(arg) for arg in args]))]
logger.info("salome: {}".format(cmd[1 : 6])) logger.info("salome: {}".format(cmd[1 : 6]))
logpath = os.path.join("/".join(args[0].split("/")[:-1]), "salome.log") case = args[1]
logpath = os.path.join(case, "salome.log")
#p = subprocess.Popen(["salome", "start", "--shutdown-servers=1", "--port", str(port), "-t", scriptpath, "args:{}".format(", ".join([str(arg) for arg in args]))], #p = subprocess.Popen(["salome", "start", "--shutdown-servers=1", "--port", str(port), "-t", scriptpath, "args:{}".format(", ".join([str(arg) for arg in args]))],
# stderr = subprocess.STDOUT) # stderr = subprocess.STDOUT)