diff --git a/.gitignore b/.gitignore index ca3024d..7789e4b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,5 @@ env/ *.run.xml *.synctex.gz *.toc -*.png *.out *.egg-info diff --git a/anisotropy/__init__.py b/anisotropy/__init__.py index a15ed92..0454390 100644 --- a/anisotropy/__init__.py +++ b/anisotropy/__init__.py @@ -26,6 +26,7 @@ env.update( ) env.update( logger_name = "anisotropy", + db_name = "anisotropy", db_path = env["BUILD"], salome_timeout = 15 * 60, openfoam_template = os.path.join(env["ROOT"], "anisotropy/openfoam/template") diff --git a/anisotropy/core/cli.py b/anisotropy/core/cli.py index a6712e0..0ac4271 100644 --- a/anisotropy/core/cli.py +++ b/anisotropy/core/cli.py @@ -81,6 +81,16 @@ def anisotropy(): default = 1, help = "Count of parallel processes" ) +@click.option( + "-D", "--database", "database", + help = "Database path" +) +@click.option( + "-f", "--force", "force", + type = click.BOOL, + default = False, + help = "Overwrite existing entries" +) @click.option( "-p", "--param", "params", metavar = "key=value", @@ -88,8 +98,8 @@ def anisotropy(): cls = KeyValueOption, help = "Overwrite existing parameter (except control variables)" ) -def compute(stage, nprocs, params): - from anisotropy.core.main import Anisotropy, logger +def compute(stage, nprocs, database, force, params): + from anisotropy.core.main import Anisotropy, Database, logger from anisotropy.core.utils import timer, parallel args = dict() @@ -99,13 +109,30 @@ def compute(stage, nprocs, params): ### model = Anisotropy() + + if database: + if database[-3: ] == ".db": + splitted = database.split("/") + db_path = "/".join(splitted[ :-1]) + db_name = splitted[-1: ][0][ :-3] + + else: + raise Exception("Invalid database extension") + + model.db = Database(db_name, db_path) + + logger.info("Constructing database, tables ...") model.db.setup() - if model.db.isempty(): - paramsAll = model.loadFromScratch() + def fill_db(): + if model.db.isempty(): + paramsAll = model.loadFromScratch() - for entry in paramsAll: - model.db.update(entry) + for entry in paramsAll: + model.db.update(entry) + + _, fill_elapsed = timer(fill_db)() + logger.info(f"Elapsed time = { fill_elapsed }") ### def computeCase(stage, type, direction, theta): @@ -114,37 +141,48 @@ def compute(stage, nprocs, params): case.evalParams() case.update() + logger.info(f"Case: type = { type }, direction = { direction }, theta = { theta }") + logger.info(f"Stage: { stage }") + if stage == "all" or stage == "mesh": - (out, err, returncode), elapsed = timer(case.computeMesh)() + if not case.params.get("meshresult", {}).get("status") == "Done" or force: + (out, err, returncode), elapsed = timer(case.computeMesh)() - click.echo(out) - click.echo(err) + if out: logger.info(out) + if err: logger.error(err) - case.load(type, direction, theta) + case.load(type, direction, theta) - if case.params.get("meshresult"): - case.params["meshresult"]["calculationTime"] = elapsed - case.update() + if case.params.get("meshresult"): + case.params["meshresult"]["calculationTime"] = elapsed + case.update() - if returncode: - logger.error("Mesh computation failed. Skipping flow computation ...") - return + if returncode: + logger.error("Mesh computation failed. Skipping flow computation ...") + return + + else: + logger.info("Mesh exists. Skipping ...") if stage == "all" or stage == "flow": - (out, err, returncode), elapsed = timer(case.computeFlow)() + if not case.params.get("flowresult", {}).get("status") == "Done" or force: + (out, err, returncode), elapsed = timer(case.computeFlow)() - click.echo(out) - click.echo(err) + if out: logger.info(out) + if err: logger.error(err) - case.load(type, direction, theta) + case.load(type, direction, theta) - if case.params.get("flowresult"): - case.params["flowresult"]["calculationTime"] = elapsed - case.update() - - if returncode: - logger.error("Flow computation failed.") - return + if case.params.get("flowresult"): + case.params["flowresult"]["calculationTime"] = elapsed + case.update() + + if returncode: + logger.error("Flow computation failed.") + return + + else: + logger.info("Flow exists. Skipping ...") ### diff --git a/anisotropy/core/main.py b/anisotropy/core/main.py index 15d5b75..b137b74 100644 --- a/anisotropy/core/main.py +++ b/anisotropy/core/main.py @@ -27,8 +27,8 @@ from anisotropy.samples import Simple, FaceCentered, BodyCentered logger = logging.getLogger(env["logger_name"]) setupLogger(logger, logging.INFO, env["LOG"]) -peeweeLogger = logging.getLogger("peewee") -peeweeLogger.setLevel(logging.INFO) +#peeweeLogger = logging.getLogger("peewee") +#peeweeLogger.setLevel(logging.INFO) class Anisotropy(object): @@ -38,7 +38,7 @@ class Anisotropy(object): """Constructor method""" self.env = env - self.db = Database("anisotropy", env["db_path"]) + self.db = Database(self.env["db_name"], self.env["db_path"]) self.params = [] @@ -245,7 +245,7 @@ class Anisotropy(object): *salomeargs, timeout = self.env["salome_timeout"], root = self.env["ROOT"], - logpath = os.path.join(self.env["LOG"], "salome.log") + logpath = self.env["LOG"] ) @@ -260,20 +260,14 @@ class Anisotropy(object): p = self.params - logger.info("\n".join([ - "genmesh:", - f"structure type:\t{ p['structure']['type'] }", - f"coefficient:\t{ p['structure']['theta'] }", - f"fillet:\t{ p['structure']['fillets'] }", - f"flow direction:\t{ p['structure']['direction'] }" - ])) - salome.salome_init() ### # Shape ## + logger.info("Constructing shape ...") + geompy = salomepl.geometry.getGeom() structure = dict( simple = Simple, @@ -284,17 +278,12 @@ class Anisotropy(object): [length, surfaceArea, volume] = geompy.BasicProperties(shape, theTolerance = 1e-06) - logger.info("\n".join([ - "shape:", - f"edges length:\t{ length }", - f"surface area:\t{ surfaceArea }", - f"volume:\t{ volume }" - ])) - ### # Mesh ## + logger.info("Prepairing mesh ...") + mp = p["mesh"] lengths = [ @@ -332,6 +321,7 @@ class Anisotropy(object): self.update() + logger.info("Computing mesh ...") out, err, returncode = mesh.compute() ### @@ -345,6 +335,7 @@ class Anisotropy(object): casePath = self.getCasePath() os.makedirs(casePath, exist_ok = True) + logger.info("Exporting mesh ...") mesh.exportUNV(os.path.join(casePath, "mesh.unv")) meshStats = mesh.stats() @@ -356,10 +347,6 @@ class Anisotropy(object): ) self.update() - logger.info("mesh stats:\n{}".format( - "\n".join(map(lambda v: f"{ v[0] }:\t{ v[1] }", meshStats.items())) - )) - else: logger.error(err) @@ -389,6 +376,11 @@ class Anisotropy(object): # ISSUE: ideasUnvToFoam cannot import mesh with '-case' flag so 'os.chdir' for that casePath = self.getCasePath() + + if not os.path.exists(casePath): + logger.warning(f"Cannot find case path. Skipping computation ...\n\t{ casePath }") + return "", "", 1 + os.chdir(casePath) openfoam.foamClean() @@ -404,7 +396,7 @@ class Anisotropy(object): if not os.path.exists("mesh.unv"): logger.error(f"missed 'mesh.unv'") os.chdir(self.env["ROOT"]) - return 1 + return "", "", 1 out, err, returncode = openfoam.ideasUnvToFoam("mesh.unv") @@ -499,8 +491,6 @@ class Anisotropy(object): # ) out, err, returncode = openfoam.simpleFoam() - if out: - logger.info(out) ### # Results @@ -521,8 +511,7 @@ class Anisotropy(object): else: self.params["flowresult"].update( - status = "Failed", - flowRate = flowRate + status = "Failed" ) @@ -530,6 +519,6 @@ class Anisotropy(object): os.chdir(self.env["ROOT"]) - return out, err, returncode + return out, str(err, "utf-8"), returncode diff --git a/anisotropy/core/utils.py b/anisotropy/core/utils.py index c90bc8f..b057153 100644 --- a/anisotropy/core/utils.py +++ b/anisotropy/core/utils.py @@ -48,7 +48,7 @@ def setupLogger(logger, level: int, filepath: str = None): :param filepath: Path to directory :type filepath: str, optional """ - + logger.handlers = [] logger.setLevel(level) streamhandler = logging.StreamHandler() diff --git a/anisotropy/openfoam/application.py b/anisotropy/openfoam/application.py index fa48e15..1578815 100644 --- a/anisotropy/openfoam/application.py +++ b/anisotropy/openfoam/application.py @@ -42,9 +42,9 @@ def application(name: str, *args: str, case: str = None, stderr: bool = True, us out, err = p.communicate() logfile.write(err) - if err and stderr: - logger.error("""{}: - {}""".format(name, str(err, "utf-8"))) + #if err and stderr: + # logger.error("""{}: + # {}""".format(name, str(err, "utf-8"))) return out, err, p.returncode diff --git a/anisotropy/openfoam/solvers.py b/anisotropy/openfoam/solvers.py index 6109b80..8e8e408 100644 --- a/anisotropy/openfoam/solvers.py +++ b/anisotropy/openfoam/solvers.py @@ -8,10 +8,12 @@ import re def potentialFoam(case: str = None, useMPI: bool = False): if useMPI: - application("potentialFoam", "-parallel", useMPI = True, case = case, stderr = True) + out, err, returncode = application("potentialFoam", "-parallel", useMPI = True, case = case, stderr = True) else: - application("potentialFoam", case = case, stderr = True) + out, err, returncode = application("potentialFoam", case = case, stderr = True) + + return out, err, returncode def simpleFoam(case: str = None, useMPI: bool = False): diff --git a/anisotropy/samples/faceCentered.py b/anisotropy/samples/faceCentered.py index cb1bb02..87d2830 100644 --- a/anisotropy/samples/faceCentered.py +++ b/anisotropy/samples/faceCentered.py @@ -155,13 +155,13 @@ class FaceCentered(object): xy = geompy.MakeVectorDXDYDZ(1, 1, 0) xmy = geompy.MakeVectorDXDYDZ(1, -1, 0) - grain = geompy.MakeSpherePntR(geompy.MakeVertex(*spos1), radius) + grain = geompy.MakeSpherePntR(geompy.MakeVertex(*spos1), self.radius) lattice1 = geompy.MakeMultiTranslation2D(grain, xy, length, xn, xmy, length, yn) - lattice1 = geompy.MakeMultiTranslation1D(lattice1, oz, L, zn - 1) + lattice1 = geompy.MakeMultiTranslation1D(lattice1, oz, self.L, zn - 1) - grain = geompy.MakeSpherePntR(geompy.MakeVertex(*spos2), radius) + grain = geompy.MakeSpherePntR(geompy.MakeVertex(*spos2), self.radius) lattice2 = geompy.MakeMultiTranslation2D(grain, xy, length, xn + 1, xmy, length, yn + 1) - lattice2 = geompy.MakeMultiTranslation1D(lattice2, oz, L, zn) + lattice2 = geompy.MakeMultiTranslation1D(lattice2, oz, self.L, zn) grains = geompy.ExtractShapes(lattice1, geompy.ShapeType["SOLID"], True) grains += geompy.ExtractShapes(lattice2, geompy.ShapeType["SOLID"], True) diff --git a/docs/source/static/er-diagram.png b/docs/source/static/er-diagram.png new file mode 100644 index 0000000..f91db61 Binary files /dev/null and b/docs/source/static/er-diagram.png differ diff --git a/docs/source/static/structure.png b/docs/source/static/structure.png new file mode 100644 index 0000000..5d0dc5b Binary files /dev/null and b/docs/source/static/structure.png differ