FEM: elmer, add it to the new solver framework and add equation object for elmer
This commit is contained in:
@@ -120,6 +120,7 @@ SET(FemObjectsScripts_SRCS
|
||||
SET(FemSolver_SRCS
|
||||
femsolver/__init__.py
|
||||
femsolver/solverbase.py
|
||||
femsolver/equationbase.py
|
||||
femsolver/report.py
|
||||
femsolver/reportdialog.py
|
||||
femsolver/settings.py
|
||||
@@ -128,6 +129,24 @@ SET(FemSolver_SRCS
|
||||
femsolver/signal.py
|
||||
)
|
||||
|
||||
SET(FemElmer_SRCS
|
||||
femsolver/elmer/__init__.py
|
||||
femsolver/elmer/sifio.py
|
||||
femsolver/elmer/solver.py
|
||||
femsolver/elmer/tasks.py
|
||||
femsolver/elmer/writer.py
|
||||
)
|
||||
|
||||
SET(FemEquationsElmer_SRCS
|
||||
femsolver/elmer/equations/__init__.py
|
||||
femsolver/elmer/equations/equation.py
|
||||
femsolver/elmer/equations/linear.py
|
||||
femsolver/elmer/equations/nonlinear.py
|
||||
femsolver/elmer/equations/elasticity.py
|
||||
femsolver/elmer/equations/heat.py
|
||||
femsolver/elmer/equations/flow.py
|
||||
)
|
||||
|
||||
SET(FemCalculix_SRCS
|
||||
femsolver/calculix/__init__.py
|
||||
femsolver/calculix/solver.py
|
||||
@@ -169,6 +188,8 @@ SET(FemGuiScripts_SRCS
|
||||
PyGui/_CommandFemResultShow.py
|
||||
PyGui/_CommandFemResultsPurge.py
|
||||
PyGui/_CommandFemSolverCalculix.py
|
||||
PyGui/_CommandFemSolverElmer.py
|
||||
PyGui/_CommandFemEquation.py
|
||||
PyGui/_CommandFemSolverControl.py
|
||||
PyGui/_CommandFemSolverRun.py
|
||||
PyGui/_CommandFemSolverZ88.py
|
||||
@@ -353,8 +374,10 @@ fc_target_copy_resource(Fem
|
||||
${FemGuiScripts_SRCS}
|
||||
${FemTests_SRCS}
|
||||
${FemSolver_SRCS}
|
||||
${FemElmer_SRCS}
|
||||
${FemCalculix_SRCS}
|
||||
${FemZ88_SRCS}
|
||||
${FemEquationsElmer_SRCS}
|
||||
)
|
||||
|
||||
SET_BIN_DIR(Fem Fem /Mod/Fem)
|
||||
|
||||
@@ -73,6 +73,7 @@ INSTALL(
|
||||
FILES
|
||||
femsolver/__init__.py
|
||||
femsolver/solverbase.py
|
||||
femsolver/equationbase.py
|
||||
femsolver/report.py
|
||||
femsolver/reportdialog.py
|
||||
femsolver/settings.py
|
||||
@@ -83,6 +84,30 @@ INSTALL(
|
||||
Mod/Fem/femsolver
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
femsolver/elmer/__init__.py
|
||||
femsolver/elmer/sifio.py
|
||||
femsolver/elmer/solver.py
|
||||
femsolver/elmer/tasks.py
|
||||
femsolver/elmer/writer.py
|
||||
DESTINATION
|
||||
Mod/Fem/femsolver/elmer
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
femsolver/elmer/equations/__init__.py
|
||||
femsolver/elmer/equations/equation.py
|
||||
femsolver/elmer/equations/linear.py
|
||||
femsolver/elmer/equations/nonlinear.py
|
||||
femsolver/elmer/equations/elasticity.py
|
||||
femsolver/elmer/equations/heat.py
|
||||
femsolver/elmer/equations/flow.py
|
||||
DESTINATION
|
||||
Mod/Fem/femsolver/elmer/equations
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES
|
||||
femsolver/calculix/__init__.py
|
||||
@@ -109,6 +134,8 @@ INSTALL(
|
||||
PyGui/FemSelectionObserver.py
|
||||
PyGui/FemSelectionWidgets.py
|
||||
PyGui/__init__.py
|
||||
PyGui/_CommandFemSolverElmer.py
|
||||
PyGui/_CommandFemEquation.py
|
||||
PyGui/_CommandFemConstraintBodyHeatSource.py
|
||||
PyGui/_CommandFemConstraintFlowVelocity.py
|
||||
PyGui/_CommandFemConstraintInitialFlowVelocity.py
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "DlgSettingsFemExportAbaqusImp.h"
|
||||
#include "DlgSettingsFemGmshImp.h"
|
||||
#include "DlgSettingsFemZ88Imp.h"
|
||||
#include "DlgSettingsFemElmerImp.h"
|
||||
#include "ViewProviderFemMesh.h"
|
||||
#include "ViewProviderFemMeshShape.h"
|
||||
#include "ViewProviderFemMeshShapeNetgen.h"
|
||||
@@ -160,6 +161,7 @@ PyMOD_INIT_FUNC(FemGui)
|
||||
new Gui::PrefPageProducer<FemGui::DlgSettingsFemCcxImp> (QT_TRANSLATE_NOOP("QObject","FEM"));
|
||||
new Gui::PrefPageProducer<FemGui::DlgSettingsFemGmshImp> (QT_TRANSLATE_NOOP("QObject","FEM"));
|
||||
new Gui::PrefPageProducer<FemGui::DlgSettingsFemZ88Imp> (QT_TRANSLATE_NOOP("QObject","FEM"));
|
||||
new Gui::PrefPageProducer<FemGui::DlgSettingsFemElmerImp> (QT_TRANSLATE_NOOP("QObject","FEM"));
|
||||
|
||||
// register preferences pages on Import-Export
|
||||
new Gui::PrefPageProducer<FemGui::DlgSettingsFemExportAbaqusImp> (QT_TRANSLATE_NOOP("QObject","Import-Export"));
|
||||
|
||||
@@ -46,6 +46,7 @@ set(FemGui_MOC_HDRS
|
||||
DlgSettingsFemGeneralImp.h
|
||||
DlgSettingsFemGmshImp.h
|
||||
DlgSettingsFemZ88Imp.h
|
||||
DlgSettingsFemElmerImp.h
|
||||
PropertyFemMeshItem.h
|
||||
TaskObjectName.h
|
||||
TaskCreateNodeSet.h
|
||||
@@ -87,6 +88,7 @@ set(FemGui_UIC_SRCS
|
||||
DlgSettingsFemGeneral.ui
|
||||
DlgSettingsFemGmsh.ui
|
||||
DlgSettingsFemZ88.ui
|
||||
DlgSettingsFemElmer.ui
|
||||
TaskCreateNodeSet.ui
|
||||
TaskObjectName.ui
|
||||
TaskFemConstraint.ui
|
||||
@@ -143,6 +145,9 @@ SET(FemGui_DLG_SRCS
|
||||
DlgSettingsFemZ88.ui
|
||||
DlgSettingsFemZ88Imp.cpp
|
||||
DlgSettingsFemZ88Imp.h
|
||||
DlgSettingsFemElmer.ui
|
||||
DlgSettingsFemElmerImp.cpp
|
||||
DlgSettingsFemElmerImp.h
|
||||
TaskFemConstraint.ui
|
||||
TaskFemConstraint.cpp
|
||||
TaskFemConstraint.h
|
||||
|
||||
312
src/Mod/Fem/Gui/DlgSettingsFemElmer.ui
Normal file
312
src/Mod/Fem/Gui/DlgSettingsFemElmer.ui
Normal file
@@ -0,0 +1,312 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FemGui::DlgSettingsFemElmerImp</class>
|
||||
<widget class="QWidget" name="FemGui::DlgSettingsFemElmerImp">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>377</width>
|
||||
<height>451</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Elmer</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gb_elmer_param">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Binaries</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="gl_elmer">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="l_elmer_binary_std">
|
||||
<property name="text">
|
||||
<string>ElmerSolver:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="Gui::PrefFileChooser" name="fc_elmer_binary_path" native="true">
|
||||
<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>
|
||||
<item row="1" column="1">
|
||||
<widget class="Gui::PrefCheckBox" name="cb_elmer_binary_std">
|
||||
<property name="text">
|
||||
<string>use standard path</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="2" column="0">
|
||||
<widget class="QLabel" name="l_grid_binary_std">
|
||||
<property name="text">
|
||||
<string>ElmerGrid:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="Gui::PrefFileChooser" name="fc_grid_binary_path" native="true">
|
||||
<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/Grid</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="Gui::PrefCheckBox" name="cb_grid_binary_std">
|
||||
<property name="text">
|
||||
<string>use standard path</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/Grid</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Gui::PrefCheckBox</class>
|
||||
<extends>QCheckBox</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::FileChooser</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Gui/FileDialog.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefFileChooser</class>
|
||||
<extends>Gui::FileChooser</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefRadioButton</class>
|
||||
<extends>QRadioButton</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Gui::PrefLineEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>Gui/PrefWidgets.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="Resources/Fem.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>cb_elmer_binary_std</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>fc_elmer_binary_path</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>cb_elmer_binary_std</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>fc_elmer_binary_path</receiver>
|
||||
<slot>setDisabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>cb_grid_binary_std</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>fc_grid_binary_path</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>cb_grid_binary_std</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>fc_grid_binary_path</receiver>
|
||||
<slot>setDisabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>20</x>
|
||||
<y>20</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>cb_wd_custom</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>le_wd_custom</receiver>
|
||||
<slot>setDisabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>188</x>
|
||||
<y>314</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>137</x>
|
||||
<y>372</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>cb_wd_custom</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>le_wd_custom</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>188</x>
|
||||
<y>314</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>137</x>
|
||||
<y>372</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
75
src/Mod/Fem/Gui/DlgSettingsFemElmerImp.cpp
Normal file
75
src/Mod/Fem/Gui/DlgSettingsFemElmerImp.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/***************************************************************************
|
||||
* Copyright (c) 2015 FreeCAD Developers *
|
||||
* Author: Bernd Hahnebach <bernd@bimstatik.ch> *
|
||||
* Based on src/Mod/Fem/Gui/DlgSettingsFemCcxImp.cpp *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#include "PreCompiled.h"
|
||||
|
||||
#include "Gui/Application.h"
|
||||
#include "DlgSettingsFemElmerImp.h"
|
||||
#include <Gui/PrefWidgets.h>
|
||||
|
||||
using namespace FemGui;
|
||||
|
||||
DlgSettingsFemElmerImp::DlgSettingsFemElmerImp( QWidget* parent )
|
||||
: PreferencePage( parent )
|
||||
{
|
||||
this->setupUi(this);
|
||||
}
|
||||
|
||||
DlgSettingsFemElmerImp::~DlgSettingsFemElmerImp()
|
||||
{
|
||||
// no need to delete child widgets, Qt does it all for us
|
||||
}
|
||||
|
||||
void DlgSettingsFemElmerImp::saveSettings()
|
||||
{
|
||||
cb_elmer_binary_std->onSave();
|
||||
fc_elmer_binary_path->onSave();
|
||||
|
||||
cb_grid_binary_std->onSave();
|
||||
fc_grid_binary_path->onSave();
|
||||
}
|
||||
|
||||
void DlgSettingsFemElmerImp::loadSettings()
|
||||
{
|
||||
cb_elmer_binary_std->onRestore();
|
||||
fc_elmer_binary_path->onRestore();
|
||||
|
||||
cb_grid_binary_std->onRestore();
|
||||
fc_grid_binary_path->onRestore();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strings of the subwidgets using the current language.
|
||||
*/
|
||||
void DlgSettingsFemElmerImp::changeEvent(QEvent *e)
|
||||
{
|
||||
if (e->type() == QEvent::LanguageChange) {
|
||||
}
|
||||
else {
|
||||
QWidget::changeEvent(e);
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_DlgSettingsFemElmerImp.cpp"
|
||||
50
src/Mod/Fem/Gui/DlgSettingsFemElmerImp.h
Normal file
50
src/Mod/Fem/Gui/DlgSettingsFemElmerImp.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/**************************************************************************
|
||||
* Copyright (c) 2016 FreeCAD Developers *
|
||||
* Author: Bernd Hahnebach <bernd@bimstatik.ch> *
|
||||
* Based on src/Mod/Fem/Gui/DlgSettingsFemCcx.h *
|
||||
* *
|
||||
* This file is part of the FreeCAD CAx development system. *
|
||||
* *
|
||||
* This library is free software; you can redistribute it and/or *
|
||||
* modify it under the terms of the GNU Library General Public *
|
||||
* License as published by the Free Software Foundation; either *
|
||||
* version 2 of the License, or (at your option) any later version. *
|
||||
* *
|
||||
* This library is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Library General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Library General Public *
|
||||
* License along with this library; see the file COPYING.LIB. If not, *
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place, *
|
||||
* Suite 330, Boston, MA 02111-1307, USA *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
#ifndef FEMGUI_DLGSETTINGSFEMELMERIMP_H
|
||||
#define FEMGUI_DLGSETTINGSFEMELMERIMP_H
|
||||
|
||||
#include "ui_DlgSettingsFemElmer.h"
|
||||
#include <Gui/PropertyPage.h>
|
||||
|
||||
namespace FemGui {
|
||||
|
||||
class DlgSettingsFemElmerImp : public Gui::Dialog::PreferencePage, public Ui_DlgSettingsFemElmerImp
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DlgSettingsFemElmerImp( QWidget* parent = 0 );
|
||||
~DlgSettingsFemElmerImp();
|
||||
|
||||
protected:
|
||||
void saveSettings();
|
||||
void loadSettings();
|
||||
void changeEvent(QEvent *e);
|
||||
};
|
||||
|
||||
} // namespace FemGui
|
||||
|
||||
#endif // FEMGUI_DLGSETTINGSFEMELMERIMP_H
|
||||
@@ -34,6 +34,10 @@
|
||||
<file>icons/fem-cylinder.svg</file>
|
||||
<file>icons/fem-DataAlongLine.svg</file>
|
||||
<file>icons/fem-data.svg</file>
|
||||
<file>icons/fem-elmer.png</file>
|
||||
<file>icons/fem-equation-elasticity.svg</file>
|
||||
<file>icons/fem-equation-flow.svg</file>
|
||||
<file>icons/fem-equation-heat.svg</file>
|
||||
<file>icons/fem-femmesh-boundary-layer.svg</file>
|
||||
<file>icons/fem-femmesh-clear-mesh.svg</file>
|
||||
<file>icons/fem-femmesh-create-node-by-poly.svg</file>
|
||||
|
||||
BIN
src/Mod/Fem/Gui/Resources/icons/fem-elmer.png
Executable file
BIN
src/Mod/Fem/Gui/Resources/icons/fem-elmer.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
95
src/Mod/Fem/Gui/Resources/icons/fem-equation-elasticity.svg
Normal file
95
src/Mod/Fem/Gui/Resources/icons/fem-equation-elasticity.svg
Normal file
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
height="64"
|
||||
width="64">
|
||||
<defs
|
||||
id="defs4">
|
||||
<linearGradient
|
||||
id="linearGradient3802">
|
||||
<stop
|
||||
id="stop3804"
|
||||
offset="0"
|
||||
style="stop-color:#2e3436;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3806"
|
||||
offset="1"
|
||||
style="stop-color:#555753;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="42"
|
||||
x2="47"
|
||||
y1="58"
|
||||
x1="49"
|
||||
id="linearGradient3808"
|
||||
xlink:href="#linearGradient3802" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[Alexander Gryson]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>fem-warp</dc:title>
|
||||
<dc:date>2017-03-11</dc:date>
|
||||
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(0,-988.36218)"
|
||||
id="layer1">
|
||||
<rect
|
||||
transform="translate(0,988.36218)"
|
||||
y="39"
|
||||
x="3"
|
||||
height="22"
|
||||
width="58"
|
||||
id="rect2987"
|
||||
style="fill:url(#linearGradient3808);stroke:#172a04;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:9.59999999999999964;fill-opacity:1" />
|
||||
<rect
|
||||
y="1029.3622"
|
||||
x="5"
|
||||
height="18"
|
||||
width="54"
|
||||
id="rect2987-6"
|
||||
style="fill:none;stroke:#555753;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:9.6;stroke-opacity:1" />
|
||||
<path
|
||||
id="rect2987-3"
|
||||
d="m 3,1027.3622 c 18,0 24,-20 30,-32.00002 l 20,10.00002 c -4,8 -18,44 -50,44 z"
|
||||
style="fill:#888a85;stroke:#172a04;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:9.6;fill-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
258
src/Mod/Fem/Gui/Resources/icons/fem-equation-flow.svg
Normal file
258
src/Mod/Fem/Gui/Resources/icons/fem-equation-flow.svg
Normal file
@@ -0,0 +1,258 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64px"
|
||||
height="64px"
|
||||
id="svg2860"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.92.1 r"
|
||||
sodipodi:docname="fem-equation-flow.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs2862">
|
||||
<inkscape:path-effect
|
||||
effect="spiro"
|
||||
id="path-effect3038"
|
||||
is_visible="true" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377"
|
||||
id="radialGradient3692"
|
||||
cx="45.883327"
|
||||
cy="28.869568"
|
||||
fx="45.883327"
|
||||
fy="28.869568"
|
||||
r="19.467436"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377"
|
||||
id="radialGradient3703"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="135.38333"
|
||||
cy="97.369568"
|
||||
fx="135.38333"
|
||||
fy="97.369568"
|
||||
r="19.467436"
|
||||
gradientTransform="matrix(0.97435,0.2250379,-0.4623105,2.0016728,48.487554,-127.99883)" />
|
||||
<linearGradient
|
||||
id="linearGradient3377">
|
||||
<stop
|
||||
id="stop3379"
|
||||
offset="0"
|
||||
style="stop-color:#faff2b;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3381"
|
||||
offset="1"
|
||||
style="stop-color:#ffaa00;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3377"
|
||||
id="radialGradient3705"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
cx="148.88333"
|
||||
cy="81.869568"
|
||||
fx="148.88333"
|
||||
fy="81.869568"
|
||||
r="19.467436"
|
||||
gradientTransform="matrix(1.3852588,-5.1367833e-2,3.7056289e-2,0.9993132,-60.392403,7.7040438)" />
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective2868" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3809-5"
|
||||
id="linearGradient3815-7"
|
||||
x1="43"
|
||||
y1="58"
|
||||
x2="42"
|
||||
y2="48"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3809-5">
|
||||
<stop
|
||||
style="stop-color:#3465a4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3811-3" />
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3813-5" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="3.8890873"
|
||||
inkscape:cx="37.49133"
|
||||
inkscape:cy="21.628156"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:document-units="px"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="956"
|
||||
inkscape:window-height="1155"
|
||||
inkscape:window-x="2880"
|
||||
inkscape:window-y="43"
|
||||
inkscape:window-maximized="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3003"
|
||||
empspacing="2"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2865">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[qingfengxia]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>fem-constraint-fluid-boundary</dc:title>
|
||||
<dc:date>2016-08-10</dc:date>
|
||||
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g2689"
|
||||
transform="translate(1.4142133,-1.5706127)">
|
||||
<g
|
||||
transform="matrix(0.94877631,0,0,0.94877631,0.22494458,3.1949428)"
|
||||
id="g2671">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 9.466838,26.650801 14.178715,32 9.418501,37.380527"
|
||||
id="path3907-3-0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 56.058735,32 H 7.9412655"
|
||||
id="path3881"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#729fcf;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 56.058735,32 H 7.9412655"
|
||||
id="path3881-0"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:none;stroke:#729fcf;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 9.466838,26.650801 14.178715,32 9.418501,37.380527"
|
||||
id="path3907-9-6-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.94877631,0,0,0.94877631,0.22494458,3.5249658)"
|
||||
id="g2665">
|
||||
<g
|
||||
id="g2643"
|
||||
transform="translate(0,2.7272727)">
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3907-3"
|
||||
d="m 7.9412655,45.365964 h 7.1285135 l 0.891065,7.128514"
|
||||
style="fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3861-1"
|
||||
d="M 56.058735,40.019578 H 27.544679 c -10.692771,0 -15.148092,8.019578 -19.6034135,16.039157"
|
||||
style="fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3861-1-7"
|
||||
d="M 56.058735,40.019578 H 27.544679 c -10.692771,0 -15.148092,8.019578 -19.6034135,16.039157"
|
||||
style="fill:none;stroke:#729fcf;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3907-9-6"
|
||||
d="m 7.9412655,45.365964 h 7.1285135 l 0.891065,7.128514"
|
||||
style="fill:none;stroke:#729fcf;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(1,0,0,-1,0,60.608303)"
|
||||
id="g2653">
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 7.9412655,45.365964 h 7.1285135 l 0.891065,7.128514"
|
||||
id="path2645"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:7;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 56.058735,40.019578 H 27.544679 c -10.692771,0 -15.148092,8.019578 -19.6034135,16.039157"
|
||||
id="path2647"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#729fcf;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 56.058735,40.019578 H 27.544679 c -10.692771,0 -15.148092,8.019578 -19.6034135,16.039157"
|
||||
id="path2649"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#729fcf;stroke-width:3;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 7.9412655,45.365964 h 7.1285135 l 0.891065,7.128514"
|
||||
id="path2651"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.7 KiB |
173
src/Mod/Fem/Gui/Resources/icons/fem-equation-heat.svg
Normal file
173
src/Mod/Fem/Gui/Resources/icons/fem-equation-heat.svg
Normal file
@@ -0,0 +1,173 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
id="svg2860"
|
||||
height="64px"
|
||||
width="64px">
|
||||
<defs
|
||||
id="defs2862">
|
||||
<linearGradient
|
||||
id="linearGradient3929">
|
||||
<stop
|
||||
id="stop3931"
|
||||
offset="0"
|
||||
style="stop-color:#a40000;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop3933"
|
||||
offset="1"
|
||||
style="stop-color:#ef2929;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
gradientTransform="matrix(0.97435,0.2250379,-0.4623105,2.0016728,48.487554,-127.99883)"
|
||||
r="19.467436"
|
||||
fy="97.369568"
|
||||
fx="135.38333"
|
||||
cy="97.369568"
|
||||
cx="135.38333"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3703"
|
||||
xlink:href="#linearGradient3377" />
|
||||
<linearGradient
|
||||
id="linearGradient3377">
|
||||
<stop
|
||||
style="stop-color:#faff2b;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3379" />
|
||||
<stop
|
||||
style="stop-color:#ffaa00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3381" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
gradientTransform="matrix(1.3852588,-0.05136783,0.03705629,0.9993132,-60.392403,7.7040438)"
|
||||
r="19.467436"
|
||||
fy="81.869568"
|
||||
fx="148.88333"
|
||||
cy="81.869568"
|
||||
cx="148.88333"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3705"
|
||||
xlink:href="#linearGradient3377" />
|
||||
<radialGradient
|
||||
gradientTransform="matrix(0.97435,0.2250379,-0.4623105,2.0016728,48.487554,-127.99883)"
|
||||
r="19.467436"
|
||||
fy="97.369568"
|
||||
fx="135.38333"
|
||||
cy="97.369568"
|
||||
cx="135.38333"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3703-8"
|
||||
xlink:href="#linearGradient3377-4" />
|
||||
<linearGradient
|
||||
id="linearGradient3377-4">
|
||||
<stop
|
||||
style="stop-color:#faff2b;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3379-3" />
|
||||
<stop
|
||||
style="stop-color:#ffaa00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3381-0" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="51.200001"
|
||||
x2="4.8000002"
|
||||
y1="60.799999"
|
||||
x1="9.6000004"
|
||||
id="linearGradient3935"
|
||||
xlink:href="#linearGradient3929" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata2865">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>[vdwalts]</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:title>fem-constraint-temperature</dc:title>
|
||||
<dc:date>2016-08-01</dc:date>
|
||||
<dc:relation>http://www.freecadweb.org/wiki/index.php?title=Artwork</dc:relation>
|
||||
<dc:publisher>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:publisher>
|
||||
<dc:identifier>FreeCAD/src/Mod/</dc:identifier>
|
||||
<dc:rights>
|
||||
<cc:Agent>
|
||||
<dc:title>FreeCAD LGPL2+</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:rights>
|
||||
<cc:license>https://www.gnu.org/copyleft/lesser.html</cc:license>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>[agryson] Alexander Gryson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1">
|
||||
<g
|
||||
transform="matrix(1.569104,0,0,1.569104,16.30896,-37.780432)"
|
||||
id="g6350">
|
||||
<path
|
||||
style="fill:none;stroke:#280000;stroke-width:8;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 10,31 V 57"
|
||||
id="path3083" />
|
||||
<circle
|
||||
r="8"
|
||||
cy="56"
|
||||
cx="8"
|
||||
style="fill:#cc0000;stroke:#280000;stroke-width:2.28571439;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none"
|
||||
id="path3909"
|
||||
transform="matrix(0.875,0,0,0.875,3,5)" />
|
||||
<path
|
||||
style="fill:none;stroke:#d3d7cf;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 10,31 V 57"
|
||||
id="path3083-3" />
|
||||
<path
|
||||
style="fill:none;stroke:#cc0000;stroke-width:4;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 10,40 V 56"
|
||||
id="path3083-3-6" />
|
||||
<path
|
||||
style="fill:none;stroke:#ef2929;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 9,40 V 50"
|
||||
id="path3083-3-6-7" />
|
||||
<circle
|
||||
r="8"
|
||||
cy="56"
|
||||
cx="8"
|
||||
style="fill:url(#linearGradient3935);fill-opacity:1;stroke:#ef2929;stroke-width:3.20000005;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-dasharray:none"
|
||||
id="path3909-5"
|
||||
transform="matrix(0.625,0,0,0.625,5,19)" />
|
||||
<path
|
||||
style="fill:none;stroke:#280000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 11,33 h 2"
|
||||
id="path3937" />
|
||||
<path
|
||||
style="fill:none;stroke:#280000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 11,39 h 2"
|
||||
id="path3937-3" />
|
||||
<path
|
||||
style="fill:none;stroke:#280000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 11,45 h 2"
|
||||
id="path3937-5" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
@@ -112,6 +112,11 @@ Gui::ToolBarItem* Workbench::setupToolBars() const
|
||||
Gui::ToolBarItem* solve = new Gui::ToolBarItem(root);
|
||||
solve->setCommand("Solve");
|
||||
*solve << "FEM_SolverCalculix"
|
||||
<< "FEM_AddSolverElmer"
|
||||
<< "Separator"
|
||||
<< "FEM_AddEquationHeat"
|
||||
<< "FEM_AddEquationElasticity"
|
||||
<< "FEM_AddEquationFlow"
|
||||
<< "Separator"
|
||||
<< "FEM_SolverControl"
|
||||
<< "FEM_SolverRun";
|
||||
@@ -209,6 +214,11 @@ Gui::MenuItem* Workbench::setupMenuBar() const
|
||||
solve->setCommand("&Solve");
|
||||
*solve << "FEM_SolverCalculix"
|
||||
<< "FEM_SolverZ88"
|
||||
<< "FEM_AddSolverElmer"
|
||||
<< "Separator"
|
||||
<< "FEM_AddEquationHeat"
|
||||
<< "FEM_AddEquationElasticity"
|
||||
<< "FEM_AddEquationFlow"
|
||||
<< "Separator"
|
||||
<< "FEM_SolverControl"
|
||||
<< "FEM_SolverRun";
|
||||
|
||||
@@ -67,6 +67,8 @@ class FemWorkbench (Workbench):
|
||||
import PyGui._CommandFemResultShow
|
||||
import PyGui._CommandFemResultsPurge
|
||||
import PyGui._CommandFemSolverCalculix
|
||||
import PyGui._CommandFemSolverElmer
|
||||
import PyGui._CommandFemEquation
|
||||
import PyGui._CommandFemSolverControl
|
||||
import PyGui._CommandFemSolverRun
|
||||
import PyGui._CommandFemSolverZ88
|
||||
|
||||
@@ -361,6 +361,13 @@ def makeSolverCalculix(doc, name="SolverCalculiX"):
|
||||
return obj
|
||||
|
||||
|
||||
def makeSolverElmer(doc, name="SolverElmer"):
|
||||
'''makeSolverElmer(document, [name]): makes a Elmer solver object'''
|
||||
import femsolver.elmer.solver
|
||||
obj = femsolver.elmer.solver.create(doc, name)
|
||||
return obj
|
||||
|
||||
|
||||
def makeSolverZ88(doc, name="SolverZ88"):
|
||||
'''makeSolverZ88(document, [name]): makes a Z88 solver object'''
|
||||
import femsolver.z88.solver
|
||||
|
||||
102
src/Mod/Fem/PyGui/_CommandFemEquation.py
Normal file
102
src/Mod/Fem/PyGui/_CommandFemEquation.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "_CommandFemEquation"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
from PySide import QtCore
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
import FemUtils
|
||||
|
||||
|
||||
class _Base(QtCore.QObject):
|
||||
|
||||
def getSpecifier(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def Activated(self):
|
||||
s = Gui.Selection.getSelection()
|
||||
if len(s) == 1 and FemUtils.isDerivedFrom(s[0], "Fem::FemSolverObject"):
|
||||
App.ActiveDocument.openTransaction(
|
||||
"Add %s equation to %s"
|
||||
% (self.getSpecifier(), s[0].Label))
|
||||
Gui.doCommand(
|
||||
"App.ActiveDocument.%(obj)s.Proxy.addEquation("
|
||||
"App.ActiveDocument.%(obj)s, '%(name)s')"
|
||||
% {"obj": s[0].Name, "name": self.getSpecifier()})
|
||||
App.ActiveDocument.commitTransaction()
|
||||
App.ActiveDocument.recompute()
|
||||
|
||||
def IsActive(self):
|
||||
s = Gui.Selection.getSelection()
|
||||
if len(s) == 1 and FemUtils.isDerivedFrom(s[0], "Fem::FemSolverObject"):
|
||||
return s[0].Proxy.isSupported(self.getSpecifier())
|
||||
return False
|
||||
|
||||
|
||||
class Heat(_Base):
|
||||
|
||||
def getSpecifier(self):
|
||||
return "Heat"
|
||||
|
||||
def GetResources(self):
|
||||
return {
|
||||
'Pixmap': 'fem-equation-heat',
|
||||
'MenuText': "Heat Equation",
|
||||
'ToolTip': "Creates a FEM constraint body heat flux"
|
||||
}
|
||||
|
||||
|
||||
class Elasticity(_Base):
|
||||
|
||||
def getSpecifier(self):
|
||||
return "Elasticity"
|
||||
|
||||
def GetResources(self):
|
||||
return {
|
||||
'Pixmap': 'fem-equation-elasticity',
|
||||
'MenuText': "Elasticity Equation",
|
||||
'ToolTip': "Creates a FEM constraint for elasticity"
|
||||
}
|
||||
|
||||
|
||||
class Flow(_Base):
|
||||
|
||||
def getSpecifier(self):
|
||||
return "Flow"
|
||||
|
||||
def GetResources(self):
|
||||
return {
|
||||
'Pixmap': 'fem-equation-flow',
|
||||
'MenuText': "Flow Equation",
|
||||
'ToolTip': "Creates a FEM constraint body heat flux"
|
||||
}
|
||||
|
||||
|
||||
Gui.addCommand('FEM_AddEquationHeat', Heat())
|
||||
Gui.addCommand('FEM_AddEquationElasticity', Elasticity())
|
||||
Gui.addCommand('FEM_AddEquationFlow', Flow())
|
||||
63
src/Mod/Fem/PyGui/_CommandFemSolverElmer.py
Normal file
63
src/Mod/Fem/PyGui/_CommandFemSolverElmer.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "Elmer"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
from PySide import QtCore
|
||||
|
||||
import FreeCAD as App
|
||||
import FreeCADGui as Gui
|
||||
import FemGui
|
||||
|
||||
|
||||
class Command(QtCore.QObject):
|
||||
|
||||
def Activated(self):
|
||||
analysis = FemGui.getActiveAnalysis()
|
||||
App.ActiveDocument.openTransaction("Create Elmer solver object")
|
||||
Gui.addModule("femsolver.elmer.solver")
|
||||
Gui.doCommand(
|
||||
"App.ActiveDocument.%s.Member += "
|
||||
"[femsolver.elmer.solver.create(App.ActiveDocument)]"
|
||||
% analysis.Name)
|
||||
App.ActiveDocument.commitTransaction()
|
||||
App.ActiveDocument.recompute()
|
||||
|
||||
def GetResources(self):
|
||||
return {
|
||||
'Pixmap': 'fem-elmer',
|
||||
'MenuText': "Solver Elmer",
|
||||
'Accel': "S, E",
|
||||
'ToolTip': "Creates a FEM solver Elmer"
|
||||
}
|
||||
|
||||
def IsActive(self):
|
||||
analysis = FemGui.getActiveAnalysis()
|
||||
return (analysis is not None
|
||||
and analysis.Document == App.ActiveDocument)
|
||||
|
||||
|
||||
Gui.addCommand('FEM_AddSolverElmer', Command())
|
||||
@@ -54,6 +54,8 @@ class _CommandFemSolverRun(FemCommands):
|
||||
self.solver = FreeCADGui.Selection.getSelection()[0] # see 'with_solver' in FemCommands for selection check
|
||||
if FemUtils.isDerivedFrom(self.solver, "Fem::FemSolverObjectZ88"):
|
||||
self._newActivated()
|
||||
elif FemUtils.isDerivedFrom(self.solver, "Fem::FemSolverObjectElmer"):
|
||||
self._newActivated()
|
||||
elif FemUtils.isDerivedFrom(self.solver, "Fem::FemSolverObjectCalculix"):
|
||||
self._newActivated()
|
||||
elif self.solver.SolverType == "FemSolverCalculix":
|
||||
|
||||
0
src/Mod/Fem/femsolver/elmer/__init__.py
Normal file
0
src/Mod/Fem/femsolver/elmer/__init__.py
Normal file
0
src/Mod/Fem/femsolver/elmer/equations/__init__.py
Normal file
0
src/Mod/Fem/femsolver/elmer/equations/__init__.py
Normal file
68
src/Mod/Fem/femsolver/elmer/equations/elasticity.py
Normal file
68
src/Mod/Fem/femsolver/elmer/equations/elasticity.py
Normal file
@@ -0,0 +1,68 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "Elasticity"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
import FemUtils
|
||||
from ... import equationbase
|
||||
from . import linear
|
||||
|
||||
|
||||
def create(doc, name="Elasticity"):
|
||||
return FemUtils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(linear.Proxy, equationbase.ElasticityProxy):
|
||||
|
||||
Type = "Fem::FemEquationElmerElasticity"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
obj.addProperty(
|
||||
"App::PropertyBool", "DoFrequencyAnalysis",
|
||||
"Elasticity", "Select type of solver for linear system")
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "EigenmodesCount",
|
||||
"Elasticity", "Select type of solver for linear system")
|
||||
obj.addProperty(
|
||||
"App::PropertyBool", "CalculateStrains",
|
||||
"Elasticity", "Select type of solver for linear system")
|
||||
obj.addProperty(
|
||||
"App::PropertyBool", "CalculateStresses",
|
||||
"Elasticity", "Select type of solver for linear system")
|
||||
obj.addProperty(
|
||||
"App::PropertyBool", "CalculatePrincipal",
|
||||
"Elasticity", "Select type of solver for linear system")
|
||||
obj.addProperty(
|
||||
"App::PropertyBool", "CalculatePangle",
|
||||
"Elasticity", "Select type of solver for linear system")
|
||||
obj.EigenmodesCount = 5
|
||||
obj.Priority = 10
|
||||
|
||||
|
||||
class ViewProxy(linear.ViewProxy, equationbase.ElasticityViewProxy):
|
||||
pass
|
||||
111
src/Mod/Fem/femsolver/elmer/equations/equation.py
Normal file
111
src/Mod/Fem/femsolver/elmer/equations/equation.py
Normal file
@@ -0,0 +1,111 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "Equation"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
import FreeCAD as App
|
||||
from ... import equationbase
|
||||
import FemUtils
|
||||
|
||||
if App.GuiUp:
|
||||
import FreeCADGui as Gui
|
||||
import PyGui.FemSelectionWidgets as FemSelectionWidgets
|
||||
|
||||
|
||||
class Proxy(equationbase.BaseProxy):
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "Priority",
|
||||
"Base", "Select type of solver for linear system")
|
||||
|
||||
|
||||
class ViewProxy(equationbase.BaseViewProxy):
|
||||
|
||||
def setEdit(self, vobj, mode=0):
|
||||
task = _TaskPanel(vobj.Object)
|
||||
Gui.Control.showDialog(task)
|
||||
|
||||
def unsetEdit(self, vobj, mode=0):
|
||||
Gui.Control.closeDialog()
|
||||
|
||||
def doubleClicked(self, vobj):
|
||||
if Gui.Control.activeDialog():
|
||||
Gui.Control.closeDialog()
|
||||
Gui.ActiveDocument.setEdit(vobj.Object.Name)
|
||||
return True
|
||||
|
||||
def getTaskWidget(self, vobj):
|
||||
return None
|
||||
|
||||
|
||||
class _TaskPanel(object):
|
||||
|
||||
def __init__(self, obj):
|
||||
self._obj = obj
|
||||
self._refWidget = FemSelectionWidgets.SolidSelector()
|
||||
self._refWidget.setReferences(obj.References)
|
||||
propWidget = obj.ViewObject.Proxy.getTaskWidget(
|
||||
obj.ViewObject)
|
||||
if propWidget is None:
|
||||
self.form = self._refWidget
|
||||
else:
|
||||
self.form = [self.refWidget, propWidget]
|
||||
analysis = FemUtils.findAnalysisOfMember(obj)
|
||||
self._mesh = FemUtils.getSingleMember(analysis, "Fem::FemMeshObject")
|
||||
self._part = self._mesh.Part if self._mesh is not None else None
|
||||
self._partVisible = None
|
||||
self._meshVisible = None
|
||||
|
||||
def open(self):
|
||||
if self._mesh is not None and self._part is not None:
|
||||
self._meshVisible = self._mesh.ViewObject.isVisible()
|
||||
self._partVisible = self._part.ViewObject.isVisible()
|
||||
self._mesh.ViewObject.hide()
|
||||
self._part.ViewObject.show()
|
||||
|
||||
def reject(self):
|
||||
self._restoreVisibility()
|
||||
return True
|
||||
|
||||
def accept(self):
|
||||
if self._obj.References != self._refWidget.references():
|
||||
self._obj.References = self._refWidget.references()
|
||||
self._obj.Document.recompute()
|
||||
self._restoreVisibility()
|
||||
return True
|
||||
|
||||
def _restoreVisibility(self):
|
||||
if self._mesh is not None and self._part is not None:
|
||||
if self._meshVisible:
|
||||
self._mesh.ViewObject.show()
|
||||
else:
|
||||
self._mesh.ViewObject.hide()
|
||||
if self._partVisible:
|
||||
self._part.ViewObject.show()
|
||||
else:
|
||||
self._part.ViewObject.hide()
|
||||
49
src/Mod/Fem/femsolver/elmer/equations/flow.py
Normal file
49
src/Mod/Fem/femsolver/elmer/equations/flow.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "Flow"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
import FemUtils
|
||||
from . import nonlinear
|
||||
from ... import equationbase
|
||||
|
||||
|
||||
def create(doc, name="Flow"):
|
||||
return FemUtils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(nonlinear.Proxy, equationbase.FlowProxy):
|
||||
|
||||
Type = "Fem::FemEquationElmerFlow"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
obj.Priority = 10
|
||||
|
||||
|
||||
class ViewProxy(nonlinear.ViewProxy, equationbase.FlowViewProxy):
|
||||
pass
|
||||
49
src/Mod/Fem/femsolver/elmer/equations/heat.py
Normal file
49
src/Mod/Fem/femsolver/elmer/equations/heat.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "Heat"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
import FemUtils
|
||||
from . import nonlinear
|
||||
from ... import equationbase
|
||||
|
||||
|
||||
def create(doc, name="Heat"):
|
||||
return FemUtils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(nonlinear.Proxy, equationbase.HeatProxy):
|
||||
|
||||
Type = "Fem::FemEquationElmerHeat"
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
obj.Priority = 20
|
||||
|
||||
|
||||
class ViewProxy(nonlinear.ViewProxy, equationbase.HeatViewProxy):
|
||||
pass
|
||||
103
src/Mod/Fem/femsolver/elmer/equations/linear.py
Normal file
103
src/Mod/Fem/femsolver/elmer/equations/linear.py
Normal file
@@ -0,0 +1,103 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "_Linear"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
from . import equation
|
||||
|
||||
|
||||
LINEAR_SOLVER = ["Direct", "Iterative"]
|
||||
LINEAR_DIRECT = ["Banded", "umfpack"]
|
||||
LINEAR_ITERATIVE = [
|
||||
"CG",
|
||||
"CGS",
|
||||
"BiCGStab",
|
||||
"BiCGStabl",
|
||||
"TFQMR",
|
||||
"GMRES",
|
||||
"GCR",
|
||||
]
|
||||
LINEAR_PRECONDITIONING = [
|
||||
"None",
|
||||
"Diagonal",
|
||||
"ILU0",
|
||||
"ILU1",
|
||||
"ILU2",
|
||||
"ILU3",
|
||||
"ILU4",
|
||||
]
|
||||
|
||||
|
||||
class Proxy(equation.Proxy):
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration", "LinearSolverType",
|
||||
"Linear System", "Select type of solver for linear system")
|
||||
obj.LinearSolverType = LINEAR_SOLVER
|
||||
obj.LinearSolverType = "Iterative"
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration", "LinearDirectMethod",
|
||||
"Linear System", "Select type of solver for linear system")
|
||||
obj.LinearDirectMethod = LINEAR_DIRECT
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration", "LinearIterativeMethod",
|
||||
"Linear System", "Select type of solver for linear system")
|
||||
obj.LinearIterativeMethod = LINEAR_ITERATIVE
|
||||
obj.LinearIterativeMethod = "BiCGStab"
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "BiCGstablDegree",
|
||||
"Linear System", "Select type of solver for linear system")
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration", "LinearPreconditioning",
|
||||
"Linear System", "Select type of solver for linear system")
|
||||
obj.LinearPreconditioning = LINEAR_PRECONDITIONING
|
||||
obj.LinearPreconditioning = "ILU0"
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat", "LinearTolerance",
|
||||
"Linear System", "Select type of solver for linear system")
|
||||
obj.LinearTolerance = 1e-8
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "LinearIterations",
|
||||
"Linear System", "Select type of solver for linear system")
|
||||
obj.LinearIterations = 500
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat", "SteadyStateTolerance",
|
||||
"Steady State", "Select type of solver for linear system")
|
||||
obj.SteadyStateTolerance = 1e-5
|
||||
obj.addProperty(
|
||||
"App::PropertyBool", "Stabilize",
|
||||
"Base", "Select type of solver for linear system")
|
||||
obj.Stabilize = True
|
||||
obj.addProperty(
|
||||
"App::PropertyBool", "Bubbles",
|
||||
"Base", "Select type of solver for linear system")
|
||||
obj.Bubbles = False
|
||||
|
||||
|
||||
class ViewProxy(equation.ViewProxy):
|
||||
pass
|
||||
59
src/Mod/Fem/femsolver/elmer/equations/nonlinear.py
Normal file
59
src/Mod/Fem/femsolver/elmer/equations/nonlinear.py
Normal file
@@ -0,0 +1,59 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "_NonLinear"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
from . import linear
|
||||
|
||||
|
||||
class Proxy(linear.Proxy):
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat", "NonlinearTolerance",
|
||||
"Nonlinear System", "Select type of solver for linear system")
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "NonlinearIterations",
|
||||
"Nonlinear System", "Select type of solver for linear system")
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat", "RelaxationFactor",
|
||||
"Nonlinear System", "Select type of solver for linear system")
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "NonlinearNewtonAfterIterations",
|
||||
"Nonlinear System", "Select type of solver for linear system")
|
||||
obj.addProperty(
|
||||
"App::PropertyFloat", "NonlinearNewtonAfterTolerance",
|
||||
"Nonlinear System", "Select type of solver for linear system")
|
||||
obj.NonlinearTolerance = 1e-8
|
||||
obj.NonlinearIterations = 500
|
||||
obj.RelaxationFactor = 1
|
||||
obj.NonlinearNewtonAfterIterations = 3
|
||||
obj.NonlinearNewtonAfterTolerance = 1e-3
|
||||
|
||||
|
||||
class ViewProxy(linear.ViewProxy):
|
||||
pass
|
||||
429
src/Mod/Fem/femsolver/elmer/sifio.py
Normal file
429
src/Mod/Fem/femsolver/elmer/sifio.py
Normal file
@@ -0,0 +1,429 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2016 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
import collections
|
||||
|
||||
|
||||
SIMULATION = "Simulation"
|
||||
CONSTANTS = "Constants"
|
||||
BODY = "Body"
|
||||
MATERIAL = "Material"
|
||||
BODY_FORCE = "Body Force"
|
||||
EQUATION = "Equation"
|
||||
SOLVER = "Solver"
|
||||
BOUNDARY_CONDITION = "Boundary Condition"
|
||||
INITIAL_CONDITION = "Initial Condition"
|
||||
COMPONENT = "Component"
|
||||
|
||||
|
||||
_VALID_SECTIONS = (
|
||||
SIMULATION,
|
||||
CONSTANTS,
|
||||
BODY,
|
||||
MATERIAL,
|
||||
BODY_FORCE,
|
||||
EQUATION,
|
||||
SOLVER,
|
||||
BOUNDARY_CONDITION,
|
||||
INITIAL_CONDITION,
|
||||
COMPONENT,
|
||||
)
|
||||
|
||||
|
||||
_NUMBERED_SECTIONS = (
|
||||
BODY,
|
||||
MATERIAL,
|
||||
BODY_FORCE,
|
||||
EQUATION,
|
||||
SOLVER,
|
||||
BOUNDARY_CONDITION,
|
||||
INITIAL_CONDITION,
|
||||
COMPONENT,
|
||||
)
|
||||
|
||||
|
||||
_SECTION_DELIM = "End"
|
||||
_WHITESPACE = " "
|
||||
_INDENT = " " * 2
|
||||
_NEWLINE = "\n"
|
||||
|
||||
|
||||
_TYPE_REAL = "Real"
|
||||
_TYPE_INTEGER = "Integer"
|
||||
_TYPE_LOGICAL = "Logical"
|
||||
_TYPE_STRING = "String"
|
||||
_TYPE_FILE = "File"
|
||||
|
||||
|
||||
WARN = "Warn"
|
||||
IGNORE = "Ignore"
|
||||
ABORT = "Abort"
|
||||
SILENT = "Silent"
|
||||
|
||||
|
||||
def createSection(name):
|
||||
section = Section(name)
|
||||
if not isValid(section):
|
||||
raise ValueError("Invalid section name: %s" % name)
|
||||
return section
|
||||
|
||||
|
||||
def writeSections(sections, stream):
|
||||
ids = _IdManager()
|
||||
_Writer(ids, sections, stream).write()
|
||||
|
||||
|
||||
def isNumbered(section):
|
||||
return section.name in _NUMBERED_SECTIONS
|
||||
|
||||
|
||||
def isValid(section):
|
||||
return section.name in _VALID_SECTIONS
|
||||
|
||||
|
||||
class Builder(object):
|
||||
|
||||
_ACTIVE_SOLVERS = "Active Solvers"
|
||||
|
||||
def __init__(self):
|
||||
self._customSections = set()
|
||||
self._simulation = createSection(SIMULATION)
|
||||
self._constants = createSection(CONSTANTS)
|
||||
self._bodies = {}
|
||||
self._boundaries = {}
|
||||
|
||||
def getBoundaryNames(self):
|
||||
return self._boundaries.keys()
|
||||
|
||||
def getBodyNames(self):
|
||||
return self._bodies.keys()
|
||||
|
||||
def simulation(self, key, attr):
|
||||
self._simulation[key] = attr
|
||||
|
||||
def constant(self, key, attr):
|
||||
self._constants[key] = attr
|
||||
|
||||
def initial(self, body, key, attr):
|
||||
section = self._getFromBody(body, INITIAL_CONDITION)
|
||||
section[key] = attr
|
||||
|
||||
def material(self, body, key, attr):
|
||||
section = self._getFromBody(body, MATERIAL)
|
||||
section[key] = attr
|
||||
|
||||
def equation(self, body, key, attr):
|
||||
section = self._getFromBody(body, EQUATION)
|
||||
section[key] = attr
|
||||
|
||||
def bodyForce(self, body, key, attr):
|
||||
section = self._getFromBody(body, BODY_FORCE)
|
||||
section[key] = attr
|
||||
|
||||
def addSolver(self, body, solverSection):
|
||||
section = self._getFromBody(body, EQUATION)
|
||||
if self._ACTIVE_SOLVERS not in section:
|
||||
section[self._ACTIVE_SOLVERS] = []
|
||||
section[self._ACTIVE_SOLVERS].append(solverSection)
|
||||
|
||||
def boundary(self, boundary, key, attr):
|
||||
if boundary not in self._boundaries:
|
||||
self._boundaries[boundary] = createSection(BOUNDARY_CONDITION)
|
||||
self._boundaries[boundary][key] = attr
|
||||
|
||||
def addSection(self, section):
|
||||
self._customSections.add(section)
|
||||
|
||||
def _getFromBody(self, body, key):
|
||||
if body not in self._bodies:
|
||||
self._bodies[body] = createSection(BODY)
|
||||
if key not in self._bodies[body]:
|
||||
self._bodies[body][key] = createSection(key)
|
||||
return self._bodies[body][key]
|
||||
|
||||
def __iter__(self):
|
||||
allSections = set(self._customSections)
|
||||
allSections.add(self._simulation)
|
||||
allSections.add(self._constants)
|
||||
for name, section in self._bodies.iteritems():
|
||||
section["Name"] = name
|
||||
allSections.add(section)
|
||||
if MATERIAL in section:
|
||||
allSections.add(section[MATERIAL])
|
||||
if EQUATION in section:
|
||||
eqSection = section[EQUATION]
|
||||
allSections.add(eqSection)
|
||||
if self._ACTIVE_SOLVERS in eqSection:
|
||||
for solverSection in eqSection[self._ACTIVE_SOLVERS]:
|
||||
allSections.add(solverSection)
|
||||
if BODY_FORCE in section:
|
||||
allSections.add(section[BODY_FORCE])
|
||||
if INITIAL_CONDITION in section:
|
||||
allSections.add(section[INITIAL_CONDITION])
|
||||
for name, section in self._boundaries.iteritems():
|
||||
section["Name"] = name
|
||||
allSections.add(section)
|
||||
return iter(allSections)
|
||||
|
||||
|
||||
class Sif(object):
|
||||
|
||||
_CHECK_KEYWORDS = "Check Keywords"
|
||||
_HEADER = "Header"
|
||||
_MESHDB_ATTR = "Mesh DB"
|
||||
_INCLUDE_ATTR = "Include Path"
|
||||
_RESULT_ATTR = "Results Directory"
|
||||
|
||||
def __init__(self, sections=[], meshLocation="."):
|
||||
self.sections = sections
|
||||
self.meshPath = meshLocation
|
||||
self.checkKeywords = WARN
|
||||
self.incPath = ""
|
||||
self.resPath = ""
|
||||
|
||||
def write(self, stream):
|
||||
self._writeCheckKeywords(stream)
|
||||
stream.write(_NEWLINE * 2)
|
||||
self._writeHeader(stream)
|
||||
stream.write(_NEWLINE * 2)
|
||||
writeSections(self.sections, stream)
|
||||
|
||||
def _writeCheckKeywords(self, stream):
|
||||
stream.write(self._CHECK_KEYWORDS)
|
||||
stream.write(_WHITESPACE)
|
||||
stream.write(self.checkKeywords)
|
||||
|
||||
def _writeHeader(self, stream):
|
||||
stream.write(self._HEADER)
|
||||
stream.write(_NEWLINE)
|
||||
self._writeAttr(self._MESHDB_ATTR, self.meshPath, stream)
|
||||
stream.write(_NEWLINE)
|
||||
if self.incPath:
|
||||
self._writeAttr(self._INCLUDE_ATTR, self.incPath, stream)
|
||||
stream.write(_NEWLINE)
|
||||
if self.resPath:
|
||||
self._writeAttr(self._RESULT_ATTR, self.resPath, stream)
|
||||
stream.write(_NEWLINE)
|
||||
stream.write(_SECTION_DELIM)
|
||||
|
||||
def _writeAttr(self, name, value, stream):
|
||||
stream.write(_INDENT)
|
||||
stream.write(name)
|
||||
stream.write(_WHITESPACE)
|
||||
stream.write('"%s"' % value)
|
||||
|
||||
|
||||
class Section(object):
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.priority = 0
|
||||
self._attrs = dict()
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._attrs[key] = value
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self._attrs[key]
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._attrs[key]
|
||||
|
||||
def __iter__(self):
|
||||
return self._attrs.iteritems()
|
||||
|
||||
def __contains__(self, item):
|
||||
return item in self._attrs
|
||||
|
||||
def __str__(self):
|
||||
return str(self._attrs)
|
||||
|
||||
def __repr__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class FileAttr(str):
|
||||
pass
|
||||
|
||||
|
||||
class _Writer(object):
|
||||
|
||||
def __init__(self, idManager, sections, stream):
|
||||
self._idMgr = idManager
|
||||
self._sections = sections
|
||||
self._stream = stream
|
||||
|
||||
def write(self):
|
||||
sortedSections = sorted(
|
||||
self._sections, key=lambda s: s.priority, reverse=True)
|
||||
for s in sortedSections:
|
||||
self._writeSection(s)
|
||||
self._stream.write(_NEWLINE)
|
||||
|
||||
def _writeSection(self, s):
|
||||
self._writeSectionHeader(s)
|
||||
self._writeSectionBody(s)
|
||||
self._writeSectionFooter(s)
|
||||
self._stream.write(_NEWLINE)
|
||||
|
||||
def _writeSectionHeader(self, s):
|
||||
self._stream.write(s.name)
|
||||
self._stream.write(_WHITESPACE)
|
||||
if isNumbered(s):
|
||||
self._stream.write(str(self._idMgr.getId(s)))
|
||||
|
||||
def _writeSectionFooter(self, s):
|
||||
self._stream.write(_NEWLINE)
|
||||
self._stream.write(_SECTION_DELIM)
|
||||
|
||||
def _writeSectionBody(self, s):
|
||||
for key, data in s:
|
||||
self._writeAttribute(key, data)
|
||||
|
||||
def _writeAttribute(self, key, data):
|
||||
if isinstance(data, Section):
|
||||
self._stream.write(_NEWLINE)
|
||||
self._writeScalarAttr(key, data)
|
||||
elif isinstance(data, FileAttr):
|
||||
self._stream.write(_NEWLINE)
|
||||
self._writeFileAttr(key, data)
|
||||
elif self._isCollection(data):
|
||||
if len(data) == 1:
|
||||
scalarData = self._getOnlyElement(data)
|
||||
self._stream.write(_NEWLINE)
|
||||
self._writeScalarAttr(key, scalarData)
|
||||
elif len(data) > 1:
|
||||
self._stream.write(_NEWLINE)
|
||||
self._writeArrAttr(key, data)
|
||||
else:
|
||||
self._stream.write(_NEWLINE)
|
||||
self._writeScalarAttr(key, data)
|
||||
|
||||
def _getOnlyElement(self, collection):
|
||||
it = iter(collection)
|
||||
return it.next()
|
||||
|
||||
def _isCollection(self, data):
|
||||
return (not isinstance(data, basestring)
|
||||
and isinstance(data, collections.Iterable))
|
||||
|
||||
def _checkScalar(self, dataType):
|
||||
if issubclass(dataType, int):
|
||||
return self._genIntAttr
|
||||
if issubclass(dataType, float):
|
||||
return self._genFloatAttr
|
||||
if issubclass(dataType, bool):
|
||||
return self._genBoolAttr
|
||||
if issubclass(dataType, basestring):
|
||||
return self._genStrAttr
|
||||
return None
|
||||
|
||||
def _writeScalarAttr(self, key, data):
|
||||
attrType = self._getAttrTypeScalar(data)
|
||||
if attrType is None:
|
||||
raise ValueError("Unsupported data type: %s" % type(data))
|
||||
self._stream.write(_INDENT)
|
||||
self._stream.write(key)
|
||||
self._stream.write(_WHITESPACE)
|
||||
self._stream.write("=")
|
||||
self._stream.write(_WHITESPACE)
|
||||
self._stream.write(attrType)
|
||||
self._stream.write(_WHITESPACE)
|
||||
self._stream.write(self._preprocess(data, type(data)))
|
||||
|
||||
def _writeArrAttr(self, key, data):
|
||||
attrType = self._getAttrTypeArr(data)
|
||||
self._stream.write(_INDENT)
|
||||
self._stream.write(key)
|
||||
self._stream.write("(%d)" % len(data))
|
||||
self._stream.write(_WHITESPACE)
|
||||
self._stream.write("=")
|
||||
self._stream.write(_WHITESPACE)
|
||||
self._stream.write(attrType)
|
||||
for val in data:
|
||||
self._stream.write(_WHITESPACE)
|
||||
self._stream.write(self._preprocess(val, type(val)))
|
||||
|
||||
def _writeFileAttr(self, key, data):
|
||||
self._stream.write(_INDENT)
|
||||
self._stream.write(key)
|
||||
self._stream.write(_WHITESPACE)
|
||||
self._stream.write("=")
|
||||
self._stream.write(_WHITESPACE)
|
||||
self._stream.write(_TYPE_FILE)
|
||||
for val in data.split("/"):
|
||||
if val:
|
||||
self._stream.write(_WHITESPACE)
|
||||
self._stream.write('"%s"' % val)
|
||||
|
||||
def _getSifDataType(self, dataType):
|
||||
if issubclass(dataType, Section):
|
||||
return _TYPE_INTEGER
|
||||
if issubclass(dataType, bool):
|
||||
return _TYPE_LOGICAL
|
||||
if issubclass(dataType, int):
|
||||
return _TYPE_INTEGER
|
||||
if issubclass(dataType, float):
|
||||
return _TYPE_REAL
|
||||
if issubclass(dataType, basestring):
|
||||
return _TYPE_STRING
|
||||
raise ValueError("Unsupported data type: %s" % dataType)
|
||||
|
||||
def _preprocess(self, data, dataType):
|
||||
if issubclass(dataType, Section):
|
||||
return str(self._idMgr.getId(data))
|
||||
if issubclass(dataType, basestring):
|
||||
return '"%s"' % data
|
||||
return str(data)
|
||||
|
||||
def _getAttrTypeScalar(self, data):
|
||||
return self._getSifDataType(type(data))
|
||||
|
||||
def _getAttrTypeArr(self, data):
|
||||
if not data:
|
||||
raise ValueError("Collections must not be empty.")
|
||||
it = iter(data)
|
||||
dataType = type(it.next())
|
||||
for entry in it:
|
||||
if not isinstance(entry, dataType):
|
||||
raise ValueError("Collection must be homogenueous")
|
||||
return self._getSifDataType(dataType)
|
||||
|
||||
|
||||
class _IdManager(object):
|
||||
|
||||
def __init__(self, firstId=1):
|
||||
self._pool = dict()
|
||||
self._ids = dict()
|
||||
self.firstId = firstId
|
||||
|
||||
def setId(self, section):
|
||||
if section.name not in self._pool:
|
||||
self._pool[section.name] = self.firstId
|
||||
self._ids[section] = self._pool[section.name]
|
||||
self._pool[section.name] += 1
|
||||
|
||||
def getId(self, section):
|
||||
if section not in self._ids:
|
||||
self.setId(section)
|
||||
return self._ids[section]
|
||||
93
src/Mod/Fem/femsolver/elmer/solver.py
Normal file
93
src/Mod/Fem/femsolver/elmer/solver.py
Normal file
@@ -0,0 +1,93 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "Elmer"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
import FemUtils
|
||||
|
||||
from .. import run
|
||||
from .. import solverbase
|
||||
from . import tasks
|
||||
|
||||
from .equations import heat
|
||||
from .equations import elasticity
|
||||
from .equations import flow
|
||||
|
||||
|
||||
def create(doc, name="ElmerSolver"):
|
||||
return FemUtils.createObject(
|
||||
doc, name, Proxy, ViewProxy)
|
||||
|
||||
|
||||
class Proxy(solverbase.Proxy):
|
||||
"""Proxy for FemSolverElmers Document Object."""
|
||||
|
||||
Type = "Fem::FemSolverObjectElmer"
|
||||
|
||||
_EQUATIONS = {
|
||||
"Heat": heat,
|
||||
"Elasticity": elasticity,
|
||||
"Flow": flow,
|
||||
}
|
||||
|
||||
def __init__(self, obj):
|
||||
super(Proxy, self).__init__(obj)
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "SteadyStateMaxIterations",
|
||||
"Steady State", "")
|
||||
obj.addProperty(
|
||||
"App::PropertyInteger", "SteadyStateMinIterations",
|
||||
"Steady State", "")
|
||||
obj.addProperty(
|
||||
"App::PropertyLink", "ElmerResult",
|
||||
"Base", "", 4 | 8)
|
||||
obj.addProperty(
|
||||
"App::PropertyLink", "ElmerOutput",
|
||||
"Base", "", 4 | 8)
|
||||
|
||||
obj.SteadyStateMaxIterations = 1
|
||||
obj.SteadyStateMinIterations = 0
|
||||
|
||||
def createMachine(self, obj, directory):
|
||||
return run.Machine(
|
||||
solver=obj, directory=directory,
|
||||
check=tasks.Check(),
|
||||
prepare=tasks.Prepare(),
|
||||
solve=tasks.Solve(),
|
||||
results=tasks.Results())
|
||||
|
||||
def createEquation(self, doc, eqId):
|
||||
return self._EQUATIONS[eqId].create(doc)
|
||||
|
||||
def isSupported(self, eqId):
|
||||
return eqId in self._EQUATIONS
|
||||
|
||||
|
||||
class ViewProxy(solverbase.ViewProxy):
|
||||
"""Proxy for FemSolverElmers View Provider."""
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/fem-elmer.png"
|
||||
148
src/Mod/Fem/femsolver/elmer/tasks.py
Normal file
148
src/Mod/Fem/femsolver/elmer/tasks.py
Normal file
@@ -0,0 +1,148 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "FemElmerTasks"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
import subprocess
|
||||
import os.path
|
||||
import FemUtils
|
||||
|
||||
from .. import run
|
||||
from .. import settings
|
||||
from . import writer
|
||||
|
||||
|
||||
class Check(run.Check):
|
||||
|
||||
def run(self):
|
||||
self.pushStatus("Checking analysis...\n")
|
||||
if (self.checkMesh()):
|
||||
self.checkMeshType()
|
||||
self.checkMaterial()
|
||||
self.checkEquations()
|
||||
|
||||
def checkMeshType(self):
|
||||
mesh = FemUtils.getSingleMember(self.analysis, "Fem::FemMeshObject")
|
||||
if not FemUtils.isOfType(mesh, "FemMeshGmsh"):
|
||||
self.report.error(
|
||||
"Unsupported type of mesh. "
|
||||
"Mesh must be created with gmsh.")
|
||||
self.fail()
|
||||
return False
|
||||
return True
|
||||
|
||||
def checkEquations(self):
|
||||
equations = self.solver.Group
|
||||
if not equations:
|
||||
self.report.error(
|
||||
"Solver has no equations. "
|
||||
"Add at least one equation.")
|
||||
self.fail()
|
||||
|
||||
|
||||
class Prepare(run.Prepare):
|
||||
|
||||
def run(self):
|
||||
self.pushStatus("Preparing input files...\n")
|
||||
w = writer.Writer(self.solver, self.directory)
|
||||
try:
|
||||
w.write()
|
||||
self.checkHandled(w)
|
||||
except writer.WriteError as e:
|
||||
self.report.error(str(e))
|
||||
self.fail()
|
||||
except IOError as e:
|
||||
self.report.error("Can't access working directory.")
|
||||
self.fail()
|
||||
|
||||
def checkHandled(self, w):
|
||||
handled = w.getHandledConstraints()
|
||||
allConstraints = FemUtils.getMember(self.analysis, "Fem::Constraint")
|
||||
for obj in set(allConstraints) - handled:
|
||||
self.report.warning("Ignored constraint %s." % obj.Label)
|
||||
|
||||
|
||||
class Solve(run.Solve):
|
||||
|
||||
def run(self):
|
||||
self.pushStatus("Executing solver...\n")
|
||||
binary = settings.getBinary("ElmerSolver")
|
||||
if binary is not None:
|
||||
self._process = subprocess.Popen(
|
||||
[binary], 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)
|
||||
if not self.aborted:
|
||||
self._updateOutput(output)
|
||||
else:
|
||||
self.report.error("ElmerSolver executable not found.")
|
||||
self.fail()
|
||||
|
||||
def _observeSolver(self, process):
|
||||
output = ""
|
||||
line = process.stdout.readline()
|
||||
self.pushStatus(line)
|
||||
output += line
|
||||
line = process.stdout.readline()
|
||||
while line:
|
||||
line = "\n%s" % line.rstrip()
|
||||
self.pushStatus(line)
|
||||
output += line
|
||||
line = process.stdout.readline()
|
||||
return output
|
||||
|
||||
def _updateOutput(self, output):
|
||||
if self.solver.ElmerOutput is None:
|
||||
self._createOutput()
|
||||
self.solver.ElmerOutput.Text = output
|
||||
|
||||
def _createOutput(self):
|
||||
self.solver.ElmerOutput = self.analysis.Document.addObject(
|
||||
"App::TextDocument", self.solver.Name + "Output")
|
||||
self.solver.ElmerOutput.Label = self.solver.Label + "Output"
|
||||
self.solver.ElmerOutput.ReadOnly = True
|
||||
self.analysis.Member += [self.solver.ElmerOutput]
|
||||
|
||||
|
||||
class Results(run.Results):
|
||||
|
||||
def run(self):
|
||||
if self.solver.ElmerResult is None:
|
||||
self._createResults()
|
||||
postPath = os.path.join(self.directory, "case0001.vtu")
|
||||
self.solver.ElmerResult.read(postPath)
|
||||
self.solver.ElmerResult.getLastPostObject().touch()
|
||||
self.solver.Document.recompute()
|
||||
|
||||
def _createResults(self):
|
||||
self.solver.ElmerResult = self.analysis.Document.addObject(
|
||||
"Fem::FemPostPipeline", self.solver.Name + "Result")
|
||||
self.solver.ElmerResult.Label = self.solver.Label + "Result"
|
||||
self.analysis.Member += [self.solver.ElmerResult]
|
||||
682
src/Mod/Fem/femsolver/elmer/writer.py
Normal file
682
src/Mod/Fem/femsolver/elmer/writer.py
Normal file
@@ -0,0 +1,682 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "FemWriterElmer"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import subprocess
|
||||
import tempfile
|
||||
|
||||
from FreeCAD import Units
|
||||
import Fem
|
||||
import FemUtils
|
||||
import FemGmshTools
|
||||
from .. import settings
|
||||
from . import sifio
|
||||
|
||||
|
||||
_STARTINFO_NAME = "ELMERSOLVER_STARTINFO"
|
||||
_SIF_NAME = "case.sif"
|
||||
_ELMERGRID_IFORMAT = "8"
|
||||
_ELMERGRID_OFORMAT = "2"
|
||||
_SOLID_PREFIX = "Solid"
|
||||
|
||||
|
||||
UNITS = {
|
||||
"L": "mm",
|
||||
"M": "kg",
|
||||
"T": "s",
|
||||
"I": "A",
|
||||
"O": "K",
|
||||
"N": "mol",
|
||||
"J": "cd",
|
||||
}
|
||||
|
||||
|
||||
CONSTS_DEF = {
|
||||
"Gravity": "9.82 m/s^2",
|
||||
"StefanBoltzmann": "5.67e-8 W/(m^2*K^4)",
|
||||
"PermittivityOfVacuum": "8.8542e-12 s^4*A^2/(m*kg)",
|
||||
"BoltzmannConstant": "1.3807e-23 J/K",
|
||||
}
|
||||
|
||||
|
||||
def getFromUi(value, unit, outputDim):
|
||||
quantity = Units.Quantity(str(value) + str(unit))
|
||||
return convert(quantity, outputDim)
|
||||
|
||||
|
||||
def convert(quantityStr, unit):
|
||||
quantity = Units.Quantity(quantityStr)
|
||||
for key, setting in UNITS.iteritems():
|
||||
unit = unit.replace(key, setting)
|
||||
return float(quantity.getValueAs(unit))
|
||||
|
||||
|
||||
def _getAllSubObjects(obj):
|
||||
s = ["Solid" + str(i + 1) for i in range(len(obj.Shape.Solids))]
|
||||
s.extend(("Face" + str(i + 1) for i in range(len(obj.Shape.Faces))))
|
||||
s.extend(("Edge" + str(i + 1) for i in range(len(obj.Shape.Edges))))
|
||||
s.extend(("Vertex" + str(i + 1) for i in range(len(obj.Shape.Vertexes))))
|
||||
return s
|
||||
|
||||
|
||||
def getConstant(name, dimension):
|
||||
return convert(CONSTS_DEF[name], dimension)
|
||||
|
||||
|
||||
class Writer(object):
|
||||
|
||||
def __init__(self, solver, directory):
|
||||
self.analysis = FemUtils.findAnalysisOfMember(solver)
|
||||
self.solver = solver
|
||||
self.directory = directory
|
||||
self._usedVarNames = set()
|
||||
self._builder = sifio.Builder()
|
||||
self._handledObjects = set()
|
||||
|
||||
def getHandledConstraints(self):
|
||||
return self._handledObjects
|
||||
|
||||
def write(self):
|
||||
self._handleSimulation()
|
||||
self._handleHeat()
|
||||
self._handleElasticity()
|
||||
self._handleFlow()
|
||||
self._addOutputSolver()
|
||||
|
||||
self._writeSif()
|
||||
self._writeMesh()
|
||||
self._writeStartinfo()
|
||||
|
||||
def _writeMesh(self):
|
||||
mesh = FemUtils.getSingleMember(self.analysis, "Fem::FemMeshObject")
|
||||
unvPath = os.path.join(self.directory, "mesh.unv")
|
||||
groups = []
|
||||
groups.extend(self._builder.getBodyNames())
|
||||
groups.extend(self._builder.getBoundaryNames())
|
||||
self._exportToUnv(groups, mesh, unvPath)
|
||||
binary = settings.getBinary("ElmerGrid")
|
||||
if binary is None:
|
||||
raise WriteError("Couldn't find ElmerGrid binary.")
|
||||
args = [binary,
|
||||
_ELMERGRID_IFORMAT,
|
||||
_ELMERGRID_OFORMAT,
|
||||
unvPath,
|
||||
"-out", self.directory]
|
||||
subprocess.call(args)
|
||||
|
||||
def _writeStartinfo(self):
|
||||
path = os.path.join(self.directory, _STARTINFO_NAME)
|
||||
with open(path, 'w') as f:
|
||||
f.write(_SIF_NAME)
|
||||
|
||||
def _exportToUnv(self, groups, mesh, meshPath):
|
||||
unvGmshFd, unvGmshPath = tempfile.mkstemp(suffix=".unv")
|
||||
brepFd, brepPath = tempfile.mkstemp(suffix=".brep")
|
||||
geoFd, geoPath = tempfile.mkstemp(suffix=".geo")
|
||||
os.close(brepFd)
|
||||
os.close(geoFd)
|
||||
os.close(unvGmshFd)
|
||||
|
||||
tools = FemGmshTools.FemGmshTools(mesh)
|
||||
tools.group_elements = {g: [g] for g in groups}
|
||||
tools.ele_length_map = {}
|
||||
tools.temp_file_geometry = brepPath
|
||||
tools.temp_file_geo = geoPath
|
||||
tools.temp_file_mesh = unvGmshPath
|
||||
|
||||
tools.get_dimension()
|
||||
tools.get_gmsh_command()
|
||||
tools.get_region_data()
|
||||
tools.get_boundary_layer_data()
|
||||
tools.write_part_file()
|
||||
tools.write_geo()
|
||||
tools.run_gmsh_with_geo()
|
||||
|
||||
ioMesh = Fem.FemMesh()
|
||||
ioMesh.read(unvGmshPath)
|
||||
ioMesh.write(meshPath)
|
||||
|
||||
os.remove(brepPath)
|
||||
os.remove(geoPath)
|
||||
os.remove(unvGmshPath)
|
||||
|
||||
def _handleSimulation(self):
|
||||
self._simulation("Coordinate System", "Cartesian 3D")
|
||||
self._simulation("Coordinate Mapping", (1, 2, 3))
|
||||
self._simulation("Simulation Type", "Steady state")
|
||||
self._simulation("Steady State Max Iterations", 1)
|
||||
self._simulation("Output Intervals", 1)
|
||||
self._simulation("Timestepping Method", "BDF")
|
||||
self._simulation("BDF Order", 1)
|
||||
self._simulation("Use Mesh Names", True)
|
||||
self._simulation(
|
||||
"Steady State Max Iterations",
|
||||
self.solver.SteadyStateMaxIterations)
|
||||
self._simulation(
|
||||
"Steady State Min Iterations",
|
||||
self.solver.SteadyStateMinIterations)
|
||||
|
||||
def _handleHeat(self):
|
||||
activeIn = []
|
||||
for equation in self.solver.Group:
|
||||
if FemUtils.isOfType(equation, "Fem::FemEquationElmerHeat"):
|
||||
if equation.References:
|
||||
activeIn = equation.References[0][1]
|
||||
else:
|
||||
activeIn = self._getAllBodies()
|
||||
solverSection = self._getHeatSolver(equation)
|
||||
for body in activeIn:
|
||||
self._addSolver(body, solverSection)
|
||||
if activeIn:
|
||||
self._handleHeatConstants()
|
||||
self._handleHeatBndConditions()
|
||||
self._handleHeatInitial(activeIn)
|
||||
self._handleHeatBodyForces(activeIn)
|
||||
self._handleHeatMaterial(activeIn)
|
||||
|
||||
def _getHeatSolver(self, equation):
|
||||
s = self._createNonlinearSolver(equation)
|
||||
s["Equation"] = equation.Name
|
||||
s["Procedure"] = sifio.FileAttr("HeatSolve/HeatSolver")
|
||||
s["Variable"] = self._getUniqueVarName("Temperature")
|
||||
s["Exec Solver"] = "Always"
|
||||
s["Stabilize"] = equation.Stabilize
|
||||
s["Bubbles"] = equation.Bubbles
|
||||
s["Optimize Bandwidth"] = True
|
||||
return s
|
||||
|
||||
def _handleHeatConstants(self):
|
||||
self._constant(
|
||||
"Stefan Boltzmann",
|
||||
getConstant("StefanBoltzmann", "M/(O^4*T^3)"))
|
||||
|
||||
def _handleHeatBndConditions(self):
|
||||
for obj in self._getMember("Fem::ConstraintTemperature"):
|
||||
if obj.References:
|
||||
for name in obj.References[0][1]:
|
||||
if obj.ConstraintType == "Temperature":
|
||||
temp = getFromUi(obj.Temperature, "K", "O")
|
||||
self._boundary(name, "Temperature", temp)
|
||||
elif obj.ConstraintType == "CFlux":
|
||||
flux = getFromUi(obj.CFlux, "kg*mm^2*s^-3", "M*L^2*T^-3")
|
||||
self._boundary(name, "Temperature Load", flux)
|
||||
self._handled(obj)
|
||||
for obj in self._getMember("Fem::ConstraintHeatflux"):
|
||||
if obj.References:
|
||||
for name in obj.References[0][1]:
|
||||
if obj.ConstraintType == "Convection":
|
||||
film = getFromUi(obj.FilmCoef, "W/(m^2*K)", "M/(T^3*O)")
|
||||
temp = getFromUi(obj.AmbientTemp, "K", "O")
|
||||
self._boundary(name, "Heat Transfer Coefficient", film)
|
||||
self._boundary(name, "External Temperature", temp)
|
||||
elif obj.ConstraintType == "DFlux":
|
||||
flux = getFromUi(obj.DFlux, "W/m^2", "M*T^-3")
|
||||
self._boundary(name, "Heat Flux BC", True)
|
||||
self._boundary(name, "Heat Flux", flux)
|
||||
self._handled(obj)
|
||||
|
||||
def _handleHeatInitial(self, bodies):
|
||||
obj = self._getSingleMember("Fem::ConstraintInitialTemperature")
|
||||
if obj is not None:
|
||||
for name in bodies:
|
||||
temp = getFromUi(obj.initialTemperature, "K", "O")
|
||||
self._initial(name, "Temperature", temp)
|
||||
self._handled(obj)
|
||||
|
||||
def _handleHeatBodyForces(self, bodies):
|
||||
obj = self._getSingleMember("Fem::FemConstraintBodyHeatSource")
|
||||
if obj is not None:
|
||||
for name in bodies:
|
||||
heatSource = getFromUi(obj.HeatFlux, "W/kg", "L^2*T^-3")
|
||||
self._bodyForce(name, "Heat Source", heatSource)
|
||||
self._handled(obj)
|
||||
|
||||
def _handleHeatMaterial(self, bodies):
|
||||
tempObj = self._getSingleMember("Fem::ConstraintInitialTemperature")
|
||||
if tempObj is not None:
|
||||
refTemp = getFromUi(tempObj.initialTemperature, "K", "O")
|
||||
for name in bodies:
|
||||
self._material(name, "Reference Temperature", refTemp)
|
||||
for obj in self._getMember("App::MaterialObject"):
|
||||
m = obj.Material
|
||||
refs = (
|
||||
obj.References[0][1]
|
||||
if obj.References
|
||||
else self._getAllBodies())
|
||||
for name in (n for n in refs if n in bodies):
|
||||
self._material(
|
||||
name, "Density",
|
||||
self._getDensity(m))
|
||||
self._material(
|
||||
name, "Heat Conductivity",
|
||||
convert(m["ThermalConductivity"], "M*L/(T^3*O)"))
|
||||
self._material(
|
||||
name, "Heat Capacity",
|
||||
convert(m["SpecificHeat"], "L^2/(T^2*O)"))
|
||||
|
||||
def _handleElasticity(self):
|
||||
activeIn = []
|
||||
for equation in self.solver.Group:
|
||||
if FemUtils.isOfType(equation, "Fem::FemEquationElmerElasticity"):
|
||||
if equation.References:
|
||||
activeIn = equation.References[0][1]
|
||||
else:
|
||||
activeIn = self._getAllBodies()
|
||||
solverSection = self._getElasticitySolver(equation)
|
||||
for body in activeIn:
|
||||
self._addSolver(body, solverSection)
|
||||
if activeIn:
|
||||
self._handleElasticityConstants()
|
||||
self._handleElasticityBndConditions()
|
||||
self._handleElasticityInitial(activeIn)
|
||||
self._handleElasticityBodyForces(activeIn)
|
||||
self._handleElasticityMaterial(activeIn)
|
||||
|
||||
def _getElasticitySolver(self, equation):
|
||||
s = self._createLinearSolver(equation)
|
||||
s["Equation"] = equation.Name
|
||||
s["Procedure"] = sifio.FileAttr("StressSolve/StressSolver")
|
||||
s["Variable"] = self._getUniqueVarName("Displacement")
|
||||
s["Variable DOFs"] = 3
|
||||
s["Eigen Analysis"] = equation.DoFrequencyAnalysis
|
||||
s["Eigen System Values"] = equation.EigenmodesCount
|
||||
s["Calculate Strains"] = equation.CalculateStrains
|
||||
s["Calculate Stresses"] = equation.CalculateStresses
|
||||
s["Calculate Principal"] = equation.CalculatePrincipal
|
||||
s["Calculate Pangle"] = equation.CalculatePangle
|
||||
s["Displace mesh"] = False
|
||||
s["Exec Solver"] = "Always"
|
||||
s["Stabilize"] = equation.Stabilize
|
||||
s["Bubbles"] = equation.Bubbles
|
||||
s["Optimize Bandwidth"] = True
|
||||
return s
|
||||
|
||||
def _handleElasticityConstants(self):
|
||||
pass
|
||||
|
||||
def _handleElasticityBndConditions(self):
|
||||
for obj in self._getMember("Fem::ConstraintPressure"):
|
||||
if obj.References:
|
||||
for name in obj.References[0][1]:
|
||||
pressure = getFromUi(obj.Pressure, "MPa", "M/(L*T^2)")
|
||||
if not obj.Reversed:
|
||||
pressure *= -1
|
||||
self._boundary(name, "Normal Force", pressure)
|
||||
self._handled(obj)
|
||||
for obj in self._getMember("Fem::ConstraintFixed"):
|
||||
if obj.References:
|
||||
for name in obj.References[0][1]:
|
||||
self._boundary(name, "Displacement 1", 0.0)
|
||||
self._boundary(name, "Displacement 2", 0.0)
|
||||
self._boundary(name, "Displacement 3", 0.0)
|
||||
self._handled(obj)
|
||||
for obj in self._getMember("Fem::ConstraintForce"):
|
||||
if obj.References:
|
||||
for name in obj.References[0][1]:
|
||||
force = getFromUi(obj.Force, "N", "M*L*T^-2")
|
||||
self._boundary(name, "Force 1", obj.DirectionVector.x * force)
|
||||
self._boundary(name, "Force 2", obj.DirectionVector.y * force)
|
||||
self._boundary(name, "Force 3", obj.DirectionVector.z * force)
|
||||
self._boundary(name, "Force 1 Normalize by Area", True)
|
||||
self._boundary(name, "Force 2 Normalize by Area", True)
|
||||
self._boundary(name, "Force 3 Normalize by Area", True)
|
||||
self._handled(obj)
|
||||
for obj in self._getMember("Fem::ConstraintDisplacement"):
|
||||
if obj.References:
|
||||
for name in obj.References[0][1]:
|
||||
if not obj.xFree:
|
||||
self._boundary(
|
||||
name, "Displacement 1", obj.xDisplacement * 0.001)
|
||||
elif obj.xFix:
|
||||
self._boundary(name, "Displacement 1", 0.0)
|
||||
if not obj.yFree:
|
||||
self._boundary(
|
||||
name, "Displacement 2", obj.yDisplacement * 0.001)
|
||||
elif obj.yFix:
|
||||
self._boundary(name, "Displacement 2", 0.0)
|
||||
if not obj.zFree:
|
||||
self._boundary(
|
||||
name, "Displacement 3", obj.zDisplacement * 0.001)
|
||||
elif obj.zFix:
|
||||
self._boundary(name, "Displacement 3", 0.0)
|
||||
self._handled(obj)
|
||||
|
||||
def _handleElasticityInitial(self, bodies):
|
||||
pass
|
||||
|
||||
def _handleElasticityBodyForces(self, bodies):
|
||||
obj = self._getSingleMember("FemConstraintSelfWeight")
|
||||
if obj is not None:
|
||||
for name in bodies:
|
||||
gravity = getConstant("Gravity", "L/T^2")
|
||||
m = self._getBodyMaterial(name).Material
|
||||
|
||||
densityQuantity = Units.Quantity(m["Density"])
|
||||
dimension = "M/L^3"
|
||||
if name.startswith("Edge"):
|
||||
density.Unit = Units.Unit(-2, 1)
|
||||
dimension = "M/L^2"
|
||||
density = convert(densityQuantity, dimension)
|
||||
|
||||
force1 = gravity * obj.Gravity_x * density
|
||||
force2 = gravity * obj.Gravity_y * density
|
||||
force3 = gravity * obj.Gravity_z * density
|
||||
self._bodyForce(name, "Stress Bodyforce 1", force1)
|
||||
self._bodyForce(name, "Stress Bodyforce 2", force2)
|
||||
self._bodyForce(name, "Stress Bodyforce 3", force3)
|
||||
self._handled(obj)
|
||||
|
||||
def _getBodyMaterial(self, name):
|
||||
for obj in self._getMember("App::MaterialObject"):
|
||||
if not obj.References or name in obj.References[0][1]:
|
||||
return obj
|
||||
return None
|
||||
|
||||
def _handleElasticityMaterial(self, bodies):
|
||||
tempObj = self._getSingleMember("Fem::ConstraintInitialTemperature")
|
||||
if tempObj is not None:
|
||||
refTemp = getFromUi(tempObj.initialTemperature, "K", "O")
|
||||
for name in bodies:
|
||||
self._material(name, "Reference Temperature", refTemp)
|
||||
for obj in self._getMember("App::MaterialObject"):
|
||||
m = obj.Material
|
||||
refs = (
|
||||
obj.References[0][1]
|
||||
if obj.References
|
||||
else self._getAllBodies())
|
||||
for name in (n for n in refs if n in bodies):
|
||||
self._material(
|
||||
name, "Density",
|
||||
self._getDensity(m))
|
||||
self._material(
|
||||
name, "Youngs Modulus",
|
||||
self._getYoungsModulus(m))
|
||||
self._material(
|
||||
name, "Poisson ratio",
|
||||
float(m["PoissonRatio"]))
|
||||
self._material(
|
||||
name, "Heat expansion Coefficient",
|
||||
convert(m["ThermalExpansionCoefficient"], "O^-1"))
|
||||
|
||||
def _getDensity(self, m):
|
||||
density = convert(m["Density"], "M/L^3")
|
||||
if self._getMeshDimension() == 2:
|
||||
density *= 1e3
|
||||
return density
|
||||
|
||||
def _getYoungsModulus(self, m):
|
||||
youngsModulus = convert(m["YoungsModulus"], "M/(L*T^2)")
|
||||
if self._getMeshDimension() == 2:
|
||||
youngsModulus *= 1e3
|
||||
return youngsModulus
|
||||
|
||||
def _handleFlow(self):
|
||||
activeIn = []
|
||||
for equation in self.solver.Group:
|
||||
if FemUtils.isOfType(equation, "Fem::FemEquationElmerFlow"):
|
||||
if equation.References:
|
||||
activeIn = equation.References[0][1]
|
||||
else:
|
||||
activeIn = self._getAllBodies()
|
||||
solverSection = self._getFlowSolver(equation)
|
||||
for body in activeIn:
|
||||
self._addSolver(body, solverSection)
|
||||
if activeIn:
|
||||
self._handleFlowConstants()
|
||||
self._handleFlowBndConditions()
|
||||
self._handleFlowInitialVelocity(activeIn)
|
||||
#self._handleFlowInitial(activeIn)
|
||||
#self._handleFlowBodyForces(activeIn)
|
||||
self._handleFlowMaterial(activeIn)
|
||||
self._handleFlowEquation(activeIn)
|
||||
|
||||
def _getFlowSolver(self, equation):
|
||||
s = self._createNonlinearSolver(equation)
|
||||
s["Equation"] = "Navier-Stokes"
|
||||
#s["Equation"] = equation.Name
|
||||
s["Procedure"] = sifio.FileAttr("FlowSolve/FlowSolver")
|
||||
s["Exec Solver"] = "Always"
|
||||
s["Stabilize"] = equation.Stabilize
|
||||
s["Bubbles"] = equation.Bubbles
|
||||
s["Optimize Bandwidth"] = True
|
||||
return s
|
||||
|
||||
def _handleFlowConstants(self):
|
||||
gravity = getConstant("Gravity", "L/T^2")
|
||||
self._constant("Gravity", (0.0, -1.0, 0.0, gravity))
|
||||
|
||||
def _handleFlowMaterial(self, bodies):
|
||||
tempObj = self._getSingleMember("Fem::ConstraintInitialTemperature")
|
||||
if tempObj is not None:
|
||||
refTemp = getFromUi(tempObj.initialTemperature, "K", "O")
|
||||
for name in bodies:
|
||||
self._material(name, "Reference Temperature", refTemp)
|
||||
for obj in self._getMember("App::MaterialObject"):
|
||||
m = obj.Material
|
||||
refs = (
|
||||
obj.References[0][1]
|
||||
if obj.References
|
||||
else self._getAllBodies())
|
||||
for name in (n for n in refs if n in bodies):
|
||||
if "Density" in m:
|
||||
self._material(
|
||||
name, "Density",
|
||||
self._getDensity(m))
|
||||
if "ThermalConductivity" in m:
|
||||
self._material(
|
||||
name, "Heat Conductivity",
|
||||
convert(m["ThermalConductivity"], "M*L/(T^3*O)"))
|
||||
if "KinematicViscosity" in m:
|
||||
density = self._getDensity(m)
|
||||
kViscosity = convert(m["KinematicViscosity"], "L^2/T")
|
||||
self._material(
|
||||
name, "Viscosity", kViscosity * density)
|
||||
if "ThermalExpansionCoefficient" in m:
|
||||
value = convert(m["ThermalExpansionCoefficient"], "O^-1")
|
||||
if value > 0:
|
||||
self._material(
|
||||
name, "Heat expansion Coefficient", value)
|
||||
if "ReferencePressure" in m:
|
||||
pressure = convert(m["ReferencePressure"], "M/(L*T^2)")
|
||||
self._material(name, "Reference Pressure", pressure)
|
||||
if "SpecificHeatRatio" in m:
|
||||
self._material(
|
||||
name, "Specific Heat Ratio",
|
||||
float(m["SpecificHeatRatio"]))
|
||||
if "CompressibilityModel" in m:
|
||||
self._material(
|
||||
name, "Compressibility Model",
|
||||
m["CompressibilityModel"])
|
||||
|
||||
def _handleFlowInitialVelocity(self, bodies):
|
||||
obj = self._getSingleMember("Fem::ConstraintInitialFlowVelocity")
|
||||
if obj is not None:
|
||||
for name in bodies:
|
||||
if obj.VelocityXEnabled:
|
||||
velocity = getFromUi(obj.VelocityX, "m/s", "L/T")
|
||||
self._initial(name, "Velocity 1", velocity)
|
||||
if obj.VelocityYEnabled:
|
||||
velocity = getFromUi(obj.VelocityY, "m/s", "L/T")
|
||||
self._initial(name, "Velocity 2", velocity)
|
||||
if obj.VelocityZEnabled:
|
||||
velocity = getFromUi(obj.VelocityZ, "m/s", "L/T")
|
||||
self._initial(name, "Velocity 3", velocity)
|
||||
self._handled(obj)
|
||||
|
||||
def _handleFlowBndConditions(self):
|
||||
for obj in self._getMember("Fem::ConstraintFlowVelocity"):
|
||||
if obj.References:
|
||||
for name in obj.References[0][1]:
|
||||
if obj.VelocityXEnabled:
|
||||
velocity = getFromUi(obj.VelocityX, "m/s", "L/T")
|
||||
self._boundary(name, "Velocity 1", velocity)
|
||||
if obj.VelocityYEnabled:
|
||||
velocity = getFromUi(obj.VelocityY, "m/s", "L/T")
|
||||
self._boundary(name, "Velocity 2", velocity)
|
||||
if obj.VelocityZEnabled:
|
||||
velocity = getFromUi(obj.VelocityZ, "m/s", "L/T")
|
||||
self._boundary(name, "Velocity 3", velocity)
|
||||
if obj.NormalToBoundary:
|
||||
self._boundary(name, "Normal-Tangential Velocity", True)
|
||||
self._handled(obj)
|
||||
|
||||
def _handleFlowEquation(self, bodies):
|
||||
for b in bodies:
|
||||
self._equation(b, "Convection", "Computed")
|
||||
|
||||
def _createLinearSolver(self, equation):
|
||||
s = sifio.createSection(sifio.SOLVER)
|
||||
s.priority = equation.Priority
|
||||
s["Linear System Solver"] = equation.LinearSolverType
|
||||
if equation.LinearSolverType == "Direct":
|
||||
s["Linear System Direct Method"] = \
|
||||
equation.LinearDirectMethod
|
||||
elif equation.LinearSolverType == "Iterative":
|
||||
s["Linear System Iterative Method"] = \
|
||||
equation.LinearIterativeMethod
|
||||
if equation.LinearIterativeMethod == "BiCGStabl":
|
||||
s["BiCGstabl polynomial degree"] = \
|
||||
equation.BiCGstablDegree
|
||||
s["Linear System Max Iterations"] = \
|
||||
equation.LinearIterations
|
||||
s["Linear System Convergence Tolerance"] = \
|
||||
equation.LinearTolerance
|
||||
s["Linear System Preconditioning"] = \
|
||||
equation.LinearPreconditioning
|
||||
s["Steady State Convergence Tolerance"] = \
|
||||
equation.SteadyStateTolerance
|
||||
s["Linear System Abort Not Converged"] = False
|
||||
s["Linear System Residual Output"] = 1
|
||||
s["Linear System Precondition Recompute"] = 1
|
||||
return s
|
||||
|
||||
def _createNonlinearSolver(self, equation):
|
||||
s = self._createLinearSolver(equation)
|
||||
s["Nonlinear System Max Iterations"] = \
|
||||
equation.NonlinearIterations
|
||||
s["Nonlinear System Convergence Tolerance"] = \
|
||||
equation.NonlinearTolerance
|
||||
s["Nonlinear System Relaxation Factor"] = \
|
||||
equation.RelaxationFactor
|
||||
s["Nonlinear System Newton After Iterations"] = \
|
||||
equation.NonlinearNewtonAfterIterations
|
||||
s["Nonlinear System Newton After Tolerance"] = \
|
||||
equation.NonlinearNewtonAfterTolerance
|
||||
return s
|
||||
|
||||
def _getUniqueVarName(self, varName):
|
||||
postfix = 1
|
||||
if varName in self._usedVarNames:
|
||||
varName += "%2d" % postfix
|
||||
while varName in self._usedVarNames:
|
||||
postfix += 1
|
||||
varName = varName[:-2] + "%2d" % postfix
|
||||
self._usedVarNames.add(varName)
|
||||
return varName
|
||||
|
||||
def _getAllBodies(self):
|
||||
obj = FemUtils.getSingleMember(self.analysis, "Fem::FemMeshObject")
|
||||
bodyCount = 0
|
||||
prefix = ""
|
||||
if obj.Part.Shape.Solids:
|
||||
prefix = "Solid"
|
||||
bodyCount = len(obj.Part.Shape.Solids)
|
||||
elif obj.Part.Shape.Faces:
|
||||
prefix = "Face"
|
||||
bodyCount = len(obj.Part.Shape.Faces)
|
||||
elif obj.Part.Shape.Edges:
|
||||
prefix = "Edge"
|
||||
bodyCount = len(obj.Part.Shape.Edges)
|
||||
return [prefix + str(i + 1) for i in range(bodyCount)]
|
||||
|
||||
def _getMeshDimension(self):
|
||||
obj = FemUtils.getSingleMember(self.analysis, "Fem::FemMeshObject")
|
||||
if obj.Part.Shape.Solids:
|
||||
return 3
|
||||
elif obj.Part.Shape.Faces:
|
||||
return 2
|
||||
elif obj.Part.Shape.Edges:
|
||||
return 1
|
||||
return None
|
||||
|
||||
def _addOutputSolver(self):
|
||||
s = sifio.createSection(sifio.SOLVER)
|
||||
s["Equation"] = "ResultOutput"
|
||||
s["Exec Solver"] = "After simulation"
|
||||
s["Procedure"] = sifio.FileAttr("ResultOutputSolve/ResultOutputSolver")
|
||||
s["Output File Name"] = sifio.FileAttr("case")
|
||||
s["Vtu Format"] = True
|
||||
for name in self._getAllBodies():
|
||||
self._addSolver(name, s)
|
||||
|
||||
def _writeSif(self):
|
||||
sifPath = os.path.join(self.directory, _SIF_NAME)
|
||||
with open(sifPath, 'w') as fstream:
|
||||
sif = sifio.Sif(self._builder)
|
||||
sif.write(fstream)
|
||||
|
||||
def _handled(self, obj):
|
||||
self._handledObjects.add(obj)
|
||||
|
||||
def _simulation(self, key, attr):
|
||||
self._builder.simulation(key, attr)
|
||||
|
||||
def _constant(self, key, attr):
|
||||
self._builder.constant(key, attr)
|
||||
|
||||
def _initial(self, body, key, attr):
|
||||
self._builder.initial(body, key, attr)
|
||||
|
||||
def _material(self, body, key, attr):
|
||||
self._builder.material(body, key, attr)
|
||||
|
||||
def _equation(self, body, key, attr):
|
||||
self._builder.equation(body, key, attr)
|
||||
|
||||
def _bodyForce(self, body, key, attr):
|
||||
self._builder.bodyForce(body, key, attr)
|
||||
|
||||
def _addSolver(self, body, solverSection):
|
||||
self._builder.addSolver(body, solverSection)
|
||||
|
||||
def _boundary(self, boundary, key, attr):
|
||||
self._builder.boundary(boundary, key, attr)
|
||||
|
||||
def _addSection(self, section):
|
||||
self._builder.addSection(section)
|
||||
|
||||
def _getMember(self, t):
|
||||
return FemUtils.getMember(self.analysis, t)
|
||||
|
||||
def _getSingleMember(self, t):
|
||||
return FemUtils.getSingleMember(self.analysis, t)
|
||||
|
||||
|
||||
class WriteError(Exception):
|
||||
pass
|
||||
96
src/Mod/Fem/femsolver/equationbase.py
Normal file
96
src/Mod/Fem/femsolver/equationbase.py
Normal file
@@ -0,0 +1,96 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2017 - Markus Hovorka <m.hovorka@live.de> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
|
||||
__title__ = "_Base"
|
||||
__author__ = "Markus Hovorka"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
|
||||
|
||||
import FreeCAD
|
||||
if FreeCAD.GuiUp:
|
||||
from pivy import coin
|
||||
|
||||
|
||||
class BaseProxy(object):
|
||||
|
||||
BaseType = "App::FeaturePython"
|
||||
|
||||
def __init__(self, obj):
|
||||
obj.Proxy = self
|
||||
obj.addProperty(
|
||||
"App::PropertyLinkSubList", "References",
|
||||
"Base", "")
|
||||
|
||||
def execute(self, obj):
|
||||
return True
|
||||
|
||||
|
||||
class BaseViewProxy(object):
|
||||
|
||||
def __init__(self, vobj):
|
||||
vobj.Proxy = self
|
||||
|
||||
def attach(self, vobj):
|
||||
default = coin.SoGroup()
|
||||
vobj.addDisplayMode(default, "Default")
|
||||
|
||||
def getDisplayModes(self, obj):
|
||||
"Return a list of display modes."
|
||||
modes = ["Default"]
|
||||
return modes
|
||||
|
||||
def getDefaultDisplayMode(self):
|
||||
return "Default"
|
||||
|
||||
def setDisplayMode(self, mode):
|
||||
return mode
|
||||
|
||||
|
||||
class HeatProxy(BaseProxy):
|
||||
pass
|
||||
|
||||
|
||||
class HeatViewProxy(BaseViewProxy):
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/fem-equation-heat.svg"
|
||||
|
||||
|
||||
class ElasticityProxy(BaseProxy):
|
||||
pass
|
||||
|
||||
|
||||
class ElasticityViewProxy(BaseViewProxy):
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/fem-equation-elasticity.svg"
|
||||
|
||||
|
||||
class FlowProxy(BaseProxy):
|
||||
pass
|
||||
|
||||
|
||||
class FlowViewProxy(BaseViewProxy):
|
||||
|
||||
def getIcon(self):
|
||||
return ":/icons/fem-equation-flow.svg"
|
||||
Reference in New Issue
Block a user