FEM: tasks module for z88, mystran and calculix, code improvements

This commit is contained in:
Bernd Hahnebach
2021-08-06 09:20:09 +02:00
parent afd885330a
commit 6dbe713d7b
3 changed files with 89 additions and 70 deletions

View File

@@ -51,7 +51,7 @@ _inputFileName = None
class Check(run.Check):
def run(self):
self.pushStatus("Checking analysis...\n")
self.pushStatus("Checking analysis member...\n")
self.check_mesh_exists()
# workaround use Calculix ccxtools pre checks
@@ -73,13 +73,12 @@ class Prepare(run.Prepare):
def run(self):
global _inputFileName
self.pushStatus("Preparing input files...\n")
mesh_obj = membertools.get_mesh_to_solve(self.analysis)[0] # pre check done already
self.pushStatus("Preparing input...\n")
# get mesh set data
# TODO evaluate if it makes sense to add new task
# between check and prepare to the solver frame work
mesh_obj = membertools.get_mesh_to_solve(self.analysis)[0] # pre check done already
meshdatagetter = meshsetsgetter.MeshSetsGetter(
self.analysis,
self.solver,
@@ -88,7 +87,7 @@ class Prepare(run.Prepare):
)
meshdatagetter.get_mesh_sets()
# write input file
# write solver input
w = writer.FemInputWriterCcx(
self.analysis,
self.solver,
@@ -100,9 +99,9 @@ class Prepare(run.Prepare):
path = w.write_solver_input()
# report to user if task succeeded
if path != "" and os.path.isfile(path):
self.pushStatus("Write completed.")
self.pushStatus("Writing solver input completed.")
else:
self.pushStatus("Writing CalculiX solver input file failed,")
self.pushStatus("Writing solver input failed.")
self.fail()
_inputFileName = os.path.splitext(os.path.basename(path))[0]
@@ -112,7 +111,13 @@ class Solve(run.Solve):
def run(self):
self.pushStatus("Executing solver...\n")
# get solver binary
self.pushStatus("Get solver binary...\n")
binary = settings.get_binary("Calculix")
if binary is None:
self.fail() # a print has been made in settings module
# run solver
self._process = subprocess.Popen(
[binary, "-i", _inputFileName],
cwd=self.directory,
@@ -131,10 +136,6 @@ class Solve(run.Solve):
class Results(run.Results):
def run(self):
if not _inputFileName:
# TODO do not run solver
# do not try to read results in a smarter way than an Exception
raise Exception("Error on writing CalculiX input file.\n")
prefs = FreeCAD.ParamGet(
"User parameter:BaseApp/Preferences/Mod/Fem/General")
if not prefs.GetBool("KeepResultsOnReRun", False):
@@ -142,10 +143,12 @@ class Results(run.Results):
self.load_results()
def purge_results(self):
# dat file will not be removed
# results from other solvers will be removed too
# the user should decide if purge should only delete the solver results or all results
self.pushStatus("Purge existing results...\n")
# TODO dat file will not be removed
# TODO implement a generic purge method
# TODO results from other solvers will be removed too
# the user should decide if purge should only
# delete this solver results or results from all solvers
for m in membertools.get_member(self.analysis, "Fem::FemResultObject"):
if m.Mesh and femutils.is_of_type(m.Mesh, "Fem::MeshResult"):
self.analysis.Document.removeObject(m.Mesh.Name)
@@ -153,10 +156,11 @@ class Results(run.Results):
self.analysis.Document.recompute()
def load_results(self):
self.load_results_ccxfrd()
self.load_results_ccxdat()
self.pushStatus("Import new results...\n")
self.load_ccxfrd_results()
self.load_ccxdat_results()
def load_results_ccxfrd(self):
def load_ccxfrd_results(self):
frd_result_file = os.path.join(
self.directory, _inputFileName + ".frd")
if os.path.isfile(frd_result_file):
@@ -164,18 +168,26 @@ class Results(run.Results):
importCcxFrdResults.importFrd(
frd_result_file, self.analysis, result_name_prefix)
else:
raise Exception(
"FEM: No results found at {}!".format(frd_result_file))
# TODO: use solver framework status message system
FreeCAD.Console.PrintError(
"FEM: No results found at {}!\n"
.format(frd_result_file)
)
self.fail()
def load_results_ccxdat(self):
def load_ccxdat_results(self):
dat_result_file = os.path.join(
self.directory, _inputFileName + ".dat")
if os.path.isfile(dat_result_file):
mode_frequencies = importCcxDatResults.import_dat(
dat_result_file, self.analysis)
else:
raise Exception(
"FEM: No .dat results found at {}!".format(dat_result_file))
# TODO: use solver framework status message system
FreeCAD.Console.PrintError(
"FEM: No results found at {}!\n"
.format(dat_result_file)
)
self.fail()
if mode_frequencies:
for m in membertools.get_member(self.analysis, "Fem::FemResultObject"):
if m.Eigenmode > 0:

View File

@@ -57,7 +57,7 @@ _inputFileName = None
class Check(run.Check):
def run(self):
self.pushStatus("Checking analysis...\n")
self.pushStatus("Checking analysis member...\n")
self.check_mesh_exists()
self.check_material_exists()
self.check_material_single() # no multiple material
@@ -70,13 +70,11 @@ class Prepare(run.Prepare):
def run(self):
global _inputFileName
self.pushStatus("Preparing input files...\n")
mesh_obj = membertools.get_mesh_to_solve(self.analysis)[0] # pre check done already
self.pushStatus("Preparing solver input...\n")
# get mesh set data
# TODO evaluate if it makes sense to add new task
# between check and prepare to the solver frame work
# TODO see calculix tasks get mesh set data
mesh_obj = membertools.get_mesh_to_solve(self.analysis)[0] # pre check done already
meshdatagetter = meshsetsgetter.MeshSetsGetter(
self.analysis,
self.solver,
@@ -85,44 +83,36 @@ class Prepare(run.Prepare):
)
meshdatagetter.get_mesh_sets()
# write input file
# write solver input
w = writer.FemInputWriterMystran(
self.analysis,
self.solver,
mesh_obj,
meshdatagetter.member,
self.directory,
meshdatagetter.mat_geo_sets
)
path = w.write_solver_input()
# report to user if task succeeded
if path != "":
self.pushStatus("Write completed!")
self.pushStatus("Writing solver input completed.")
else:
self.pushStatus("Writing CalculiX input file failed!")
self.pushStatus("Writing solver input failed.")
self.fail()
_inputFileName = os.path.splitext(os.path.basename(path))[0]
class Solve(run.Solve):
def run(self):
# print(_inputFileName)
if not _inputFileName:
# TODO do not run solver, do not try to read results in a smarter way than an Exception
raise Exception("Error on writing Mystran input file.\n")
self.pushStatus("Executing solver...\n")
infile = _inputFileName + ".bdf"
# TODO use solver framework status system
FreeCAD.Console.PrintMessage("Mystran: solver input file: {} \n\n".format(infile))
# get binary
self.pushStatus("Get solver...\n")
# get solver binary
self.pushStatus("Get solver binary...\n")
binary = settings.get_binary("Mystran")
# use preferences editor to add a group Mystran and the prefs:
# "UseStandardMystranLocation" --> bool, set to False
# "mystranBinaryPath, string" --> the binary path
if binary is None:
return # a print has been made in settings module
self.fail() # a print has been made in settings module
# run solver
self.pushStatus("Executing solver...\n")
@@ -147,19 +137,19 @@ class Results(run.Results):
if not prefs.GetBool("KeepResultsOnReRun", False):
self.purge_results()
if result_reading is True:
self.load_results() # ToDo in all solvers generischer name
self.load_results()
def purge_results(self):
self.pushStatus("Purge existing results...\n")
# TODO see calculix result tasks
for m in membertools.get_member(self.analysis, "Fem::FemResultObject"):
if femutils.is_of_type(m.Mesh, "Fem::MeshResult"):
self.analysis.Document.removeObject(m.Mesh.Name)
self.analysis.Document.removeObject(m.Name)
self.analysis.Document.recompute()
# deletes all results from any solver
# TODO: delete only the mystran results, fix in all solver
def load_results(self):
self.pushStatus("Import results...\n")
self.pushStatus("Import new results...\n")
neu_result_file = os.path.join(self.directory, _inputFileName + ".NEU")
if os.path.isfile(neu_result_file):
hfcMystranNeuIn.import_neu(neu_result_file)
@@ -169,11 +159,11 @@ class Results(run.Results):
self.analysis.addObject(o)
break
else:
# TODO: use solver framework error and status message system
# TODO: use solver framework status message system
FreeCAD.Console.PrintError(
"FEM: No results found at {}!\n".format(neu_result_file)
"FEM: No results found at {}!\n"
.format(neu_result_file)
)
return
self.fail()
## @}

View File

@@ -45,7 +45,7 @@ from femtools import membertools
class Check(run.Check):
def run(self):
self.pushStatus("Checking analysis...\n")
self.pushStatus("Checking analysis member...\n")
self.check_mesh_exists()
self.check_material_exists()
self.check_material_single() # no multiple material
@@ -57,7 +57,7 @@ class Check(run.Check):
class Prepare(run.Prepare):
def run(self):
self.pushStatus("Preparing input files...\n")
self.pushStatus("Preparing solver input...\n")
w = writer.FemInputWriterZ88(
self.analysis,
self.solver,
@@ -68,33 +68,45 @@ class Prepare(run.Prepare):
path = w.write_solver_input()
# report to user if task succeeded
if path is not None:
self.pushStatus("Write completed!")
self.pushStatus("Writing solver input completed.")
else:
self.pushStatus("Writing Z88 solver input files failed!")
self.pushStatus("Writing solver input failed.")
self.fail()
# print(path)
# z88 does not pass a main input file to the solver
# it passes the directory all input files are in
# not _inputFileName is needed
class Solve(run.Solve):
def run(self):
# AFAIK: z88r needs to be run twice, once in test mode and once in real solve mode
# the subprocess was just copied, it seems to work :-)
# TODO: search out for "Vektor GS" and "Vektor KOI" and print values
# may be compared with the used ones
self.pushStatus("Executing test solver...\n")
# get solver binary
self.pushStatus("Get solver binary...\n")
binary = settings.get_binary("Z88")
if binary is None:
self.fail() # a print has been made in settings module
# run solver test mode
# AFAIK: z88r needs to be run twice
# once in test mode and once in real solve mode
# the subprocess was just copied, it works :-)
# TODO: search out for "Vektor GS" and "Vektor KOI" and print values
# may be compare with the used ones
self.pushStatus("Executing solver in test mode...\n")
self._process = subprocess.Popen(
[binary, "-t", "-choly"],
cwd=self.directory,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.signalAbort.add(self._process.terminate)
# output = self._observeSolver(self._process)
self._process.communicate()
self.signalAbort.remove(self._process.terminate)
self.pushStatus("Executing real solver...\n")
# run solver real mode
self.pushStatus("Executing solver in real mode...\n")
binary = settings.get_binary("Z88")
self._process = subprocess.Popen(
[binary, "-c", "-choly"],
@@ -102,12 +114,10 @@ class Solve(run.Solve):
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
self.signalAbort.add(self._process.terminate)
# output = self._observeSolver(self._process)
self._process.communicate()
self.signalAbort.remove(self._process.terminate)
# if not self.aborted:
# self._updateOutput(output)
# del output # get flake8 quiet
# for chatching the output see CalculiX or Elmer solver tasks module
class Results(run.Results):
@@ -120,6 +130,8 @@ class Results(run.Results):
self.load_results()
def purge_results(self):
self.pushStatus("Purge existing results...\n")
# TODO see calculix result tasks
for m in membertools.get_member(self.analysis, "Fem::FemResultObject"):
if femutils.is_of_type(m.Mesh, "Fem::MeshResult"):
self.analysis.Document.removeObject(m.Mesh.Name)
@@ -127,6 +139,7 @@ class Results(run.Results):
self.analysis.Document.recompute()
def load_results(self):
self.pushStatus("Import new results...\n")
# displacements from z88o2 file
disp_result_file = os.path.join(
self.directory, "z88o2.txt")
@@ -135,7 +148,11 @@ class Results(run.Results):
importZ88O2Results.import_z88_disp(
disp_result_file, self.analysis, result_name_prefix)
else:
raise Exception(
"FEM: No results found at {}!".format(disp_result_file))
# TODO: use solver framework status message system
FreeCAD.Console.PrintError(
"FEM: No results found at {}!\n"
.format(disp_result_file)
)
self.fail()
## @}