diff --git a/anisotropy/core/runner.py b/anisotropy/core/runner.py index 4d89265..cdb11cc 100644 --- a/anisotropy/core/runner.py +++ b/anisotropy/core/runner.py @@ -18,7 +18,7 @@ from anisotropy.database import database, tables as T from anisotropy.shaping import Simple, BodyCentered, FaceCentered from anisotropy.meshing import Mesh from anisotropy.openfoam.presets import CreatePatchDict -from anisotropy.solving.onephase import OnePhaseFlow +from anisotropy.solving import OnePhaseFlow from multiprocessing import current_process, parent_process class UltimateRunner(object): @@ -141,7 +141,8 @@ class UltimateRunner(object): r0 = params.r0, filletsEnabled = params.filletsEnabled ) - out, err, returncode = self.shape.build() + #out, err, returncode = self.shape.build() + self.shape.build() os.makedirs(self.casepath(), exist_ok = True) out, err, returncode = self.shape.export(path.join(self.casepath(), filename)) @@ -178,7 +179,8 @@ class UltimateRunner(object): # TODO: load from object or file self.mesh = Mesh(self.shape.shape) - out, err, returncode = self.mesh.build() + #out, err, returncode = self.mesh.build() + self.mesh.build() os.makedirs(self.casepath(), exist_ok = True) out, err, returncode = self.mesh.export(path.join(self.casepath(), filename)) @@ -263,15 +265,20 @@ class UltimateRunner(object): }) self.flow.append(createPatchDict) - out, err, returncode = self.flow.write() + self.flow.write() # Build a flow - out, err, returncode = self.flow.build() + try: + out, err, returncode = self.flow.build() + + except Exception as e: + out, err, returncode = "", e, 1 + logger.error(e, exc_info = True) if returncode == 0: params.flowStatus = "done" else: - logger.error(err) + #logger.error(err) params.flowStatus = "failed" with self.database: @@ -284,20 +291,23 @@ class UltimateRunner(object): stage = stage or self.config["stage"] - try: - if stage in ["shape", "all"]: - self.computeShape() + # TODO: fix flow + # TODO: change case path to execDATE/label-direction-theta/* + # TODO: fix nprocs + #try: + if stage in ["shape", "all"]: + self.computeShape() - if stage in ["mesh", "all"]: - self.computeMesh() + if stage in ["mesh", "all"]: + self.computeMesh() - #elif stage in ["flow", "all"]: - # self.computeFlow() + if stage in ["flow", "all"]: + self.computeFlow() #elif stage in ["postProcess", "all"]: # self.postProcess() - except: - pass + #except Exception as e: + # logger.error(e) diff --git a/anisotropy/openfoam/__init__.py b/anisotropy/openfoam/__init__.py index 526f9ee..8025c89 100644 --- a/anisotropy/openfoam/__init__.py +++ b/anisotropy/openfoam/__init__.py @@ -3,35 +3,15 @@ # License: GNU GPL version 3, see the file "LICENSE" for details. -from .meshConversion import ideasUnvToFoam, netgenNeutralToFoam -from .meshManipulation import createPatch, transformPoints, checkMesh, renumberMesh -from .miscellaneous import foamDictionary -from .parallelProcessing import decomposePar -from .solvers import potentialFoam, simpleFoam -from .utils import version, foamClean, uniform +#from .meshConversion import ideasUnvToFoam, netgenNeutralToFoam +#from .meshManipulation import createPatch, transformPoints, checkMesh, renumberMesh +#from .miscellaneous import foamDictionary +#from .parallelProcessing import decomposePar +#from .solvers import potentialFoam, simpleFoam +from .utils import version, uniform #, foamClean +from .foamfile import FoamFile +from .foamcase import FoamCase +from .runner import FoamRunner -__all__ = [ - # meshConversion - "ideasUnvToFoam", - - # meshManipulation - "createPatch", - "transformPoints", - "checkMesh", - "renumberMesh", - - # miscellaneous - "foamDictionary", - - # parallelProcessing - "decomposePar", - - # solvers - "potentialFoam", - "simpleFoam", - - # utils - "version", - "foamClean", - "uniform" -] +from . import presets +from . import runnerPresets diff --git a/anisotropy/openfoam/meshManipulation.py b/anisotropy/openfoam/meshManipulation.py index 2dc4934..4d0640c 100644 --- a/anisotropy/openfoam/meshManipulation.py +++ b/anisotropy/openfoam/meshManipulation.py @@ -28,7 +28,7 @@ def checkMesh(case: str = None) -> str: with open("checkMesh.log", "r") as io: warnings = [] for line in io: - if re.search(r"***", line): + if re.search(r"\*\*\*", line): warnings.append(line.replace("***", "").strip()) if warnings: diff --git a/anisotropy/openfoam/runner.py b/anisotropy/openfoam/runner.py index e888062..062b08b 100644 --- a/anisotropy/openfoam/runner.py +++ b/anisotropy/openfoam/runner.py @@ -2,4 +2,72 @@ # This file is part of anisotropy. # License: GNU GPL version 3, see the file "LICENSE" for details. +import os +import subprocess +import sys +from typing import List +import logging +logger = logging.getLogger(__name__) + +class FoamRunner(object): + def __init__(self, command: str, args: List[str] = None, mpi: bool = False, cwd: str = None, logpath: str = None, exit: bool = False): + self.command = command + self.args = args + self.mpi = mpi + self.cwd = cwd or os.getcwd() + self.logpath = logpath + self.exit = exit + self.output = "" + self.error = "" + self.returncode = 0 + + def fullcommand(self) -> List[str]: + command = [] + + if self.mpi: + nprocs = os.cpu_count() + command.extend(["mpirun", "-np", str(nprocs), "--oversubscribe"]) + + command.append(self.command) + + if self.args: + command.extend([ str(arg) for arg in self.args ]) + + return command + + def run(self) -> tuple[str, str, int]: + try: + proc = subprocess.Popen( + self.fullcommand(), + stdout = subprocess.PIPE, + stderr = subprocess.PIPE, + encoding = "utf-8", + cwd = self.cwd + ) + + logger.debug(f"Starting subprocess: { proc.args }") + + self.output, self.error = proc.communicate() + self.returncode = proc.returncode + + except FileNotFoundError as err: + self.error = err + self.returncode = 2 + + logger.error(self.error, exc_info = True) + + if self.logpath: + with open(self.logpath, "w") as io: + if self.output: + io.write(self.output) + + if self.error: + io.write(self.error) + + io.write(f"Exit code { self.returncode }") + + if not self.returncode == 0 and self.exit: + raise Exception(f"Subprocess failed: { proc.args }") + + return self.output, self.error, self.returncode \ No newline at end of file diff --git a/anisotropy/openfoam/runnerPresets.py b/anisotropy/openfoam/runnerPresets.py new file mode 100644 index 0000000..3eca8c1 --- /dev/null +++ b/anisotropy/openfoam/runnerPresets.py @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- +# This file is part of anisotropy. +# License: GNU GPL version 3, see the file "LICENSE" for details. + +from typing import List +from .runner import FoamRunner + +### +# meshConversion +## + +def netgenNeutralToFoam(meshfile: str, **kwargs) -> tuple[str, str, int]: + command = "netgenNeutralToFoam" + kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log")) + kwargs.update(exit = True) + args = [ meshfile ] + + return FoamRunner(command, args = args, **kwargs).run() + + +def ideasUnvToFoam(meshfile: str, **kwargs) -> tuple[str, str, int]: + command = "ideasUnvToFoam" + kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log")) + kwargs.update(exit = True) + args = [ meshfile ] + + return FoamRunner(command, args = args, **kwargs).run() + + +### +# meshManipulation +## + +def createPatch(dictfile: str = None, overwrite: bool = True, **kwargs) -> tuple[str, str, int]: + command = "createPatch" + kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log")) + kwargs.update(exit = True) + args = [] + + if dictfile: + args.extend(["-dict", dictfile]) + + if overwrite: + args.append("-overwrite") + + return FoamRunner(command, args = args, **kwargs).run() + + +def transformPoints(transformations: dict, **kwargs) -> tuple[str, str, int]: + command = "transformPoints" + kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log")) + kwargs.update(exit = True) + args = [] + arg = [] + + for k, v in transformations.items(): + if type(v) == int or type(v) == float: + value = str(v) + + elif type(v) == tuple or type(v) == list: + value = "({} {} {})".format(*v) + + arg.append("{}={}".format(k, value)) + + args.append(", ".join(arg)) + + return FoamRunner(command, args = args, **kwargs).run() + + +def checkMesh(allGeometry: bool = True, allTopology: bool = True, **kwargs) -> tuple[str, str, int]: + command = "checkMesh" + kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log")) + kwargs.update(exit = True) + args = [] + + if allGeometry: + args.append("-allGeometry") + + if allTopology: + args.append("-allTopology") + + return FoamRunner(command, args = args, **kwargs).run() + + +def renumberMesh(overwrite: bool = True, **kwargs) -> tuple[str, str, int]: + command = "renumberMesh" + kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log")) + kwargs.update(exit = True) + args = [] + + if overwrite: + args.append("-overwrite") + + return FoamRunner(command, args = args, **kwargs).run() + + +### +# miscellaneous +## + +# def foamDictionary() + + +### +# parallelProcessing +## + +def decomposePar(**kwargs) -> tuple[str, str, int]: + command = "decomposePar" + kwargs.update(logpath = kwargs.get("logpath", f"{command}.log")) + kwargs.update(exit = True) + args = [] + + return FoamRunner(command, args = args, **kwargs).run() + + +### +# solvers +## + +def potentialFoam(parallel: bool = False, **kwargs) -> tuple[str, str, int]: + command = "potentialFoam" + kwargs.update(logpath = kwargs.get("logpath", f"{command}.log")) + kwargs.update(exit = True) + args = [] + + if parallel: + args.append("-parallel") + kwargs.update(mpi = True) + + return FoamRunner(command, args = args, **kwargs).run() + + +def simpleFoam(parallel: bool = False, **kwargs) -> tuple[str, str, int]: + command = "simpleFoam" + kwargs.update(logpath = kwargs.get("logpath", f"{command}.log")) + kwargs.update(exit = True) + args = [] + + if parallel: + args.append("-parallel") + kwargs.update(mpi = True) + + return FoamRunner(command, args = args, **kwargs).run() diff --git a/anisotropy/openfoam/utils.py b/anisotropy/openfoam/utils.py index 2c77f9d..5b0856a 100644 --- a/anisotropy/openfoam/utils.py +++ b/anisotropy/openfoam/utils.py @@ -4,7 +4,7 @@ import os import shutil -from .application import application +#from .application import application def version() -> str: return os.environ.get("WM_PROJECT_VERSION") @@ -19,15 +19,15 @@ def foamCleanCustom(case: str = None): if os.path.exists(os.path.join(path, d)): shutil.rmtree(os.path.join(path, d)) -def foamClean(case: str = None): - rmDirs = ["0", "constant", "system"] - path = case if case else "" - - for d in rmDirs: - if os.path.exists(os.path.join(path, d)): - shutil.rmtree(os.path.join(path, d)) - - application("foamCleanTutorials", useMPI = False, case = case, stderr = True) +#def foamClean(case: str = None): +# rmDirs = ["0", "constant", "system"] +# path = case if case else "" +# +# for d in rmDirs: +# if os.path.exists(os.path.join(path, d)): +# shutil.rmtree(os.path.join(path, d)) +# +# application("foamCleanTutorials", useMPI = False, case = case, stderr = True) def uniform(value) -> str: if type(value) == list or type(value) == tuple: diff --git a/anisotropy/solving/__init__.py b/anisotropy/solving/__init__.py index e888062..f632f63 100644 --- a/anisotropy/solving/__init__.py +++ b/anisotropy/solving/__init__.py @@ -2,4 +2,4 @@ # This file is part of anisotropy. # License: GNU GPL version 3, see the file "LICENSE" for details. - +from .onephase import OnePhaseFlow diff --git a/anisotropy/solving/onephase.py b/anisotropy/solving/onephase.py index 660997e..b3e0f41 100644 --- a/anisotropy/solving/onephase.py +++ b/anisotropy/solving/onephase.py @@ -2,19 +2,18 @@ # This file is part of anisotropy. # License: GNU GPL version 3, see the file "LICENSE" for details. -import anisotropy.openfoam as openfoam -from anisotropy.openfoam.presets import ( - ControlDict, FvSchemes, FvSolution, - TransportProperties, TurbulenceProperties, CreatePatchDict, - P, U -) -from anisotropy.openfoam.foamcase import FoamCase +import anisotropy.openfoam.presets as F +import anisotropy.openfoam.runnerPresets as R +from anisotropy.openfoam import FoamCase, uniform +import logging + +logger = logging.getLogger(__name__) class OnePhaseFlow(FoamCase): def __init__(self, path: str = None): FoamCase.__init__(self, path = path) - controlDict = ControlDict() + controlDict = F.ControlDict() controlDict.update( startFrom = "latestTime", endTime = 5000, @@ -22,9 +21,9 @@ class OnePhaseFlow(FoamCase): runTimeModifiable = "true" ) - fvSchemes = FvSchemes() + fvSchemes = F.FvSchemes() - fvSolution = FvSolution() + fvSolution = F.FvSolution() fvSolution["solvers"]["U"].update( nSweeps = 2, tolerance = 1e-08 @@ -56,20 +55,20 @@ class OnePhaseFlow(FoamCase): ) fvSolution["relaxationFactors"]["equations"]["U"] = 0.5 - transportProperties = TransportProperties() + transportProperties = F.TransportProperties() transportProperties.update( nu = 1e-06 ) - turbulenceProperties = TurbulenceProperties() + turbulenceProperties = F.TurbulenceProperties() turbulenceProperties.content = dict( simulationType = "laminar" ) boundaries = [ "inlet", "outlet", "symetry", "wall"] - p = P() + p = F.P() p["boundaryField"] = {} - u = U() + u = F.U() u["boundaryField"] = {} # ISSUE: add proxy from geometry direction to outlet boundaryField. @@ -77,17 +76,17 @@ class OnePhaseFlow(FoamCase): if boundary == "inlet": p["boundaryField"][boundary] = dict( type = "fixedValue", - value = "uniform 1e-3" + value = uniform(1e-3) ) u["boundaryField"][boundary] = dict( type = "fixedValue", - value = "uniform (0 0 -6e-5)" # * direction + value = uniform([0, 0, -6e-5]) # * direction ) elif boundary == "outlet": p["boundaryField"][boundary] = dict( type = "fixedValue", - value = "uniform 0" + value = uniform(0) ) u["boundaryField"][boundary] = dict( type = "zeroGradient", @@ -99,7 +98,7 @@ class OnePhaseFlow(FoamCase): ) u["boundaryField"][boundary] = dict( type = "fixedValue", - value = "uniform (0 0 0)" + value = uniform([0, 0, 0]) ) self.extend([ @@ -112,24 +111,28 @@ class OnePhaseFlow(FoamCase): u ]) - def build(self): + def build(self) -> tuple[str, str, int]: # TODO: configure working directory (FoamCase) with self: self.write() - openfoam.netgenNeutralToFoam("mesh.mesh") - openfoam.createPatch() - openfoam.checkMesh() - openfoam.transformPoints((1e-5, 1e-5, 1e-5)) - openfoam.renumberMesh() - openfoam.potentialFoam() - + R.netgenNeutralToFoam("mesh.mesh") + R.createPatch() + R.checkMesh() + R.transformPoints({ + "scale": [1e-5, 1e-5, 1e-5] + }) + R.renumberMesh() + R.potentialFoam() + self.read() self.U["boundaryField"]["outlet"] = dict( type = "pressureInletVelocity", - value = "uniform (0 0 0)" # * direction + value = uniform([0, 0, 0]) # * direction ) self.write() - - openfoam.simpleFoam() + + R.simpleFoam() + + return "", "", 0