Mod: core: improve pipeline

Fix: openfoam: wrong path expressions
This commit is contained in:
L-Nafaryus 2022-02-18 00:28:05 +05:00
parent c5d2bf1783
commit fc1b8432cb
No known key found for this signature in database
GPG Key ID: C76D8DCD2727DBB7
7 changed files with 183 additions and 69 deletions

View File

@ -65,7 +65,7 @@ def init(path, verbose):
@click.option( @click.option(
"-f", "--force", "overwrite", "-f", "--force", "overwrite",
is_flag = True, is_flag = True,
# default = False, default = None,
help = "Overwrite existing entries" help = "Overwrite existing entries"
) )
@click.option( @click.option(
@ -135,6 +135,7 @@ def compute(path, configFile, nprocs, stage, overwrite, params, verbose, executi
if v is not None: if v is not None:
config.update(**{ k: v }) config.update(**{ k: v })
print(config.options)
if pid: if pid:
pid = pathlib.Path(pid).resolve() pid = pathlib.Path(pid).resolve()

View File

@ -12,6 +12,7 @@ from anisotropy.database import Database, tables
from anisotropy import shaping from anisotropy import shaping
from anisotropy import meshing from anisotropy import meshing
from anisotropy import solving from anisotropy import solving
from anisotropy import openfoam
from . import config as core_config from . import config as core_config
from . import postprocess from . import postprocess
@ -51,6 +52,24 @@ class UltimateRunner(object):
# Parameters # Parameters
self.queue = [] self.queue = []
def _query_database(self, tableName: str, to_dict: bool = False):
tableName = tableName.lower()
get_row = {
"shape": self.database.getShape,
"mesh": self.database.getMesh,
"flowonephase": self.database.getFlowOnephase
}[tableName]
# query
args = (
self.config.params["label"],
self.config.params["direction"],
self.config.params["alpha"],
self.exec_id,
to_dict
)
return get_row(*args)
def prepare_database(self): def prepare_database(self):
# create a row in each table for the current case # create a row in each table for the current case
# shape # shape
@ -128,25 +147,16 @@ class UltimateRunner(object):
def compute_shape(self): def compute_shape(self):
params = self.config.params params = self.config.params
shapeParams = self.database.getShape( shapeParams = self._query_database("shape")
params["label"],
params["direction"],
params["alpha"],
self.exec_id
)
logger.info("Computing shape for {} with direction = {} and alpha = {}".format( logger.info("Computing shape for {} with direction = {} and alpha = {}".format(
params["label"], params["direction"], params["alpha"] params["label"], params["direction"], params["alpha"]
)) ))
timer = utils.Timer() timer = utils.Timer()
# check # check physical existence
if ( if self.shapefile.exists() and self.config["overwrite"] is not True:
self.shapefile.exists() and logger.info("Shape exists, skipping ...")
shapeParams.shapeStatus == "done" and
not self.config["overwrite"]
):
logger.info("Shape exists. Skipping ...")
return return
# #
@ -187,25 +197,16 @@ class UltimateRunner(object):
def compute_mesh(self): def compute_mesh(self):
params = self.config.params params = self.config.params
meshParams = self.database.getMesh( meshParams = self._query_database("mesh")
params["label"],
params["direction"],
params["alpha"],
self.exec_id
)
logger.info("Computing mesh for {} with direction = {} and alpha = {}".format( logger.info("Computing mesh for {} with direction = {} and alpha = {}".format(
params["label"], params["direction"], params["alpha"] params["label"], params["direction"], params["alpha"]
)) ))
timer = utils.Timer() timer = utils.Timer()
# check # check physical existence
if ( if self.meshfile.exists() and self.config["overwrite"] is not True:
self.meshfile.exists() and logger.info("Mesh exists, skipping ...")
meshParams.meshStatus == "done" and
not self.config["overwrite"]
):
logger.info("Mesh exists. Skipping ...")
return return
elif not self.shapefile.exists(): elif not self.shapefile.exists():
@ -246,21 +247,15 @@ class UltimateRunner(object):
def compute_flow(self): def compute_flow(self):
params = self.config.params params = self.config.params
query = ( flowParams = self._query_database("flowonephase")
params["label"],
params["direction"],
params["alpha"],
self.exec_id
)
flowParams = self.database.getFlowOnephase(*query)
logger.info("Computing flow for {} with direction = {} and alpha = {}".format( logger.info("Computing flow for {} with direction = {} and alpha = {}".format(
params["label"], params["direction"], params["alpha"] params["label"], params["direction"], params["alpha"]
)) ))
timer = utils.Timer() timer = utils.Timer()
# check # check physical existence
if flowParams.flowStatus == "done" and not self.config["overwrite"]: if openfoam.FoamCase(path = self.casepath).is_converged() and not self.config["overwrite"]:
logger.info("Solution exists. Skipping ...") logger.info("Solution exists. Skipping ...")
return return
@ -277,7 +272,7 @@ class UltimateRunner(object):
self.database.csave(flowParams) self.database.csave(flowParams)
# #
flowParamsDict = self.database.getFlowOnephase(*query, to_dict = True) flowParamsDict = self._query_database("flowonephase", to_dict = True)
try: try:
# load shape # load shape
@ -309,18 +304,14 @@ class UltimateRunner(object):
def compute_postprocess(self): def compute_postprocess(self):
params = self.config.params params = self.config.params
flowParams = self.database.getFlowOnephase( flowParams = self._query_database("flowonephase")
params["label"],
params["direction"],
params["alpha"],
self.exec_id
)
logger.info("Computing post process for {} with direction = {} and alpha = {}".format( logger.info("Computing post process for {} with direction = {} and alpha = {}".format(
params["label"], params["direction"], params["alpha"] params["label"], params["direction"], params["alpha"]
)) ))
if flowParams.flowStatus == "done": if flowParams.flowStatus == "done":
if flowParams.flowRate is None and self.config["overwrite"] is not True:
flowParams.flowRate = postprocess.flowRate("outlet", self.casepath) flowParams.flowRate = postprocess.flowRate("outlet", self.casepath)
self.database.csave(flowParams) self.database.csave(flowParams)
@ -335,15 +326,43 @@ class UltimateRunner(object):
for current in stages: for current in stages:
if current == "shape": if current == "shape":
params = self._query_database("shape")
# check database entry
if params.shapeStatus == "done" and self.config["overwrite"] is not True:
logger.info("Successful shape entry exists, skipping ...")
continue
self.compute_shape() self.compute_shape()
if current == "mesh": if current == "mesh":
params = self._query_database("mesh")
# check database entry
if params.meshStatus == "done" and self.config["overwrite"] is not True:
logger.info("Successful mesh entry exists, skipping ...")
continue
self.compute_mesh() self.compute_mesh()
if current == "flow": if current == "flow":
params = self._query_database("flowonephase")
# check database entry
if params.flowStatus == "done" and self.config["overwrite"] is not True:
logger.info("Successful flow entry exists, skipping ...")
continue
self.compute_flow() self.compute_flow()
if current == "postProcess": if current == "postProcess":
params = self._query_database("flowonephase")
# check database entry
# if params.flowStatus == "done" and self.config["overwrite"] is not True:
# logger.info("Successful flow entry exists, skipping ...")
# continue
self.compute_postprocess() self.compute_postprocess()
if current == stage or current == "all": if current == stage or current == "all":

View File

@ -57,7 +57,7 @@ class Database(pw.SqliteDatabase):
return self return self
def csave(self, table: pw.Model, tries: int = 100): def csave(self, table: pw.Model, tries: int = 5000):
"""Try to save data from model to the database ignoring """Try to save data from model to the database ignoring
peewee.OperationalError. Usefull for concurrent processes. peewee.OperationalError. Usefull for concurrent processes.
@ -82,7 +82,12 @@ class Database(pw.SqliteDatabase):
self.close() self.close()
break break
def getExecution(self, idn: int) -> tables.Execution | None: def getExecution(
self,
idn: int,
to_dict: bool = False,
**kwargs
) -> tables.Execution | None:
"""Get execution entry from database. """Get execution entry from database.
:param idn: :param idn:
@ -93,6 +98,10 @@ class Database(pw.SqliteDatabase):
query = tables.Execution.select().where(tables.Execution.exec_id == idn) query = tables.Execution.select().where(tables.Execution.exec_id == idn)
with self: with self:
if to_dict:
table = query.dicts().get() if query.exists() else None
else:
table = query.get() if query.exists() else None table = query.get() if query.exists() else None
return table return table
@ -116,6 +125,7 @@ class Database(pw.SqliteDatabase):
direction: list[float] | ndarray = None, direction: list[float] | ndarray = None,
alpha: float = None, alpha: float = None,
execution: int = None, execution: int = None,
to_dict: bool = False,
**kwargs **kwargs
) -> tables.Shape | None: ) -> tables.Shape | None:
"""Get shape entry from database. """Get shape entry from database.
@ -145,6 +155,10 @@ class Database(pw.SqliteDatabase):
) )
with self: with self:
if to_dict:
table = query.dicts().get() if query.exists() else None
else:
table = query.get() if query.exists() else None table = query.get() if query.exists() else None
return table return table
@ -155,6 +169,7 @@ class Database(pw.SqliteDatabase):
direction: list[float] | ndarray = None, direction: list[float] | ndarray = None,
alpha: float = None, alpha: float = None,
execution: int = None, execution: int = None,
to_dict: bool = False,
**kwargs **kwargs
) -> tables.Mesh | None: ) -> tables.Mesh | None:
"""Get mesh entry from database. """Get mesh entry from database.
@ -185,6 +200,10 @@ class Database(pw.SqliteDatabase):
) )
with self: with self:
if to_dict:
table = query.dicts().get() if query.exists() else None
else:
table = query.get() if query.exists() else None table = query.get() if query.exists() else None
return table return table

