diff --git a/anisotropy/config/default.toml b/anisotropy/config/default.toml index 3d8f4eb..0fe2804 100644 --- a/anisotropy/config/default.toml +++ b/anisotropy/config/default.toml @@ -82,7 +82,7 @@ faceCentered = true approx.pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } approx.pressure.boundaryField.outlet = { type = "fixedValue", value = 0 } - # multiplication velocity value with direction vector + # multiplication velocity value with flow direction vector approx.velocity.boundaryField.inlet = { type = "fixedValue", value = 6e-5 } approx.velocity.boundaryField.outlet = { type = "zeroGradient", value = "None" } diff --git a/anisotropy/core/cli.py b/anisotropy/core/cli.py index b4a4898..89a6992 100644 --- a/anisotropy/core/cli.py +++ b/anisotropy/core/cli.py @@ -1,5 +1,43 @@ import click +import ast +class LiteralOption(click.Option): + def type_cast_value(self, ctx, value): + try: + return ast.literal_eval(value) + + except: + raise click.BadParameter(f"{ value } (Type error)") + +class KeyValueOption(click.Option): + def _convert(self, ctx, value): + if value.find("=") == -1: + raise click.BadParameter(f"{ value } (Missed '=')") + + params = value.split("=") + + if not len(params) == 2: + raise click.BadParameter(f"{ value } (Syntax error)") + + key, val = params[0].strip(), params[1].strip() + + if val[0].isalpha(): + val = f"'{ val }'" + + try: + return { key: ast.literal_eval(val) } + + except: + raise click.BadParameter(f"{ value } (Type error)") + + def type_cast_value(self, ctx, value): + if isinstance(value, list): + return [ self._convert(ctx, val) for val in value ] + + else: + return self._convert(ctx, value) + + #pass_anisotropy = click.make_pass_decorator(Anisotropy) def version(): msg = "Missed package anisotropy" @@ -20,10 +58,16 @@ def anisotropy(): @anisotropy.command() @click.option("-s", "--stage", "stage", type = click.Choice(["all", "mesh", "flow"]), default = "all") -@click.option("-p", "--param", "params", metavar = "key=value", multiple = True) +@click.option("-p", "--param", "params", metavar = "key=value", multiple = True, cls = KeyValueOption) def compute(stage, params): from anisotropy.core.main import Anisotropy + args = dict() + + for param in params: + args.update(param) + + model = Anisotropy() model.db.setup() @@ -33,14 +77,15 @@ def compute(stage, params): for entry in paramsAll: model.db.update(entry) - (type, direction, theta) = ("simple", [1.0, 0.0, 0.0], 0.01) + type, direction, theta = args["type"], args["direction"], args["theta"] model.load(type, direction, theta) # TODO: merge cli params with db params here model.evalParams() model.update() - # TODO: do smth with output + # TODO: single compute / queue + if stage == "all" or stage == "mesh": ((out, err, code), elapsed) = model.computeMesh(type, direction, theta) @@ -51,6 +96,10 @@ def compute(stage, params): 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() + @anisotropy.command() @click.argument("root") @@ -58,6 +107,7 @@ def compute(stage, params): @click.argument("direction") @click.argument("theta") def computemesh(root, type, direction, theta): + # ISSUE: can't hide command from help, hidden = True doesn't work # [Salome Environment] ### diff --git a/anisotropy/core/database.py b/anisotropy/core/database.py index dc2d641..6a0b717 100644 --- a/anisotropy/core/database.py +++ b/anisotropy/core/database.py @@ -8,7 +8,7 @@ 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 +from anisotropy.core.models import db, JOIN, Structure, Mesh, SubMesh, MeshResult, Flow, FlowResult logger = logging.getLogger(env["logger_name"]) setupLogger(logger, logging.INFO, env["LOG"]) @@ -32,7 +32,9 @@ class Database(object): Structure, Mesh, SubMesh, - MeshResult + MeshResult, + Flow, + FlowResult ]) @@ -77,6 +79,20 @@ class Database(object): return params + def loadGeneral(self) -> list: + query = ( + Structure + .select() + .order_by(Structure.type, Structure.direction, Structure.theta) + ) + response = [] + + for entry in query.dicts(): + response.append({ "structure": entry }) + + return response + + def update(self, params: dict): if not params: logger.error("Trying to update db from empty parameters") @@ -106,6 +122,7 @@ class Database(object): self._updateMeshResult(params.get("meshresult", {}), query, meshID) + # TODO: update method flow flow / flowresult def _updateStructure(self, src: dict, queryMain) -> int: raw = deepcopy(src) diff --git a/anisotropy/core/main.py b/anisotropy/core/main.py index 0894e19..424949b 100644 --- a/anisotropy/core/main.py +++ b/anisotropy/core/main.py @@ -119,8 +119,22 @@ class Anisotropy(object): filletsEnabled = entry["structure"]["filletsEnabled"] ), "mesh": mesh, - "submesh": deepcopy(entry["submesh"]) + "submesh": deepcopy(entry["submesh"]), + "flow": deepcopy(entry["flow"]) } + + # TODO: optimize it + # For type = fixedValue only + _velocity = entryNew["flow"]["approx"]["velocity"]["boundaryField"]["inlet"]["value"] + entryNew["flow"]["approx"]["velocity"]["boundaryField"]["inlet"]["value"] = [ + val * _velocity for val in entryNew["structure"]["direction"] + ] + + _velocity = entryNew["flow"]["velocity"]["boundaryField"]["inlet"]["value"] + entryNew["flow"]["velocity"]["boundaryField"]["inlet"]["value"] = [ + val * _velocity for val in entryNew["structure"]["direction"] + ] + paramsAll.append(entryNew) @@ -378,11 +392,13 @@ class Anisotropy(object): if out: logger.info(out) - # TODO: replace all task variables + openfoam.transformPoints(flow["scale"]) ### # Decomposition and initial approximation + # + # NOTE: Temporarily without decomposition ## openfoam.foamDictionary( "constant/transportProperties", @@ -390,7 +406,7 @@ class Anisotropy(object): str(flow["constant"]["nu"]) ) - openfoam.decomposePar() + #openfoam.decomposePar() openfoam.renumberMesh() @@ -412,11 +428,11 @@ class Anisotropy(object): "boundaryField.outlet.value", openfoam.uniform(pressureBF["outlet"]["value"]) ) - # TODO: flow variable + openfoam.foamDictionary( "0/U", "boundaryField.inlet.value", - openfoam.uniform(velocityBF.inlet.value[direction]) + openfoam.uniform(velocityBF["inlet"]["value"]) ) openfoam.potentialFoam() @@ -424,20 +440,31 @@ class Anisotropy(object): ### # Main computation ## - pressureBF = task.flow.main.pressure.boundaryField - velocityBF = task.flow.main.velocity.boundaryField + pressureBF = flow["pressure"]["boundaryField"] + velocityBF = flow["velocity"]["boundaryField"] - for n in range(os.cpu_count()): - openfoam.foamDictionary( - f"processor{n}/0/U", - "boundaryField.inlet.type", - velocityBF.inlet.type - ) - openfoam.foamDictionary( - f"processor{n}/0/U", - "boundaryField.inlet.value", - openfoam.uniform(velocityBF.inlet.value[direction]) - ) + openfoam.foamDictionary( + "0/U", + "boundaryField.inlet.type", + velocityBF["inlet"]["type"] + ) + openfoam.foamDictionary( + "0/U", + "boundaryField.inlet.value", + velocityBF["inlet"]["value"] + ) + + #for n in range(os.cpu_count()): + # openfoam.foamDictionary( + # f"processor{n}/0/U", + # "boundaryField.inlet.type", + # velocityBF.inlet.type + # ) + # openfoam.foamDictionary( + # f"processor{n}/0/U", + # "boundaryField.inlet.value", + # openfoam.uniform(velocityBF.inlet.value[direction]) + # ) returncode, out = openfoam.simpleFoam() if out: @@ -446,25 +473,21 @@ class Anisotropy(object): ### # Check results ## - elapsed = time.monotonic() - stime - logger.info("computeFlow: elapsed time: {}".format(timedelta(seconds = elapsed))) if returncode == 0: - task.status.flow = True - task.statistics.flowTime = elapsed - postProcessing = "postProcessing/flowRatePatch(name=outlet)/0/surfaceFieldValue.dat" with open(postProcessing, "r") as io: lastLine = io.readlines()[-1] flowRate = float(lastLine.replace(" ", "").replace("\n", "").split("\t")[1]) - task.statistics.flowRate = flowRate + self.params["flowresult"] = dict( + flowRate = flowRate + ) - with open(os.path.join(case, "task.toml"), "w") as io: - toml.dump(dict(task), io) + self.update() - os.chdir(ROOT) + os.chdir(self.env["ROOT"]) return returncode diff --git a/anisotropy/core/models.py b/anisotropy/core/models.py index b5a6d56..cb2a602 100644 --- a/anisotropy/core/models.py +++ b/anisotropy/core/models.py @@ -132,8 +132,37 @@ class MeshResult(BaseModel): calculationTime = TimeField(null = True) class Flow(BaseModel): - # TODO: flow model - pass + # TODO: find better way + flow_id = AutoField() + structure_id = ForeignKeyField(Structure, backref = "flows") -class FlowResults(BaseModel): - pass + approx_pressure_boundaryField_inlet_type = TextField(null = True) + approx_pressure_boundaryField_inlet_value = FloatField(null = True) + + approx_pressure_boundaryField_outlet_type = TextField(null = True) + approx_pressure_boundaryField_outlet_value = FloatField(null = True) + + 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) + +class FlowResult(BaseModel): + flowresult_id = AutoField() + flow_id = ForeignKeyField(Flow, backref = "flowresults") + + flowRate = FloatField(null = True) + calculationTime = TimeField(null = True) diff --git a/anisotropy/core/utils.py b/anisotropy/core/utils.py index b9ef4aa..c391d5f 100644 --- a/anisotropy/core/utils.py +++ b/anisotropy/core/utils.py @@ -171,7 +171,7 @@ def queue(cmd, qin, qout, *args): break # Execute command - res = cmd(*var, *args) + res = cmd(var, *args) # Put results to the queue qout.put((pos, res)) @@ -189,10 +189,6 @@ def parallel(np, var, cmd): qin = Queue(1) qout = Queue() - logging.info("cpu count: {}".format(np)) - logging.info("var: {}".format(var)) - logging.info("cmd: {}".format(cmd)) - # Create processes for n in range(nprocs): pargs = [cmd, qin, qout] diff --git a/anisotropy/openfoam/solvers.py b/anisotropy/openfoam/solvers.py index 9a1f2d3..91b3991 100644 --- a/anisotropy/openfoam/solvers.py +++ b/anisotropy/openfoam/solvers.py @@ -2,12 +2,21 @@ from .application import application import re -def potentialFoam(case: str = None): - application("potentialFoam", "-parallel", useMPI = True, case = case, stderr = True) +def potentialFoam(case: str = None, useMPI: bool = False): + if useMPI: + application("potentialFoam", "-parallel", useMPI = True, case = case, stderr = True) + + else: + application("potentialFoam", case = case, stderr = True) -def simpleFoam(case: str = None): - _, returncode = application("simpleFoam", "-parallel", useMPI = True, case = case, stderr = True) +def simpleFoam(case: str = None, useMPI: bool = False): + if useMPI: + _, returncode = application("simpleFoam", "-parallel", useMPI = True, case = case, stderr = True) + + else: + _, returncode = application("simpleFoam", case = case, stderr = True) + out = "" with open("simpleFoam.log", "r") as io: