diff --git a/anisotropy/anisotropy.py b/anisotropy/anisotropy.py index adff911..e42eda2 100644 --- a/anisotropy/anisotropy.py +++ b/anisotropy/anisotropy.py @@ -71,7 +71,7 @@ if os.path.exists(env["CONFIG"]): for restricted in ["ROOT", "BUILD", "LOG", "CONFIG"]: if config.get(restricted): config.pop(restricted) - + for m, structure in enumerate(config["structures"]): for n, estructure in enumerate(env["structures"]): if estructure["name"] == structure["name"]: @@ -110,10 +110,12 @@ def timer(func): class Anisotropy(object): def __init__(self): - self.db = self._setupDB() + self.env = env + self.db = None self.params = [] - self.evalParameters(env) + #self.evalParameters(env) + self.setupDB() @staticmethod def version(): @@ -133,23 +135,21 @@ class Anisotropy(object): return "\n".join([ f"{ k }: { v }" for k, v in versions.items() ]) - @staticmethod - def _setupDB(): - db.init(env["db_path"]) + def setupDB(self): + self.db = db.init(self.env["db_path"]) - if not os.path.exists(env["db_path"]): - db.create_tables([Structure, Mesh]) + if not os.path.exists(self.env["db_path"]): + self.db.create_tables([Structure, Mesh]) - return db - - def evalParameters(self, _env: dict): + def evalEnvParameters(self): + """ 'Uncompress' and eval environment parameters """ from math import sqrt - structures = deepcopy(_env["structures"]) + structures = deepcopy(self.env["structures"]) for structure in structures: _theta = structure["geometry"]["theta"] - thetaMin = int(_theta[0] / _theta[2]) + thetaMin = int(_theta[0] / _theta[2]) thetaMax = int(_theta[1] / _theta[2]) + 1 thetaList = list( map(lambda n: n * _theta[2], range(thetaMin, thetaMax)) @@ -168,7 +168,7 @@ class Anisotropy(object): L = 2 * r0 radius = r0 / (1 - theta) - C1, C2 = 0.8, 0.5 + C1, C2 = 0.8, 0.5 Cf = C1 + (C2 - C1) / (thetaMax - thetaMin) * (theta - thetaMin) delta = 0.2 fillets = delta - Cf * (radius - r0) @@ -188,14 +188,14 @@ class Anisotropy(object): r0 = L * sqrt(3) / 4 radius = r0 / (1 - theta) - C1, C2 = 0.3, 0.2 + C1, C2 = 0.3, 0.2 Cf = C1 + (C2 - C1) / (thetaMax - thetaMin) * (theta - thetaMin) delta = 0.02 fillets = delta - Cf * (radius - r0) - + path = os.path.join( - _env["BUILD"], + self.env["BUILD"], structure["name"], f"direction-{ direction }", f"theta-{ theta }" @@ -214,16 +214,25 @@ class Anisotropy(object): mesh.update( thickness = thicknessList[n] ) - self.params.append({ - "name": structure["name"], - "path": path, - "geometry": geometry, - "mesh": mesh, - "submesh": deepcopy(structure["submesh"]) - }) + self.params.append(dict( + name = structure["name"], + path = path, + geometry = geometry, + mesh = mesh, + submesh = deepcopy(structure["submesh"]) + )) + def getParams(structure, direction, theta): + for entry in self.params: + if entry["name"] == structure and + entry["geometry"]["direction"] == direction and + entry["geometry"]["theta"] == theta: + return entry + # SELECT * FROM structure LEFT OUTER JOIN mesh ON mesh.structure_id = structure.id WHERE name = "faceCentered" AND direction = "[1, 1, 1]" AND theta = 0.12; + # Structure.select().join(Mesh, JOIN.LEFT_OUTER, on = (Mesh.structure_id == Structure.id)).where(Structure.name == "simple", Structure.direction == "[1, 0, 0]", Structure.theta == 0.13).dicts().get() + @timer def updateDB(self): for entry in self.params: query = (Structure @@ -242,7 +251,7 @@ class Anisotropy(object): ) m = deepcopy(entry["mesh"]) - + if not query.exists(): with self.db.atomic(): stab = Structure.create(**s) @@ -251,12 +260,38 @@ class Anisotropy(object): mtab = Mesh.create(**m) else: - # TODO: not working update; incorrect update (all entries) with self.db.atomic(): - stab = Structure.update(**s) + (Structure.update(**s) + .where( + Structure.name == entry["name"], + Structure.direction == str(entry["geometry"]["direction"]), + Structure.theta == entry["geometry"]["theta"] + ) + .execute()) - m.update(structure_id = stab) - mtab = Mesh.update(**m) + (Mesh.update(**m) + .where( + Mesh.structure_id == query.get().id + ) + .execute()) + + @timer + def updateFromDB(self): + squery = Structure.select().order_by(Structure.id) + mquery = Mesh.select().order_by(Mesh.structure_id) + + for s, m in zip(squery.dicts(), mquery.dicts()): + name = s.pop("name") + path = s.pop("path") + + self.params.append(dict( + name = name, + path = path, + geometry = s, + mesh = m + )) + + self.params = sorted(self.params, key = lambda entry: f"{ entry['name'] } { entry['geometry']['direction'] } { entry['geometry']['theta'] }") @timer def computeMesh(self): diff --git a/anisotropy/models.py b/anisotropy/models.py index 9aa9efd..047a3fb 100644 --- a/anisotropy/models.py +++ b/anisotropy/models.py @@ -15,32 +15,32 @@ class ListField(Field): except: pass - + finally: - pval.append(ch.strip()) + pval.append(ch.strip().replace("'", "")) return pval db = SqliteDatabase( - None, + None, pragmas = { "foreign_keys": 1 }, field_types = { "list": "text" } ) class BaseModel(Model): class Meta: - database = db + database = db class Structure(BaseModel): name = TextField() - direction = TextField() + direction = ListField() theta = FloatField() - + r0 = FloatField() L = FloatField() radius = FloatField() - + filletsEnabled = BooleanField() fillets = FloatField() path = TextField() diff --git a/salomepl/genmesh.py b/salomepl/genmesh.py index 98b2a6a..d094bce 100644 --- a/salomepl/genmesh.py +++ b/salomepl/genmesh.py @@ -2,115 +2,159 @@ # This file executes inside salome environment # # salome starts at user home directory -# -# sys.argv = [ .., ROOT, case ] ## import os, sys import math import salome -# get project path from args -ROOT = sys.argv[1] -CASE = sys.argv[2] -sys.path.append(ROOT) -# site-packages from virtual env -sys.path.append(os.path.join(ROOT, "env/lib/python3.9/site-packages")) - -import toml -import logging -from anisotropy.utils import struct - -from salomepl.simple import simple -from salomepl.faceCentered import faceCentered -from salomepl.bodyCentered import bodyCentered - -from salomepl.geometry import getGeom -from salomepl.mesh import Mesh, Fineness, ExtrusionMethod, defaultParameters +@click.command() +@click.argument("root") +@click.argument("name") +@click.argument("direction") +@click.argument("theta", type = click.FLOAT) +def genmesh(root, name, direction, theta): + ### + # Args + ## + direction = list(map(lambda num: float(num), direction[1:-1].split(","))) -def genmesh(config): - - logger.info(f"""genmesh: - structure type:\t{ config.structure } - coefficient:\t{ config.geometry.theta } - fillet:\t{ config.geometry.fillet } - flow direction:\t{ config.geometry.direction }""") + ### + # Modules + ## + sys.path.extend([ + root, + os.path.join(root, "env/lib/python3.9/site-packages") + ]) + + import logging + import click + + from anisotropy import Anisotropy + + from salomepl.simple import simple + from salomepl.faceCentered import faceCentered + from salomepl.bodyCentered import bodyCentered + + from salomepl.geometry import getGeom + from salomepl.mesh import Mesh, Fineness, ExtrusionMethod, defaultParameters + + + ### + # Model + ## + model = Anisotropy() + model.updateFromDB() + + p = model.getParams(name, direction, theta) + + + ### + # Logger + ## + logging.basicConfig( + level = logging.INFO, + format = model.env["logger"]["format"], + handlers = [ + logging.StreamHandler(), + logging.FileHandler( + os.path.join(model.env["LOG"], model.env["logger"]["name"]) + ) + ] + ) + logger = logging.getLogger(model.env["logger"]["name"]) + + + ### + # Entry + ## + logger.info("\n".join([ + "genmesh:", + f"structure type:\t{ p['name'] }", + f"coefficient:\t{ p['geometry']['theta'] }", + f"fillet:\t{ p['geometry']['fillets'] }", + f"flow direction:\t{ p['geometry']['direction'] }" + ])) salome.salome_init() - + + ### # Shape ## geompy = getGeom() - structure = globals().get(config.structure) - shape, groups = structure(config.geometry.theta, config.geometry.fillet, config.geometry.direction) + structure = globals().get(p["name"]) + shape, groups = structure( + p["geometry"]["theta"], + p["geometry"]["fillets"], + p["geometry"]["direction"] + ) + [length, surfaceArea, volume] = geompy.BasicProperties(shape, theTolerance = 1e-06) - logger.info(f"""shape: - edges length:\t{ length } - surface area:\t{ surfaceArea } - volume:\t{ volume }""") - + logger.info("\n".join([ + "shape:" + f"edges length:\t{ length }", + f"surface area:\t{ surfaceArea }", + f"volume:\t{ volume }" + ])) + + ### # Mesh ## - config = dict(config) + mp = p["mesh"] - mconfig = defaultParameters(**config["mesh"]) - - lengths = [ geompy.BasicProperties(edge)[0] for edge in geompy.SubShapeAll(shape, geompy.ShapeType["EDGE"]) ] + lengths = [ + geompy.BasicProperties(edge)[0] for edge in geompy.SubShapeAll(shape, geompy.ShapeType["EDGE"]) + ] meanSize = sum(lengths) / len(lengths) - mconfig["maxSize"] = meanSize - mconfig["minSize"] = meanSize * 1e-1 - mconfig["chordalError"] = mconfig["maxSize"] / 2 + mp["maxSize"] = meanSize + mp["minSize"] = meanSize * 1e-1 + mp["chordalError"] = mp["maxSize"] / 2 faces = [] for group in groups: if group.GetName() in mconfig["facesToIgnore"]: faces.append(group) - mconfig["faces"] = faces mesh = Mesh(shape) - mesh.Tetrahedron(**mconfig) + mesh.Tetrahedron(**mp) - if mconfig["viscousLayers"]: - mesh.ViscousLayers(**mconfig) - - config["mesh"].update(mconfig) - smconfigs = config["mesh"]["submesh"] + if mp["viscousLayers"]: + mesh.ViscousLayers(**mp, faces = faces) - for name in smconfigs.keys(): + smp = p["submesh"] + + for name in smp.keys(): for group in groups: if group.GetName() == name: subshape = group - - smconfig = defaultParameters(**smconfigs[name]) - smconfig["maxSize"] = meanSize * 1e-1 - smconfig["minSize"] = meanSize * 1e-3 - smconfig["chordalError"] = smconfig["minSize"] * 1e+1 - - mesh.Triangle(subshape, **smconfig) - config["mesh"]["submesh"][name].update(smconfig) + + smp["maxSize"] = meanSize * 1e-1 + smp["minSize"] = meanSize * 1e-3 + smp["chordalError"] = smp["minSize"] * 1e+1 + + mesh.Triangle(subshape, **smp) returncode, errors = mesh.compute() if not returncode: - config["status"]["mesh"] = True - + # TODO: MeshResult + pass + else: logger.error(errors) - with open(CONFIG, "w") as io: - toml.dump(config, io) mesh.removePyramids() mesh.assignGroups() - mesh.exportUNV(os.path.join(CASE, "mesh.unv")) + mesh.exportUNV(os.path.join(p["path"], "mesh.unv")) stats = "" for k, v in mesh.stats().items(): @@ -120,23 +164,3 @@ def genmesh(config): salome.salome_close() - -if __name__ == "__main__": - CONFIG = os.path.join(CASE, "task.toml") - config = struct(toml.load(CONFIG)) - - LOG = os.path.join(ROOT, "logs") - - logging.basicConfig( - level = logging.INFO, - format = config.logger.format, - handlers = [ - logging.StreamHandler(), - logging.FileHandler(f"{ LOG }/{ config.logger.name }.log") - ] - ) - logger = logging.getLogger(config.logger.name) - - genmesh(config) - - diff --git a/salomepl/utils.py b/salomepl/utils.py index 2fd5ef5..35c5f1e 100644 --- a/salomepl/utils.py +++ b/salomepl/utils.py @@ -40,14 +40,14 @@ def runSalome(port: int, scriptpath: str, root: str, logpath: str = None, *args) if not logpath: logpath = "/tmp/salome.log" + fullargs = list(args) + fullargs.extend([ root, logpath ]) fmtargs = "args:{}".format(", ".join([ str(arg) for arg in args ])) cmdargs = [ - "start", "-t", - "--shutdown-servers=1", - "--port", str(port), - scriptpath, - root, - logpath, + "start", "-t", + "--shutdown-servers=1", + "--port", str(port), + scriptpath, fmtargs ]