[FEM] enable to run Elmer multi-threaded

- this needs proper testing, especially on a non-Windows system

- note that for some tasks multi-threading requires non-standard additional solvers like MUMPS. Ideally the user should be informed about this, depending on the equations he uses. But this should not block this PR, meaning to use multi-threading in general.
This commit is contained in:
Uwe
2022-07-10 17:25:19 +02:00
parent 74e77f0191
commit eec258ab37
11 changed files with 401 additions and 231 deletions

View File

@@ -1879,7 +1879,7 @@ void FemMesh::read(const char *FileName)
readNastran(File.filePath());
}
#ifdef FC_USE_VTK
else if (File.hasExtension("vtk") || File.hasExtension("vtu")) {
else if (File.hasExtension("vtk") || File.hasExtension("vtu") || File.hasExtension("pvtu")) {
// read *.vtk legacy format or *.vtu XML unstructure Mesh
FemVTKTools::readVTKMesh(File.filePath().c_str(), this);
}

View File

@@ -33,6 +33,7 @@
# include <vtkRectilinearGrid.h>
# include <vtkAppendFilter.h>
# include <vtkXMLUnstructuredGridReader.h>
# include <vtkXMLPUnstructuredGridReader.h>
# include <vtkXMLPolyDataReader.h>
# include <vtkXMLStructuredGridReader.h>
# include <vtkXMLRectilinearGridReader.h>
@@ -121,7 +122,8 @@ bool FemPostPipeline::canRead(Base::FileInfo File) {
File.hasExtension("vts") ||
File.hasExtension("vtr") ||
File.hasExtension("vti") ||
File.hasExtension("vtu"))
File.hasExtension("vtu") ||
File.hasExtension("pvtu"))
return true;
return false;
@@ -135,6 +137,8 @@ void FemPostPipeline::read(Base::FileInfo File) {
if (File.hasExtension("vtu"))
readXMLFile<vtkXMLUnstructuredGridReader>(File.filePath());
else if (File.hasExtension("pvtu"))
readXMLFile<vtkXMLPUnstructuredGridReader>(File.filePath());
else if (File.hasExtension("vtp"))
readXMLFile<vtkXMLPolyDataReader>(File.filePath());
else if (File.hasExtension("vts"))

View File

@@ -53,6 +53,7 @@
# include <vtkRectilinearGrid.h>
# include <vtkUnstructuredGrid.h>
# include <vtkXMLUnstructuredGridReader.h>
# include <vtkXMLPUnstructuredGridReader.h>
# include <vtkXMLUnstructuredGridWriter.h>
# include <vtkPointData.h>
# include <vtkCellData.h>
@@ -215,6 +216,14 @@ FemMesh* FemVTKTools::readVTKMesh(const char* filename, FemMesh* mesh)
}
importVTKMesh(dataset, mesh);
}
else if (f.hasExtension("pvtu")) {
vtkSmartPointer<vtkDataSet> dataset = readVTKFile<vtkXMLPUnstructuredGridReader>(filename);
if (!dataset.Get()) {
Base::Console().Error("Failed to load file %s\n", filename);
return nullptr;
}
importVTKMesh(dataset, mesh);
}
else if(f.hasExtension("vtk"))
{
vtkSmartPointer<vtkDataSet> dataset = readVTKFile<vtkDataSetReader>(filename);

View File

@@ -202,6 +202,7 @@
#include <vtkXMLPolyDataReader.h>
#include <vtkXMLStructuredGridReader.h>
#include <vtkXMLUnstructuredGridReader.h>
#include <vtkXMLPUnstructuredGridReader.h>
#include <vtkXMLRectilinearGridReader.h>
#include <vtkXMLImageDataReader.h>

View File

@@ -7,205 +7,247 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>199</height>
<height>203</height>
</rect>
</property>
<property name="windowTitle">
<string>Elmer</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>6</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="gb_gmsh_param">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="title">
<string>Elmer binaries</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
<widget class="QGroupBox" name="gb_gmsh_param">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="title">
<string>Elmer binaries</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="l_grid_binary_std">
<property name="text">
<string>ElmerGrid:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::PrefCheckBox" name="cb_grid_binary_std">
<property name="text">
<string>Search in known binary directories</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>UseStandardGridLocation</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Elmer</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="l_grid_binary_path">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>ElmerGrid binary path</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::PrefFileChooser" name="fc_grid_binary_path">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="sizeIncrement">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Leave blank to use default ElmerGrid binary file</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>gridBinaryPath</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Elmer</cstring>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="l_elmer_binary_std">
<property name="text">
<string>ElmerSolver:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Gui::PrefCheckBox" name="cb_elmer_binary_std">
<property name="text">
<string>Search in known binary directories</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>UseStandardElmerLocation</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Elmer</cstring>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="l_elmer_binary_path">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>ElmerSolver binary path</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="Gui::PrefFileChooser" name="fc_elmer_binary_path">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="sizeIncrement">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Leave blank to use default Elmer elmer binary file&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Note:&lt;/span&gt; To use multithreading you must specify here&lt;br&gt; the executable variant with the suffix &amp;quot;_mpi&amp;quot;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>elmerBinaryPath</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Elmer</cstring>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="l_elmer_binary_std_2">
<property name="text">
<string>Multithreading:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QGridLayout" name="gl_01">
<item row="0" column="0">
<widget class="QLabel" name="l_grid_binary_std">
<property name="text">
<string>ElmerGrid:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::PrefCheckBox" name="cb_grid_binary_std">
<property name="text">
<string>Search in known binary directories</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>UseStandardGridLocation</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Elmer</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="l_grid_binary_path">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>ElmerGrid binary path</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::PrefFileChooser" name="fc_grid_binary_path">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="sizeIncrement">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Leave blank to use default ElmerGrid binary file</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>gridBinaryPath</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Elmer</cstring>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="l_elmer_binary_std">
<property name="text">
<string>ElmerSolver:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="Gui::PrefCheckBox" name="cb_elmer_binary_std">
<property name="text">
<string>Search in known binary directories</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="prefEntry" stdset="0">
<cstring>UseStandardElmerLocation</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Elmer</cstring>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="l_elmer_binary_path">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>ElmerSolver binary path</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="Gui::PrefFileChooser" name="fc_elmer_binary_path">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="sizeIncrement">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Leave blank to use default Elmer elmer binary file</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>elmerBinaryPath</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Elmer</cstring>
</property>
</widget>
</item>
</layout>
<widget class="QLabel" name="label_cores">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>CPU cores to be used:</string>
</property>
</widget>
</item>
<item>
<widget class="Gui::PrefSpinBox" name="sb_elmer_num_cores">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Note:&lt;/span&gt; It is recommended to use an even number of cores to benefit from mesh symmetries. (Using 8 cores can be faster than 9 cores.)&lt;br/&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Note too:&lt;/span&gt; In extreme cases ElmerSolver might not converge if the core number is too high.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>32</number>
</property>
<property name="prefEntry" stdset="0">
<cstring>UseNumberOfCores</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/Fem/Elmer</cstring>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
@@ -218,7 +260,7 @@
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
<height>20</height>
</size>
</property>
</spacer>
@@ -237,6 +279,11 @@
<extends>Gui::FileChooser</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefSpinBox</class>
<extends>QSpinBox</extends>
<header>Gui/PrefWidgets.h</header>
</customwidget>
<customwidget>
<class>Gui::PrefCheckBox</class>
<extends>QCheckBox</extends>
@@ -279,22 +326,6 @@
</hint>
</hints>
</connection>
<connection>
<sender>cb_elmer_binary_std</sender>
<signal>toggled(bool)</signal>
<receiver>l_elmer_binary_path</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>247</x>
<y>91</y>
</hint>
<hint type="destinationlabel">
<x>71</x>
<y>114</y>
</hint>
</hints>
</connection>
<connection>
<sender>cb_elmer_binary_std</sender>
<signal>toggled(bool)</signal>
@@ -311,5 +342,21 @@
</hint>
</hints>
</connection>
<connection>
<sender>cb_elmer_binary_std</sender>
<signal>toggled(bool)</signal>
<receiver>l_elmer_binary_path</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>247</x>
<y>91</y>
</hint>
<hint type="destinationlabel">
<x>71</x>
<y>114</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -24,6 +24,7 @@
#include "PreCompiled.h"
#ifndef _PreComp_
# include <thread>
# include <QMessageBox>
#endif
@@ -39,10 +40,20 @@ DlgSettingsFemElmerImp::DlgSettingsFemElmerImp(QWidget* parent)
{
ui->setupUi(this);
// determine number of CPU cores
processor_count = std::thread::hardware_concurrency();
// hardware check might fail and then returns 0
if (processor_count > 0)
ui->sb_elmer_num_cores->setMaximum(processor_count);
connect(ui->fc_grid_binary_path, &Gui::PrefFileChooser::fileNameChanged,
this, &DlgSettingsFemElmerImp::onfileNameChanged);
connect(ui->fc_elmer_binary_path, &Gui::PrefFileChooser::fileNameChanged,
this, &DlgSettingsFemElmerImp::onfileNameChanged);
connect(ui->fc_elmer_binary_path, &Gui::PrefFileChooser::fileNameChanged,
this, &DlgSettingsFemElmerImp::onfileNameChanged);
this, &DlgSettingsFemElmerImp::onfileNameChangedMT);
connect(ui->sb_elmer_num_cores, qOverload<int>(&Gui::PrefSpinBox::valueChanged),
this, &DlgSettingsFemElmerImp::onCoresValueChanged);
}
DlgSettingsFemElmerImp::~DlgSettingsFemElmerImp()
@@ -57,6 +68,8 @@ void DlgSettingsFemElmerImp::saveSettings()
ui->cb_grid_binary_std->onSave();
ui->fc_grid_binary_path->onSave();
ui->sb_elmer_num_cores->onSave();
}
void DlgSettingsFemElmerImp::loadSettings()
@@ -66,6 +79,8 @@ void DlgSettingsFemElmerImp::loadSettings()
ui->cb_grid_binary_std->onRestore();
ui->fc_grid_binary_path->onRestore();
ui->sb_elmer_num_cores->onRestore();
}
/**
@@ -91,4 +106,44 @@ void DlgSettingsFemElmerImp::onfileNameChanged(QString FileName)
}
}
void DlgSettingsFemElmerImp::onfileNameChangedMT(QString FileName)
{
// reset in case it was prevoisly set to 1
ui->sb_elmer_num_cores->setMaximum(processor_count);
if (ui->sb_elmer_num_cores->value() == 1)
return;
auto strName = FileName.toStdString();
#if defined(FC_OS_WIN32)
// name ends with "_mpi.exe"
if (strName.substr(strName.length() - 8) != "_mpi.exe") {
QMessageBox::warning(this, tr("Not suitable for mulithreading"),
tr("You use more than one CPU core.\n"
"Therefore an executable with the suffix '_mpi.exe' is required."));
ui->sb_elmer_num_cores->setValue(1);
ui->sb_elmer_num_cores->setMaximum(1);
return;
}
#elif defined(FC_OS_LINUX) || defined(FC_OS_CYGWIN) || defined(FC_OS_MACOSX) || defined(FC_OS_BSD)
// name ends with "_mpi"
if (strName.substr(strName.length() - 4) != "_mpi") {
QMessageBox::warning(this, tr("Not suitable for mulithreading"),
tr("You use more than one CPU core.\n"
"Therefore an executable with the suffix '_mpi' is required."));
ui->sb_elmer_num_cores->setValue(1);
ui->sb_elmer_num_cores->setMaximum(1);
return;
}
#endif
}
void DlgSettingsFemElmerImp::onCoresValueChanged(int cores)
{
if (cores > 1) {
// check if the right executable is loaded
onfileNameChangedMT(ui->fc_elmer_binary_path->fileName());
}
}
#include "moc_DlgSettingsFemElmerImp.cpp"

View File

@@ -41,6 +41,8 @@ public:
protected Q_SLOTS:
void onfileNameChanged(QString FileName);
void onfileNameChangedMT(QString FileName);
void onCoresValueChanged(int cores);
protected:
void saveSettings();
@@ -49,6 +51,7 @@ protected:
private:
std::unique_ptr<Ui_DlgSettingsFemElmerImp> ui;
unsigned int processor_count;
};
} // namespace FemGui

View File

@@ -63,7 +63,7 @@ FreeCAD.addExportType("FEM mesh Python (*.meshpy)", "feminout.importPyMesh")
FreeCAD.addExportType("FEM mesh TetGen (*.poly)", "feminout.convert2TetGen")
# see FemMesh::read() and FemMesh::write() methods in src/Mod/Fem/App/FemMesh.cpp
FreeCAD.addImportType("FEM mesh formats (*.bdf *.dat *.inp *.med *.unv *.vtk *.vtu *.z88)", "Fem")
FreeCAD.addImportType("FEM mesh formats (*.bdf *.dat *.inp *.med *.unv *.vtk *.vtu *.pvtu *.z88)", "Fem")
FreeCAD.addExportType("FEM mesh formats (*.dat *.inp *.med *.stl *.unv *.vtk *.vtu *.z88)", "Fem")
FreeCAD.addExportType("FEM mesh Nastran (*.bdf)", "feminout.exportNastranMesh")
@@ -86,5 +86,5 @@ FreeCAD.addExportType("FEM mesh Z88 (*i1.txt)", "feminout.importZ88Mesh")
FreeCAD.addImportType("FEM result Z88 displacements (*o2.txt)", "feminout.importZ88O2Results")
if "BUILD_FEM_VTK" in FreeCAD.__cmake__:
FreeCAD.addImportType("FEM result VTK (*.vtk *.vtu)", "feminout.importVTKResults")
FreeCAD.addImportType("FEM result VTK (*.vtk *.vtu *.pvtu)", "feminout.importVTKResults")
FreeCAD.addExportType("FEM result VTK (*.vtk *.vtu)", "feminout.importVTKResults")

View File

@@ -121,10 +121,19 @@ class Solve(run.Solve):
if os.path.isdir(solvpath):
os.environ["ELMER_HOME"] = solvpath
os.environ["LD_LIBRARY_PATH"] = "$LD_LIBRARY_PATH:{}/modules".format(solvpath)
# hide the popups on Windows
# different call depending if with multithreading or not
num_cores = settings.get_cores("ElmerSolver")
args = []
if int(num_cores) > 1:
if system() != "Windows":
args.extend(["mpirun"])
else:
args.extend(["mpiexec"])
args.extend(["-np", num_cores])
args.extend([binary])
if system() == "Windows":
self._process = subprocess.Popen(
[binary],
args,
cwd=self.directory,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
@@ -132,7 +141,7 @@ class Solve(run.Solve):
)
else:
self._process = subprocess.Popen(
[binary],
args,
cwd=self.directory,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
@@ -190,12 +199,16 @@ class Results(run.Results):
# elmer post file path changed with version x.x
# see https://forum.freecadweb.org/viewtopic.php?f=18&t=42732
# workaround
possible_post_file_0 = os.path.join(self.directory, "case0001.vtu")
possible_post_file_t = os.path.join(self.directory, "case_t0001.vtu")
if os.path.isfile(possible_post_file_0):
postPath = possible_post_file_0
elif os.path.isfile(possible_post_file_t):
postPath = possible_post_file_t
possible_post_file_old = os.path.join(self.directory, "case0001.vtu")
possible_post_file_single = os.path.join(self.directory, "case_t0001.vtu")
possible_post_file_multi = os.path.join(self.directory, "case_t0001.pvtu")
# first try the multi-thread result, then single then old name
if os.path.isfile(possible_post_file_multi):
postPath = possible_post_file_multi
elif os.path.isfile(possible_post_file_single):
postPath = possible_post_file_single
elif os.path.isfile(possible_post_file_old):
postPath = possible_post_file_old
else:
self.report.error("Result file not found.")
self.fail()

View File

@@ -216,23 +216,38 @@ class Writer(object):
)
else:
binary = settings.get_binary("ElmerGrid")
num_cores = settings.get_cores("ElmerGrid")
if binary is None:
raise WriteError("Could not find ElmerGrid binary.")
args = [binary,
_ELMERGRID_IFORMAT,
_ELMERGRID_OFORMAT,
unvPath,
"-scale", "0.001", "0.001", "0.001",
"-out", self.directory]
# hide the popups on Windows
# for multithreading we first need a normal mesh creation run
# then a second to split the mesh into the number of used cores
argsBasic = [binary,
_ELMERGRID_IFORMAT,
_ELMERGRID_OFORMAT,
unvPath,
"-scale", "0.001", "0.001", "0.001"]
args = argsBasic
args.extend(["-out", self.directory])
if system() == "Windows":
subprocess.call(
args,
stdout=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
startupinfo=femutils.startProgramInfo("hide")
)
else:
subprocess.call(args, stdout=subprocess.DEVNULL)
if int(num_cores) > 1:
args = argsBasic
args.extend(["-partdual", "-metiskway", num_cores,
"-out", self.directory])
if system() == "Windows":
subprocess.call(
args,
stdout=subprocess.DEVNULL,
startupinfo=femutils.startProgramInfo("hide")
)
else:
subprocess.call(args, stdout=subprocess.DEVNULL)
def _writeStartinfo(self):
path = os.path.join(self.directory, _STARTINFO_NAME)

View File

@@ -94,10 +94,7 @@ def get_binary(name):
"""
if name in _SOLVER_PARAM:
binary = _SOLVER_PARAM[name].get_binary()
FreeCAD.Console.PrintMessage(
'Solver binary path (returned from binary getter): {} \n'
.format(binary)
)
FreeCAD.Console.PrintMessage('Solver binary path: {} \n'.format(binary))
return binary
else:
FreeCAD.Console.PrintError(
@@ -107,6 +104,28 @@ def get_binary(name):
)
return None
def get_cores(name):
""" Read number of CPU cores for solver *name* honoring user settings.
Returns number of CPU cores to be used for the solvier run
:param name: solver id as a ``str`` (see :mod:`femsolver.settings`)
"""
if name in _SOLVER_PARAM:
cores = _SOLVER_PARAM[name].get_cores()
FreeCAD.Console.PrintMessage(
'Number of CPU cores to be used for the solvier run: {} \n'
.format(cores)
)
return cores
else:
FreeCAD.Console.PrintError(
"Settings solver name: {} not found in "
"solver settings modules _SOLVER_PARAM dirctionary.\n"
.format(name)
)
return None
def get_write_comments(name):
""" Check whether "write_comments" is set for solver.
@@ -220,6 +239,10 @@ class _SolverDlg(object):
FreeCAD.Console.PrintLog("Solver binary found path: {}\n".format(the_found_binary))
return the_found_binary
def get_cores(self):
cores = str(self.param_group.GetInt("UseNumberOfCores"))
return cores
def get_write_comments(self):
return self.param_group.GetBool(self.WRITE_COMMENTS_PARAM, True)