New: cli command 'query'

Remove: unknown trash
Mod: database micro migration
This commit is contained in:
L-Nafaryus 2021-09-06 17:00:15 +05:00
parent 422806777e
commit 193e1991f4
No known key found for this signature in database
GPG Key ID: EF672A5303B2FA96
7 changed files with 213 additions and 32 deletions

View File

@ -78,7 +78,7 @@ faceCentered = true
fuseEdges = true fuseEdges = true
checkChartBoundary = false checkChartBoundary = false
[structures.flowapprox] [structures.flowapproximation]
transportProperties.nu = 1e-6 transportProperties.nu = 1e-6
pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 }
@ -167,7 +167,7 @@ faceCentered = true
fuseEdges = true fuseEdges = true
checkChartBoundary = false checkChartBoundary = false
[structures.flowapprox] [structures.flowapproximation]
transportProperties.nu = 1e-6 transportProperties.nu = 1e-6
pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 }
@ -256,7 +256,7 @@ faceCentered = true
fuseEdges = true fuseEdges = true
checkChartBoundary = false checkChartBoundary = false
[structures.flowapprox] [structures.flowapproximation]
transportProperties.nu = 1e-6 transportProperties.nu = 1e-6
pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 } pressure.boundaryField.inlet = { type = "fixedValue", value = 1e-3 }

View File

@ -4,7 +4,7 @@
import click import click
import ast import ast
import os, shutil import os, sys, shutil
import logging import logging
class LiteralOption(click.Option): class LiteralOption(click.Option):
@ -192,7 +192,7 @@ def compute(stage, nprocs, force, update, params, path):
logger.info(f"Stage: { stage }") logger.info(f"Stage: { stage }")
if stage == "all" or stage == "mesh": if stage == "all" or stage == "mesh":
if not case.params.get("meshresult", {}).get("status") == "Done" or force: if not case.params.get("meshresult", {}).get("meshStatus") == "Done" or force:
(out, err, returncode), elapsed = timer(case.computeMesh)(path) (out, err, returncode), elapsed = timer(case.computeMesh)(path)
if out: logger.info(out) if out: logger.info(out)
@ -201,7 +201,7 @@ def compute(stage, nprocs, force, update, params, path):
case.load(type, direction, theta) case.load(type, direction, theta)
if case.params.get("meshresult"): if case.params.get("meshresult"):
case.params["meshresult"]["calculationTime"] = elapsed case.params["meshresult"]["meshCalculationTime"] = elapsed
case.update() case.update()
if returncode: if returncode:
@ -212,7 +212,7 @@ def compute(stage, nprocs, force, update, params, path):
logger.info("Mesh exists. Skipping ...") logger.info("Mesh exists. Skipping ...")
if stage == "all" or stage == "flow": if stage == "all" or stage == "flow":
if not case.params.get("flowresult", {}).get("status") == "Done" or force: if not case.params.get("flowresult", {}).get("flowStatus") == "Done" or force:
(out, err, returncode), elapsed = timer(case.computeFlow)(path) (out, err, returncode), elapsed = timer(case.computeFlow)(path)
if out: logger.info(out) if out: logger.info(out)
@ -221,7 +221,7 @@ def compute(stage, nprocs, force, update, params, path):
case.load(type, direction, theta) case.load(type, direction, theta)
if case.params.get("flowresult"): if case.params.get("flowresult"):
case.params["flowresult"]["calculationTime"] = elapsed case.params["flowresult"]["flowCalculationTime"] = elapsed
case.update() case.update()
if returncode: if returncode:
@ -281,7 +281,7 @@ def kill(path, pidfile):
SalomeManager().killall() SalomeManager().killall()
@anisotropy.command( @anisotropy.command(
help = "! Not a user command" help = "! Internal command"
) )
@click.argument("root") @click.argument("root")
@click.argument("type") @click.argument("type")
@ -392,9 +392,118 @@ def postprocessing(path, plot):
plt.show() plt.show()
@anisotropy.command()
@click.option(
"-p", "--param", "params",
metavar = "key=value",
multiple = True,
cls = KeyValueOption,
help = "Select by control parameter (type, direction, theta)"
)
@click.option(
"-P", "--path", "path",
default = os.getcwd(),
help = "Specify directory to use (instead of cwd)"
)
@click.option(
"--list", "printlist",
is_flag = True,
help = "Print a list of avaliable fields."
)
@click.option(
"--export",
metavar = "PATH",
help = "Export query result to CSV."
)
@click.argument(
"fields",
required = False
)
def query(params, path, printlist, export, fields):
from anisotropy import env
from anisotropy.core.database import Database, Structure
from pandas import DataFrame
env.update(
LOG = os.path.join(path, "logs"),
BUILD = os.path.join(path, "build"),
CONFIG = os.path.join(path, "anisotropy.toml"),
db_path = path
)
args = dict()
for param in params:
args.update(param)
fields = [ field.strip() for field in fields.split(",") ] if fields else []
###
db = Database(env["db_name"], env["db_path"])
db.setup()
searchargs = []
if args.get("type"):
searchargs.append(Structure.type == args["type"])
if args.get("direction"):
searchargs.append(Structure.direction == str(args["direction"]))
if args.get("theta"):
searchargs.append(Structure.theta == args["theta"])
result = db.search(searchargs)
result.sort(key = lambda src: f"{ src['type'] }{ src['direction'] }{ src['theta'] }")
df = DataFrame(result)
df_keys = [ key for key in df.keys() ]
if printlist:
click.echo("Avaliable fields for query:")
click.echo("\t{}".format("\n\t".join(df_keys)))
return
if not result:
click.echo("Empty result.")
return
if fields:
for field in fields:
if field not in df_keys:
click.echo(f"Unknown field '{ field }'. Try to use '--list' flag to see all avaliable fields.")
return
df = df[fields]
if export:
df.to_csv(export, sep = ";")
else:
click.echo(df.to_string())
### ###
# CLI entry # CLI entry
## ##
if __name__ == "__main__": if __name__ == "__main__":
anisotropy() try:
anisotropy()
except KeyboardInterrupt:
click.echo("Interrupted!")
finally:
from anisotropy.salomepl.utils import SalomeManager
click.echo("Exiting ...")
if os.path.exists("anisotropy.pid"):
os.remove("anisotropy.pid")
SalomeManager().killall()
sys.exit(0)

