Mod: improved openfoam interface
Mod: improved runners exception handlers Delete: some useless trash New: post process pipeline block
This commit is contained in:
parent
8e769ec1ce
commit
49368cc681
@ -124,7 +124,7 @@ def init(path, verbose):
|
||||
)
|
||||
@click.option(
|
||||
"-s", "--stage", "stage",
|
||||
type = click.Choice(["all", "shape", "mesh", "flow", "postProcessing"]),
|
||||
type = click.Choice(["all", "shape", "mesh", "flow", "postProcess"]),
|
||||
default = "all",
|
||||
help = "Current computation stage"
|
||||
)
|
||||
@ -146,7 +146,10 @@ def init(path, verbose):
|
||||
count = True,
|
||||
help = "Increase verbose level"
|
||||
)
|
||||
def compute(path, configFile, nprocs, stage, overwrite, params, verbose):
|
||||
@click.option(
|
||||
"--exec-id", "execution"
|
||||
)
|
||||
def compute(path, configFile, nprocs, stage, overwrite, params, verbose, execution):
|
||||
from anisotropy.core.runner import UltimateRunner
|
||||
from anisotropy.core.config import DefaultConfig
|
||||
from anisotropy.core.utils import setupLogger
|
||||
@ -170,7 +173,7 @@ def compute(path, configFile, nprocs, stage, overwrite, params, verbose):
|
||||
overwrite = overwrite
|
||||
)
|
||||
|
||||
runner = UltimateRunner(config = config)
|
||||
runner = UltimateRunner(config = config, exec_id = execution)
|
||||
runner.fill()
|
||||
runner.start()
|
||||
|
||||
|
@ -1,380 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# This file is part of anisotropy.
|
||||
# License: GNU GPL version 3, see the file "LICENSE" for details.
|
||||
|
||||
import os, sys
|
||||
import time
|
||||
from datetime import timedelta, datetime
|
||||
import shutil
|
||||
import logging
|
||||
from copy import deepcopy
|
||||
from math import sqrt
|
||||
|
||||
import toml
|
||||
|
||||
from anisotropy import (
|
||||
__version__, env,
|
||||
openfoam
|
||||
)
|
||||
from anisotropy.core.utils import setupLogger, Timer
|
||||
from anisotropy.core.database import Database
|
||||
from anisotropy import salomepl
|
||||
import anisotropy.salomepl.utils
|
||||
import anisotropy.salomepl.geometry
|
||||
import anisotropy.salomepl.mesh
|
||||
from anisotropy.samples import Simple, FaceCentered, BodyCentered
|
||||
|
||||
logger = logging.getLogger(env["logger_name"])
|
||||
#setupLogger(logger, logging.INFO, env["LOG"])
|
||||
|
||||
#peeweeLogger = logging.getLogger("peewee")
|
||||
#peeweeLogger.setLevel(logging.INFO)
|
||||
|
||||
|
||||
class Anisotropy(object):
|
||||
"""Ultimate class that organizes whole working process"""
|
||||
|
||||
def __init__(self):
|
||||
"""Constructor method"""
|
||||
|
||||
self.env = env
|
||||
self.db = None #Database(self.env["db_name"], self.env["db_path"])
|
||||
self.params = []
|
||||
|
||||
|
||||
def load(self, structure_type: str, structure_direction: list, structure_theta: float):
|
||||
"""Shortcut for `Database.setup` and `Database.load`.
|
||||
|
||||
See :class:`anisotropy.core.database.Database` for more details.
|
||||
"""
|
||||
self.db.setup()
|
||||
self.params = self.db.load(structure_type, structure_direction, structure_theta)
|
||||
|
||||
def update(self, params: dict = None):
|
||||
"""Shortcut for `Database.setup` and `Database.update`.
|
||||
|
||||
See :class:`anisotropy.core.database.Database` for more details.
|
||||
"""
|
||||
self.db.setup()
|
||||
self.db.update(self.params if not params else params)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def version():
|
||||
"""Returns versions of all used main programs
|
||||
|
||||
:return:
|
||||
Versions joined by next line symbol
|
||||
"""
|
||||
versions = {
|
||||
"anisotropy": __version__,
|
||||
"Python": sys.version.split(" ")[0],
|
||||
"Salome": "[missed]",
|
||||
"OpenFOAM": "[missed]"
|
||||
}
|
||||
|
||||
try:
|
||||
versions["Salome"] = salomepl.utils.SalomeManager().version()
|
||||
versions["OpenFOAM"] = openfoam.version()
|
||||
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return "\n".join([ f"{ k }: { v }" for k, v in versions.items() ])
|
||||
|
||||
|
||||
def loadFromScratch(self, configpath: str = None) -> list:
|
||||
"""Loads parameters from configuration file and expands special values
|
||||
|
||||
:return:
|
||||
List of dicts with parameters
|
||||
"""
|
||||
config = configpath or self.env["CONFIG"]
|
||||
|
||||
if not os.path.exists(config):
|
||||
logger.error("Missed configuration file")
|
||||
return
|
||||
|
||||
else:
|
||||
logger.info(f"Configuration file: { config }")
|
||||
|
||||
buf = toml.load(config).get("structures")
|
||||
paramsAll = []
|
||||
|
||||
|
||||
for entry in buf:
|
||||
# Shortcuts
|
||||
_theta = entry["structure"]["theta"]
|
||||
thetaMin = int(_theta[0] / _theta[2])
|
||||
thetaMax = int(_theta[1] / _theta[2]) + 1
|
||||
thetaList = list(
|
||||
map(lambda n: n * _theta[2], range(thetaMin, thetaMax))
|
||||
)
|
||||
|
||||
_thickness = entry["mesh"]["thickness"]
|
||||
count = len(thetaList)
|
||||
thicknessList = list(
|
||||
map(lambda n: _thickness[0] + n * (_thickness[1] - _thickness[0]) / (count - 1), range(0, count))
|
||||
)
|
||||
|
||||
for direction in entry["structure"]["directions"]:
|
||||
for n, theta in enumerate(thetaList):
|
||||
mesh = deepcopy(entry["mesh"])
|
||||
mesh["thickness"] = thicknessList[n]
|
||||
|
||||
entryNew = {
|
||||
"structure": dict(
|
||||
type = entry["structure"]["type"],
|
||||
theta = theta,
|
||||
direction = [ float(num) for num in direction ],
|
||||
filletsEnabled = entry["structure"]["filletsEnabled"]
|
||||
),
|
||||
"mesh": mesh,
|
||||
"submesh": deepcopy(entry["submesh"]),
|
||||
"meshresult": dict(),
|
||||
"flow": deepcopy(entry["flow"]),
|
||||
"flowapproximation": deepcopy(entry["flowapproximation"]),
|
||||
"flowresult": dict(),
|
||||
}
|
||||
|
||||
|
||||
|
||||
paramsAll.append(entryNew)
|
||||
|
||||
return paramsAll
|
||||
|
||||
|
||||
|
||||
def getCasePath(self, path: str = None) -> str:
|
||||
"""Constructs case path from control parameters
|
||||
|
||||
:return: Absolute path to case
|
||||
:rtype: str
|
||||
"""
|
||||
structure = self.params.get("structure")
|
||||
|
||||
if not structure:
|
||||
logger.error("Trying to use empty parameters")
|
||||
return
|
||||
|
||||
if path:
|
||||
path = os.path.join(path, "build")
|
||||
|
||||
else:
|
||||
path = self.env["BUILD"]
|
||||
|
||||
return os.path.join(
|
||||
path,
|
||||
structure["type"],
|
||||
"direction-{}".format(str(structure['direction']).replace(" ", "")),
|
||||
f"theta-{ structure['theta'] }"
|
||||
)
|
||||
|
||||
|
||||
def computeMesh(self, path):
|
||||
"""Computes a mesh on shape via Salome
|
||||
|
||||
:return: Process output, error messages and returncode
|
||||
:rtype: tuple(str, str, int)
|
||||
"""
|
||||
p = self.params["structure"]
|
||||
scriptpath = os.path.join(self.env["ROOT"], "anisotropy/core/cli.py")
|
||||
salomeargs = [
|
||||
"computemesh",
|
||||
p["type"],
|
||||
p["direction"],
|
||||
p["theta"],
|
||||
path
|
||||
]
|
||||
manager = salomepl.utils.SalomeManager()
|
||||
casepath = self.getCasePath(path)
|
||||
|
||||
self.params["meshresult"]["meshStatus"] = "Computing"
|
||||
self.update()
|
||||
timer = Timer()
|
||||
|
||||
out, err, returncode = manager.execute(
|
||||
scriptpath,
|
||||
*salomeargs,
|
||||
timeout = self.env["salome_timeout"],
|
||||
root = self.env["ROOT"],
|
||||
logpath = casepath
|
||||
)
|
||||
self.load(p["type"], p["direction"], p["theta"])
|
||||
|
||||
if not returncode:
|
||||
self.params["meshresult"].update(
|
||||
meshStatus = "Done",
|
||||
meshCalculationTime = timer.elapsed()
|
||||
)
|
||||
|
||||
else:
|
||||
self.params["meshresult"].update(
|
||||
meshStatus = "Failed"
|
||||
)
|
||||
|
||||
self.update()
|
||||
|
||||
return out, err, returncode
|
||||
|
||||
|
||||
def genmesh(self, path):
|
||||
"""Computes a mesh on shape
|
||||
|
||||
Warning: Working only inside Salome Environment
|
||||
"""
|
||||
|
||||
setupLogger(logger, logging.INFO, self.env["LOG"])
|
||||
p = self.params
|
||||
|
||||
sGeometry, sMesh = dict(
|
||||
simple = (Simple, SimpleMesh),
|
||||
bodyCentered = (BodyCentered, BodyCenteredMesh),
|
||||
faceCentered = (FaceCentered, FaceCenteredMesh)
|
||||
)[p["structure"]["type"]]
|
||||
|
||||
# Shape
|
||||
logger.info("Constructing shape ...")
|
||||
geometry = sGeometry(**p["structure"])
|
||||
geometry.build()
|
||||
|
||||
# Mesh
|
||||
logger.info("Prepairing mesh ...")
|
||||
mesh = sMesh(geometry)
|
||||
mesh.build()
|
||||
|
||||
logger.info("Computing mesh ...")
|
||||
out, err, returncode = mesh.compute()
|
||||
|
||||
|
||||
if not returncode:
|
||||
mesh.removePyramids()
|
||||
mesh.createGroups()
|
||||
|
||||
casePath = self.getCasePath(path)
|
||||
os.makedirs(casePath, exist_ok = True)
|
||||
logger.info("Exporting mesh ...")
|
||||
out, err, returncode = mesh.export(os.path.join(casePath, "mesh.unv"))
|
||||
|
||||
if returncode:
|
||||
logger.error(err)
|
||||
|
||||
# NOTE: edit from here
|
||||
meshStats = mesh.stats()
|
||||
p["meshresult"].update(
|
||||
surfaceArea = surfaceArea,
|
||||
volume = volume,
|
||||
volumeCell = shapeGeometry.volumeCell,
|
||||
**meshStats
|
||||
)
|
||||
self.update()
|
||||
|
||||
else:
|
||||
logger.error(err)
|
||||
|
||||
p["meshresult"].update(
|
||||
surfaceArea = surfaceArea,
|
||||
volume = volume,
|
||||
volumeCell = shapeGeometry.volumeCell
|
||||
)
|
||||
self.update()
|
||||
|
||||
|
||||
def computeFlow(self, path):
|
||||
"""Computes a flow on mesh via OpenFOAM
|
||||
|
||||
:return:
|
||||
Process output, error messages and returncode
|
||||
"""
|
||||
###
|
||||
# Case preparation
|
||||
##
|
||||
foamCase = [ "0", "constant", "system" ]
|
||||
#self.params["flowresult"] = dict()
|
||||
self.params["flowresult"]["flowStatus"] = "Computing"
|
||||
self.update()
|
||||
timer = Timer()
|
||||
|
||||
flow = self.params["flow"]
|
||||
flowapproximation = self.params["flowapproximation"]
|
||||
|
||||
# ISSUE: ideasUnvToFoam cannot import mesh with '-case' flag so 'os.chdir' for that
|
||||
casePath = self.getCasePath(path)
|
||||
|
||||
if not os.path.exists(casePath):
|
||||
err = f"Cannot find case path { casePath }"
|
||||
self.params["flowresult"]["flowStatus"] = "Failed"
|
||||
self.update()
|
||||
|
||||
return "", err, 1
|
||||
|
||||
os.chdir(casePath)
|
||||
openfoam.foamClean()
|
||||
|
||||
for d in foamCase:
|
||||
shutil.copytree(
|
||||
os.path.join(self.env["openfoam_template"], d),
|
||||
os.path.join(casePath, d)
|
||||
)
|
||||
|
||||
###
|
||||
# Mesh manipulations
|
||||
##
|
||||
if not os.path.exists("mesh.unv"):
|
||||
os.chdir(path or self.env["ROOT"])
|
||||
|
||||
err = f"Missed 'mesh.unv'"
|
||||
self.params["flowresult"]["flowStatus"] = "Failed"
|
||||
self.update()
|
||||
|
||||
return "", err, 1
|
||||
|
||||
out, err, returncode = openfoam.ideasUnvToFoam("mesh.unv")
|
||||
|
||||
out, err, returncode = openfoam.checkMesh()
|
||||
|
||||
if out: logger.warning(out)
|
||||
|
||||
out, err, returncode = openfoam.simpleFoam()
|
||||
|
||||
if not returncode:
|
||||
self.params["flowresult"]["flowCalculationTime"] = timer.elapsed()
|
||||
self.params["flowresult"]["flowStatus"] = "Done"
|
||||
|
||||
else:
|
||||
self.params["flowresult"]["flowStatus"] = "Failed"
|
||||
|
||||
self.update()
|
||||
os.chdir(path or self.env["ROOT"])
|
||||
|
||||
return out, str(err, "utf-8"), returncode
|
||||
|
||||
|
||||
def flowRate(self):
|
||||
casePath = self.getCasePath()
|
||||
foamPostProcessing = "postProcessing/flowRatePatch(name=outlet)/0/surfaceFieldValue.dat"
|
||||
path = os.path.join(casePath, foamPostProcessing)
|
||||
|
||||
if not os.path.exists(path):
|
||||
logger.warning(f"Unable to compute flow rate. Missed { path }")
|
||||
|
||||
return
|
||||
|
||||
with open(path, "r") as io:
|
||||
lastLine = io.readlines()[-1]
|
||||
flowRate = float(lastLine.replace(" ", "").replace("\n", "").split("\t")[1])
|
||||
|
||||
self.params["flowresult"]["flowRate"] = flowRate
|
||||
self.update()
|
||||
|
||||
return flowRate
|
||||
|
||||
|
||||
def porosity(self):
|
||||
mr = self.params["meshresult"]
|
||||
fr = self.params["flowresult"]
|
||||
|
||||
fr["porosity"] = mr["volume"] / mr["volumeCell"]
|
||||
self.update()
|
||||
|
||||
return fr["porosity"]
|
@ -2,4 +2,24 @@
|
||||
# This file is part of anisotropy.
|
||||
# License: GNU GPL version 3, see the file "LICENSE" for details.
|
||||
|
||||
from os import path
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from anisotropy.openfoam.runnerPresets import postProcess
|
||||
from anisotropy.openfoam import datReader
|
||||
|
||||
|
||||
class PostProcess(object):
|
||||
def __init__(self, dirpath):
|
||||
self.path = path.abspath(dirpath)
|
||||
|
||||
def flowRate(self, patch: str):
|
||||
func = "patchFlowRate(patch={})".format(patch)
|
||||
filepath = path.join(self.path, "postProcessing", func, "0", "surfaceFieldValue.dat")
|
||||
postProcess(func, cwd = self.path)
|
||||
surfaceFieldValue = datReader(filepath)
|
||||
|
||||
return surfaceFieldValue["sum(phi)"][-1]
|
||||
|
||||
|
@ -9,44 +9,36 @@ from os import path
|
||||
from anisotropy.core.config import DefaultConfig
|
||||
|
||||
import logging
|
||||
|
||||
from anisotropy.core.postProcess import PostProcess
|
||||
from anisotropy.core.utils import ParallelRunner, Timer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
from anisotropy.database import Database, tables as T
|
||||
|
||||
from anisotropy.shaping import Simple, BodyCentered, FaceCentered
|
||||
from anisotropy.shaping import Simple, BodyCentered, FaceCentered, Shape
|
||||
from anisotropy.meshing import Mesh
|
||||
from anisotropy.openfoam.presets import CreatePatchDict
|
||||
from anisotropy.solving import OnePhaseFlow
|
||||
from multiprocessing import current_process, parent_process
|
||||
|
||||
class UltimateRunner(object):
|
||||
def __init__(self, config = None, exec_id: int = None): #t_exec = None, t_shape = None):
|
||||
def __init__(self, config = None, exec_id: int = None, typo: str = "master"):
|
||||
# Configuration file
|
||||
self.config = config or DefaultConfig()
|
||||
|
||||
# Process recognition
|
||||
typo = True if not exec_id else False
|
||||
#if current_process().name == "MainProcess" and parent_process() == None:
|
||||
# current_process().name = "master"
|
||||
self.typo = typo
|
||||
|
||||
# Database preparation
|
||||
if typo: #current_process().name == "master":
|
||||
self.database = Database(path = self.config["database"])
|
||||
|
||||
if typo: #current_process().name == "master":
|
||||
with self.database:
|
||||
self.t_exec = T.Execution(date = datetime.now())
|
||||
self.t_exec.save()
|
||||
|
||||
#self.t_shape = None
|
||||
|
||||
else:
|
||||
#self.t_exec = self.database.getExecution(exec_id)
|
||||
if exec_id:
|
||||
if self.database.getExecution(exec_id):
|
||||
self.exec_id = exec_id
|
||||
#self.t_exec = t_exec
|
||||
#self.t_shape = t_shape
|
||||
|
||||
if not self.exec_id:
|
||||
with self.database:
|
||||
self.exec_id = T.Execution.create(date=datetime.now())
|
||||
|
||||
# Parameters
|
||||
self.shape = None
|
||||
@ -59,12 +51,20 @@ class UltimateRunner(object):
|
||||
def createRow(self):
|
||||
# create a row in each table for the current case
|
||||
with self.database:
|
||||
t_shape = T.Shape(exec_id = self.exec_id, **self.config.params)
|
||||
t_shape.save()
|
||||
t_mesh = T.Mesh(shape_id = t_shape.shape_id)
|
||||
t_mesh.save()
|
||||
t_flow = T.FlowOnephase(mesh_id = t_mesh.mesh_id)
|
||||
t_flow.save()
|
||||
shape = self.database.getShape(execution = self.exec_id, **self.config.params)
|
||||
|
||||
if not shape:
|
||||
shape = T.Shape.create(exec_id = self.exec_id, **self.config.params)
|
||||
|
||||
mesh = self.database.getMesh(execution = self.exec_id, **self.config.params)
|
||||
|
||||
if not mesh:
|
||||
mesh = T.Mesh.create(shape_id = shape)
|
||||
|
||||
flow = self.database.getFlowOnephase(execution = self.exec_id, **self.config.params)
|
||||
|
||||
if not flow:
|
||||
flow = T.FlowOnephase.create(mesh_id = mesh)
|
||||
|
||||
def fill(self):
|
||||
self.config.expand()
|
||||
@ -75,19 +75,11 @@ class UltimateRunner(object):
|
||||
config.chooseParams(idn)
|
||||
config.minimize()
|
||||
|
||||
#with self.database:
|
||||
# t_shape = T.Shape(
|
||||
# exec_id = self.t_exec,
|
||||
# **case
|
||||
# )
|
||||
# t_shape.save()
|
||||
|
||||
self.queue.append(UltimateRunner(
|
||||
config = config,
|
||||
exec_id = self.t_exec.exec_id
|
||||
#t_exec = self.t_exec,
|
||||
#t_shape = t_shape
|
||||
))
|
||||
kwargs = {
|
||||
"config": config,
|
||||
"exec_id": self.exec_id
|
||||
}
|
||||
self.queue.append(kwargs)
|
||||
|
||||
|
||||
def start(self, queue: list = None, nprocs: int = None):
|
||||
@ -97,44 +89,22 @@ class UltimateRunner(object):
|
||||
parallel = ParallelRunner(nprocs = nprocs)
|
||||
parallel.start()
|
||||
|
||||
for runner in self.queue:
|
||||
parallel.append(runner.pipeline, args = [self.config["stage"]])
|
||||
for kwargs in self.queue:
|
||||
parallel.append(self.subrunner, kwargs = kwargs)
|
||||
|
||||
parallel.wait()
|
||||
# TODO: if runner done - remove from queue; results from parallel function
|
||||
|
||||
def casepath(self):
|
||||
#with self.database:
|
||||
# params = T.Shape.get(
|
||||
# T.Shape.exec_id == self.t_exec,
|
||||
# T.Shape.shape_id == self.t_shape.shape_id
|
||||
# )
|
||||
params = self.config.params
|
||||
shapeParams = self.database.getShape(
|
||||
params["label"],
|
||||
params["direction"],
|
||||
params["alpha"],
|
||||
self.exec_id
|
||||
)
|
||||
|
||||
execution = "execution-{}".format(self.exec_id)
|
||||
case = "{}-[{},{},{}]-{}".format(params["label"], *[ str(d) for d in params["direction"] ], params["alpha"])
|
||||
#alpha = "alpha-{}".format(shapeParams.alpha)
|
||||
#dirpath = path.join(self.config["build"], shapeParams.label, direction, alpha)
|
||||
dirpath = path.join(self.config["build"], execution, case)
|
||||
|
||||
return path.abspath(dirpath)
|
||||
|
||||
def computeShape(self):
|
||||
#if current_process().name == "master":
|
||||
# return
|
||||
|
||||
#with self.database:
|
||||
# params = T.Shape.get(
|
||||
# T.Shape.exec_id == self.t_exec,
|
||||
# T.Shape.shape_id == self.t_shape.shape_id
|
||||
# )
|
||||
|
||||
out, err, returncode = "", "", 0
|
||||
params = self.config.params
|
||||
shapeParams = self.database.getShape(
|
||||
params["label"],
|
||||
@ -161,14 +131,19 @@ class UltimateRunner(object):
|
||||
r0 = shapeParams.r0,
|
||||
filletsEnabled = shapeParams.filletsEnabled
|
||||
)
|
||||
#out, err, returncode = self.shape.build()
|
||||
# TODO: wrap build function for exceptions
|
||||
|
||||
try:
|
||||
self.shape.build()
|
||||
|
||||
except Exception as e:
|
||||
err = e
|
||||
returncode = 1
|
||||
|
||||
if not returncode:
|
||||
os.makedirs(self.casepath(), exist_ok = True)
|
||||
out, err, returncode = self.shape.export(path.join(self.casepath(), filename))
|
||||
|
||||
if returncode == 0:
|
||||
if not returncode:
|
||||
shapeParams.shapeStatus = "done"
|
||||
|
||||
else:
|
||||
@ -180,18 +155,7 @@ class UltimateRunner(object):
|
||||
shapeParams.save()
|
||||
|
||||
def computeMesh(self):
|
||||
#if not self.type == "worker":
|
||||
# return
|
||||
|
||||
#with self.database:
|
||||
# t_params = T.Shape.get(
|
||||
# T.Shape.exec_id == self.t_exec,
|
||||
# T.Shape.shape_id == self.t_shape.shape_id
|
||||
# )
|
||||
# params = T.Mesh.get(
|
||||
# T.Mesh.shape_id == self.t_shape.shape_id
|
||||
# )
|
||||
|
||||
out, err, returncode = "", "", 0
|
||||
params = self.config.params
|
||||
meshParams = self.database.getMesh(
|
||||
params["label"],
|
||||
@ -206,16 +170,33 @@ class UltimateRunner(object):
|
||||
filename = "mesh.mesh"
|
||||
timer = Timer()
|
||||
|
||||
# TODO: load from object or file
|
||||
if not self.shape:
|
||||
filename = "shape.step"
|
||||
filepath = path.join(self.casepath(), filename)
|
||||
|
||||
if not path.exists(filepath) and not path.isfile(filepath):
|
||||
err = f"File not found: { filepath }"
|
||||
returncode = 2
|
||||
|
||||
if not returncode:
|
||||
self.shape = Shape()
|
||||
self.shape.load(filepath)
|
||||
|
||||
if not returncode:
|
||||
self.mesh = Mesh(self.shape.shape)
|
||||
#out, err, returncode = self.mesh.build()
|
||||
# TODO: wrap build function for exceptions
|
||||
|
||||
try:
|
||||
self.mesh.build()
|
||||
|
||||
except Exception as e:
|
||||
err = e
|
||||
returncode = 1
|
||||
|
||||
if not returncode:
|
||||
os.makedirs(self.casepath(), exist_ok = True)
|
||||
out, err, returncode = self.mesh.export(path.join(self.casepath(), filename))
|
||||
|
||||
if returncode == 0:
|
||||
if not returncode:
|
||||
meshParams.meshStatus = "done"
|
||||
|
||||
else:
|
||||
@ -227,21 +208,6 @@ class UltimateRunner(object):
|
||||
meshParams.save()
|
||||
|
||||
def computeFlow(self):
|
||||
# if not self.type == "worker":
|
||||
# return
|
||||
|
||||
#with self.database:
|
||||
# t_params = T.Shape.get(
|
||||
# T.Shape.exec_id == self.t_exec,
|
||||
# T.Shape.shape_id == self.t_shape.shape_id
|
||||
# )
|
||||
# m_params = T.Mesh.get(
|
||||
# T.Mesh.shape_id == self.t_shape.shape_id
|
||||
# )
|
||||
# params = T.FlowOnephase.get(
|
||||
# T.FlowOnephase.mesh_id == self.t_mesh.mesh_id
|
||||
# )
|
||||
|
||||
params = self.config.params
|
||||
flowParams = self.database.getFlowOnephase(
|
||||
params["label"],
|
||||
@ -255,55 +221,26 @@ class UltimateRunner(object):
|
||||
))
|
||||
timer = Timer()
|
||||
|
||||
self.flow = OnePhaseFlow(path = self.casepath())
|
||||
self.flow = OnePhaseFlow(params["direction"], path = self.casepath())
|
||||
|
||||
# initial 43 unnamed patches ->
|
||||
# 6 named patches (inlet, outlet, wall, symetry0 - 3/5) ->
|
||||
# 4 inGroups (inlet, outlet, wall, symetry)
|
||||
createPatchDict = CreatePatchDict()
|
||||
createPatchDict["patches"] = []
|
||||
patches = {}
|
||||
if not self.shape:
|
||||
filename = "shape.step"
|
||||
filepath = path.join(self.casepath(), filename)
|
||||
|
||||
for n, patch in enumerate(self.shape.shape.faces):
|
||||
# shifted index
|
||||
n += 1
|
||||
name = patch.name
|
||||
if not path.exists(filepath) and not path.isfile(filepath):
|
||||
err = f"File not found: { filepath }"
|
||||
returncode = 2
|
||||
|
||||
if patches.get(name):
|
||||
patches[name].append(f"patch{ n }")
|
||||
if not returncode:
|
||||
self.shape = Shape()
|
||||
self.shape.load(filepath)
|
||||
|
||||
else:
|
||||
patches[name] = [ f"patch{ n }" ]
|
||||
|
||||
for name in patches.keys():
|
||||
if name == "inlet":
|
||||
patchGroup = "inlet"
|
||||
patchType = "patch"
|
||||
|
||||
elif name == "outlet":
|
||||
patchGroup = "outlet"
|
||||
patchType = "patch"
|
||||
|
||||
elif name == "wall":
|
||||
patchGroup = "wall"
|
||||
patchType = "wall"
|
||||
|
||||
else:
|
||||
patchGroup = "symetry"
|
||||
patchType = "symetryPlane"
|
||||
|
||||
createPatchDict["patches"].append({
|
||||
"name": name,
|
||||
"patchInfo": {
|
||||
"type": patchType,
|
||||
"inGroups": [patchGroup]
|
||||
},
|
||||
"constructFrom": "patches",
|
||||
"patches": patches[name]
|
||||
})
|
||||
faces = [ (n, face.name) for n, face in enumerate(self.shape.shape.faces) ]
|
||||
createPatchDict = OnePhaseFlow.facesToPatches(faces)
|
||||
|
||||
self.flow.append(createPatchDict)
|
||||
self.flow.write()
|
||||
|
||||
# Build a flow
|
||||
try:
|
||||
out, err, returncode = self.flow.build()
|
||||
@ -323,16 +260,30 @@ class UltimateRunner(object):
|
||||
flowParams.flowExecutionTime = timer.elapsed()
|
||||
flowParams.save()
|
||||
|
||||
def pipeline(self, stage: str = None):
|
||||
self.database = Database(path = self.config["database"])
|
||||
self.createRow()
|
||||
def computePostProcess(self):
|
||||
params = self.config.params
|
||||
flowParams = self.database.getFlowOnephase(
|
||||
params["label"],
|
||||
params["direction"],
|
||||
params["alpha"],
|
||||
self.exec_id
|
||||
)
|
||||
|
||||
logger.info("Computing post process for {} with direction = {} and alpha = {}".format(
|
||||
params["label"], params["direction"], params["alpha"]
|
||||
))
|
||||
|
||||
postProcess = PostProcess(self.casepath())
|
||||
|
||||
if flowParams.flowStatus == "done":
|
||||
flowParams.flowRate = postProcess.flowRate("outlet")
|
||||
|
||||
with self.database:
|
||||
flowParams.save()
|
||||
|
||||
def pipeline(self, stage: str = None):
|
||||
stage = stage or self.config["stage"]
|
||||
|
||||
# TODO: fix flow
|
||||
# TODO: change case path to execDATE/label-direction-theta/*
|
||||
# TODO: fix nprocs
|
||||
#try:
|
||||
if stage in ["shape", "all"]:
|
||||
self.computeShape()
|
||||
|
||||
@ -342,10 +293,16 @@ class UltimateRunner(object):
|
||||
if stage in ["flow", "all"]:
|
||||
self.computeFlow()
|
||||
|
||||
#elif stage in ["postProcess", "all"]:
|
||||
# self.postProcess()
|
||||
#except Exception as e:
|
||||
# logger.error(e)
|
||||
if stage in ["postProcess", "all"]:
|
||||
self.computePostProcess()
|
||||
|
||||
#logger.info("Pipeline done")
|
||||
|
||||
@staticmethod
|
||||
def subrunner(*args, **kwargs):
|
||||
runner = UltimateRunner(config = kwargs["config"], exec_id = kwargs["exec_id"], typo = "worker")
|
||||
runner.createRow()
|
||||
runner.pipeline()
|
||||
|
||||
|
||||
|
||||
|
@ -74,11 +74,10 @@ def setupLogger(level: int, filepath: str = None):
|
||||
os.makedirs(filepath, exist_ok = True)
|
||||
|
||||
filehandler = logging.FileHandler(
|
||||
os.path.join(filepath, "{}.log".format(logger.name))
|
||||
os.path.join(filepath, "{}.log".format("anisotropy"))
|
||||
)
|
||||
filehandler.setLevel(level)
|
||||
filehandler.setLevel(logging.INFO)
|
||||
filehandler.setFormatter(CustomFormatter())
|
||||
#logger.addHandler(filehandler)
|
||||
|
||||
logging.root.addHandler(filehandler)
|
||||
|
||||
@ -182,21 +181,6 @@ def expand(source, sep = "_"):
|
||||
cur[kk] = v
|
||||
return res
|
||||
|
||||
#if os.path.exists(env["CONFIG"]):
|
||||
# config = toml.load(env["CONFIG"])
|
||||
|
||||
# for restricted in ["ROOT", "BUILD", "LOG", "CONFIG"]:
|
||||
# if config.get(restricted):
|
||||
# config.pop(restricted)
|
||||
|
||||
# TODO: not working if custom config empty and etc
|
||||
# for m, structure in enumerate(config["structures"]):
|
||||
# for n, estructure in enumerate(env["structures"]):
|
||||
# if estructure["name"] == structure["name"]:
|
||||
# deepupdate(env["structures"][n], config["structures"][m])
|
||||
|
||||
# config.pop("structures")
|
||||
# deepupdate(env, config)
|
||||
|
||||
def timer(func: FunctionType) -> (tuple, float):
|
||||
"""(Decorator) Returns output of inner function and execution time
|
||||
|
@ -44,9 +44,9 @@ class Database(SqliteDatabase):
|
||||
|
||||
def getExecution(self, idn):
|
||||
query = models.Execution.select().where(models.Execution.exec_id == idn)
|
||||
self.connect()
|
||||
|
||||
with self:
|
||||
table = query.get() if query.exists() else None
|
||||
self.close()
|
||||
|
||||
return table
|
||||
|
||||
@ -58,7 +58,7 @@ class Database(SqliteDatabase):
|
||||
|
||||
return table
|
||||
|
||||
def getShape(self, label, direction, alpha, execution = None):
|
||||
def getShape(self, label = None, direction = None, alpha = None, execution = None, **kwargs):
|
||||
execution = execution or self.getLatest()
|
||||
query = (
|
||||
models.Shape
|
||||
@ -77,7 +77,7 @@ class Database(SqliteDatabase):
|
||||
|
||||
return table
|
||||
|
||||
def getMesh(self, label, direction, alpha, execution = None):
|
||||
def getMesh(self, label = None, direction = None, alpha = None, execution = None, **kwargs):
|
||||
execution = execution or self.getLatest()
|
||||
query = (
|
||||
models.Mesh
|
||||
@ -97,7 +97,7 @@ class Database(SqliteDatabase):
|
||||
|
||||
return table
|
||||
|
||||
def getFlowOnephase(self, label, direction, alpha, execution = None):
|
||||
def getFlowOnephase(self, label = None, direction = None, alpha = None, execution = None, **kwargs):
|
||||
execution = execution or self.getLatest()
|
||||
query = (
|
||||
models.FlowOnephase
|
||||
|
@ -60,7 +60,6 @@ class Mesh(object):
|
||||
ext = os.path.splitext(filename)[1][1: ]
|
||||
|
||||
try:
|
||||
# TODO: write correct boundary names
|
||||
if ext == "vol":
|
||||
self.mesh.Save(filename)
|
||||
|
||||
|
@ -2,13 +2,7 @@
|
||||
# This file is part of anisotropy.
|
||||
# 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, uniform #, foamClean
|
||||
from .utils import version, uniform, datReader
|
||||
from .foamfile import FoamFile
|
||||
from .foamcase import FoamCase
|
||||
from .runner import FoamRunner
|
||||
|
@ -1,13 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# This file is part of anisotropy.
|
||||
# License: GNU GPL version 3, see the file "LICENSE" for details.
|
||||
|
||||
from .application import application
|
||||
|
||||
def ideasUnvToFoam(mesh: str, case: str = None) -> (str, int):
|
||||
return application("ideasUnvToFoam", mesh, case = case, stderr = True)
|
||||
|
||||
|
||||
def netgenNeutralToFoam(mesh: str, case: str = None) -> (str, int):
|
||||
return application("netgenNeutralToFoam", mesh, case = case, stderr = True)
|
||||
|
@ -1,42 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# This file is part of anisotropy.
|
||||
# License: GNU GPL version 3, see the file "LICENSE" for details.
|
||||
|
||||
from .application import application
|
||||
|
||||
import re
|
||||
|
||||
def createPatch(dictfile: str = None, case: str = None):
|
||||
args = ["-overwrite"]
|
||||
|
||||
if dictfile:
|
||||
args.extend(["-dict", dictfile])
|
||||
|
||||
application("createPatch", *args, case = case, stderr = True)
|
||||
|
||||
|
||||
def transformPoints(scale, case: str = None):
|
||||
_scale = f"({ scale[0] } { scale[1] } { scale[2] })"
|
||||
|
||||
application("transformPoints", "-scale", _scale, case = case, stderr = True)
|
||||
|
||||
|
||||
def checkMesh(case: str = None) -> str:
|
||||
_, err, returncode = application("checkMesh", "-allGeometry", "-allTopology", case = case, stderr = True)
|
||||
out = ""
|
||||
|
||||
with open("checkMesh.log", "r") as io:
|
||||
warnings = []
|
||||
for line in io:
|
||||
if re.search(r"\*\*\*", line):
|
||||
warnings.append(line.replace("***", "").strip())
|
||||
|
||||
if warnings:
|
||||
out = "checkMesh:\n\t{}".format("\n\t".join(warnings))
|
||||
|
||||
return out, err, returncode
|
||||
|
||||
|
||||
def renumberMesh(case: str = None):
|
||||
application("renumberMesh", "-overwrite", useMPI = False, case = case, stderr = True)
|
||||
|
@ -1,14 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# This file is part of anisotropy.
|
||||
# License: GNU GPL version 3, see the file "LICENSE" for details.
|
||||
|
||||
from .application import application
|
||||
|
||||
def foamDictionary(filepath: str, entry: str, value: str = None, case: str = None):
|
||||
args = [filepath, "-entry", entry]
|
||||
|
||||
if value:
|
||||
args.extend(["-set", value])
|
||||
|
||||
application("foamDictionary", *args, case = case, stderr = False)
|
||||
|
@ -1,9 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# This file is part of anisotropy.
|
||||
# License: GNU GPL version 3, see the file "LICENSE" for details.
|
||||
|
||||
from .application import application
|
||||
|
||||
def decomposePar(case: str = None):
|
||||
application("decomposePar", case = case, stderr = True)
|
||||
|
@ -48,25 +48,30 @@ class FoamRunner(object):
|
||||
|
||||
logger.debug(f"Starting subprocess: { proc.args }")
|
||||
|
||||
if self.logpath:
|
||||
with proc, open(self.logpath, "w") as io:
|
||||
while True:
|
||||
output = proc.stdout.read(1)
|
||||
|
||||
if output == "" and proc.poll() is not None:
|
||||
break
|
||||
|
||||
if not output == "":
|
||||
io.write(output)
|
||||
|
||||
self.output, self.error = proc.communicate()
|
||||
self.returncode = proc.returncode
|
||||
|
||||
if self.logpath and self.error:
|
||||
with open(self.logpath, "a") as io:
|
||||
io.write(self.error)
|
||||
|
||||
except FileNotFoundError as err:
|
||||
self.error = err.args[1]
|
||||
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: { self.error }")
|
||||
|
||||
|
@ -9,29 +9,39 @@ from .runner import FoamRunner
|
||||
# meshConversion
|
||||
##
|
||||
|
||||
def netgenNeutralToFoam(meshfile: str, **kwargs) -> tuple[str, str, int]:
|
||||
def netgenNeutralToFoam(meshfile: str, run: bool = True, **kwargs) -> FoamRunner:
|
||||
command = "netgenNeutralToFoam"
|
||||
kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log"))
|
||||
kwargs.update(exit = True)
|
||||
args = [ meshfile ]
|
||||
|
||||
return FoamRunner(command, args = args, **kwargs).run()
|
||||
runner = FoamRunner(command, args = args, **kwargs)
|
||||
|
||||
if run:
|
||||
runner.run()
|
||||
|
||||
return runner
|
||||
|
||||
|
||||
def ideasUnvToFoam(meshfile: str, **kwargs) -> tuple[str, str, int]:
|
||||
def ideasUnvToFoam(meshfile: str, run: bool = True, **kwargs) -> FoamRunner:
|
||||
command = "ideasUnvToFoam"
|
||||
kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log"))
|
||||
kwargs.update(exit = True)
|
||||
args = [ meshfile ]
|
||||
|
||||
return FoamRunner(command, args = args, **kwargs).run()
|
||||
runner = FoamRunner(command, args = args, **kwargs)
|
||||
|
||||
if run:
|
||||
runner.run()
|
||||
|
||||
return runner
|
||||
|
||||
|
||||
###
|
||||
# meshManipulation
|
||||
##
|
||||
|
||||
def createPatch(dictfile: str = None, overwrite: bool = True, **kwargs) -> tuple[str, str, int]:
|
||||
def createPatch(dictfile: str = None, overwrite: bool = True, run: bool = True, **kwargs) -> FoamRunner:
|
||||
command = "createPatch"
|
||||
kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log"))
|
||||
kwargs.update(exit = True)
|
||||
@ -43,10 +53,15 @@ def createPatch(dictfile: str = None, overwrite: bool = True, **kwargs) -> tuple
|
||||
if overwrite:
|
||||
args.append("-overwrite")
|
||||
|
||||
return FoamRunner(command, args = args, **kwargs).run()
|
||||
runner = FoamRunner(command, args = args, **kwargs)
|
||||
|
||||
if run:
|
||||
runner.run()
|
||||
|
||||
return runner
|
||||
|
||||
|
||||
def transformPoints(transformations: dict, **kwargs) -> tuple[str, str, int]:
|
||||
def transformPoints(transformations: dict, run: bool = True, **kwargs) -> FoamRunner:
|
||||
command = "transformPoints"
|
||||
kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log"))
|
||||
kwargs.update(exit = True)
|
||||
@ -64,10 +79,15 @@ def transformPoints(transformations: dict, **kwargs) -> tuple[str, str, int]:
|
||||
|
||||
args.append(", ".join(arg))
|
||||
|
||||
return FoamRunner(command, args = args, **kwargs).run()
|
||||
runner = FoamRunner(command, args = args, **kwargs)
|
||||
|
||||
if run:
|
||||
runner.run()
|
||||
|
||||
return runner
|
||||
|
||||
|
||||
def checkMesh(allGeometry: bool = True, allTopology: bool = True, **kwargs) -> tuple[str, str, int]:
|
||||
def checkMesh(allGeometry: bool = True, allTopology: bool = True, run: bool = True, **kwargs) -> FoamRunner:
|
||||
command = "checkMesh"
|
||||
kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log"))
|
||||
kwargs.update(exit = True)
|
||||
@ -79,10 +99,15 @@ def checkMesh(allGeometry: bool = True, allTopology: bool = True, **kwargs) -> t
|
||||
if allTopology:
|
||||
args.append("-allTopology")
|
||||
|
||||
return FoamRunner(command, args = args, **kwargs).run()
|
||||
runner = FoamRunner(command, args = args, **kwargs)
|
||||
|
||||
if run:
|
||||
runner.run()
|
||||
|
||||
return runner
|
||||
|
||||
|
||||
def renumberMesh(overwrite: bool = True, **kwargs) -> tuple[str, str, int]:
|
||||
def renumberMesh(overwrite: bool = True, run: bool = True, **kwargs) -> FoamRunner:
|
||||
command = "renumberMesh"
|
||||
kwargs.update(logpath = kwargs.get("logpath", f"{ command }.log"))
|
||||
kwargs.update(exit = True)
|
||||
@ -91,7 +116,12 @@ def renumberMesh(overwrite: bool = True, **kwargs) -> tuple[str, str, int]:
|
||||
if overwrite:
|
||||
args.append("-overwrite")
|
||||
|
||||
return FoamRunner(command, args = args, **kwargs).run()
|
||||
runner = FoamRunner(command, args = args, **kwargs)
|
||||
|
||||
if run:
|
||||
runner.run()
|
||||
|
||||
return runner
|
||||
|
||||
|
||||
###
|
||||
@ -105,20 +135,25 @@ def renumberMesh(overwrite: bool = True, **kwargs) -> tuple[str, str, int]:
|
||||
# parallelProcessing
|
||||
##
|
||||
|
||||
def decomposePar(**kwargs) -> tuple[str, str, int]:
|
||||
def decomposePar(run: bool = True, **kwargs) -> FoamRunner:
|
||||
command = "decomposePar"
|
||||
kwargs.update(logpath = kwargs.get("logpath", f"{command}.log"))
|
||||
kwargs.update(exit = True)
|
||||
args = []
|
||||
|
||||
return FoamRunner(command, args = args, **kwargs).run()
|
||||
runner = FoamRunner(command, args = args, **kwargs)
|
||||
|
||||
if run:
|
||||
runner.run()
|
||||
|
||||
return runner
|
||||
|
||||
|
||||
###
|
||||
# solvers
|
||||
##
|
||||
|
||||
def potentialFoam(parallel: bool = False, **kwargs) -> tuple[str, str, int]:
|
||||
def potentialFoam(parallel: bool = False, run: bool = True, **kwargs) -> FoamRunner:
|
||||
command = "potentialFoam"
|
||||
kwargs.update(logpath = kwargs.get("logpath", f"{command}.log"))
|
||||
kwargs.update(exit = True)
|
||||
@ -128,10 +163,15 @@ def potentialFoam(parallel: bool = False, **kwargs) -> tuple[str, str, int]:
|
||||
args.append("-parallel")
|
||||
kwargs.update(mpi = True)
|
||||
|
||||
return FoamRunner(command, args = args, **kwargs).run()
|
||||
runner = FoamRunner(command, args = args, **kwargs)
|
||||
|
||||
if run:
|
||||
runner.run()
|
||||
|
||||
return runner
|
||||
|
||||
|
||||
def simpleFoam(parallel: bool = False, **kwargs) -> tuple[str, str, int]:
|
||||
def simpleFoam(parallel: bool = False, run: bool = True, **kwargs) -> FoamRunner:
|
||||
command = "simpleFoam"
|
||||
kwargs.update(logpath = kwargs.get("logpath", f"{command}.log"))
|
||||
kwargs.update(exit = True)
|
||||
@ -141,4 +181,32 @@ def simpleFoam(parallel: bool = False, **kwargs) -> tuple[str, str, int]:
|
||||
args.append("-parallel")
|
||||
kwargs.update(mpi = True)
|
||||
|
||||
return FoamRunner(command, args = args, **kwargs).run()
|
||||
runner = FoamRunner(command, args = args, **kwargs)
|
||||
|
||||
if run:
|
||||
runner.run()
|
||||
|
||||
return runner
|
||||
|
||||
###
|
||||
# postProcessing
|
||||
##
|
||||
|
||||
def postProcess(func: str = None, latestTime: bool = False, run: bool = True, **kwargs) -> FoamRunner:
|
||||
command = "postProcess"
|
||||
kwargs.update(logpath=kwargs.get("logpath", f"{command}.log"))
|
||||
kwargs.update(exit = True)
|
||||
args = []
|
||||
|
||||
if func:
|
||||
args.extend(["-func", func])
|
||||
|
||||
if latestTime:
|
||||
args.append("-latestTime")
|
||||
|
||||
runner = FoamRunner(command, args = args, **kwargs)
|
||||
|
||||
if run:
|
||||
runner.run()
|
||||
|
||||
return runner
|
||||
|
@ -1,34 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# This file is part of anisotropy.
|
||||
# License: GNU GPL version 3, see the file "LICENSE" for details.
|
||||
|
||||
from .application import application
|
||||
|
||||
import re
|
||||
|
||||
def potentialFoam(case: str = None, useMPI: bool = False):
|
||||
if useMPI:
|
||||
out, err, returncode = application("potentialFoam", "-parallel", useMPI = True, case = case, stderr = True)
|
||||
|
||||
else:
|
||||
out, err, returncode = application("potentialFoam", case = case, stderr = True)
|
||||
|
||||
return out, err, returncode
|
||||
|
||||
|
||||
def simpleFoam(case: str = None, useMPI: bool = False):
|
||||
if useMPI:
|
||||
out, err, returncode = application("simpleFoam", "-parallel", useMPI = True, case = case, stderr = True)
|
||||
|
||||
else:
|
||||
out, err, returncode = application("simpleFoam", case = case, stderr = True)
|
||||
|
||||
out = ""
|
||||
|
||||
with open("simpleFoam.log", "r") as io:
|
||||
for line in io:
|
||||
if re.search("solution converged", line):
|
||||
out = "simpleFoam:\n\t{}".format(line.strip())
|
||||
|
||||
return out, err, returncode
|
||||
|
@ -1,58 +0,0 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: v2012 |
|
||||
| \\ / A nd | Website: www.openfoam.com |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class volVectorField;
|
||||
location "0";
|
||||
object U;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
dimensions [0 1 -1 0 0 0 0];
|
||||
|
||||
|
||||
internalField uniform (0 0 0);
|
||||
|
||||
boundaryField
|
||||
{
|
||||
inlet
|
||||
{
|
||||
type fixedValue;
|
||||
value uniform (0 0 -6e-5);
|
||||
}
|
||||
outlet
|
||||
{
|
||||
type zeroGradient;
|
||||
}
|
||||
symetryPlane
|
||||
{
|
||||
type fixedValue;
|
||||
value uniform (0 0 0);
|
||||
}
|
||||
wall
|
||||
{
|
||||
type fixedValue;
|
||||
value uniform (0 0 0);
|
||||
}
|
||||
strips
|
||||
{
|
||||
type fixedValue;
|
||||
value uniform (0 0 0);
|
||||
}
|
||||
|
||||
defaultFaces
|
||||
{
|
||||
type fixedValue;
|
||||
value uniform (0 0 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
@ -1,55 +0,0 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: v2012 |
|
||||
| \\ / A nd | Website: www.openfoam.com |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class volScalarField;
|
||||
location "0";
|
||||
object p;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
dimensions [0 2 -2 0 0 0 0];
|
||||
|
||||
|
||||
internalField uniform 0;
|
||||
|
||||
boundaryField
|
||||
{
|
||||
inlet
|
||||
{
|
||||
type fixedValue;
|
||||
value uniform 0.001;
|
||||
}
|
||||
outlet
|
||||
{
|
||||
type fixedValue;
|
||||
value uniform 0;
|
||||
}
|
||||
symetryPlane
|
||||
{
|
||||
type zeroGradient;
|
||||
}
|
||||
wall
|
||||
{
|
||||
type zeroGradient;
|
||||
}
|
||||
strips
|
||||
{
|
||||
type zeroGradient;
|
||||
}
|
||||
|
||||
defaultFaces
|
||||
{
|
||||
type zeroGradient;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
@ -1,22 +0,0 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: v2012 |
|
||||
| \\ / A nd | Website: www.openfoam.com |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class dictionary;
|
||||
location "constant";
|
||||
object transportProperties;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
transportModel Newtonian;
|
||||
|
||||
nu 1e-06;
|
||||
|
||||
// ************************************************************************* //
|
@ -1,23 +0,0 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: v2012 |
|
||||
| \\ / A nd | Website: www.openfoam.com |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class dictionary;
|
||||
location "constant";
|
||||
object turbulenceProperties;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
simulationType laminar;
|
||||
|
||||
|
||||
|
||||
|
||||
// ************************************************************************* //
|
@ -1,28 +0,0 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: v2012 |
|
||||
| \\ / A nd | Website: www.openfoam.com |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class dictionary;
|
||||
object collapseDict;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
collapseEdgesCoeffs
|
||||
{
|
||||
// Edges shorter than this absolute value will be merged
|
||||
minimumEdgeLength 2e-7;
|
||||
|
||||
// The maximum angle between two edges that share a point attached to
|
||||
// no other edges
|
||||
maximumMergeAngle 5;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
@ -1,80 +0,0 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: v2012 |
|
||||
| \\ / A nd | Website: www.openfoam.com |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class dictionary;
|
||||
location "system";
|
||||
object controlDict;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
application simpleFoam;
|
||||
|
||||
startFrom latestTime; //startTime;
|
||||
|
||||
startTime 0;
|
||||
|
||||
stopAt endTime;
|
||||
|
||||
endTime 5000;
|
||||
|
||||
deltaT 1;
|
||||
|
||||
writeControl timeStep;
|
||||
|
||||
writeInterval 50;
|
||||
|
||||
purgeWrite 0;
|
||||
|
||||
writeFormat ascii;
|
||||
|
||||
writePrecision 6;
|
||||
|
||||
writeCompression off;
|
||||
|
||||
timeFormat general;
|
||||
|
||||
timePrecision 6;
|
||||
|
||||
runTimeModifiable true;
|
||||
|
||||
functions
|
||||
{
|
||||
flowRatePatch(name=inlet)
|
||||
{
|
||||
name inlet;
|
||||
type surfaceFieldValue;
|
||||
libs ( "libfieldFunctionObjects.so" );
|
||||
writeControl timeStep;
|
||||
writeInterval 1;
|
||||
writeFields false;
|
||||
log false;
|
||||
regionType patch;
|
||||
fields ( phi );
|
||||
operation sum;
|
||||
}
|
||||
|
||||
flowRatePatch(name=outlet)
|
||||
{
|
||||
name outlet;
|
||||
type surfaceFieldValue;
|
||||
libs ( "libfieldFunctionObjects.so" );
|
||||
writeControl timeStep;
|
||||
writeInterval 1;
|
||||
writeFields false;
|
||||
log false;
|
||||
regionType patch;
|
||||
fields ( phi );
|
||||
operation sum;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
@ -1,168 +0,0 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: v2012 |
|
||||
| \\ / A nd | Website: www.openfoam.com |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class dictionary;
|
||||
object createPatchDict;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
pointSync false;
|
||||
|
||||
// Patches to create.
|
||||
patches
|
||||
(
|
||||
{
|
||||
name defaultFaces;
|
||||
|
||||
patchInfo
|
||||
{
|
||||
type empty;
|
||||
}
|
||||
|
||||
constructFrom patches;
|
||||
patches (defaultFaces);
|
||||
}
|
||||
|
||||
{
|
||||
name inlet;
|
||||
|
||||
patchInfo
|
||||
{
|
||||
type patch;
|
||||
inGroups (inlet);
|
||||
}
|
||||
|
||||
constructFrom patches;
|
||||
patches (smesh_inlet);
|
||||
}
|
||||
|
||||
{
|
||||
name outlet;
|
||||
|
||||
|
||||
patchInfo
|
||||
{
|
||||
type patch;
|
||||
inGroups (outlet);
|
||||
}
|
||||
|
||||
constructFrom patches;
|
||||
patches (smesh_outlet);
|
||||
}
|
||||
|
||||
{
|
||||
name wall;
|
||||
|
||||
patchInfo
|
||||
{
|
||||
type wall;
|
||||
inGroups (wall);
|
||||
}
|
||||
|
||||
constructFrom patches;
|
||||
patches (smesh_wall);
|
||||
}
|
||||
|
||||
{
|
||||
name symetry0;
|
||||
|
||||
patchInfo
|
||||
{
|
||||
type symetryPlane;
|
||||
inGroups (symetryPlane);
|
||||
}
|
||||
|
||||
constructFrom patches;
|
||||
patches (smesh_symetry0);
|
||||
}
|
||||
|
||||
{
|
||||
name symetry1;
|
||||
|
||||
patchInfo
|
||||
{
|
||||
type symetryPlane;
|
||||
inGroups (symetryPlane);
|
||||
}
|
||||
|
||||
constructFrom patches;
|
||||
patches (smesh_symetry1);
|
||||
}
|
||||
|
||||
{
|
||||
name symetry2;
|
||||
|
||||
patchInfo
|
||||
{
|
||||
type symetryPlane;
|
||||
inGroups (symetryPlane);
|
||||
}
|
||||
|
||||
constructFrom patches;
|
||||
patches (smesh_symetry2);
|
||||
}
|
||||
|
||||
{
|
||||
name symetry3;
|
||||
|
||||
patchInfo
|
||||
{
|
||||
type symetryPlane;
|
||||
inGroups (symetryPlane);
|
||||
}
|
||||
|
||||
constructFrom patches;
|
||||
patches (smesh_symetry3);
|
||||
}
|
||||
|
||||
{
|
||||
name symetry4;
|
||||
|
||||
patchInfo
|
||||
{
|
||||
type symetryPlane;
|
||||
inGroups (symetryPlane);
|
||||
}
|
||||
|
||||
constructFrom patches;
|
||||
patches (smesh_symetry4);
|
||||
}
|
||||
|
||||
{
|
||||
name symetry5;
|
||||
|
||||
patchInfo
|
||||
{
|
||||
type symetryPlane;
|
||||
inGroups (symetryPlane);
|
||||
}
|
||||
|
||||
constructFrom patches;
|
||||
patches (smesh_symetry5);
|
||||
}
|
||||
|
||||
{
|
||||
name strips;
|
||||
|
||||
patchInfo
|
||||
{
|
||||
type wall;
|
||||
inGroups (wall);
|
||||
}
|
||||
|
||||
constructFrom patches;
|
||||
patches (smesh_strips);
|
||||
}
|
||||
|
||||
|
||||
);
|
||||
|
||||
// ************************************************************************* //
|
@ -1,26 +0,0 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: v2012 |
|
||||
| \\ / A nd | Website: www.openfoam.com |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class dictionary;
|
||||
object decomposeParDict;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
numberOfSubdomains 4;
|
||||
|
||||
method simple;
|
||||
|
||||
coeffs
|
||||
{
|
||||
n (2 2 1);
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
@ -1,53 +0,0 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: v2012 |
|
||||
| \\ / A nd | Website: www.openfoam.com |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class dictionary;
|
||||
location "system";
|
||||
object fvSchemes;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
ddtSchemes
|
||||
{
|
||||
default steadyState;
|
||||
}
|
||||
|
||||
gradSchemes
|
||||
{
|
||||
default Gauss linear;
|
||||
// grad(Phi) Gauss linear;
|
||||
}
|
||||
|
||||
divSchemes
|
||||
{
|
||||
default none;
|
||||
div(phi,U) bounded Gauss linearUpwind grad(U);
|
||||
div((nuEff*dev2(T(grad(U))))) Gauss linear;
|
||||
div(nonlinearStress) Gauss linear;
|
||||
}
|
||||
|
||||
laplacianSchemes
|
||||
{
|
||||
default Gauss linear corrected;
|
||||
// laplacian(1, Phi) Gauss linear corrected;
|
||||
}
|
||||
|
||||
interpolationSchemes
|
||||
{
|
||||
default linear;
|
||||
}
|
||||
|
||||
snGradSchemes
|
||||
{
|
||||
default corrected;
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
@ -1,84 +0,0 @@
|
||||
/*--------------------------------*- C++ -*----------------------------------*\
|
||||
| ========= | |
|
||||
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
|
||||
| \\ / O peration | Version: missed |
|
||||
| \\ / A nd | |
|
||||
| \\/ M anipulation | |
|
||||
\*---------------------------------------------------------------------------*/
|
||||
FoamFile
|
||||
{
|
||||
version 2.0;
|
||||
format ascii;
|
||||
class dictionary;
|
||||
location "system";
|
||||
object fvSolution;
|
||||
}
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
solvers
|
||||
{
|
||||
p
|
||||
{
|
||||
solver GAMG;
|
||||
tolerance 1e-06;
|
||||
relTol 0.1;
|
||||
smoother GaussSeidel;
|
||||
}
|
||||
U
|
||||
{
|
||||
solver smoothSolver;
|
||||
smoother GaussSeidel;
|
||||
nSweeps 2;
|
||||
tolerance 1e-08;
|
||||
relTol 0.1;
|
||||
} /*Phi
|
||||
{
|
||||
solver GAMG;
|
||||
smoother GaussSeidel;
|
||||
tolerance 1e-08;
|
||||
relTol 0.01;
|
||||
}*/
|
||||
Phi
|
||||
{
|
||||
solver GAMG;
|
||||
smoother DIC;
|
||||
cacheAgglomeration yes;
|
||||
agglomerator faceAreaPair;
|
||||
nCellsInCoarsestLevel 10;
|
||||
mergeLevels 1;
|
||||
tolerance 1e-06;
|
||||
relTol 0.01;
|
||||
}
|
||||
}
|
||||
potentialFlow
|
||||
{
|
||||
nNonOrthogonalCorrectors 20;
|
||||
PhiRefCell 0;
|
||||
PhiRefPoint 0;
|
||||
PhiRefValue 0;
|
||||
Phi 0;
|
||||
}
|
||||
cache
|
||||
{
|
||||
grad(p) /* empty */ ;
|
||||
}
|
||||
SIMPLE
|
||||
{
|
||||
nNonOrthogonalCorrectors 10;
|
||||
residualControl
|
||||
{
|
||||
p 1e-05;
|
||||
U 1e-05;
|
||||
}
|
||||
}
|
||||
relaxationFactors
|
||||
{
|
||||
fields
|
||||
{
|
||||
p 0.3;
|
||||
}
|
||||
equations
|
||||
{
|
||||
U 0.5;
|
||||
}
|
||||
}
|
||||
// ************************************************************************* //
|
@ -4,6 +4,7 @@
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from numpy import ndarray
|
||||
#from .application import application
|
||||
|
||||
def version() -> str:
|
||||
@ -30,7 +31,7 @@ def foamCleanCustom(case: str = None):
|
||||
# application("foamCleanTutorials", useMPI = False, case = case, stderr = True)
|
||||
|
||||
def uniform(value) -> str:
|
||||
if type(value) == list or type(value) == tuple:
|
||||
if type(value) == list or type(value) == tuple or type(value) == ndarray:
|
||||
return f"uniform ({ value[0] } { value[1] } { value[2] })"
|
||||
|
||||
elif type(value) == int or type(value) == float:
|
||||
@ -38,3 +39,51 @@ def uniform(value) -> str:
|
||||
|
||||
else:
|
||||
return ""
|
||||
|
||||
def datReader(filename: str):
|
||||
header = []
|
||||
content = []
|
||||
|
||||
with open(filename, "r") as io:
|
||||
for line in io.readlines():
|
||||
if line.startswith("#"):
|
||||
header.append(line)
|
||||
|
||||
else:
|
||||
content.append(line)
|
||||
|
||||
columns = []
|
||||
|
||||
if header[-1].find(":") < 0:
|
||||
for column in header[-1].replace("#", "").split("\t"):
|
||||
columns.append(column.strip())
|
||||
|
||||
header.pop(-1)
|
||||
|
||||
else:
|
||||
for column in range(len(content[0].split("\t"))):
|
||||
columns.append(str(column))
|
||||
|
||||
output = {}
|
||||
|
||||
for row in header:
|
||||
key, value = row.replace("#", "").split(":")
|
||||
|
||||
try:
|
||||
value = float(value.strip())
|
||||
|
||||
except:
|
||||
value = value.strip()
|
||||
|
||||
output[key.strip()] = value
|
||||
|
||||
for column in columns:
|
||||
output[column] = []
|
||||
|
||||
for row in content:
|
||||
values = row.split("\t")
|
||||
|
||||
for column, value in zip(columns, values):
|
||||
output[column].append(float(value))
|
||||
|
||||
return output
|
@ -43,6 +43,14 @@ class Shape(object):
|
||||
|
||||
return out, err, returncode
|
||||
|
||||
def load(self, filename: str):
|
||||
ext = os.path.splitext(filename)[1][1:]
|
||||
|
||||
if ext in ["step", "iges", "brep"]:
|
||||
self.shape = OCCGeometry(filename).shape
|
||||
|
||||
else:
|
||||
raise NotImplementedError(f"{ext} is not supported")
|
||||
|
||||
def normal(self, face: FACE) -> numpy.array:
|
||||
"""
|
||||
|
@ -5,12 +5,13 @@
|
||||
import anisotropy.openfoam.presets as F
|
||||
import anisotropy.openfoam.runnerPresets as R
|
||||
from anisotropy.openfoam import FoamCase, uniform
|
||||
from numpy import array
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class OnePhaseFlow(FoamCase):
|
||||
def __init__(self, path: str = None):
|
||||
def __init__(self, direction, path: str = None):
|
||||
FoamCase.__init__(self, path = path)
|
||||
|
||||
controlDict = F.ControlDict()
|
||||
@ -80,7 +81,7 @@ class OnePhaseFlow(FoamCase):
|
||||
)
|
||||
u["boundaryField"][boundary] = dict(
|
||||
type = "fixedValue",
|
||||
value = uniform([0, 0, -6e-5]) # * direction
|
||||
value = uniform(array(direction) * -6e-5) # uniform([0, 0, -6e-5])
|
||||
)
|
||||
|
||||
elif boundary == "outlet":
|
||||
@ -111,6 +112,55 @@ class OnePhaseFlow(FoamCase):
|
||||
u
|
||||
])
|
||||
|
||||
@staticmethod
|
||||
def facesToPatches(faces: tuple[int, str]):
|
||||
# initial 43 unnamed patches ->
|
||||
# 6 named patches (inlet, outlet, wall, symetry0 - 3/5) ->
|
||||
# 4 inGroups (inlet, outlet, wall, symetry)
|
||||
|
||||
createPatchDict = F.CreatePatchDict()
|
||||
createPatchDict["patches"] = []
|
||||
patches = {}
|
||||
|
||||
for n, name in faces:
|
||||
# shifted index
|
||||
n += 1
|
||||
|
||||
if patches.get(name):
|
||||
patches[name].append(f"patch{n}")
|
||||
|
||||
else:
|
||||
patches[name] = [f"patch{n}"]
|
||||
|
||||
for name in patches.keys():
|
||||
if name == "inlet":
|
||||
patchGroup = "inlet"
|
||||
patchType = "patch"
|
||||
|
||||
elif name == "outlet":
|
||||
patchGroup = "outlet"
|
||||
patchType = "patch"
|
||||
|
||||
elif name == "wall":
|
||||
patchGroup = "wall"
|
||||
patchType = "wall"
|
||||
|
||||
else:
|
||||
patchGroup = "symetry"
|
||||
patchType = "symetryPlane"
|
||||
|
||||
createPatchDict["patches"].append({
|
||||
"name": name,
|
||||
"patchInfo": {
|
||||
"type": patchType,
|
||||
"inGroups": [patchGroup]
|
||||
},
|
||||
"constructFrom": "patches",
|
||||
"patches": patches[name]
|
||||
})
|
||||
|
||||
return createPatchDict
|
||||
|
||||
def build(self) -> tuple[str, str, int]:
|
||||
# TODO: configure working directory (FoamCase)
|
||||
with self:
|
||||
@ -129,7 +179,7 @@ class OnePhaseFlow(FoamCase):
|
||||
|
||||
self.U["boundaryField"]["outlet"] = dict(
|
||||
type = "pressureInletVelocity",
|
||||
value = uniform([0, 0, 0]) # * direction
|
||||
value = uniform([0, 0, 0])
|
||||
)
|
||||
self.write()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user