diff --git a/anisotropy/config/default.toml b/anisotropy/config/default.toml index 0fe2804..169e8c7 100644 --- a/anisotropy/config/default.toml +++ b/anisotropy/config/default.toml @@ -77,14 +77,7 @@ faceCentered = true [structures.flow] scale = [ 1e-5, 1e-5, 1e-5 ] - constant.nu = 1e-6 - - approx.pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } - approx.pressure.boundaryField.outlet = { type = "fixedValue", value = 0 } - - # multiplication velocity value with flow direction vector - approx.velocity.boundaryField.inlet = { type = "fixedValue", value = 6e-5 } - approx.velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" } + transportProperties.nu = 1e-6 pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } pressure.boundaryField.outlet = { type = "fixedValue", value = 0 } @@ -92,6 +85,16 @@ faceCentered = true velocity.boundaryField.inlet = { type = "fixedValue", value = 0.0 } velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" } + [structures.flowapprox] + transportProperties.nu = 1e-6 + + pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } + pressure.boundaryField.outlet = { type = "fixedValue", value = 0 } + + # multiplication velocity value with flow direction vector + velocity.boundaryField.inlet = { type = "fixedValue", value = 6e-5 } + velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" } + [[structures]] [structures.structure] type = "bodyCentered" @@ -162,14 +165,7 @@ faceCentered = true [structures.flow] scale = [ 1e-5, 1e-5, 1e-5 ] - constant.nu = 1e-6 - - approx.pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } - approx.pressure.boundaryField.outlet = { type = "fixedValue", value = 0 } - - # multiplication velocity value with direction vector - approx.velocity.boundaryField.inlet = { type = "fixedValue", value = 6e-5 } - approx.velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" } + transportProperties.nu = 1e-6 pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } pressure.boundaryField.outlet = { type = "fixedValue", value = 0 } @@ -177,6 +173,16 @@ faceCentered = true velocity.boundaryField.inlet = { type = "fixedValue", value = 0.0 } velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" } + [structures.flowapprox] + transportProperties.nu = 1e-6 + + pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } + pressure.boundaryField.outlet = { type = "fixedValue", value = 0 } + + # multiplication velocity value with direction vector + velocity.boundaryField.inlet = { type = "fixedValue", value = 6e-5 } + velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" } + [[structures]] [structures.structure] type = "faceCentered" @@ -247,18 +253,21 @@ faceCentered = true [structures.flow] scale = [ 1e-5, 1e-5, 1e-5 ] - constant.nu = 1e-6 - - approx.pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } - approx.pressure.boundaryField.outlet = { type = "fixedValue", value = 0 } - - # multiplication velocity value with direction vector - approx.velocity.boundaryField.inlet = { type = "fixedValue", value = 6e-5 } - approx.velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" } - + transportProperties.nu = 1e-6 + pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } pressure.boundaryField.outlet = { type = "fixedValue", value = 0 } velocity.boundaryField.inlet = { type = "fixedValue", value = 0.0 } velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" } + [structures.flowapprox] + transportProperties.nu = 1e-6 + + pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } + pressure.boundaryField.outlet = { type = "fixedValue", value = 0 } + + # multiplication velocity value with direction vector + velocity.boundaryField.inlet = { type = "fixedValue", value = 6e-5 } + velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" } + diff --git a/anisotropy/core/cli.py b/anisotropy/core/cli.py index 89a6992..ba4a04d 100644 --- a/anisotropy/core/cli.py +++ b/anisotropy/core/cli.py @@ -11,6 +11,9 @@ class LiteralOption(click.Option): class KeyValueOption(click.Option): def _convert(self, ctx, value): + if not value: + return {} + if value.find("=") == -1: raise click.BadParameter(f"{ value } (Missed '=')") @@ -60,7 +63,7 @@ def anisotropy(): @click.option("-s", "--stage", "stage", type = click.Choice(["all", "mesh", "flow"]), default = "all") @click.option("-p", "--param", "params", metavar = "key=value", multiple = True, cls = KeyValueOption) def compute(stage, params): - from anisotropy.core.main import Anisotropy + from anisotropy.core.main import Anisotropy, logger args = dict() @@ -89,16 +92,20 @@ def compute(stage, params): if stage == "all" or stage == "mesh": ((out, err, code), elapsed) = model.computeMesh(type, direction, theta) - model.load(type, direction, theta) - model.params["meshresult"]["calculationTime"] = elapsed - model.update() + if out: click.echo(out) + if err: click.echo(err) + if model.params.get("meshresult"): + model.load(type, direction, theta) + model.params["meshresult"]["calculationTime"] = elapsed + model.update() if stage == "all" or stage == "flow": ((out, err, code), elapsed) = model.computeFlow(type, direction, theta) - model.load(type, direction, theta) - model.params["flowresult"]["calculationTime"] = elapsed - model.update() + if model.params.get("flowresult"): + model.load(type, direction, theta) + model.params["flowresult"]["calculationTime"] = elapsed + model.update() @anisotropy.command() diff --git a/anisotropy/core/database.py b/anisotropy/core/database.py index 6a0b717..4df95d4 100644 --- a/anisotropy/core/database.py +++ b/anisotropy/core/database.py @@ -8,7 +8,12 @@ from copy import deepcopy from anisotropy import env from anisotropy.core.utils import setupLogger -from anisotropy.core.models import db, JOIN, Structure, Mesh, SubMesh, MeshResult, Flow, FlowResult +from anisotropy.core.models import ( + db, JOIN, + Structure, + Mesh, SubMesh, MeshResult, + Flow, FlowApproximation, FlowResult +) logger = logging.getLogger(env["logger_name"]) setupLogger(logger, logging.INFO, env["LOG"]) @@ -34,6 +39,7 @@ class Database(object): SubMesh, MeshResult, Flow, + FlowApproximation, FlowResult ]) @@ -76,6 +82,21 @@ class Database(object): if meshresultQuery.exists(): params["meshresult"] = meshresultQuery.dicts().get() + flowQuery = structureQuery.get().flows + + if flowQuery.exists(): + params["flow"] = flowQuery.dicts().get() + + flowapproxQuery = flowQuery.get().flowapprox + + if flowapproxQuery.exists(): + params["flowapprox"] = flowapproxQuery.dicts().get() + + flowresultsQuery = flowQuery.get().flowresults + + if flowresultsQuery.exists(): + params["flowresult"] = flowresultsQuery.dicts().get() + return params @@ -100,12 +121,17 @@ class Database(object): query = ( Structure - .select(Structure, Mesh) + .select(Structure, Mesh, Flow) .join( Mesh, JOIN.INNER, on = (Mesh.structure_id == Structure.structure_id) ) + .join( + Flow, + JOIN.INNER, + on = (Flow.structure_id == Structure.structure_id) + ) .where( Structure.type == params["structure"]["type"], Structure.direction == str(params["structure"]["direction"]), @@ -122,7 +148,11 @@ class Database(object): self._updateMeshResult(params.get("meshresult", {}), query, meshID) - # TODO: update method flow flow / flowresult + flowID = self._updateFlow(params["flow"], query, structureID) + + self._updateFlowApproximation(params.get("flowapprox", {}), query, flowID) + + self._updateFlowResult(params.get("flowresult", {}), query, flowID) def _updateStructure(self, src: dict, queryMain) -> int: raw = deepcopy(src) @@ -217,3 +247,73 @@ class Database(object): ) ) query.execute() + + def _updateFlow(self, src: dict, queryMain, structureID): + raw = deepcopy(src) + + with self.__db.atomic(): + if not queryMain.exists(): + tabID = Flow.create( + structure_id = structureID, + **raw + ) + + else: + req = queryMain.dicts().get() + tabID = req["flow_id"] + + query = ( + Flow.update(**raw) + .where( + Flow.structure_id == structureID + ) + ) + query.execute() + + return tabID + + def _updateFlowApproximation(self, src: dict, queryMain, flowID): + if not src: + return + + raw = deepcopy(src) + + with self.__db.atomic(): + if not FlowApproximation.select().where(FlowApproximation.flow_id == flowID).exists(): + tabID = FlowApproximation.create( + flow_id = flowID, + **raw + ) + logger.debug(f"[ DB ] Created FlowApproximation entry { tabID }") + + else: + query = ( + FlowApproximation.update(**raw) + .where( + FlowApproximation.flow_id == flowID + ) + ) + query.execute() + + def _updateFlowResult(self, src: dict, queryMain, flowID): + if not src: + return + + raw = deepcopy(src) + + with self.__db.atomic(): + if not FlowResult.select().where(FlowResult.flow_id == flowID).exists(): + tabID = FlowResult.create( + flow_id = flowID, + **raw + ) + logger.debug(f"[ DB ] Created FlowResult entry { tabID }") + + else: + query = ( + FlowResult.update(**raw) + .where( + FlowResult.flow_id == flowID + ) + ) + query.execute() diff --git a/anisotropy/core/main.py b/anisotropy/core/main.py index 424949b..5965c6b 100644 --- a/anisotropy/core/main.py +++ b/anisotropy/core/main.py @@ -120,13 +120,13 @@ class Anisotropy(object): ), "mesh": mesh, "submesh": deepcopy(entry["submesh"]), - "flow": deepcopy(entry["flow"]) + "flow": deepcopy(entry["flow"]), + "flowapprox": deepcopy(entry["flowapprox"]) } - # TODO: optimize it # For type = fixedValue only - _velocity = entryNew["flow"]["approx"]["velocity"]["boundaryField"]["inlet"]["value"] - entryNew["flow"]["approx"]["velocity"]["boundaryField"]["inlet"]["value"] = [ + _velocity = entryNew["flowapprox"]["velocity"]["boundaryField"]["inlet"]["value"] + entryNew["flowapprox"]["velocity"]["boundaryField"]["inlet"]["value"] = [ val * _velocity for val in entryNew["structure"]["direction"] ] @@ -212,7 +212,7 @@ class Anisotropy(object): return os.path.join( self.env["BUILD"], structure["type"], - f"direction-{ structure['direction'] }", + "direction-{}".format(str(structure['direction']).replace(" ", "")), f"theta-{ structure['theta'] }" ) @@ -350,15 +350,17 @@ class Anisotropy(object): foamCase = [ "0", "constant", "system" ] flow = self.params["flow"] + flowapprox = self.params["flowapprox"] # ISSUE: ideasUnvToFoam cannot import mesh with '-case' flag so 'os.chdir' for that - os.chdir(self.getCasePath()) + casePath = self.getCasePath() + os.chdir(casePath) openfoam.foamClean() for d in foamCase: shutil.copytree( os.path.join(self.env["openfoam_template"], d), - os.path.join(case, d) + os.path.join(casePath, d) ) ### @@ -369,11 +371,11 @@ class Anisotropy(object): os.chdir(self.env["ROOT"]) return 1 - _, returncode = openfoam.ideasUnvToFoam("mesh.unv") + out, err, returncode = openfoam.ideasUnvToFoam("mesh.unv") if returncode: os.chdir(self.env["ROOT"]) - return returncode + return out, err, returncode openfoam.createPatch(dictfile = "system/createPatchDict") @@ -398,25 +400,20 @@ class Anisotropy(object): ### # Decomposition and initial approximation # - # NOTE: Temporarily without decomposition + # NOTE: Temporary without decomposition ## openfoam.foamDictionary( "constant/transportProperties", "nu", - str(flow["constant"]["nu"]) + str(flow["transportProperties"]["nu"]) ) #openfoam.decomposePar() openfoam.renumberMesh() - pressureBF = flow["approx"]["pressure"]["boundaryField"] - velocityBF = flow["approx"]["velocity"]["boundaryField"] - direction = { - "[1, 0, 0]": 0, - "[0, 0, 1]": 1, - "[1, 1, 1]": 2 - }[str(task.geometry.direction)] + pressureBF = flowapprox["pressure"]["boundaryField"] + velocityBF = flowapprox["velocity"]["boundaryField"] openfoam.foamDictionary( "0/p", @@ -451,7 +448,7 @@ class Anisotropy(object): openfoam.foamDictionary( "0/U", "boundaryField.inlet.value", - velocityBF["inlet"]["value"] + openfoam.uniform(velocityBF["inlet"]["value"]) ) #for n in range(os.cpu_count()): @@ -466,7 +463,7 @@ class Anisotropy(object): # openfoam.uniform(velocityBF.inlet.value[direction]) # ) - returncode, out = openfoam.simpleFoam() + out, err, returncode = openfoam.simpleFoam() if out: logger.info(out) @@ -477,7 +474,7 @@ class Anisotropy(object): if returncode == 0: postProcessing = "postProcessing/flowRatePatch(name=outlet)/0/surfaceFieldValue.dat" - with open(postProcessing, "r") as io: + with open(os.path.join(casePath, postProcessing), "r") as io: lastLine = io.readlines()[-1] flowRate = float(lastLine.replace(" ", "").replace("\n", "").split("\t")[1]) @@ -489,7 +486,7 @@ class Anisotropy(object): os.chdir(self.env["ROOT"]) - return returncode + return out, err, returncode def _queue(self): diff --git a/anisotropy/core/models.py b/anisotropy/core/models.py index cb2a602..070b1fe 100644 --- a/anisotropy/core/models.py +++ b/anisotropy/core/models.py @@ -10,6 +10,7 @@ from peewee import ( IntegerField, BooleanField, TimeField ) +import json db = SqliteDatabase( None, @@ -42,6 +43,15 @@ class ListField(Field): return pval +class JSONField(TextField): + def db_value(self, value): + return json.dumps(value) + + def python_value(self, value): + if value is not None: + return json.loads(value) + + class Structure(BaseModel): structure_id = AutoField() @@ -132,33 +142,22 @@ class MeshResult(BaseModel): calculationTime = TimeField(null = True) class Flow(BaseModel): - # TODO: find better way flow_id = AutoField() structure_id = ForeignKeyField(Structure, backref = "flows") - approx_pressure_boundaryField_inlet_type = TextField(null = True) - approx_pressure_boundaryField_inlet_value = FloatField(null = True) + scale = ListField(null = True) + pressure = JSONField(null = True) + velocity = JSONField(null = True) + transportProperties = JSONField(null = True) - approx_pressure_boundaryField_outlet_type = TextField(null = True) - approx_pressure_boundaryField_outlet_value = FloatField(null = True) + +class FlowApproximation(BaseModel): + flow_approximation_id = AutoField() + flow_id = ForeignKeyField(Flow, backref = "flowapprox") - approx_velocity_boundaryField_inlet_type = TextField(null = True) - approx_velocity_boundaryField_inlet_value = ListField(null = True) - - approx_velocity_boundaryField_outlet_type = TextField(null = True) - approx_velocity_boundaryField_outlet_value = ListField(null = True) - - pressure_boundaryField_inlet_type = TextField(null = True) - pressure_boundaryField_inlet_value = FloatField(null = True) - - pressure_boundaryField_outlet_type = TextField(null = True) - pressure_boundaryField_outlet_value = FloatField(null = True) - - velocity_boundaryField_inlet_type = TextField(null = True) - velocity_boundaryField_inlet_value = ListField(null = True) - - velocity_boundaryField_outlet_type = TextField(null = True) - velocity_boundaryField_outlet_value = ListField(null = True) + pressure = JSONField(null = True) + velocity = JSONField(null = True) + transportProperties = JSONField(null = True) class FlowResult(BaseModel): flowresult_id = AutoField() diff --git a/anisotropy/core/utils.py b/anisotropy/core/utils.py index c391d5f..6e37708 100644 --- a/anisotropy/core/utils.py +++ b/anisotropy/core/utils.py @@ -105,24 +105,64 @@ class struct: def deepupdate(target, src): for k, v in src.items(): - #if type(v) == list: - # if not k in target: - # target[k] = copy.deepcopy(v) - # else: - # target[k].extend(v) - if type(v) == dict: + if isinstance(v, dict): if not k in target: target[k] = copy.deepcopy(v) + else: deepupdate(target[k], v) - #elif type(v) == set: - # if not k in target: - # target[k] = v.copy() - # else: - # target[k].update(v.copy()) + else: target[k] = copy.copy(v) +def collapse(source, key = None, level = 0, sep = "_"): + if isinstance(source, dict) and source: + level = level + 1 + res = {} + + for k, v in source.items(): + ret, lvl = collapse(v, k, level) + + for kk,vv in ret.items(): + if level == lvl: + newkey = k + + else: + newkey = "{}{}{}".format(k, sep, kk) + + res.update({ newkey: vv }) + + if level == 1: + return res + + else: + return res, level + + else: + return { key: source }, level + +def expand(source, sep = "_"): + res = {} + + for k, v in source.items(): + if k.find(sep) == -1: + res.update({ k: v }) + + else: + keys = k.split(sep) + cur = res + + for n, kk in enumerate(keys): + if not len(keys) == n + 1: + if not cur.get(kk): + cur.update({ kk: {} }) + + cur = cur[kk] + + else: + cur[kk] = v + return res + #if os.path.exists(env["CONFIG"]): # config = toml.load(env["CONFIG"]) diff --git a/anisotropy/openfoam/application.py b/anisotropy/openfoam/application.py index 4bf723d..2a033f0 100644 --- a/anisotropy/openfoam/application.py +++ b/anisotropy/openfoam/application.py @@ -42,6 +42,6 @@ def application(name: str, *args: str, case: str = None, stderr: bool = True, us logger.error("""{}: {}""".format(name, str(err, "utf-8"))) - return out, p.returncode + return out, err, p.returncode diff --git a/anisotropy/openfoam/meshManipulation.py b/anisotropy/openfoam/meshManipulation.py index a200fba..1b3c173 100644 --- a/anisotropy/openfoam/meshManipulation.py +++ b/anisotropy/openfoam/meshManipulation.py @@ -34,5 +34,5 @@ def checkMesh(case: str = None) -> str: def renumberMesh(case: str = None): - application("renumberMesh", "-parallel", "-overwrite", useMPI = True, case = case, stderr = True) + application("renumberMesh", "-overwrite", useMPI = False, case = case, stderr = True) diff --git a/anisotropy/openfoam/solvers.py b/anisotropy/openfoam/solvers.py index 91b3991..04e3faa 100644 --- a/anisotropy/openfoam/solvers.py +++ b/anisotropy/openfoam/solvers.py @@ -12,10 +12,10 @@ def potentialFoam(case: str = None, useMPI: bool = False): def simpleFoam(case: str = None, useMPI: bool = False): if useMPI: - _, returncode = application("simpleFoam", "-parallel", useMPI = True, case = case, stderr = True) + out, err, returncode = application("simpleFoam", "-parallel", useMPI = True, case = case, stderr = True) else: - _, returncode = application("simpleFoam", case = case, stderr = True) + out, err, returncode = application("simpleFoam", case = case, stderr = True) out = "" @@ -24,5 +24,5 @@ def simpleFoam(case: str = None, useMPI: bool = False): if re.search("solution converged", line): out = "simpleFoam:\n\t{}".format(line.strip()) - return returncode, out + return out, err, returncode diff --git a/anisotropy/salomepl/geometry.py b/anisotropy/salomepl/geometry.py index 319442d..c10dbb5 100644 --- a/anisotropy/salomepl/geometry.py +++ b/anisotropy/salomepl/geometry.py @@ -7,7 +7,7 @@ try: from salome.geom import geomBuilder except ImportError: - logger.warning("Trying to get SALOME geometry modules outside SALOME environment. Modules won't be imported.") + logger.debug("Trying to get SALOME geometry modules outside SALOME environment. Modules won't be imported.") if globals().get("geomBuilder"): geompy = geomBuilder.New() diff --git a/anisotropy/salomepl/mesh.py b/anisotropy/salomepl/mesh.py index 8af8314..7bbe252 100644 --- a/anisotropy/salomepl/mesh.py +++ b/anisotropy/salomepl/mesh.py @@ -7,7 +7,7 @@ try: from salome.smesh import smeshBuilder except ImportError: - logger.warning("Trying to get SALOME mesh modules outside SALOME environment. Modules won't be imported.") + logger.debug("Trying to get SALOME mesh modules outside SALOME environment. Modules won't be imported.") if globals().get("smeshBuilder"): smesh = smeshBuilder.New() diff --git a/anisotropy/samples/bodyCentered.py b/anisotropy/samples/bodyCentered.py index c74698f..e70cc11 100644 --- a/anisotropy/samples/bodyCentered.py +++ b/anisotropy/samples/bodyCentered.py @@ -44,7 +44,7 @@ class BodyCentered(object): ### # Bounding box ## - if direction == [1, 0, 0]: + if self.direction == [1, 0, 0]: sk = geompy.Sketcher3D() sk.addPointsAbsolute(xl, 0, 0) sk.addPointsAbsolute(0, yw, 0) @@ -56,7 +56,7 @@ class BodyCentered(object): vecflow = geompy.GetNormal(inletface) poreCell = geompy.MakePrismVecH(inletface, vecflow, diag) - elif direction == [0, 0, 1]: + elif self.direction == [0, 0, 1]: sk = geompy.Sketcher3D() sk.addPointsAbsolute(0, yw, 0) sk.addPointsAbsolute(xl, 0, 0)