From 3d4e7abb66257cdb5aad2fc9e8c6b31bada13325 Mon Sep 17 00:00:00 2001 From: L-Nafaryus Date: Mon, 7 Jun 2021 17:09:32 +0500 Subject: [PATCH] Massive improvement New: few control args Mod: struct to dict conversion New: configuration for flow Fix: missed logs from openfoam package (checkMesh, etc) --- anisotropy/anisotropy.py | 226 +++++++++++++++++++++++++++-------- anisotropy/utils.py | 12 +- bin/anisotropy | 4 +- conf/config.toml | 48 +++++++- openfoam/__init__.py | 5 +- openfoam/meshManipulation.py | 8 +- openfoam/utils.py | 10 ++ salomepl/genmesh.py | 9 +- salomepl/utils.py | 3 +- 9 files changed, 254 insertions(+), 71 deletions(-) diff --git a/anisotropy/anisotropy.py b/anisotropy/anisotropy.py index d8217f2..72b921c 100644 --- a/anisotropy/anisotropy.py +++ b/anisotropy/anisotropy.py @@ -10,7 +10,26 @@ from utils import struct import toml 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)) LOG = os.path.join(ROOT, "logs") @@ -31,26 +50,38 @@ logging.basicConfig( ) logger = logging.getLogger(config.logger.name) - +### +# Main +## def main(): if checkEnv(): 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(f"""main: - task:\t{ n + 1 } / { len(tasks) } + task:\t{ n + 1 } / { len(queue) } cpu count:\t{ os.cpu_count() } case:\t{ case }""") ### # 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: logger.critical("mesh not computed: Skipping flow computation") @@ -59,30 +90,41 @@ def main(): ### # Compute flow ## - computeFlow(case) + + if not task.status.flow or mode == "all": + computeFlow(case) + + else: + logger.info("computeFlow: flow already computed") -def createTasks(): - tasks = [] - - 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) ] +def createQueue(): + queue = [] ### - # 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(): if getattr(config.base, structure): 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( f"{ BUILD }", f"{ structure }", @@ -90,16 +132,27 @@ def createTasks(): 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): os.makedirs(case) + # prepare configuration for task task = { - "logger": config.logger.__dict__, + "logger": dict(config.logger), "structure": structure, "status": { "mesh": False, "flow": False }, + "statistics": { + "meshTime": 0, + "flowTime": 0 + }, "parameters": { "theta": theta }, @@ -107,18 +160,21 @@ def createTasks(): "direction": direction, "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: toml.dump(task, io) - - tasks.append(case) + ## + queue.append(case) - return tasks + return queue from salomepl.utils import runExecute, salomeVersion @@ -130,13 +186,24 @@ def computeMesh(case): returncode = runExecute(port, scriptpath, ROOT, case) - etime = time.monotonic() - logger.info("computeMesh: elapsed time: {}".format(timedelta(seconds = etime - stime))) + task = struct(toml.load(os.path.join(case, "task.toml"))) + 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 def computeFlow(case): + ### + # Case preparation + ## foamCase = [ "0", "constant", "system" ] os.chdir(case) @@ -151,6 +218,9 @@ def computeFlow(case): stime = time.monotonic() + ### + # Mesh manipulations + ## if not os.path.exists("mesh.unv"): logger.critical(f"computeFlow: missed 'mesh.unv'") return @@ -164,48 +234,104 @@ def computeFlow(case): openfoam.createPatch(dictfile = "system/createPatchDict.symetry") - openfoam.foamDictionary("constant/polyMesh/boundary", "entry0.defaultFaces.type", "wall") - openfoam.foamDictionary("constant/polyMesh/boundary", "entry0.defaultFaces.inGroups", "1 (wall)") + openfoam.foamDictionary( + "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(scale) + 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", "pressureInletVelocity") - openfoam.foamDictionary(f"processor{n}/0/U", "boundaryField.inlet.value", "uniform (0 0 0)") + 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 with open(os.path.join(case, "task.toml"), "w") as io: - toml.dump({ - "structure": task.structure, - "logger": task.logger.__dict__, - "status": task.status.__dict__, - "parameters": task.parameters.__dict__, - "geometry": task.geometry.__dict__, - "mesh": task.mesh.__dict__ - }, io) + toml.dump(dict(task), io) os.chdir(ROOT) - etime = time.monotonic() - logger.info("computeFlow: elapsed time: {}".format(timedelta(seconds = etime - stime))) - return returncode + def checkEnv(): missed = False diff --git a/anisotropy/utils.py b/anisotropy/utils.py index 1f5c0ec..00c47bf 100644 --- a/anisotropy/utils.py +++ b/anisotropy/utils.py @@ -11,11 +11,19 @@ class struct: for (k, v) in args[0].items(): if type(v) == dict: setattr(self, k, struct(v)) + else: setattr(self, k, v) else: - for (k, v) in kwargs.items(): - setattr(self, k, v) + self.__dict__.update(kwargs) + + 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): members = [] diff --git a/bin/anisotropy b/bin/anisotropy index ad6c874..83e8892 100755 --- a/bin/anisotropy +++ b/bin/anisotropy @@ -15,6 +15,8 @@ anisotropy-help() echo "" echo "Options:" echo " -c, --config Use custom configuration file." + echo " -s, --safe Safe mode (skip successfuly computed mesh/flow)" + echo " -a, --all All mode (overwrites everything)" } case $1 in @@ -33,7 +35,7 @@ case $1 in run) source ${OPENFOAM} source env/bin/activate - python ${DIR}/anisotropy/anisotropy.py + python ${DIR}/anisotropy/anisotropy.py ${@:2} deactivate ;; diff --git a/conf/config.toml b/conf/config.toml index 1241235..fde9203 100644 --- a/conf/config.toml +++ b/conf/config.toml @@ -43,7 +43,7 @@ useSurfaceCurvature = true fuseEdges = true checkChartBoundary = false -thickness = [0.005, 0.005] +thickness = [0.01, 0.005] numberOfLayers = 2 stretchFactor = 1.2 isFacesToIgnore = true @@ -78,7 +78,7 @@ useSurfaceCurvature = true fuseEdges = true checkChartBoundary = false -thickness = [0.005, 0.005] +thickness = [0.005, 0.001] numberOfLayers = 2 stretchFactor = 1.2 isFacesToIgnore = true @@ -113,8 +113,50 @@ useSurfaceCurvature = true fuseEdges = true checkChartBoundary = false -thickness = [0.001, 0.001] +thickness = [0.001, 0.0005] numberOfLayers = 2 stretchFactor = 1.2 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" + + diff --git a/openfoam/__init__.py b/openfoam/__init__.py index e959345..e6cd8d6 100644 --- a/openfoam/__init__.py +++ b/openfoam/__init__.py @@ -4,7 +4,7 @@ from .meshManipulation import createPatch, transformPoints, checkMesh, renumberM from .miscellaneous import foamDictionary from .parallelProcessing import decomposePar from .solvers import potentialFoam, simpleFoam -from .utils import foamVersion, foamClean +from .utils import foamVersion, foamClean, uniform __all__ = [ # meshConversion @@ -28,5 +28,6 @@ __all__ = [ # utils "foamVersion", - "foamClean" + "foamClean", + "uniform" ] diff --git a/openfoam/meshManipulation.py b/openfoam/meshManipulation.py index 44e10e5..a200fba 100644 --- a/openfoam/meshManipulation.py +++ b/openfoam/meshManipulation.py @@ -11,13 +11,13 @@ def createPatch(dictfile: str = None, case: str = None): application("createPatch", *args, case = case, stderr = True) -def transformPoints(scale: tuple, case: str = None): - scale_ = "{}".format(scale).replace(",", "") +def transformPoints(scale, case: str = None): + _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) out = "" diff --git a/openfoam/utils.py b/openfoam/utils.py index 0928b57..f89ec8f 100644 --- a/openfoam/utils.py +++ b/openfoam/utils.py @@ -14,3 +14,13 @@ def foamClean(case: str = None): if os.path.exists(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 "" diff --git a/salomepl/genmesh.py b/salomepl/genmesh.py index 1425913..4ec2b31 100644 --- a/salomepl/genmesh.py +++ b/salomepl/genmesh.py @@ -87,14 +87,7 @@ def genmesh(): config.status.mesh = True with open(CONFIG, "w") as io: - toml.dump({ - "structure": config.structure, - "logger": config.logger.__dict__, - "status": config.status.__dict__, - "parameters": config.parameters.__dict__, - "geometry": config.geometry.__dict__, - "mesh": config.mesh.__dict__ - }, io) + toml.dump(dict(config), io) meshStats(mesh) meshExport(mesh, os.path.join(CASE, "mesh.unv")) diff --git a/salomepl/utils.py b/salomepl/utils.py index 2ebbcdd..2a1f3dc 100644 --- a/salomepl/utils.py +++ b/salomepl/utils.py @@ -28,7 +28,8 @@ def runExecute(port: int, scriptpath: str, *args) -> int: scriptpath, "args:{}".format(", ".join([str(arg) for arg in args]))] 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]))], # stderr = subprocess.STDOUT)