View File

@ -29,8 +29,8 @@ def tryUntilDone(func):
ret = func(*args, **kwargs) ret = func(*args, **kwargs)
done = True done = True
except OperationalError: except OperationalError as e:
pass logger.error(e)
return ret return ret
@ -110,10 +110,10 @@ class Database(object):
if flowQuery.exists(): if flowQuery.exists():
params["flow"] = flowQuery.dicts().get() params["flow"] = flowQuery.dicts().get()
flowapproxQuery = flowQuery.get().flowapprox flowapproximationQuery = flowQuery.get().flowapproximations
if flowapproxQuery.exists(): if flowapproximationQuery.exists():
params["flowapprox"] = flowapproxQuery.dicts().get() params["flowapproximation"] = flowapproximationQuery.dicts().get()
flowresultsQuery = flowQuery.get().flowresults flowresultsQuery = flowQuery.get().flowresults
@ -173,22 +173,73 @@ class Database(object):
) )
) )
structureID = tryUntilDone(self._updateStructure)(params["structure"], query) structureID = tryUntilDone(self._updateStructure)(params.get("structure", {}), query)
meshID = tryUntilDone(self._updateMesh)(params["mesh"], query, structureID) meshID = tryUntilDone(self._updateMesh)(params.get("mesh", {}), query, structureID)
for submeshParams in params.get("submesh", []): for submeshParams in params.get("submesh", []):
tryUntilDone(self._updateSubMesh)(submeshParams, query, meshID) tryUntilDone(self._updateSubMesh)(submeshParams, query, meshID)
tryUntilDone(self._updateMeshResult)(params.get("meshresult", {}), query, meshID) tryUntilDone(self._updateMeshResult)(params.get("meshresult", {}), query, meshID)
flowID = tryUntilDone(self._updateFlow)(params["flow"], query, structureID) flowID = tryUntilDone(self._updateFlow)(params.get("flow", {}), query, structureID)
tryUntilDone(self._updateFlowApproximation)(params.get("flowapprox", {}), query, flowID) tryUntilDone(self._updateFlowApproximation)(params.get("flowapproximation", {}), query, flowID)
tryUntilDone(self._updateFlowResult)(params.get("flowresult", {}), query, flowID) tryUntilDone(self._updateFlowResult)(params.get("flowresult", {}), query, flowID)
def search(self, args: list):
result = {}
query = (
Structure
.select(Structure, Mesh, SubMesh, MeshResult, Flow, FlowApproximation, FlowResult)
.join(
Mesh,
JOIN.INNER,
on = (Mesh.structure_id == Structure.structure_id)
)
.join(
SubMesh,
JOIN.INNER,
on = (SubMesh.mesh_id == Mesh.mesh_id)
)
.join(
MeshResult,
JOIN.INNER,
on = (MeshResult.mesh_id == Mesh.mesh_id)
)
.join(
Flow,
JOIN.INNER,
on = (Flow.structure_id == Structure.structure_id)
)
.join(
FlowApproximation,
JOIN.INNER,
on = (FlowApproximation.flow_id == Flow.flow_id)
)
.join(
FlowResult,
JOIN.INNER,
on = (FlowResult.flow_id == Flow.flow_id)
)
)
for arg in args:
query = query.where(arg)
with self.__db.atomic():
if not self.isempty():
result = [ entry for entry in query.dicts() ]
else:
logger.error("Missed Structure table")
return result
def _updateStructure(self, src: dict, queryMain) -> int: def _updateStructure(self, src: dict, queryMain) -> int:
raw = deepcopy(src) raw = deepcopy(src)

