Mod: working mesh

This commit is contained in:
L-Nafaryus 2021-08-11 23:17:43 +05:00
parent 4efb13954c
commit 6abbce9eb7
No known key found for this signature in database
GPG Key ID: C76D8DCD2727DBB7
9 changed files with 396 additions and 674 deletions

View File

@ -10,4 +10,24 @@ __version__ = "1.1.0"
__author__ = __maintainer = "George Kusayko" __author__ = __maintainer = "George Kusayko"
__email__ = "gkusayko@gmail.com" __email__ = "gkusayko@gmail.com"
#from anisotropy.core.main import main ###
# Environment
##
import os
env = dict(
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
)
env.update(
BUILD = os.path.join(env["ROOT"], "build"),
LOG = os.path.join(env["ROOT"], "logs"),
CONFIG = os.path.join(env["ROOT"], "anisotropy/config/default.toml")
)
env.update(
logger_name = "anisotropy",
db_path = env["BUILD"],
salome_port = 2810,
openfoam_template = os.path.join(env["ROOT"], "anisotropy/openfoam/template")
)
del os

View File

@ -25,44 +25,51 @@ def compute(stage, params):
from anisotropy.core.main import Anisotropy from anisotropy.core.main import Anisotropy
model = Anisotropy() model = Anisotropy()
model.setupDB() model.db.setup()
if model.isEmptyDB(): if model.db.isempty():
paramsAll = model.loadFromScratch() paramsAll = model.loadFromScratch()
for entry in paramsAll: for entry in paramsAll:
model.updateDB(entry) model.db.update(entry)
model.loadDB(type, direction, theta) (type, direction, theta) = ("simple", [1.0, 0.0, 0.0], 0.01)
model.load(type, direction, theta)
# TODO: merge cli params with db params here # TODO: merge cli params with db params here
model.evalParams() model.evalParams()
model.updateDB() model.update()
# TODO: do smth with output # TODO: do smth with output
if stage == "all" or stage == "mesh": if stage == "all" or stage == "mesh":
((out, err, code), elapsed) = model.computeMesh(type, direction, theta) ((out, err, code), elapsed) = model.computeMesh(type, direction, theta)
model.load(type, direction, theta)
model.params["meshresult"]["calculationTime"] = elapsed
model.update()
if stage == "all" or stage == "flow": if stage == "all" or stage == "flow":
((out, err, code), elapsed) = model.computeFlow(type, direction, theta) ((out, err, code), elapsed) = model.computeFlow(type, direction, theta)
@anisotropy.command() @anisotropy.command()
@click.argument("root") @click.argument("root")
@click.argument("name") @click.argument("type")
@click.argument("direction") @click.argument("direction")
@click.argument("theta", type = click.FLOAT) @click.argument("theta")
def _compute_mesh(root, name, direction, theta): def computemesh(root, type, direction, theta):
# [Salome Environment] # [Salome Environment]
### ###
# Args # Args
## ##
direction = list(map(lambda num: float(num), direction[1:-1].split(","))) direction = [ float(num) for num in direction[1:-1].split(" ") if num ]
theta = float(theta)
### ###
# Modules # Modules
## ##
import salome import os, sys
sys.path.extend([ sys.path.extend([
root, root,
@ -73,8 +80,7 @@ def _compute_mesh(root, name, direction, theta):
### ###
model = Anisotropy() model = Anisotropy()
model.setupDB() model.load(type, direction, theta)
model.loadDB(type, direction, theta)
model.genmesh() model.genmesh()
@ -82,4 +88,5 @@ def _compute_mesh(root, name, direction, theta):
### ###
# CLI entry # CLI entry
## ##
#anisotropy() if __name__ == "__main__":
anisotropy()

202
anisotropy/core/database.py Normal file
View File

@ -0,0 +1,202 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
import os
import logging
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
logger = logging.getLogger(env["logger_name"])
setupLogger(logger, logging.INFO, env["LOG"])
class Database(object):
def __init__(self, name: str, filepath: str):
self.name = name
self.filepath = filepath
self.__db = db
def setup(self):
os.makedirs(self.filepath, exist_ok = True)
fullpath = os.path.join(self.filepath, "{}.db".format(self.name))
self.__db.init(fullpath)
if not os.path.exists(fullpath):
self.__db.create_tables([
Structure,
Mesh,
SubMesh,
MeshResult
])
def isempty(self) -> bool:
query = Structure.select()
return not query.exists()
def load(self, structure_type: str, structure_direction: list, structure_theta: float) -> dict:
structureQuery = (
Structure
.select()
.where(
Structure.type == structure_type,
Structure.direction == str(structure_direction),
Structure.theta == structure_theta
)
)
params = {}
with self.__db.atomic():
if structureQuery.exists():
params["structure"] = structureQuery.dicts().get()
meshQuery = structureQuery.get().meshes
if meshQuery.exists():
params["mesh"] = meshQuery.dicts().get()
submeshQuery = meshQuery.get().submeshes
if submeshQuery.exists():
params["submesh"] = [ entry for entry in submeshQuery.dicts() ]
meshresultQuery = meshQuery.get().meshresults
if meshresultQuery.exists():
params["meshresult"] = meshresultQuery.dicts().get()
return params
def update(self, params: dict):
if not params:
logger.error("Trying to update db from empty parameters")
return
query = (
Structure
.select(Structure, Mesh)
.join(
Mesh,
JOIN.INNER,
on = (Mesh.structure_id == Structure.structure_id)
)
.where(
Structure.type == params["structure"]["type"],
Structure.direction == str(params["structure"]["direction"]),
Structure.theta == params["structure"]["theta"]
)
)
structureID = self._updateStructure(params["structure"], query)
meshID = self._updateMesh(params["mesh"], query, structureID)
for submeshParams in params.get("submesh", []):
self._updateSubMesh(submeshParams, query, meshID)
self._updateMeshResult(params.get("meshresult", {}), query, meshID)
def _updateStructure(self, src: dict, queryMain) -> int:
raw = deepcopy(src)
with self.__db.atomic():
if not queryMain.exists():
tabID = Structure.create(**raw)
else:
req = queryMain.dicts().get()
tabID = req["structure_id"]
query = (
Structure.update(**raw)
.where(
Structure.type == req["type"],
Structure.direction == str(req["direction"]),
Structure.theta == req["theta"]
)
)
query.execute()
return tabID
def _updateMesh(self, src: dict, queryMain, structureID) -> int:
raw = deepcopy(src)
with self.__db.atomic():
if not queryMain.exists():
tabID = Mesh.create(
structure_id = structureID,
**raw
)
else:
req = queryMain.dicts().get()
tabID = req["mesh_id"]
query = (
Mesh.update(**raw)
.where(
Mesh.structure_id == structureID
)
)
query.execute()
return tabID
def _updateSubMesh(self, src: dict, queryMain, meshID):
if not src:
return
raw = deepcopy(src)
with self.__db.atomic():
if not SubMesh.select().where(SubMesh.mesh_id == meshID).exists():
tabID = SubMesh.create(
mesh_id = meshID,
**raw
)
logger.debug(f"[ DB ] Created SubMesh entry { tabID }")
else:
query = (
SubMesh.update(**raw)
.where(
SubMesh.mesh_id == meshID,
SubMesh.name == src["name"]
)
)
query.execute()
def _updateMeshResult(self, src: dict, queryMain, meshID):
if not src:
return
raw = deepcopy(src)
with self.__db.atomic():
if not MeshResult.select().where(MeshResult.mesh_id == meshID).exists():
tabID = MeshResult.create(
mesh_id = meshID,
**raw
)
logger.debug(f"[ DB ] Created MeshResult entry { tabID }")
else:
query = (
MeshResult.update(**raw)
.where(
MeshResult.mesh_id == meshID
)
)
query.execute()

View File

@ -1,65 +1,35 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
import os, sys import os, sys
import time import time
from datetime import timedelta, datetime from datetime import timedelta, datetime
import shutil import shutil
import logging import logging
from copy import deepcopy
from math import sqrt
import toml import toml
from copy import deepcopy
from anisotropy.core.models import db, Structure, Mesh, SubMesh, MeshResult from anisotropy import (
from anisotropy.core.utils import struct, deepupdate __version__, env,
openfoam
###
# Environment variables and config
##
env = { "ROOT": os.path.abspath(".") }
env.update(
BUILD = os.path.join(env["ROOT"], "build"),
LOG = os.path.join(env["ROOT"], "logs"),
DEFAULT_CONFIG = os.path.join(env["ROOT"], "anisotropy/config/default.toml"),
CONFIG = os.path.join(env["ROOT"], "conf/config.toml")
) )
env["db_path"] = env["BUILD"] from anisotropy.core.utils import setupLogger, timer
env["salome_port"] = 2810 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
#if os.path.exists(env["CONFIG"]): logger = logging.getLogger(env["logger_name"])
# config = toml.load(env["CONFIG"]) setupLogger(logger, logging.INFO, env["LOG"])
# 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)
###
# Logger
##
from anisotropy.core.utils import setupLogger
logger_env = env.get("logger", {})
logger = logging.getLogger(logger_env.get("name", "anisotropy"))
setupLogger(logger, logging.INFO)
peeweeLogger = logging.getLogger("peewee") peeweeLogger = logging.getLogger("peewee")
peeweeLogger.setLevel(logging.INFO) peeweeLogger.setLevel(logging.INFO)
from anisotropy.core.utils import timer
from anisotropy import __version__
from anisotropy import salomepl
from anisotropy import openfoam
from anisotropy.samples import Simple, FaceCentered, BodyCentered
from math import sqrt
from peewee import JOIN
class Anisotropy(object): class Anisotropy(object):
"""Ultimate class that organize whole working process""" """Ultimate class that organize whole working process"""
@ -68,10 +38,19 @@ class Anisotropy(object):
"""Constructor method""" """Constructor method"""
self.env = env self.env = env
self.db = None self.db = Database("anisotropy", env["db_path"])
self.params = [] self.params = []
def load(self, structure_type: str, structure_direction: list, structure_theta: float):
self.db.setup()
self.params = self.db.load(structure_type, structure_direction, structure_theta)
def update(self, params: dict = None):
self.db.setup()
self.db.update(self.params if not params else params)
@staticmethod @staticmethod
def version(): def version():
"""Returns versions of all used main programs """Returns versions of all used main programs
@ -103,11 +82,11 @@ class Anisotropy(object):
:rtype: list :rtype: list
""" """
if not os.path.exists(self.env["DEFAULT_CONFIG"]): if not os.path.exists(self.env["CONFIG"]):
logger.error("Missed default configuration file") logger.error("Missed default configuration file")
return return
buf = toml.load(self.env["DEFAULT_CONFIG"]).get("structures") buf = toml.load(self.env["CONFIG"]).get("structures")
paramsAll = [] paramsAll = []
# TODO: custom config and merge # TODO: custom config and merge
@ -224,237 +203,22 @@ class Anisotropy(object):
) )
def getParams(self, structure: str, direction: list, theta: float):
for entry in self.params:
if entry["name"] == structure and \
entry["geometry"]["direction"] == direction and \
entry["geometry"]["theta"] == theta:
return entry
def setupDB(self):
os.makedirs(self.env["db_path"], exist_ok = True)
dbname = os.path.join(self.env["db_path"], "anisotropy.db")
self.db = db
self.db.init(dbname)
if not os.path.exists(dbname):
self.db.create_tables([
Structure,
Mesh,
SubMesh,
MeshResult
])
def _updateStructure(self, src: dict, queryMain) -> int:
raw = deepcopy(src)
with self.db.atomic():
if not queryMain.exists():
tabID = Structure.create(**raw)
else:
req = queryMain.dicts().get()
tabID = req["structure_id"]
query = (
Structure.update(**raw)
.where(
Structure.type == req["type"],
Structure.direction == str(req["direction"]),
Structure.theta == req["theta"]
)
)
query.execute()
return tabID
def _updateMesh(self, src: dict, queryMain, structureID) -> int:
raw = deepcopy(src)
with self.db.atomic():
if not queryMain.exists():
tabID = Mesh.create(
structure_id = structureID,
**raw
)
else:
req = queryMain.dicts().get()
tabID = req["mesh_id"]
query = (
Mesh.update(**raw)
.where(
Mesh.structure_id == structureID #req["structure_id"]
)
)
query.execute()
return tabID
def _updateSubMesh(self, src: dict, queryMain, meshID) -> None:
if not src:
return
raw = deepcopy(src)
with self.db.atomic():
if not SubMesh.select().where(SubMesh.mesh_id == meshID).exists():
tabID = SubMesh.create(
mesh_id = meshID,
**raw
)
logger.debug(f"[ DB ] Created SubMesh entry { tabID }")
else:
#req = queryMain.dicts().get()
#tabID = req["mesh_id"]
query = (
SubMesh.update(**raw)
.where(
SubMesh.mesh_id == meshID, #req["mesh_id"],
SubMesh.name == src["name"]
)
)
query.execute()
def _updateMeshResult(self, src: dict, queryMain, meshID) -> None:
if not src:
return
raw = deepcopy(src)
with self.db.atomic():
if not MeshResult.select().where(MeshResult.mesh_id == meshID).exists():
tabID = MeshResult.create(
mesh_id = meshID,
**raw
)
logger.debug(f"[ DB ] Created MeshResult entry { tabID }")
else:
#req = queryMain.dicts().get()
#tabID = req["mesh_id"]
query = (
MeshResult.update(**raw)
.where(
MeshResult.mesh_id == meshID #req["mesh_id"]
)
)
query.execute()
@timer
def updateDB(self, src: dict = None):
if src:
params = src
elif self.params:
params = self.params
else:
logger.error("Trying to update db from empty parameters")
return
query = (
Structure
.select(Structure, Mesh)
.join(
Mesh,
JOIN.INNER,
on = (Mesh.structure_id == Structure.structure_id)
)
.where(
Structure.type == params["structure"]["type"],
Structure.direction == str(params["structure"]["direction"]),
Structure.theta == params["structure"]["theta"]
)
)
structureID = self._updateStructure(params["structure"], query)
meshID = self._updateMesh(params["mesh"], query, structureID)
for submeshParams in params.get("submesh", []):
self._updateSubMesh(submeshParams, query, meshID)
self._updateMeshResult(params.get("meshresults", {}), query, meshID)
def loadDB(self, structure_type: str, structure_direction: list, structure_theta: float):
structureQuery = (
Structure
.select()
.where(
Structure.type == structure_type,
Structure.direction == str(structure_direction),
Structure.theta == structure_theta
)
)
self.params = {}
with self.db.atomic():
if structureQuery.exists():
self.params["structure"] = structureQuery.dicts().get()
meshQuery = structureQuery.get().meshes
if meshQuery.exists():
self.params["mesh"] = meshQuery.dicts().get()
submeshQuery = meshQuery.get().submeshes
if submeshQuery.exists():
self.params["submesh"] = [ entry for entry in submeshQuery.dicts() ]
meshresultQuery = meshQuery.get().meshresults
if meshresultQuery.exists():
self.params["meshresult"] = meshresultQuery.dicts().get()
# TODO: loadDB (one model), loadsDB (all models)
@timer
def updateFromDB(self):
squery = Structure.select().order_by(Structure.structure_id)
mquery = Mesh.select().order_by(Mesh.structure_id)
smquery = SubMesh.select()
mrquery = MeshResult.select().order_dy(MeshResult.mesh_id)
self.params = []
for s, m, mr in zip(squery.dicts(), mquery.dicts(), mrquery.dicts()):
name = s.pop("name")
path = s.pop("path")
self.params.append(dict(
name = name,
path = path,
geometry = s,
mesh = m,
submesh = [ d for d in smquery.dicts() if d["mesh_id"] == m["mesh_id"] ],
meshresults = mr
))
self.params = sorted(self.params, key = lambda entry: f"{ entry['name'] } { entry['geometry']['direction'] } { entry['geometry']['theta'] }")
@timer @timer
def computeMesh(self, type, direction, theta): def computeMesh(self, type, direction, theta):
scriptpath = os.path.join(self.env["ROOT"], "anisotropy/__main__.py") scriptpath = os.path.join(self.env["ROOT"], "anisotropy/core/cli.py")
port = 2900 port = 2900
return salomepl.utils.runSalome(port, scriptpath, self.env["ROOT"], "_compute_mesh", type, direction, theta) return salomepl.utils.runSalome(
self.env["salome_port"],
scriptpath,
self.env["ROOT"],
"computemesh", type, direction, theta,
logpath = os.path.join(self.env["LOG"], "salome.log")
)
def genmesh(self): def genmesh(self):
# ISSUE: double logger output
import salome import salome
p = self.params p = self.params
@ -530,24 +294,24 @@ class Anisotropy(object):
mesh.Triangle(subshape, **submesh) mesh.Triangle(subshape, **submesh)
model.updateDB() self.update()
returncode, errors = mesh.compute() returncode, errors = mesh.compute()
if not returncode: if not returncode:
mesh.removePyramids() mesh.removePyramids()
mesh.assignGroups() mesh.assignGroups()
casePath = model.getCasePath() casePath = self.getCasePath()
os.makedirs(casePath, exist_ok = True) os.makedirs(casePath, exist_ok = True)
mesh.exportUNV(os.path.join(casePath, "mesh.unv")) mesh.exportUNV(os.path.join(casePath, "mesh.unv"))
meshStats = mesh.stats() meshStats = mesh.stats()
p["meshresults"] = dict( p["meshresult"] = dict(
surfaceArea = surfaceArea, surfaceArea = surfaceArea,
volume = volume, volume = volume,
**meshStats **meshStats
) )
model.updateDB() self.update()
logger.info("mesh stats:\n{}".format( logger.info("mesh stats:\n{}".format(
"\n".join(map(lambda v: f"{ v[0] }:\t{ v[1] }", meshStats.items())) "\n".join(map(lambda v: f"{ v[0] }:\t{ v[1] }", meshStats.items()))
@ -556,11 +320,11 @@ class Anisotropy(object):
else: else:
logger.error(errors) logger.error(errors)
p["meshresults"] = dict( p["meshresult"] = dict(
surfaceArea = surfaceArea, surfaceArea = surfaceArea,
volume = volume volume = volume
) )
model.updateDB() self.update()
salome.salome_close() salome.salome_close()
@ -571,13 +335,15 @@ class Anisotropy(object):
## ##
foamCase = [ "0", "constant", "system" ] foamCase = [ "0", "constant", "system" ]
flow = self.params["flow"]
# 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
os.chdir(self.getCasePath()) os.chdir(self.getCasePath())
openfoam.foamClean() openfoam.foamClean()
for d in foamCase: for d in foamCase:
shutil.copytree( shutil.copytree(
os.path.join(ROOT, "anisotropy/openfoam/template", d), os.path.join(self.env["openfoam_template"], d),
os.path.join(case, d) os.path.join(case, d)
) )
@ -613,7 +379,7 @@ class Anisotropy(object):
if out: if out:
logger.info(out) logger.info(out)
# TODO: replace all task variables # TODO: replace all task variables
openfoam.transformPoints(task.flow.scale) openfoam.transformPoints(flow["scale"])
### ###
# Decomposition and initial approximation # Decomposition and initial approximation
@ -621,15 +387,15 @@ class Anisotropy(object):
openfoam.foamDictionary( openfoam.foamDictionary(
"constant/transportProperties", "constant/transportProperties",
"nu", "nu",
str(task.flow.constant.nu) str(flow["constant"]["nu"])
) )
openfoam.decomposePar() openfoam.decomposePar()
openfoam.renumberMesh() openfoam.renumberMesh()
pressureBF = task.flow.approx.pressure.boundaryField pressureBF = flow["approx"]["pressure"]["boundaryField"]
velocityBF = task.flow.approx.velocity.boundaryField velocityBF = flow["approx"]["velocity"]["boundaryField"]
direction = { direction = {
"[1, 0, 0]": 0, "[1, 0, 0]": 0,
"[0, 0, 1]": 1, "[0, 0, 1]": 1,
@ -639,14 +405,14 @@ class Anisotropy(object):
openfoam.foamDictionary( openfoam.foamDictionary(
"0/p", "0/p",
"boundaryField.inlet.value", "boundaryField.inlet.value",
openfoam.uniform(pressureBF.inlet.value) openfoam.uniform(pressureBF["inlet"]["value"])
) )
openfoam.foamDictionary( openfoam.foamDictionary(
"0/p", "0/p",
"boundaryField.outlet.value", "boundaryField.outlet.value",
openfoam.uniform(pressureBF.outlet.value) openfoam.uniform(pressureBF["outlet"]["value"])
) )
# TODO: flow variable
openfoam.foamDictionary( openfoam.foamDictionary(
"0/U", "0/U",
"boundaryField.inlet.value", "boundaryField.inlet.value",
@ -710,325 +476,3 @@ class Anisotropy(object):
pass pass
###################################################################################
###
# Main
##
def main():
if checkEnv():
return
logger.info(f"args:\n\tconfig:\t{ configPath }\n\tmode:\t{ mode }")
queue = createQueue()
for n, case in enumerate(queue):
date = datetime.now()
logger.info("-" * 80)
logger.info(f"""main:
task:\t{ n + 1 } / { len(queue) }
cpu count:\t{ os.cpu_count() }
case:\t{ case }
date:\t{ date.date() }
time:\t{ date.time() }""")
###
# Compute mesh
##
taskPath = os.path.join(case, "task.toml")
task = struct(toml.load(taskPath))
if not task.status.mesh or mode == "all":
computeMesh(case)
else:
logger.info("computeMesh: mesh already computed")
task = struct(toml.load(taskPath))
if not task.status.mesh:
logger.critical("mesh not computed: skip flow computation")
continue
###
# Compute flow
##
if not task.status.flow or mode == "all":
computeFlow(case)
else:
logger.info("computeFlow: flow already computed")
def createQueue():
queue = []
###
# Special values
##
parameters_theta = {}
mesh_thickness = {}
for structure in config.base.__dict__.keys():
theta = getattr(config, structure).geometry.theta
parameters_theta[structure] = [ n * theta[2] for n in range(int(theta[0] / theta[2]), int(theta[1] / theta[2]) + 1) ]
thickness = getattr(config, structure).mesh.thickness
count = len(parameters_theta[structure])
mesh_thickness[structure] = [ thickness[0] + n * (thickness[1] - thickness[0]) / (count - 1) for n in range(0, count) ]
###
# structure type > flow direction > coefficient theta
##
for structure in config.base.__dict__.keys():
if getattr(config.base, structure):
for direction in getattr(config, structure).geometry.directions:
for n, theta in enumerate(parameters_theta[structure]):
# create dirs for case path
case = os.path.join(
f"{ BUILD }",
f"{ structure }",
"direction-{}{}{}".format(*direction),
f"theta-{ theta }"
)
taskPath = os.path.join(case, "task.toml")
if os.path.exists(taskPath) and mode == "safe":
queue.append(case)
continue
if not os.path.exists(case):
os.makedirs(case)
# prepare configuration for task
task = {
"logger": dict(config.logger),
"structure": structure,
"status": {
"mesh": False,
"flow": False
},
"statistics": {
"meshTime": 0,
"flowTime": 0
},
"geometry": {
"theta": theta,
"direction": direction,
"fillet": getattr(config, structure).geometry.fillet
},
"mesh": dict(getattr(config, structure).mesh),
"flow": dict(config.flow)
}
# reassign special values
task["mesh"]["thickness"] = mesh_thickness[structure][n]
##
with open(os.path.join(case, "task.toml"), "w") as io:
toml.dump(task, io)
##
queue.append(case)
return queue
#from salomepl.utils import runExecute, salomeVersion
def computeMesh(case):
scriptpath = os.path.join(ROOT, "salomepl/genmesh.py")
port = 2810
stime = time.monotonic()
returncode = runExecute(port, scriptpath, ROOT, case)
task = struct(toml.load(os.path.join(case, "task.toml")))
elapsed = time.monotonic() - stime
logger.info("computeMesh: elapsed time: {}".format(timedelta(seconds = elapsed)))
if returncode == 0:
task.statistics.meshTime = elapsed
with open(os.path.join(case, "task.toml"), "w") as io:
toml.dump(dict(task), io)
def computeFlow(case):
###
# Case preparation
##
foamCase = [ "0", "constant", "system" ]
os.chdir(case)
task = struct(toml.load(os.path.join(case, "task.toml")))
openfoam.foamClean()
for d in foamCase:
shutil.copytree(
os.path.join(ROOT, "openfoam/template", d),
os.path.join(case, d)
)
stime = time.monotonic()
###
# Mesh manipulations
##
if not os.path.exists("mesh.unv"):
logger.critical(f"computeFlow: missed 'mesh.unv'")
return
_, returncode = openfoam.ideasUnvToFoam("mesh.unv")
if returncode:
os.chdir(ROOT)
return returncode
openfoam.createPatch(dictfile = "system/createPatchDict")
openfoam.foamDictionary(
"constant/polyMesh/boundary",
"entry0.defaultFaces.type",
"wall"
)
openfoam.foamDictionary(
"constant/polyMesh/boundary",
"entry0.defaultFaces.inGroups",
"1 (wall)"
)
out = openfoam.checkMesh()
if out:
logger.info(out)
openfoam.transformPoints(task.flow.scale)
###
# Decomposition and initial approximation
##
openfoam.foamDictionary(
"constant/transportProperties",
"nu",
str(task.flow.constant.nu)
)
openfoam.decomposePar()
openfoam.renumberMesh()
pressureBF = task.flow.approx.pressure.boundaryField
velocityBF = task.flow.approx.velocity.boundaryField
direction = {
"[1, 0, 0]": 0,
"[0, 0, 1]": 1,
"[1, 1, 1]": 2
}[str(task.geometry.direction)]
openfoam.foamDictionary(
"0/p",
"boundaryField.inlet.value",
openfoam.uniform(pressureBF.inlet.value)
)
openfoam.foamDictionary(
"0/p",
"boundaryField.outlet.value",
openfoam.uniform(pressureBF.outlet.value)
)
openfoam.foamDictionary(
"0/U",
"boundaryField.inlet.value",
openfoam.uniform(velocityBF.inlet.value[direction])
)
openfoam.potentialFoam()
###
# Main computation
##
pressureBF = task.flow.main.pressure.boundaryField
velocityBF = task.flow.main.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])
)
returncode, out = openfoam.simpleFoam()
if out:
logger.info(out)
###
# 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
with open(os.path.join(case, "task.toml"), "w") as io:
toml.dump(dict(task), io)
os.chdir(ROOT)
return returncode
def checkEnv():
missed = False
try:
pythonVersion = "Python {}".format(sys.version.split(" ")[0])
salomeplVersion = salomeVersion()
openfoamVersion = openfoam.foamVersion()
except Exception as e:
logger.critical("Missed environment %s", e)
missed = True
else:
logger.info(f"environment:\n\t{pythonVersion}\n\t{salomeplVersion}\n\t{openfoamVersion}")
finally:
return missed
def postprocessing(queue):
pass
###
# Main entry
##
if __name__ == "__main__":
main()

View File

@ -1,5 +1,9 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
from peewee import ( from peewee import (
SqliteDatabase, SqliteDatabase, JOIN,
Model, Field, Model, Field,
AutoField, ForeignKeyField, AutoField, ForeignKeyField,
TextField, FloatField, TextField, FloatField,
@ -7,6 +11,18 @@ from peewee import (
TimeField TimeField
) )
db = SqliteDatabase(
None,
pragmas = { "foreign_keys": 1 },
field_types = { "list": "text" }
)
class BaseModel(Model):
class Meta:
database = db
class ListField(Field): class ListField(Field):
field_type = "list" field_type = "list"
@ -25,16 +41,6 @@ class ListField(Field):
return pval return pval
db = SqliteDatabase(
None,
pragmas = { "foreign_keys": 1 },
field_types = { "list": "text" }
)
class BaseModel(Model):
class Meta:
database = db
class Structure(BaseModel): class Structure(BaseModel):
structure_id = AutoField() structure_id = AutoField()

View File

@ -8,6 +8,7 @@ from types import FunctionType
import os import os
class CustomFormatter(logging.Formatter): class CustomFormatter(logging.Formatter):
def _getFormat(self, level: int):
grey = "\x1b[38;21m" grey = "\x1b[38;21m"
yellow = "\x1b[33;21m" yellow = "\x1b[33;21m"
red = "\x1b[31;21m" red = "\x1b[31;21m"
@ -15,7 +16,7 @@ class CustomFormatter(logging.Formatter):
reset = "\x1b[0m" reset = "\x1b[0m"
format = "[ %(asctime)s ] [ %(levelname)s ] %(message)s" format = "[ %(asctime)s ] [ %(levelname)s ] %(message)s"
FORMATS = { formats = {
logging.DEBUG: grey + format + reset, logging.DEBUG: grey + format + reset,
logging.INFO: grey + format + reset, logging.INFO: grey + format + reset,
logging.WARNING: yellow + format + reset, logging.WARNING: yellow + format + reset,
@ -23,27 +24,45 @@ class CustomFormatter(logging.Formatter):
logging.CRITICAL: bold_red + format + reset logging.CRITICAL: bold_red + format + reset
} }
return formats.get(level)
def format(self, record): def format(self, record):
log_fmt = self.FORMATS.get(record.levelno) log_fmt = self._getFormat(record.levelno)
formatter = logging.Formatter(log_fmt) time_fmt = "%H:%M:%S %d-%m-%y"
formatter = logging.Formatter(log_fmt, time_fmt)
return formatter.format(record) return formatter.format(record)
def setupLogger(logger, level: int):
def setupLogger(logger, level: int, filepath: str = None):
"""Applies settings to logger
:param logger: Instance of :class:`logging.Logger`
:type logger: Instance of :class:`logging.Logger`
:param level: Logging level (logging.INFO, logging.WARNING, ..)
:type level: int
:param filepath: Path to directory
:type filepath: str, optional
"""
logger.setLevel(level) logger.setLevel(level)
sh = logging.StreamHandler() streamhandler = logging.StreamHandler()
sh.setLevel(level) streamhandler.setLevel(level)
sh.setFormatter(CustomFormatter()) streamhandler.setFormatter(CustomFormatter())
logger.addHandler(streamhandler)
fh = logging.FileHandler(os.path.join("logs", logger.name)) if filepath:
fh.setLevel(level) if not os.path.exists(filepath):
fh.setFormatter(CustomFormatter()) os.makedirs(filepath, exist_ok = True)
logger.addHandler(sh) filehandler = logging.FileHandler(
logger.addHandler(fh) os.path.join(filepath, "{}.log".format(logger.name))
)
filehandler.setLevel(level)
filehandler.setFormatter(CustomFormatter())
logger.addHandler(filehandler)
return logger
class struct: class struct:
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -104,17 +123,32 @@ def deepupdate(target, src):
else: else:
target[k] = copy.copy(v) target[k] = copy.copy(v)
#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): def timer(func: FunctionType) -> (tuple, float):
"""(Decorator) Returns output of inner function and execution time """(Decorator) Returns output of inner function and execution time
:param func: inner function :param func: inner function
:type: FunctionType :type func: FunctionType
:return: output, elapsed time :return: output, elapsed time
:rtype: tuple(tuple, float) :rtype: tuple(tuple, float)
""" """
def inner(*args, **kwargs): def inner(*args, **kwargs):
start = time.monotonic() start = time.monotonic()
ret = func(*args, **kwargs) ret = func(*args, **kwargs)

View File

@ -28,8 +28,8 @@ def version() -> str:
return str(out, "utf-8").strip().split(" ")[-1] return str(out, "utf-8").strip().split(" ")[-1]
def runSalome(port: int, scriptpath: str, root: str, *args, logpath: str = None) -> int:
def runSalome(port: int, scriptpath: str, root: str, logpath: str = None, *args) -> int: # ISSUE: salome removes commas from string list
if os.environ.get("SALOME_PATH"): if os.environ.get("SALOME_PATH"):
cmd = [ os.path.join(os.environ["SALOME_PATH"], "salome") ] cmd = [ os.path.join(os.environ["SALOME_PATH"], "salome") ]
@ -40,9 +40,10 @@ def runSalome(port: int, scriptpath: str, root: str, logpath: str = None, *args)
if not logpath: if not logpath:
logpath = "/tmp/salome.log" logpath = "/tmp/salome.log"
fullargs = list(args) #fullargs = list(args)
fullargs.extend([ root, logpath ]) args = list(args)
fmtargs = "args:{}".format(", ".join([ str(arg) for arg in args ])) args.insert(1, root)
fmtargs = "args:{}".format(",".join([ '"{}"'.format(str(arg)) for arg in args ]))
cmdargs = [ cmdargs = [
"start", "-t", "start", "-t",
"--shutdown-servers=1", "--shutdown-servers=1",

10
tests/anisotropy-cli.py Normal file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, sys
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
from anisotropy.core.cli import anisotropy
anisotropy()

View File

@ -9,7 +9,7 @@ class TestAnisotropy(unittest.TestCase):
self.model = Anisotropy() self.model = Anisotropy()
def test_01_create_db(self): def test_01_create_db(self):
self.model.setupDB() self.model.db.setup()
path = os.path.join(self.model.env["db_path"], "anisotropy.db") path = os.path.join(self.model.env["db_path"], "anisotropy.db")
self.assertTrue(os.path.exists(path)) self.assertTrue(os.path.exists(path))
@ -19,10 +19,9 @@ class TestAnisotropy(unittest.TestCase):
try: try:
paramsAll = self.model.loadFromScratch() paramsAll = self.model.loadFromScratch()
self.model.setupDB()
for entry in paramsAll: for entry in paramsAll:
self.model.updateDB(entry) self.model.update(entry)
except Exception as e: except Exception as e:
passed = False passed = False
@ -31,8 +30,7 @@ class TestAnisotropy(unittest.TestCase):
self.assertTrue(passed) self.assertTrue(passed)
def test_03_load_db(self): def test_03_load_db(self):
self.model.setupDB() self.model.load("simple", [1.0, 0.0, 0.0], 0.01)
self.model.loadDB("simple", [1.0, 0.0, 0.0], 0.01)
self.assertEqual(self.model.params["structure"]["type"], "simple") self.assertEqual(self.model.params["structure"]["type"], "simple")