Mod: desc, docs, some fixes

This commit is contained in:
L-Nafaryus 2021-08-23 21:54:40 +05:00
parent a7342affee
commit eccce886be
No known key found for this signature in database
GPG Key ID: C76D8DCD2727DBB7
27 changed files with 221 additions and 37 deletions

View File

@ -7,7 +7,7 @@
__license__ = "GPL3" __license__ = "GPL3"
__version__ = "1.1.0" __version__ = "1.1.0"
__author__ = __maintainer = "George Kusayko" __author__ = __maintainer__ = "George Kusayko"
__email__ = "gkusayko@gmail.com" __email__ = "gkusayko@gmail.com"
### ###

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
[logger] [logger]
name = "anisotropy" name = "anisotropy"
format = "[ %(levelname)s ] %(message)s" format = "[ %(levelname)s ] %(message)s"

View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
import click import click
import ast import ast
@ -41,7 +45,6 @@ class KeyValueOption(click.Option):
return self._convert(ctx, value) return self._convert(ctx, value)
#pass_anisotropy = click.make_pass_decorator(Anisotropy)
def version(): def version():
msg = "Missed package anisotropy" msg = "Missed package anisotropy"
@ -59,11 +62,34 @@ def version():
def anisotropy(): def anisotropy():
pass pass
@anisotropy.command() @anisotropy.command(
@click.option("-s", "--stage", "stage", type = click.Choice(["all", "mesh", "flow"]), default = "all") help = """Computes cases by chain (mesh -> flow)
@click.option("-p", "--param", "params", metavar = "key=value", multiple = True, cls = KeyValueOption)
def compute(stage, params): Control parameters: type, direction, theta (each parameter affects on a queue)
"""
)
@click.option(
"-s", "--stage", "stage",
type = click.Choice(["all", "mesh", "flow"]),
default = "all",
help = "Current computation stage"
)
@click.option(
"-P", "--parallel", "parallel",
type = click.INT,
default = 1,
help = "Count of parallel processes"
)
@click.option(
"-p", "--param", "params",
metavar = "key=value",
multiple = True,
cls = KeyValueOption,
help = "Overwrite existing parameter (except control variables)"
)
def compute(stage, parallel, params):
from anisotropy.core.main import Anisotropy, logger from anisotropy.core.main import Anisotropy, logger
from anisotropy.core.utils import timer
args = dict() args = dict()
@ -82,6 +108,7 @@ def compute(stage, params):
type, direction, theta = args["type"], args["direction"], args["theta"] type, direction, theta = args["type"], args["direction"], args["theta"]
model.load(type, direction, theta) 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()
@ -90,17 +117,21 @@ def compute(stage, params):
# TODO: single compute / queue # TODO: single compute / queue
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) = timer(model.computeMesh)()
if out: click.echo(out) if out: click.echo(out)
if err: click.echo(err) if err: click.echo(err)
if model.params.get("meshresult"): if model.params.get("meshresult"):
model.load(type, direction, theta) model.load(type, direction, theta)
model.params["meshresult"]["calculationTime"] = elapsed model.params["meshresult"]["calculationTime"] = elapsed
model.update() 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) = timer(model.computeFlow)()
if out: click.echo(out)
if err: click.echo(err)
if model.params.get("flowresult"): if model.params.get("flowresult"):
model.load(type, direction, theta) model.load(type, direction, theta)
@ -108,13 +139,15 @@ def compute(stage, params):
model.update() model.update()
@anisotropy.command() @anisotropy.command(
help = "! Not a user command"
)
@click.argument("root") @click.argument("root")
@click.argument("type") @click.argument("type")
@click.argument("direction") @click.argument("direction")
@click.argument("theta") @click.argument("theta")
def computemesh(root, type, direction, theta): def computemesh(root, type, direction, theta):
# ISSUE: can't hide command from help, hidden = True doesn't work # ISSUE: can't hide command from help, 'hidden = True' doesn't work
# [Salome Environment] # [Salome Environment]
### ###

View File

@ -45,6 +45,11 @@ class Database(object):
def isempty(self) -> bool: def isempty(self) -> bool:
"""Checks DB for main table existence (Structure)
:return: True if exists
:rtype: bool
"""
query = Structure.select() query = Structure.select()
return not query.exists() return not query.exists()
@ -96,6 +101,8 @@ class Database(object):
if flowresultsQuery.exists(): if flowresultsQuery.exists():
params["flowresult"] = flowresultsQuery.dicts().get() params["flowresult"] = flowresultsQuery.dicts().get()
else:
logger.error("Missed Structure table")
return params return params

View File