View File

@ -101,8 +101,7 @@ class Anisotropy(object):
buf = toml.load(config).get("structures") buf = toml.load(config).get("structures")
paramsAll = [] paramsAll = []
# TODO: custom config and merge
for entry in buf: for entry in buf:
# Shortcuts # Shortcuts
_theta = entry["structure"]["theta"] _theta = entry["structure"]["theta"]
@ -133,12 +132,12 @@ class Anisotropy(object):
"mesh": mesh, "mesh": mesh,
"submesh": deepcopy(entry["submesh"]), "submesh": deepcopy(entry["submesh"]),
"flow": deepcopy(entry["flow"]), "flow": deepcopy(entry["flow"]),
"flowapprox": deepcopy(entry["flowapprox"]) "flowapproximation": deepcopy(entry["flowapproximation"])
} }
# For `type = fixedValue` only # For `type = fixedValue` only
_velocity = entryNew["flowapprox"]["velocity"]["boundaryField"]["inlet"]["value"] _velocity = entryNew["flowapproximation"]["velocity"]["boundaryField"]["inlet"]["value"]
entryNew["flowapprox"]["velocity"]["boundaryField"]["inlet"]["value"] = [ entryNew["flowapproximation"]["velocity"]["boundaryField"]["inlet"]["value"] = [
val * _velocity for val in entryNew["structure"]["direction"] val * _velocity for val in entryNew["structure"]["direction"]
] ]
@ -380,7 +379,7 @@ class Anisotropy(object):
foamCase = [ "0", "constant", "system" ] foamCase = [ "0", "constant", "system" ]
flow = self.params["flow"] flow = self.params["flow"]
flowapprox = self.params["flowapprox"] flowapproximation = self.params["flowapproximation"]
# ISSUE: ideasUnvToFoam cannot import mesh with '-case' flag so 'os.chdir' for that # ISSUE: ideasUnvToFoam cannot import mesh with '-case' flag so 'os.chdir' for that
casePath = self.getCasePath() casePath = self.getCasePath()
@ -447,8 +446,8 @@ class Anisotropy(object):
openfoam.renumberMesh() openfoam.renumberMesh()
pressureBF = flowapprox["pressure"]["boundaryField"] pressureBF = flowapproximation["pressure"]["boundaryField"]
velocityBF = flowapprox["velocity"]["boundaryField"] velocityBF = flowapproximation["velocity"]["boundaryField"]
openfoam.foamDictionary( openfoam.foamDictionary(
"0/p", "0/p",

View File

@ -138,8 +138,9 @@ class MeshResult(BaseModel):
prisms = IntegerField(null = True) prisms = IntegerField(null = True)
pyramids = IntegerField(null = True) pyramids = IntegerField(null = True)
status = TextField(null = True, default = "Idle") meshStatus = TextField(null = True, default = "Idle")
calculationTime = TimeField(null = True) meshCalculationTime = TimeField(null = True)
class Flow(BaseModel): class Flow(BaseModel):
flow_id = AutoField() flow_id = AutoField()
@ -153,17 +154,20 @@ class Flow(BaseModel):
class FlowApproximation(BaseModel): class FlowApproximation(BaseModel):
flow_approximation_id = AutoField() flow_approximation_id = AutoField()
flow_id = ForeignKeyField(Flow, backref = "flowapprox") flow_id = ForeignKeyField(Flow, backref = "flowapproximations")
pressure = JSONField(null = True) pressure = JSONField(null = True)
velocity = JSONField(null = True) velocity = JSONField(null = True)
transportProperties = JSONField(null = True) transportProperties = JSONField(null = True)
class FlowResult(BaseModel): class FlowResult(BaseModel):
flowresult_id = AutoField() flowresult_id = AutoField()
flow_id = ForeignKeyField(Flow, backref = "flowresults") flow_id = ForeignKeyField(Flow, backref = "flowresults")
flowRate = FloatField(null = True) flowRate = FloatField(null = True)
porosity = FloatField(null = True)
permeability = FloatField(null = True)
status = TextField(null = True, default = "Idle") flowStatus = TextField(null = True, default = "Idle")
calculationTime = TimeField(null = True) flowCalculationTime = TimeField(null = True)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

View File

@ -5,3 +5,21 @@ Current anisotropy database hierarchy:
.. figure:: ../static/er-diagram.png .. figure:: ../static/er-diagram.png
:align: center :align: center
peewee migration
----------------
Example of Sqlite database migration and etc:
.. code-block:: python
from playhouse.migrate import SqliteMigrator, migrate
from peewee import SqliteDatabase, FloatField
db = SqliteDatabase("anisotropy.db")
migrator = SqliteDatabase(db)
migrate(
migrator.rename_column("MeshResult", "status", "meshStatus"),
migrator.add_column("FlowResult", "porosity", FloatField(null = True))
)