View File

@ -231,7 +231,7 @@ layout = html.Div([
] ]
) )
def plotDraw(clicks, execution, structure, direction, data): def plotDraw(clicks, execution, structure, direction, data):
from peewee import JOIN import peewee as pw
from anisotropy.database import Database, tables from anisotropy.database import Database, tables
import json import json
from pandas import DataFrame from pandas import DataFrame
@ -263,20 +263,32 @@ def plotDraw(clicks, execution, structure, direction, data):
else: else:
select = (tables.Shape.alpha, column) select = (tables.Shape.alpha, column)
query = ( """query = (
tables.Shape tables.Shape
.select(*select) .select(*select)
.join(tables.Execution, JOIN.LEFT_OUTER) .join(tables.Execution, JOIN.LEFT_OUTER)
.switch(tables.Shape) .switch(tables.Shape)
.join(tables.Mesh, JOIN.LEFT_OUTER) .join(tables.Mesh, JOIN.LEFT_OUTER)
.switch(tables.Shape)
# .join(tables.FlowOnephase, JOIN.LEFT_OUTER)
#.switch(tables.Shape) #.switch(tables.Shape)
.join(tables.FlowOnephase, JOIN.LEFT_OUTER)
.switch(tables.Shape)
.where( .where(
tables.Shape.exec_id == execution, tables.Shape.exec_id == execution,
tables.Shape.label == structure, tables.Shape.label == structure,
) )
)"""
query = model.select(*select)
idn = db.tables.index(model)
for table in reversed(db.tables[ :idn]):
query = query.join(table, pw.JOIN.LEFT_OUTER)
query = query.switch(tables.Shape)
query = query.where(
tables.Shape.exec_id == execution,
tables.Shape.label == structure,
) )
query = query.order_by(tables.Shape.alpha)
if not direction == "all": if not direction == "all":
query = query.where(tables.Shape.direction == json.loads(direction)) query = query.where(tables.Shape.direction == json.loads(direction))

View File

@ -6,6 +6,8 @@ import os
import shutil import shutil
import re import re
import pathlib import pathlib
import io
from lz.reversal import reverse as lz_reverse
from . import FoamFile from . import FoamFile
@ -72,23 +74,23 @@ class FoamCase(object):
path = pathlib.Path(path or self.path or "") path = pathlib.Path(path or self.path or "")
for file in self._files: for file in self._files:
path /= ( path_ = path / (
file.location + "/" + file.object file.location + "/" + file.object
if file.location else file.object if file.location else file.object
) )
file.read(path.resolve()) file.read(path_.resolve())
def remove(self, path: str = None): def remove(self, path: str = None):
path = pathlib.Path(path or self.path or "") path = pathlib.Path(path or self.path or "")
for file in self._files: for file in self._files:
path /= ( path_ = path / (
file.location + "/" + file.object file.location + "/" + file.object
if file.location else file.object if file.location else file.object
) )
file.remove(path.resolve()) file.remove(path_.resolve())
def clean(self, included: list = ["0", "constant", "system"]): def clean(self, included: list = ["0", "constant", "system"]):
regxs = [ regxs = [
@ -105,10 +107,16 @@ class FoamCase(object):
for root, dirs, files in os.walk(os.path.abspath("")): for root, dirs, files in os.walk(os.path.abspath("")):
for _dir in dirs: for _dir in dirs:
excluded += [ os.path.join(root, _dir) for regx in regxs if re.match(regx, _dir) ] excluded += [
os.path.join(root, _dir)
for regx in regxs if re.match(regx, _dir)
]
for file in files: for file in files:
excluded += [ os.path.join(root, file) for regx in regxs if re.match(regx, file) ] excluded += [
os.path.join(root, file)
for regx in regxs if re.match(regx, file)
]
for file in excluded: for file in excluded:
if os.path.split(file)[1] not in included and os.path.exists(file): if os.path.split(file)[1] not in included and os.path.exists(file):
@ -128,3 +136,39 @@ class FoamCase(object):
path = pathlib.Path(self._backpath or "").resolve() path = pathlib.Path(self._backpath or "").resolve()
os.chdir(path) os.chdir(path)
def is_converged(self, path: str = None) -> None | bool:
path = pathlib.Path(path or self.path or "").resolve()
controlDict = FoamFile()
if controlDict.exists(path / "system" / "controlDict"):
controlDict.read(path / "system" / "controlDict")
else:
return None
application = controlDict.get("application")
if application is None:
return None
logfile = (
path / f"{ application }.log"
if (path / f"{ application }.log").exists() else (path / f"log.{ application }")
)
status = False
if logfile.exists():
with open(logfile, "r") as infile:
limit = 30
for line in lz_reverse(infile, batch_size = io.DEFAULT_BUFFER_SIZE):
if not line.find("End") < 0:
status = True
if limit <= 0:
status = False
limit -= 1
return status

View File

@ -22,6 +22,10 @@ def read_foamfile(filename: str) -> tuple[dict, dict]:
header = ppf.header or {} header = ppf.header or {}
content = ppf.content or {} content = ppf.content or {}
if type(content) == dict:
if content.get("internalField"):
content["internalField"] = np.asarray(content["internalField"])
return header, content return header, content

View File

@ -68,11 +68,17 @@ class FoamFile(object):
@property @property
def location(self) -> str: def location(self) -> str:
return self.header.get("location").replace('"', "") return (
self.header.get("location").replace('"', "")
if self.header.get("location") else None
)
def __getitem__(self, key): def __getitem__(self, key):
return self.content[key] return self.content[key]
def get(self, key, default = None):
return self.content.get(key, default)
def __setitem__(self, key, value): def __setitem__(self, key, value):
self.content[key] = value self.content[key] = value
@ -99,6 +105,15 @@ class FoamFile(object):
return FoamCase([ self, file ]) return FoamCase([ self, file ])
def exists(self, filename: str = None) -> bool:
filename = filename or (
self.location + "/" + self.object
if self.location else self.object
)
path = pathlib.Path(filename).resolve()
return path.exists() and path.is_file()
def read(self, filename: str = None): def read(self, filename: str = None):
"""Read a FoamFile. """Read a FoamFile.
@ -108,8 +123,8 @@ class FoamFile(object):
:return: :return:
Self. Self.
""" """
filename = ( filename = filename or (
filename or self.location + "/" + self.object self.location + "/" + self.object
if self.location else self.object if self.location else self.object
) )
path = pathlib.Path(filename).resolve() path = pathlib.Path(filename).resolve()
@ -131,8 +146,8 @@ class FoamFile(object):
Path to the file. If None, use location and object from header with Path to the file. If None, use location and object from header with
the current working directory. the current working directory.
""" """
filename = ( filename = filename or (
filename or self.location + "/" + self.object self.location + "/" + self.object
if self.location else self.object if self.location else self.object
) )
path = pathlib.Path(filename).resolve() path = pathlib.Path(filename).resolve()
@ -146,8 +161,8 @@ class FoamFile(object):
Path to the file. If None, use location and object from header with Path to the file. If None, use location and object from header with
the current working directory. the current working directory.
""" """
filename = ( filename = filename or (
filename or self.location + "/" + self.object self.location + "/" + self.object
if self.location else self.object if self.location else self.object
) )
path = pathlib.Path(filename).resolve() path = pathlib.Path(filename).resolve()