@ -32,7 +32,7 @@ peeweeLogger.setLevel(logging.INFO)
class Anisotropy(object): class Anisotropy(object):
"""Ultimate class that organize whole working process""" """Ultimate class that organizes whole working process"""
def __init__(self): def __init__(self):
"""Constructor method""" """Constructor method"""
@ -43,10 +43,18 @@ class Anisotropy(object):
def load(self, structure_type: str, structure_direction: list, structure_theta: float): def load(self, structure_type: str, structure_direction: list, structure_theta: float):
"""Shortcut for `Database.setup` and `Database.load`.
See :class:`anisotropy.core.database.Database` for more details.
"""
self.db.setup() self.db.setup()
self.params = self.db.load(structure_type, structure_direction, structure_theta) self.params = self.db.load(structure_type, structure_direction, structure_theta)
def update(self, params: dict = None): def update(self, params: dict = None):
"""Shortcut for `Database.setup` and `Database.update`.
See :class:`anisotropy.core.database.Database` for more details.
"""
self.db.setup() self.db.setup()
self.db.update(self.params if not params else params) self.db.update(self.params if not params else params)
@ -124,7 +132,7 @@ class Anisotropy(object):
"flowapprox": deepcopy(entry["flowapprox"]) "flowapprox": deepcopy(entry["flowapprox"])
} }
# For type = fixedValue only # For `type = fixedValue` only
_velocity = entryNew["flowapprox"]["velocity"]["boundaryField"]["inlet"]["value"] _velocity = entryNew["flowapprox"]["velocity"]["boundaryField"]["inlet"]["value"]
entryNew["flowapprox"]["velocity"]["boundaryField"]["inlet"]["value"] = [ entryNew["flowapprox"]["velocity"]["boundaryField"]["inlet"]["value"] = [
val * _velocity for val in entryNew["structure"]["direction"] val * _velocity for val in entryNew["structure"]["direction"]
@ -190,7 +198,6 @@ class Anisotropy(object):
fillets = delta - Cf * (radius - r0) fillets = delta - Cf * (radius - r0)
self.params["structure"].update( self.params["structure"].update(
#**structure,
L = L, L = L,
r0 = r0, r0 = r0,
radius = radius, radius = radius,
@ -198,7 +205,7 @@ class Anisotropy(object):
) )
def getCasePath(self) -> str: def getCasePath(self) -> str:
"""Constructs case path from main control parameters """Constructs case path from control parameters
:return: Absolute path to case :return: Absolute path to case
:rtype: str :rtype: str
@ -217,20 +224,31 @@ class Anisotropy(object):
) )
@timer def computeMesh(self):
def computeMesh(self, type, direction, theta): """Computes a mesh on shape via Salome
:return: Process output, error messages and returncode
:rtype: tuple(str, str, int)
"""
scriptpath = os.path.join(self.env["ROOT"], "anisotropy/core/cli.py") scriptpath = os.path.join(self.env["ROOT"], "anisotropy/core/cli.py")
port = 2900 port = 2900
p = self.params["structure"]
return salomepl.utils.runSalome( return salomepl.utils.runSalome(
self.env["salome_port"], self.env["salome_port"],
scriptpath, scriptpath,
self.env["ROOT"], self.env["ROOT"],
"computemesh", type, direction, theta, "computemesh",
p["type"], p["direction"], p["theta"],
logpath = os.path.join(self.env["LOG"], "salome.log") logpath = os.path.join(self.env["LOG"], "salome.log")
) )
def genmesh(self): def genmesh(self):
"""Computes a mesh on shape
Warning: Working only inside Salome Environment
"""
# ISSUE: double logger output # ISSUE: double logger output
import salome import salome
@ -309,7 +327,12 @@ class Anisotropy(object):
self.update() self.update()
returncode, errors = mesh.compute() out, err, returncode = mesh.compute()
###
# Results
##
p["meshresult"] = dict()
if not returncode: if not returncode:
mesh.removePyramids() mesh.removePyramids()
@ -320,7 +343,8 @@ class Anisotropy(object):
mesh.exportUNV(os.path.join(casePath, "mesh.unv")) mesh.exportUNV(os.path.join(casePath, "mesh.unv"))
meshStats = mesh.stats() meshStats = mesh.stats()
p["meshresult"] = dict( p["meshresult"].update(
status = "Done",
surfaceArea = surfaceArea, surfaceArea = surfaceArea,
volume = volume, volume = volume,
**meshStats **meshStats
@ -334,7 +358,8 @@ class Anisotropy(object):
else: else:
logger.error(errors) logger.error(errors)
p["meshresult"] = dict( p["meshresult"].update(
status = "Failed",
surfaceArea = surfaceArea, surfaceArea = surfaceArea,
volume = volume volume = volume
) )
@ -342,8 +367,13 @@ class Anisotropy(object):
salome.salome_close() salome.salome_close()
@timer
def computeFlow(self, type, direction, theta): def computeFlow(self):
"""Computes a flow on mesh via OpenFOAM
:return: Process output, error messages and returncode
:rtype: tuple(str, str, int)
"""
### ###
# Case preparation # Case preparation
## ##
@ -468,20 +498,29 @@ class Anisotropy(object):
logger.info(out) logger.info(out)
### ###
# Check results # Results
## ##
self.params["flowresult"] = dict()
if returncode == 0: if not returncode:
postProcessing = "postProcessing/flowRatePatch(name=outlet)/0/surfaceFieldValue.dat" postProcessing = "postProcessing/flowRatePatch(name=outlet)/0/surfaceFieldValue.dat"
with open(os.path.join(casePath, postProcessing), "r") as io: with open(os.path.join(casePath, postProcessing), "r") as io:
lastLine = io.readlines()[-1] lastLine = io.readlines()[-1]
flowRate = float(lastLine.replace(" ", "").replace("\n", "").split("\t")[1]) flowRate = float(lastLine.replace(" ", "").replace("\n", "").split("\t")[1])
self.params["flowresult"] = dict( self.params["flowresult"].update(
status = "Done",
flowRate = flowRate flowRate = flowRate
) )
else:
self.params["flowresult"].update(
status = "Failed",
flowRate = flowRate
)
self.update() self.update()
os.chdir(self.env["ROOT"]) os.chdir(self.env["ROOT"])
@ -489,10 +528,3 @@ class Anisotropy(object):
return out, err, returncode return out, err, returncode
def _queue(self):
pass
def computeAll(self):
pass

View File

@ -139,6 +139,7 @@ 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")
calculationTime = TimeField(null = True) calculationTime = TimeField(null = True)
class Flow(BaseModel): class Flow(BaseModel):
@ -164,4 +165,6 @@ class FlowResult(BaseModel):
flow_id = ForeignKeyField(Flow, backref = "flowresults") flow_id = ForeignKeyField(Flow, backref = "flowresults")
flowRate = FloatField(null = True) flowRate = FloatField(null = True)
status = TextField(null = True, default = "Idle")
calculationTime = TimeField(null = True) calculationTime = TimeField(null = True)

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
import logging import logging
from multiprocessing import Queue, Process, cpu_count from multiprocessing import Queue, Process, cpu_count

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
from .meshConversion import ideasUnvToFoam from .meshConversion import ideasUnvToFoam
from .meshManipulation import createPatch, transformPoints, checkMesh, renumberMesh from .meshManipulation import createPatch, transformPoints, checkMesh, renumberMesh

View File

@ -1,3 +1,7 @@
# -*- 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 subprocess import subprocess

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
from .application import application from .application import application
def ideasUnvToFoam(mesh: str, case: str = None) -> (str, int): def ideasUnvToFoam(mesh: str, case: str = None) -> (str, int):

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
from .application import application from .application import application
import re import re

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
from .application import application from .application import application
def foamDictionary(filepath: str, entry: str, value: str = None, case: str = None): def foamDictionary(filepath: str, entry: str, value: str = None, case: str = None):

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
from .application import application from .application import application
def decomposePar(case: str = None): def decomposePar(case: str = None):

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
from .application import application from .application import application
import re import re

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
import os import os
import shutil import shutil

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
import logging import logging
logger = logging.getLogger("anisotropy") logger = logging.getLogger("anisotropy")

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
import logging import logging
logger = logging.getLogger("anisotropy") logger = logging.getLogger("anisotropy")
@ -113,9 +117,9 @@ class Mesh(object):
def compute(self): def compute(self):
isDone = self.mesh.Compute() isDone = self.mesh.Compute()
returncode = int(not isDone) returncode = int(not isDone)
errors = self.mesh.GetComputeErrors() err = self.mesh.GetComputeErrors()
return returncode, errors return "", err, returncode
def stats(self): def stats(self):
return { return {

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
#import salome #import salome
import subprocess import subprocess
import logging import logging

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
from anisotropy.samples.simple import Simple from anisotropy.samples.simple import Simple
from anisotropy.samples.bodyCentered import BodyCentered from anisotropy.samples.bodyCentered import BodyCentered

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
from math import pi, sqrt from math import pi, sqrt
from anisotropy.salomepl import geometry from anisotropy.salomepl import geometry

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
from math import pi, sqrt from math import pi, sqrt
from anisotropy.salomepl import geometry from anisotropy.salomepl import geometry

View File

@ -1,3 +1,7 @@
# -*- coding: utf-8 -*-
# This file is part of anisotropy.
# License: GNU GPL version 3, see the file "LICENSE" for details.
from math import pi, sqrt from math import pi, sqrt
from anisotropy.salomepl import geometry from anisotropy.salomepl import geometry

View File

@ -12,6 +12,14 @@ anisotropy.core.cli module
:undoc-members: :undoc-members:
:show-inheritance: :show-inheritance:
anisotropy.core.database module
-------------------------------
.. automodule:: anisotropy.core.database
:members:
:undoc-members:
:show-inheritance:
anisotropy.core.main module anisotropy.core.main module
--------------------------- ---------------------------

View File

@ -6,3 +6,4 @@ anisotropy
anisotropy anisotropy
setup setup
tests

29
docs/source/tests.rst Normal file
View File

@ -0,0 +1,29 @@
tests package
=============
Submodules
----------
tests.anisotropy\-cli module
----------------------------
.. automodule:: tests.anisotropy-cli
:members:
:undoc-members:
:show-inheritance:
tests.test\_anisotropy module
-----------------------------
.. automodule:: tests.test_anisotropy
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: tests
:members:
:undoc-members:
:show-inheritance: