summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AppCSXCAD/AppCSXCAD.cpp3
-rw-r--r--AppCSXCAD/CMakeLists.txt31
-rw-r--r--AppCSXCAD/main.cpp14
-rw-r--r--CSXCAD/CMakeLists.txt13
-rw-r--r--CSXCAD/matlab/AddDump.m4
-rw-r--r--CSXCAD/matlab/AutoSmoothMeshLines.m6
-rw-r--r--CSXCAD/python/CSXCAD/CSPrimitives.pxd236
-rw-r--r--CSXCAD/python/CSXCAD/CSPrimitives.pyx1261
-rw-r--r--CSXCAD/python/CSXCAD/CSProperties.pxd218
-rw-r--r--CSXCAD/python/CSXCAD/CSProperties.pyx1163
-rw-r--r--CSXCAD/python/CSXCAD/CSRectGrid.pxd56
-rw-r--r--CSXCAD/python/CSXCAD/CSRectGrid.pyx222
-rw-r--r--CSXCAD/python/CSXCAD/CSTransform.pxd53
-rw-r--r--CSXCAD/python/CSXCAD/CSTransform.pyx225
-rw-r--r--CSXCAD/python/CSXCAD/CSXCAD.pxd65
-rw-r--r--CSXCAD/python/CSXCAD/CSXCAD.pyx385
-rw-r--r--CSXCAD/python/CSXCAD/ParameterObjects.pxd29
-rw-r--r--CSXCAD/python/CSXCAD/ParameterObjects.pyx34
-rw-r--r--CSXCAD/python/CSXCAD/SmoothMeshLines.py266
-rw-r--r--CSXCAD/python/CSXCAD/Utilities.pyx53
-rw-r--r--CSXCAD/python/CSXCAD/__init__.py7
-rw-r--r--CSXCAD/python/README.md14
-rw-r--r--CSXCAD/python/doc/CSPrimitives.rst26
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimBox.rst7
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimCurve.rst7
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimCylinder.rst7
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimCylindricalShell.rst7
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimLinPoly.rst8
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimPoint.rst7
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimPolygon.rst8
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimPolyhedron.rst8
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimPolyhedronReader.rst8
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimRotPoly.rst8
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimSphere.rst7
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimSphericalShell.rst7
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimWire.rst8
-rw-r--r--CSXCAD/python/doc/CSPrimitives/CSPrimitives.rst7
-rw-r--r--CSXCAD/python/doc/CSProperties.rst19
-rw-r--r--CSXCAD/python/doc/CSProperties/CSPropConductingSheet.rst7
-rw-r--r--CSXCAD/python/doc/CSProperties/CSPropDumpBox.rst7
-rw-r--r--CSXCAD/python/doc/CSProperties/CSPropExcitation.rst7
-rw-r--r--CSXCAD/python/doc/CSProperties/CSPropLumpedElement.rst7
-rw-r--r--CSXCAD/python/doc/CSProperties/CSPropMaterial.rst7
-rw-r--r--CSXCAD/python/doc/CSProperties/CSPropMetal.rst7
-rw-r--r--CSXCAD/python/doc/CSProperties/CSPropProbeBox.rst7
-rw-r--r--CSXCAD/python/doc/CSProperties/CSProperties.rst7
-rw-r--r--CSXCAD/python/doc/CSRectGrid.rst8
-rw-r--r--CSXCAD/python/doc/CSTransform.rst9
-rw-r--r--CSXCAD/python/doc/CSXCAD.rst8
-rw-r--r--CSXCAD/python/doc/CSXCAD_API.rst13
-rw-r--r--CSXCAD/python/doc/Makefile225
-rw-r--r--CSXCAD/python/doc/Mesh.rst12
-rw-r--r--CSXCAD/python/doc/Utilities.rst8
-rw-r--r--CSXCAD/python/doc/about.rst21
-rw-r--r--CSXCAD/python/doc/conf.py348
-rw-r--r--CSXCAD/python/doc/index.rst25
-rw-r--r--CSXCAD/python/doc/install.rst31
-rw-r--r--CSXCAD/python/setup.py37
-rw-r--r--CSXCAD/python/tests/sphere.plybin0 -> 2099 bytes
-rw-r--r--CSXCAD/python/tests/sphere.stlbin0 -> 4884 bytes
-rw-r--r--CSXCAD/python/tests/test_CSPrimitives.py302
-rw-r--r--CSXCAD/python/tests/test_CSProperties.py140
-rw-r--r--CSXCAD/python/tests/test_CSRectGrid.py73
-rw-r--r--CSXCAD/python/tests/test_CSTransform.py81
-rw-r--r--CSXCAD/python/tests/test_CSXCAD.py49
-rw-r--r--CSXCAD/src/CSPrimCylinder.cpp4
-rw-r--r--CSXCAD/src/CSPrimCylindricalShell.cpp4
-rw-r--r--CSXCAD/src/CSPrimLinPoly.cpp4
-rw-r--r--CSXCAD/src/CSPrimMultiBox.cpp2
-rw-r--r--CSXCAD/src/CSPrimPolygon.cpp8
-rw-r--r--CSXCAD/src/CSPrimPolyhedron.cpp1
-rw-r--r--CSXCAD/src/CSPrimRotPoly.cpp8
-rw-r--r--CSXCAD/src/CSPrimSphere.cpp4
-rw-r--r--CSXCAD/src/CSPrimSphericalShell.cpp4
-rw-r--r--CSXCAD/src/CSPrimUserDefined.cpp4
-rw-r--r--CSXCAD/src/CSPrimWire.cpp4
-rw-r--r--CSXCAD/src/CSPropConductingSheet.cpp8
-rw-r--r--CSXCAD/src/CSPropDebyeMaterial.cpp16
-rw-r--r--CSXCAD/src/CSPropDumpBox.cpp4
-rw-r--r--CSXCAD/src/CSPropExcitation.cpp16
-rw-r--r--CSXCAD/src/CSPropLorentzMaterial.cpp48
-rw-r--r--CSXCAD/src/CSPropLumpedElement.cpp12
-rw-r--r--CSXCAD/src/CSPropMaterial.cpp40
-rw-r--r--CSXCAD/src/CSPropProbeBox.cpp1
-rw-r--r--CSXCAD/src/CSProperties.cpp2
-rw-r--r--CSXCAD/src/CSProperties.h6
-rw-r--r--CSXCAD/src/CSRectGrid.cpp1
-rw-r--r--CSXCAD/src/CSXCAD_Global.h2
-rw-r--r--CSXCAD/src/ContinuousStructure.cpp9
-rw-r--r--CSXCAD/src/ContinuousStructure.h9
-rw-r--r--CSXCAD/src/ParameterCoord.cpp4
-rw-r--r--CSXCAD/src/ParameterObjects.h14
-rw-r--r--QCSXCAD/CMakeLists.txt10
-rw-r--r--QCSXCAD/QVTKStructure.cpp15
-rw-r--r--QCSXCAD/QVTKStructure.h11
-rw-r--r--debian/changelog71
-rw-r--r--debian/compat1
-rw-r--r--debian/control31
-rw-r--r--debian/gitlab-ci.yml9
-rw-r--r--debian/libopenems-dev.install1
-rw-r--r--debian/patches/0002-Spelling-fixes.patch16
-rw-r--r--debian/patches/0003-More-things-to-fix-build.patch6
-rw-r--r--debian/patches/0004-link-more.patch12
-rw-r--r--debian/patches/0007-Fix-some-imports-to-make-python-interface-work.patch54
-rw-r--r--debian/patches/0007-Guard-xmmintrin.h-include-so-it-is-only-used-when-ne.patch47
-rw-r--r--debian/patches/series2
-rw-r--r--debian/python3-openems.install2
-rwxr-xr-xdebian/rules28
-rw-r--r--debian/tests/control4
-rwxr-xr-xdebian/tests/octave-load6
-rwxr-xr-xdebian/tests/python3-import11
-rw-r--r--openEMS/CMakeLists.txt10
-rw-r--r--openEMS/Common/engine_interface_base.h4
-rw-r--r--openEMS/Common/processfields.cpp66
-rw-r--r--openEMS/Common/processfields.h4
-rw-r--r--openEMS/Common/processmodematch.cpp2
-rw-r--r--openEMS/FDTD/engine_interface_fdtd.cpp46
-rw-r--r--openEMS/FDTD/engine_interface_fdtd.h11
-rw-r--r--openEMS/FDTD/excitation.cpp10
-rw-r--r--openEMS/FDTD/excitation.h10
-rw-r--r--openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp6
-rw-r--r--openEMS/FDTD/extensions/operator_ext_tfsf.cpp2
-rw-r--r--openEMS/FDTD/operator.cpp6
-rw-r--r--openEMS/FDTD/operator_sse.cpp6
-rw-r--r--openEMS/FDTD/operator_sse.h2
-rw-r--r--openEMS/FDTD/operator_sse_compressed.cpp12
-rw-r--r--openEMS/FDTD/operator_sse_compressed.h2
-rw-r--r--openEMS/matlab/DelayFidelity.m9
-rw-r--r--openEMS/matlab/RunOpenEMS.m6
-rw-r--r--openEMS/matlab/plotRefl.m19
-rw-r--r--openEMS/matlab/setup.m8
-rw-r--r--openEMS/nf2ff/nf2ff_calc.cpp14
-rw-r--r--openEMS/openems.cpp22
-rw-r--r--openEMS/openems.h4
-rw-r--r--openEMS/python/README.md14
-rw-r--r--openEMS/python/Tutorials/Bent_Patch_Antenna.py198
-rw-r--r--openEMS/python/Tutorials/CRLH_Extraction.py239
-rw-r--r--openEMS/python/Tutorials/Helical_Antenna.py191
-rw-r--r--openEMS/python/Tutorials/MSL_NotchFilter.py123
-rw-r--r--openEMS/python/Tutorials/RCS_Sphere.py126
-rw-r--r--openEMS/python/Tutorials/Rect_Waveguide.py125
-rw-r--r--openEMS/python/Tutorials/Simple_Patch_Antenna.py151
-rw-r--r--openEMS/python/doc/Tutorials/Antenna_Tutorials.rst9
-rw-r--r--openEMS/python/doc/Tutorials/Bent_Patch_Antenna.rst35
-rw-r--r--openEMS/python/doc/Tutorials/CRLH_Extraction.rst40
-rw-r--r--openEMS/python/doc/Tutorials/Helical_Antenna.rst32
-rw-r--r--openEMS/python/doc/Tutorials/Intro_Tutorials.rst10
-rw-r--r--openEMS/python/doc/Tutorials/MSL_NotchFilter.rst27
-rw-r--r--openEMS/python/doc/Tutorials/MicroWave_Tutorials.rst10
-rw-r--r--openEMS/python/doc/Tutorials/RCS_Sphere.rst32
-rw-r--r--openEMS/python/doc/Tutorials/Rect_Waveguide.rst27
-rw-r--r--openEMS/python/doc/Tutorials/Simple_Patch_Antenna.rst42
-rw-r--r--openEMS/python/doc/Tutorials/images/Bent_Patch.pngbin0 -> 353961 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/Bent_Patch_Pattern.pngbin0 -> 128101 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/Bent_Patch_SPara.pngbin0 -> 44995 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/CRLH_Spara.pngbin0 -> 43439 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/CRLH_cell.pngbin0 -> 160686 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/CRLH_dispersion.pngbin0 -> 58633 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/Helix_Ant.pngbin0 -> 311208 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/Helix_Ant_Pattern.pngbin0 -> 63799 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/Notch_Filter_SPara.pngbin0 -> 49022 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/RCS_norm.pngbin0 -> 43421 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/RCS_pattern.pngbin0 -> 61739 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/Rect_WG_SPara.pngbin0 -> 28698 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/Simp_Patch_Pattern.pngbin0 -> 53846 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/Simp_Patch_S11.pngbin0 -> 28926 bytes
-rw-r--r--openEMS/python/doc/Tutorials/images/Simp_Patch_Zin.pngbin0 -> 39892 bytes
-rw-r--r--openEMS/python/doc/Tutorials/index.rst12
-rw-r--r--openEMS/python/doc/conf.py297
-rwxr-xr-xopenEMS/python/doc/convert_tutorials.py63
-rw-r--r--openEMS/python/doc/index.rst24
-rw-r--r--openEMS/python/doc/nf2ff.rst16
-rw-r--r--openEMS/python/doc/openEMS.rst8
-rw-r--r--openEMS/python/doc/openEMS_API.rst11
-rw-r--r--openEMS/python/doc/ports.rst37
-rw-r--r--openEMS/python/openEMS/__init__.py6
-rw-r--r--openEMS/python/openEMS/_nf2ff.pxd49
-rw-r--r--openEMS/python/openEMS/_nf2ff.pyx59
-rw-r--r--openEMS/python/openEMS/automesh.py77
-rw-r--r--openEMS/python/openEMS/nf2ff.py211
-rw-r--r--openEMS/python/openEMS/openEMS.pxd65
-rw-r--r--openEMS/python/openEMS/openEMS.pyx447
-rw-r--r--openEMS/python/openEMS/physical_constants.py26
-rw-r--r--openEMS/python/openEMS/ports.py434
-rw-r--r--openEMS/python/openEMS/utilities.py66
-rw-r--r--openEMS/python/setup.py47
-rw-r--r--openEMS/tools/sar_calculation.cpp2
187 files changed, 9872 insertions, 326 deletions
diff --git a/AppCSXCAD/AppCSXCAD.cpp b/AppCSXCAD/AppCSXCAD.cpp
index a9d7c28..d11bd60 100644
--- a/AppCSXCAD/AppCSXCAD.cpp
+++ b/AppCSXCAD/AppCSXCAD.cpp
@@ -120,10 +120,9 @@ void AppCSXCAD::SaveSettings()
void AppCSXCAD::LoadSettings()
{
QSettings settings(__APPNAME__, __APPNAME__);
-
settings.beginGroup("MainWindow");
restoreGeometry(settings.value("Geometry").toByteArray());
- restoreState(settings.value("State").toByteArray());
+ //restoreState(settings.value("State").toByteArray());
settings.endGroup();
}
diff --git a/AppCSXCAD/CMakeLists.txt b/AppCSXCAD/CMakeLists.txt
index 2d4b11b..09bba11 100644
--- a/AppCSXCAD/CMakeLists.txt
+++ b/AppCSXCAD/CMakeLists.txt
@@ -10,6 +10,10 @@ PROJECT( AppCSXCAD CXX C)
cmake_minimum_required(VERSION 2.8)
+if (UNIX)
+ set (CMAKE_CXX_FLAGS -fPIC )
+endif()
+
if(POLICY CMP0020)
cmake_policy(SET CMP0020 OLD)
endif()
@@ -100,29 +104,12 @@ find_package(HDF5 1.8 COMPONENTS C HL REQUIRED)
INCLUDE_DIRECTORIES (${HDF5_INCLUDE_DIRS})
# vtk
-if (WIN32)
- find_package(VTK 6.1 REQUIRED)
-else()
- # prefer >=6.1, fallback to >=5.4
- find_package(VTK 6.1 COMPONENTS vtkGUISupportQt NO_MODULE)
- IF (NOT ${VTK_FOUND})
- find_package(VTK REQUIRED)
- endif()
-endif()
+find_package(VTK REQUIRED)
message(STATUS "Found package VTK. Using " ${VTK_VERSION})
include(${VTK_USE_FILE})
INCLUDE_DIRECTORIES(${VTK_INCLUDE_DIR})
-if("${VTK_MAJOR_VERSION}" EQUAL 5)
- set( vtk_LIBS
- QVTK )
-elseif("${VTK_MAJOR_VERSION}" EQUAL 6)
- set( vtk_LIBS
- vtkGUISupportQt)
-endif()
-message(STATUS "vtk libraries " ${vtk_LIBS})
-
# Qt
set(CMAKE_AUTOMOC ON)
if(${VTK_VERSION} VERSION_GREATER "6" AND VTK_QT_VERSION VERSION_GREATER "4")
@@ -146,17 +133,13 @@ SET(SOURCES
ADD_EXECUTABLE( AppCSXCAD ${SOURCES} )
-if(Qt5Widgets_FOUND)
- qt5_use_modules(AppCSXCAD Widgets Xml)
-endif()
-
TARGET_LINK_LIBRARIES( AppCSXCAD
${CSXCAD_LIBRARIES}
${QCSXCAD_LIBRARIES}
${HDF5_LIBRARIES}
${HDF5_HL_LIBRARIES}
- ${QT_LIBRARIES}
- ${vtk_LIBS}
+ Qt5::Core Qt5::Widgets Qt5::Xml
+ ${VTK_LIBRARIES}
hdf5_serial_hl
)
diff --git a/AppCSXCAD/main.cpp b/AppCSXCAD/main.cpp
index 6aa19af..8ef8d58 100644
--- a/AppCSXCAD/main.cpp
+++ b/AppCSXCAD/main.cpp
@@ -17,16 +17,24 @@
#include "AppCSXCAD.h"
+#include "vtkCommand.h"
+#if VTK_MAJOR_VERSION>=8
+ #include <QVTKOpenGLWidget.h>
+ #include <QSurfaceFormat>
+#endif
#include <QApplication>
int main(int argc, char *argv[])
{
+#if VTK_MAJOR_VERSION>=8
+ QSurfaceFormat::setDefaultFormat(QVTKOpenGLWidget::defaultFormat());
+#endif
#if not defined(__WIN32) && not defined(__WIN64)
//prevent that Qt changes float handling, e.g. expecting a german 1,345e+3 will fail...
setenv("LC_NUMERIC","C",1);
#endif
QApplication a(argc, argv);
- AppCSXCAD w;
- w.show();
- return a.exec();
+ AppCSXCAD w;
+ w.show();
+ return a.exec();
}
diff --git a/CSXCAD/CMakeLists.txt b/CSXCAD/CMakeLists.txt
index d7670c1..840f17d 100644
--- a/CSXCAD/CMakeLists.txt
+++ b/CSXCAD/CMakeLists.txt
@@ -10,6 +10,8 @@ PROJECT(CSXCAD CXX C)
cmake_minimum_required(VERSION 2.8)
+set (CMAKE_CXX_FLAGS -fPIC )
+
# default
set(LIB_VERSION_MAJOR 0)
set(LIB_VERSION_MINOR 6)
@@ -114,18 +116,11 @@ find_package(Boost 1.46 COMPONENTS
date_time
serialization
chrono
+ REQUIRED
)
# vtk
-if (WIN32)
- find_package(VTK 6.1 REQUIRED)
-else()
- # prefer >=6.1, fallback to >=5.4
- find_package(VTK 6.1 COMPONENTS vtkIOGeometry vtkIOPLY NO_MODULE)
- IF (NOT ${VTK_FOUND})
- find_package(VTK REQUIRED)
- endif()
-endif()
+find_package(VTK REQUIRED COMPONENTS vtkIOGeometry vtkIOPLY NO_MODULE)
message(STATUS "Found package VTK. Using version " ${VTK_VERSION})
include(${VTK_USE_FILE})
diff --git a/CSXCAD/matlab/AddDump.m b/CSXCAD/matlab/AddDump.m
index f454992..a3adc59 100644
--- a/CSXCAD/matlab/AddDump.m
+++ b/CSXCAD/matlab/AddDump.m
@@ -8,11 +8,15 @@ function CSX = AddDump(CSX, name, varargin)
% 1 for H-field time-domain dump
% 2 for electric current time-domain dump
% 3 for total current density (rot(H)) time-domain dump
+% 4 for D-field (electric flux density) time-domain dump
+% 5 for B-field (magnetic flux density) time-domain dump
%
% 10 for E-field frequency-domain dump
% 11 for H-field frequency-domain dump
% 12 for electric current frequency-domain dump
% 13 for total current density (rot(H)) frequency-domain dump
+% 14 for D-field (electric flux density) frequency-domain dump
+% 15 for B-field (magnetic flux density) frequency-domain dump
%
% 20 local SAR frequency-domain dump
% 21 1g averaging SAR frequency-domain dump
diff --git a/CSXCAD/matlab/AutoSmoothMeshLines.m b/CSXCAD/matlab/AutoSmoothMeshLines.m
index e41e261..e520fe6 100644
--- a/CSXCAD/matlab/AutoSmoothMeshLines.m
+++ b/CSXCAD/matlab/AutoSmoothMeshLines.m
@@ -44,7 +44,7 @@ lines = sort(unique(lines));
range = lines(end)-lines(1);
if (~isempty(find(diff(lines)<range*1e-6)))
- warning('CSXCAD:AutoSmoothMeshLines','some lines found with very small distance which may cause smoothing failure!');
+ warning('CSXCAD:AutoSmoothMeshLines','some lines found with very small distance which may cause smoothing failure');
end
methods = {};
@@ -138,7 +138,7 @@ end
if ((allowed_min_res>0) && (results.min_res<allowed_min_res))
if (silent==0)
- warning('CSXCAD:AutoSmoothMeshLines','method failed to obey allowed min res!');
+ warning('CSXCAD:AutoSmoothMeshLines','method failed to obey allowed min res');
end
quality = -1;
return
@@ -152,7 +152,7 @@ if (results.max_res>max_res*1.01)
end
if (results.max_ratio>ratio*1.01)
if (silent==0)
- warning('CSXCAD:AutoSmoothMeshLines',['method failed to fulfill the max. ratio: ' num2str(results.max_ratio) ' > ' num2str(ratio)]');
+ warning('CSXCAD:AutoSmoothMeshLines',['method failed to fulfill the max. ratio: ' num2str(results.max_ratio) ' > ' num2str(ratio)]);
end
quality = quality*(ratio/results.max_ratio);
end
diff --git a/CSXCAD/python/CSXCAD/CSPrimitives.pxd b/CSXCAD/python/CSXCAD/CSPrimitives.pxd
new file mode 100644
index 0000000..8d9e1a1
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/CSPrimitives.pxd
@@ -0,0 +1,236 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from libcpp.string cimport string
+from libcpp cimport bool
+
+from ParameterObjects cimport _ParameterSet, ParameterSet
+from CSProperties cimport _CSProperties, CSProperties
+from CSTransform cimport _CSTransform, CSTransform
+from CSRectGrid cimport CoordinateSystem
+
+cdef extern from "CSXCAD/CSPrimitives.h":
+ cpdef enum PrimitiveType "CSPrimitives::PrimitiveType":
+ POINT "CSPrimitives::POINT"
+ BOX "CSPrimitives::BOX"
+ MULTIBOX "CSPrimitives::MULTIBOX"
+ SPHERE "CSPrimitives::SPHERE"
+ SPHERICALSHELL "CSPrimitives::SPHERICALSHELL"
+ CYLINDER "CSPrimitives::CYLINDER"
+ CYLINDRICALSHELL "CSPrimitives::CYLINDRICALSHELL"
+ POLYGON "CSPrimitives::POLYGON"
+ LINPOLY "CSPrimitives::LINPOLY"
+ ROTPOLY "CSPrimitives::ROTPOLY"
+ POLYHEDRON "CSPrimitives::POLYHEDRON"
+ CURVE "CSPrimitives::CURVE"
+ WIRE "CSPrimitives::WIRE"
+ USERDEFINED "CSPrimitives::USERDEFINED"
+ POLYHEDRONREADER "CSPrimitives::POLYHEDRONREADER"
+
+
+cdef extern from "CSXCAD/CSPrimitives.h":
+ cdef cppclass _CSPrimitives "CSPrimitives":
+ _CSPrimitives(_ParameterSet*, _CSProperties*) except +
+ unsigned int GetID()
+ int GetType()
+ string GetTypeName()
+
+ _CSProperties* GetProperty()
+
+ void SetPriority(int val)
+ int GetPriority()
+ bool Update(string *ErrStr)
+
+ bool GetBoundBox(double dBoundBox[6])
+
+ int GetDimension()
+
+ bool IsInside(double* Coord, double tol)
+
+ bool GetPrimitiveUsed()
+ void SetPrimitiveUsed(bool val)
+
+ void SetCoordinateSystem(CoordinateSystem cs_type)
+ CoordinateSystem GetCoordinateSystem()
+
+ _CSTransform* GetTransform()
+
+cdef class CSPrimitives:
+ cdef _CSPrimitives *thisptr
+ cdef readonly CSTransform __transform
+ cdef readonly CSProperties __prop
+ cdef __GetProperty(self)
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimPoint.h":
+ cdef cppclass _CSPrimPoint "CSPrimPoint" (_CSPrimitives):
+ _CSPrimPoint(_ParameterSet*, _CSProperties*) except +
+ void SetCoord(int idx, double val)
+ double GetCoord(int idx)
+
+cdef class CSPrimPoint(CSPrimitives):
+ pass
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimBox.h":
+ cdef cppclass _CSPrimBox "CSPrimBox" (_CSPrimitives):
+ _CSPrimBox(_ParameterSet*, _CSProperties*) except +
+ void SetCoord(int idx, double val)
+ double GetCoord(int idx)
+
+cdef class CSPrimBox(CSPrimitives):
+ pass
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimCylinder.h":
+ cdef cppclass _CSPrimCylinder "CSPrimCylinder" (_CSPrimitives):
+ _CSPrimCylinder(_ParameterSet*, _CSProperties*) except +
+ void SetCoord(int idx, double val)
+ double GetCoord(int idx)
+ void SetRadius(double val)
+ double GetRadius()
+
+cdef class CSPrimCylinder(CSPrimitives):
+ pass
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimCylindricalShell.h":
+ cdef cppclass _CSPrimCylindricalShell "CSPrimCylindricalShell" (_CSPrimCylinder):
+ _CSPrimCylindricalShell(_ParameterSet*, _CSProperties*) except +
+ void SetShellWidth(double val)
+ double GetShellWidth()
+
+cdef class CSPrimCylindricalShell(CSPrimCylinder):
+ pass
+
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimSphere.h":
+ cdef cppclass _CSPrimSphere "CSPrimSphere" (_CSPrimitives):
+ _CSPrimSphere(_ParameterSet*, _CSProperties*) except +
+ void SetCenter(double x1, double x2, double x3)
+ double GetCoord(int idx)
+ void SetRadius(double val)
+ double GetRadius()
+
+cdef class CSPrimSphere(CSPrimitives):
+ pass
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimSphericalShell.h":
+ cdef cppclass _CSPrimSphericalShell "CSPrimSphericalShell" (_CSPrimSphere):
+ _CSPrimSphericalShell(_ParameterSet*, _CSProperties*) except +
+ void SetShellWidth(double val)
+ double GetShellWidth()
+
+cdef class CSPrimSphericalShell(CSPrimSphere):
+ pass
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimPolygon.h":
+ cdef cppclass _CSPrimPolygon "CSPrimPolygon" (_CSPrimitives):
+ _CSPrimPolygon(_ParameterSet*, _CSProperties*) except +
+ void AddCoord(double val)
+ double GetCoord(int index)
+ void ClearCoords()
+ size_t GetQtyCoords()
+ void SetNormDir(int ny)
+ int GetNormDir()
+ void SetElevation(double val)
+ double GetElevation()
+
+cdef class CSPrimPolygon(CSPrimitives):
+ pass
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimLinPoly.h":
+ cdef cppclass _CSPrimLinPoly "CSPrimLinPoly" (_CSPrimPolygon):
+ _CSPrimLinPoly(_ParameterSet*, _CSProperties*) except +
+ void SetLength(double val)
+ double GetLength()
+
+cdef class CSPrimLinPoly(CSPrimPolygon):
+ pass
+
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimRotPoly.h":
+ cdef cppclass _CSPrimRotPoly "CSPrimRotPoly" (_CSPrimPolygon):
+ _CSPrimRotPoly(_ParameterSet*, _CSProperties*) except +
+ void SetRotAxisDir(int ny)
+ int GetRotAxisDir()
+ void SetAngle(int index, double val)
+ double GetAngle(int index)
+
+cdef class CSPrimRotPoly(CSPrimPolygon):
+ pass
+
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimCurve.h":
+ cdef cppclass _CSPrimCurve "CSPrimCurve" (_CSPrimitives):
+ _CSPrimCurve(_ParameterSet*, _CSProperties*) except +
+ size_t AddPoint(double *coords)
+ size_t GetNumberOfPoints()
+ bool GetPoint(size_t point_index, double point[3])
+ void ClearPoints()
+
+cdef class CSPrimCurve(CSPrimitives):
+ pass
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimWire.h":
+ cdef cppclass _CSPrimWire "CSPrimWire" (_CSPrimCurve):
+ _CSPrimWire(_ParameterSet*, _CSProperties*) except +
+ void SetWireRadius(double val)
+ double GetWireRadius()
+
+cdef class CSPrimWire(CSPrimCurve):
+ pass
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimPolyhedron.h":
+ cdef cppclass _CSPrimPolyhedron "CSPrimPolyhedron" (_CSPrimitives):
+ _CSPrimPolyhedron(_ParameterSet*, _CSProperties*) except +
+ void Reset()
+ void AddVertex(float px, float py, float pz)
+ float* GetVertex(unsigned int n)
+ unsigned int GetNumVertices()
+ void AddFace(int numVertex, int* vertices)
+ int* GetFace(unsigned int n, unsigned int &numVertices)
+ unsigned int GetNumFaces()
+
+cdef class CSPrimPolyhedron(CSPrimitives):
+ pass
+
+###############################################################################
+cdef extern from "CSXCAD/CSPrimPolyhedronReader.h":
+ ctypedef enum FileType "CSPrimPolyhedronReader::FileType":
+ UNKNOWN "CSPrimPolyhedronReader::UNKNOWN"
+ STL_FILE "CSPrimPolyhedronReader::STL_FILE"
+ PLY_FILE "CSPrimPolyhedronReader::PLY_FILE"
+ cdef cppclass _CSPrimPolyhedronReader "CSPrimPolyhedronReader" (_CSPrimPolyhedron):
+ _CSPrimPolyhedronReader(_ParameterSet*, _CSProperties*) except +
+ void SetFilename(string name)
+ string GetFilename()
+ void SetFileType(FileType ft)
+ FileType GetFileType()
+ bool ReadFile()
+
+cdef class CSPrimPolyhedronReader(CSPrimPolyhedron):
+ pass
diff --git a/CSXCAD/python/CSXCAD/CSPrimitives.pyx b/CSXCAD/python/CSXCAD/CSPrimitives.pyx
new file mode 100644
index 0000000..3a169eb
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/CSPrimitives.pyx
@@ -0,0 +1,1261 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,2016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""CSXCAD.CSPrimitives
+Module for all Primitives
+
+Notes
+-----
+Usually it is not meant to create primitives manually, but instead
+use the ContinuousStructure object to create primives using the
+e.g. AddBox or AddCylinder methods.
+
+Examples
+--------
+Create a metal box:
+
+>>> pset = ParameterObjects.ParameterSet()
+>>> metal = CSProperties.CSPropMetal(pset)
+>>> box = CSPrimitives.CSPrimBox(pset, metal)
+"""
+
+import numpy as np
+import sys
+from libcpp.string cimport string
+from libcpp cimport bool
+
+cimport CSPrimitives
+from Utilities import CheckNyDir, GetMultiDirs
+cimport CSRectGrid
+
+cdef class CSPrimitives:
+ """
+ Virtual base class for all primives, cannot be created!
+
+ """
+ @staticmethod
+ def fromType(prim_type, pset, prop, no_init=False, **kw):
+ """ fromType(prim_type, pset, prop, no_init=False, **kw)
+
+ Create a primtive specified by the `prim_type`
+
+ :param prim_type: Primitive type
+ :param pset: ParameterSet to assign to the new primitive
+ :param prop: CSProperty to assign to the new primitive
+ :param no_init: do not create an actual C++ instance
+ """
+ prim = None
+ if prim_type == POINT:
+ prim = CSPrimPoint(pset, prop, no_init=no_init, **kw)
+ elif prim_type == POINT:
+ prim = CSPrimPoint(pset, prop, no_init=no_init, **kw)
+ elif prim_type == BOX:
+ prim = CSPrimBox(pset, prop, no_init=no_init, **kw)
+ elif prim_type == MULTIBOX:
+ raise Exception('Primitive type "MULTIBOX" not yet implemented!')
+ elif prim_type == SPHERE:
+ prim = CSPrimSphere(pset, prop, no_init=no_init, **kw)
+ elif prim_type == SPHERICALSHELL:
+ prim = CSPrimSphericalShell(pset, prop, no_init=no_init, **kw)
+ elif prim_type == CYLINDER:
+ prim = CSPrimCylinder(pset, prop, no_init=no_init, **kw)
+ elif prim_type == CYLINDRICALSHELL:
+ prim = CSPrimCylindricalShell(pset, prop, no_init=no_init, **kw)
+ elif prim_type == POLYGON:
+ prim = CSPrimPolygon(pset, prop, no_init=no_init, **kw)
+ elif prim_type == LINPOLY:
+ prim = CSPrimLinPoly(pset, prop, no_init=no_init, **kw)
+ elif prim_type == ROTPOLY:
+ prim = CSPrimRotPoly(pset, prop, no_init=no_init, **kw)
+ elif prim_type == POLYHEDRON:
+ prim = CSPrimPolyhedron(pset, prop, no_init=no_init, **kw)
+ elif prim_type == CURVE:
+ prim = CSPrimCurve(pset, prop, no_init=no_init, **kw)
+ elif prim_type == WIRE:
+ prim = CSPrimWire(pset, prop, no_init=no_init, **kw)
+ elif prim_type == USERDEFINED:
+ raise Exception('Primitive type "USERDEFINED" not yet implemented!')
+ elif prim_type == POLYHEDRONREADER:
+ prim = CSPrimPolyhedronReader(pset, prop, no_init=no_init, **kw)
+ return prim
+
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ self.__transform = None
+ self.__prop = prop
+ if no_init:
+ self.thisptr = NULL
+ return
+
+ assert self.thisptr, 'Error, object cannot be created (protected)'
+ self.__prop = prop
+
+ if 'priority' in kw:
+ self.SetPriority(kw['priority'])
+ del kw['priority']
+ if 'no_init' in kw:
+ del kw['no_init']
+
+ assert len(kw)==0, 'Unknown keyword arguments: "{}"'.format(kw)
+
+ def GetID(self):
+ """
+ Get the ID for this primitive
+
+ :returns: int -- ID for this primitive
+ """
+ return self.thisptr.GetID()
+
+ def GetProperty(self):
+ """
+ Get the property for this primitive
+
+ :returns: CSProperties.CSProperties
+ """
+ return self.__GetProperty()
+
+ cdef __GetProperty(self):
+ cdef _CSProperties* _prop
+ cdef CSProperties prop
+ if self.__prop is None:
+ _prop = self.thisptr.GetProperty()
+ self.__prop = CSProperties.fromType(_prop.GetType(), pset=None, no_init=True)
+ self.__prop.thisptr = _prop
+
+ return self.__prop
+
+ def GetType(self):
+ """
+ Get the type as int for this primitive
+
+ :returns: int -- Type for this primitive (e.g. 0 --> Point, 1 --> Box, ...)
+ """
+ return self.thisptr.GetType()
+
+ def GetTypeName(self):
+ """
+ Get the type as string (UTF-8) for this primitive
+
+ :returns: str -- Type name for this primitive ("Point", "Box", ...)
+ """
+ return self.thisptr.GetTypeName().decode('UTF-8')
+
+ def SetPriority(self, val):
+ """ SetPriority(val)
+
+ Set the priority for this primitive
+
+ :param val: int -- Higher priority values will override primitives with a lower priority
+ """
+ self.thisptr.SetPriority(val)
+
+ def GetPriority(self):
+ """
+ Get the priority for this primitive
+
+ :returns: int -- Priority for this primitive
+ """
+ return self.thisptr.GetPriority()
+
+ def GetBoundBox(self):
+ """
+ Get the bounding box for this primitive
+
+ :returns: (2,3) ndarray -- bounding box for this primitive
+ """
+ bb = np.zeros([2,3])
+ cdef double _bb[6]
+ self.thisptr.GetBoundBox(_bb)
+ for n in range(3):
+ bb[0,n] = _bb[2*n]
+ bb[1,n] = _bb[2*n+1]
+ return bb
+
+ def GetDimension(self):
+ """
+ Get the dimension of this primitive
+
+ :returns: int -- dimension 0..3
+ """
+ return self.thisptr.GetDimension()
+
+ def IsInside(self, coord, tol=0):
+ """ IsInside(coord, tol=0)
+
+ Check if a given coordinate is inside this primitive.
+
+ :param coord: (3,) array -- coordinate
+ :returns: bool
+ """
+ cdef double c_coord[3]
+ for n in range(3):
+ c_coord[n] = coord[n]
+
+ return self.thisptr.IsInside(c_coord, tol)
+
+ def GetPrimitiveUsed(self):
+ """
+ Get if this primitive has been used (used flag set)
+ """
+ return self.thisptr.GetPrimitiveUsed()
+
+ def SetPrimitiveUsed(self, val):
+ """ SetPrimitiveUsed(val)
+
+ Set used flag.
+ """
+ self.thisptr.SetPrimitiveUsed(val)
+
+ def __GetCSX(self):
+ if self.__prop is None:
+ return None
+ return self.__prop.__CSX
+
+ def GetTransform(self):
+ """ GetTransform()
+
+ Get the transformation class assigned to this primitive.
+ If this primitve does not have any, it will be created.
+
+ :return: CSTransform class
+
+ See Also
+ --------
+ CSXCAD.CSTransform.CSTransform
+ """
+ if self.__transform is None:
+ self.__transform = CSTransform(no_init=True)
+ self.__transform.thisptr = self.thisptr.GetTransform()
+ return self.__transform
+
+ def AddTransform(self, transform, *args, no_init=False, **kw):
+ """ AddTransform(transform, *args, **kw)
+
+ Add a transformation to this primitive.
+
+ See Also
+ --------
+ CSXCAD.CSTransform.CSTransform.AddTransform
+ """
+ tr = self.GetTransform()
+ tr.AddTransform(transform, *args, **kw)
+
+ def HasTransform(self):
+ """
+ Check if this primitive has a transformation attached.
+ It will not create one if it does not.
+
+ :returns: bool
+ """
+ if self.__transform is None:
+ return False
+ return self.__transform.HasTransform()
+
+ def SetCoordinateSystem(self, cs_type):
+ """ SetCoordinateSystem(cs_type)
+
+ Set the coordinate system type (Cartesian or cylindrical) for this primitive.
+ If set to None, the mesh type of the assigned rect grid will be used.
+
+ :param cs_type: coordinate system (0 : Cartesian, 1 : Cylindrical) or None
+
+ See Also
+ --------
+ CSXCAD.CSRectGrid.CSRectGrid.SetMeshType
+
+ """
+ assert cs_type in [CSRectGrid.CARTESIAN, CSRectGrid.CYLINDRICAL, None], 'Unknown coordinate system: {}'.format(cs_type)
+ if cs_type is None:
+ cs_type = CSRectGrid.UNDEFINED_CS
+ self.thisptr.SetCoordinateSystem(cs_type)
+
+ def GetCoordinateSystem(self):
+ """ GetCoordinateSystem
+
+ :returns: coordinate system (0 : Cartesian, 1 : Cylindrical) or None
+ """
+ cs_type = self.thisptr.GetCoordinateSystem()
+ if cs_type == CSRectGrid.UNDEFINED_CS:
+ return None
+ return cs_type
+
+ def Update(self):
+ """ Trigger an internal update and report success and error message
+
+ :returns: bool, err_msg -- success and error message (empty on success)
+ """
+ cdef string s
+ succ = self.thisptr.Update(&s)
+ return succ, str(s)
+
+
+###############################################################################
+cdef class CSPrimPoint(CSPrimitives):
+ """ Point Primitive
+
+ A point is defined by a single 3D coordinate.
+
+ Parameters
+ ----------
+ coord : (vector)
+ Coordinate vector (3,) array
+
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimPoint(pset.thisptr, prop.thisptr)
+
+ if 'coord' in kw:
+ self.SetCoord(kw['coord'])
+ del kw['coord']
+ super(CSPrimPoint, self).__init__(pset, prop, *args, **kw)
+
+ def SetCoord(self, coord):
+ """ SetCoord(coord)
+
+ Set the coordinate for this point primitive
+
+ :param coord: list/array of float -- Set the point coordinate
+ """
+ ptr = <_CSPrimPoint*>self.thisptr
+ assert len(coord)==3, "CSPrimPoint:SetCoord: length of array needs to be 3"
+ for n in range(3):
+ ptr.SetCoord(n, coord[n])
+
+ def GetCoord(self):
+ """
+ Get the point coordinate for this primitive
+
+ :returns: (3,) ndarray -- point coordinate for this primitive
+ """
+ ptr = <_CSPrimPoint*>self.thisptr
+ coord = np.zeros(3)
+ for n in range(3):
+ coord[n] = ptr.GetCoord(n)
+ return coord
+
+###############################################################################
+cdef class CSPrimBox(CSPrimitives):
+ """ Box Primitive
+
+ A box is defined by two 3D coordinates. E.g. the lower-left (start)
+ and upper right (stop) point.
+ A box is a cube in Cartesian coordinates.
+ A box is a cylinder in cylindrical coordinates.
+
+ Parameters
+ ----------
+ start : (3,) array
+ Start point vector (3,) array
+ stop : (3,) array
+ Stop point vector (3,) array
+
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimBox(pset.thisptr, prop.thisptr)
+ if 'start' in kw:
+ self.SetStart(kw['start'])
+ del kw['start']
+ if 'stop' in kw:
+ self.SetStop(kw['stop'])
+ del kw['stop']
+ super(CSPrimBox, self).__init__(pset, prop, *args, **kw)
+
+ def SetStart(self, coord):
+ """ SetStart(coord)
+
+ Set the start coordinate for this box primitive.
+
+ :param coord: list/array of float -- Set the start point coordinate
+ """
+ ptr = <_CSPrimBox*>self.thisptr
+ assert len(coord)==3, "CSPrimBox:SetStart: length of array needs to be 3"
+ for n in range(3):
+ ptr.SetCoord(2*n, coord[n])
+
+ def SetStop(self, coord):
+ """ SetStop(coord)
+
+ Set the stop coordinate for this box primitive.
+
+ :param coord: list/array of float -- Set the stop point coordinate
+ """
+ ptr = <_CSPrimBox*>self.thisptr
+ assert len(coord)==3, "CSPrimBox:SetStop: length of array needs to be 3"
+ for n in range(3):
+ ptr.SetCoord(2*n+1, coord[n])
+
+ def GetStart(self):
+ """
+ Get the start coordinate for this primitive.
+
+ :returns: (3,) ndarray -- Start coordinate for this primitive
+ """
+ ptr = <_CSPrimBox*>self.thisptr
+ coord = np.zeros(3)
+ for n in range(3):
+ coord[n] = ptr.GetCoord(2*n)
+ return coord
+
+ def GetStop(self):
+ """
+ Get the stop coordinate for this primitive.
+
+ :returns: (3,) ndarray -- Stop coordinate for this primitive
+ """
+ ptr = <_CSPrimBox*>self.thisptr
+ coord = np.zeros(3)
+ for n in range(3):
+ coord[n] = ptr.GetCoord(2*n+1)
+ return coord
+
+###############################################################################
+cdef class CSPrimCylinder(CSPrimitives):
+ """ Cylinder Primitive
+
+ A cylinder is defined by its axis and a radius.
+ The axis is defined by two 3D coordinates (start/stop).
+
+ Parameters
+ ----------
+ start : (3,) array
+ Axis start point vector (3,) array
+ stop : (3,) array
+ Axis stop point vector (3,) array
+ radius : float
+ The cylinder radius
+
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimCylinder(pset.thisptr, prop.thisptr)
+ if 'start' in kw:
+ self.SetStart(kw['start'])
+ del kw['start']
+ if 'stop' in kw:
+ self.SetStop(kw['stop'])
+ del kw['stop']
+ if 'radius' in kw:
+ self.SetRadius(kw['radius'])
+ del kw['radius']
+ super(CSPrimCylinder, self).__init__(pset, prop, *args, **kw)
+
+ def SetStart(self, coord):
+ """ SetStart(coord)
+
+ Set the start coordinate for the cylinder axis.
+
+ :param coord: list/array of float -- Set the axis start point coordinate.
+ """
+ ptr = <_CSPrimCylinder*>self.thisptr
+ assert len(coord)==3, "CSPrimCylinder:SetStart: length of array needs to be 3"
+ for n in range(3):
+ ptr.SetCoord(2*n, coord[n])
+
+ def SetStop(self, coord):
+ """ SetStop(coord)
+
+ Set the stop coordinate for the cylinder axis.
+
+ :param coord: list/array of float -- Set the axis stop point coordinate.
+ """
+ ptr = <_CSPrimCylinder*>self.thisptr
+ assert len(coord)==3, "CSPrimCylinder:SetStop: length of array needs to be 3"
+ for n in range(3):
+ ptr.SetCoord(2*n+1, coord[n])
+
+ def GetStart(self):
+ """
+ Get the axis start coordinate.
+
+ :returns: (3,) ndarray -- Axis start coordinate.
+ """
+ ptr = <_CSPrimCylinder*>self.thisptr
+ coord = np.zeros(3)
+ for n in range(3):
+ coord[n] = ptr.GetCoord(2*n)
+ return coord
+
+ def GetStop(self):
+ """
+ Get the axis stop coordinate.
+
+ :returns: (3,) ndarray -- Axis stop coordinate.
+ """
+ ptr = <_CSPrimCylinder*>self.thisptr
+ coord = np.zeros(3)
+ for n in range(3):
+ coord[n] = ptr.GetCoord(2*n+1)
+ return coord
+
+ def SetRadius(self, val):
+ """ SetRadius(val)
+
+ Set the cylinder radius
+
+ :param val: float -- Set the cylinder radius
+ """
+ ptr = <_CSPrimCylinder*>self.thisptr
+ ptr.SetRadius(val)
+
+ def GetRadius(self):
+ """
+ Get the cylinder radius.
+
+ :returns: float -- Cylinder radius.
+ """
+ ptr = <_CSPrimCylinder*>self.thisptr
+ return ptr.GetRadius()
+
+###############################################################################
+cdef class CSPrimCylindricalShell(CSPrimCylinder):
+ """ Cylindrical Shell (hollow cylinder)
+
+ A cylindrical shell is defined like a cylinder with an additional shell width.
+
+ Parameters
+ ----------
+ shell_width : float
+ Width of the cylindrical shell
+
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimCylindricalShell(pset.thisptr, prop.thisptr)
+ if 'shell_width' in kw:
+ self.SetShellWidth(kw['shell_width'])
+ del kw['shell_width']
+ super(CSPrimCylindricalShell, self).__init__(pset, prop, *args, **kw)
+
+ def SetShellWidth(self, val):
+ """ SetShellWidth(val)
+
+ Set the cylinder shell width.
+
+ :param val: float -- Set the cylinder shell width
+ """
+ ptr = <_CSPrimCylindricalShell*>self.thisptr
+ ptr.SetShellWidth(val)
+
+ def GetShellWidth(self):
+ """
+ Get the cylinder shell width.
+
+ :returns: float -- Cylinder shell width.
+ """
+ ptr = <_CSPrimCylindricalShell*>self.thisptr
+ return ptr.GetShellWidth()
+
+###############################################################################
+cdef class CSPrimSphere(CSPrimitives):
+ """ Sphere Primitive
+
+ A sphere is defined by its center and radius.
+ The center is defined by a 3D coordinate.
+
+ Parameters
+ ----------
+ center : (3,) array
+ Center point vector (3,) array
+ radius : float
+ The sphere radius
+
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimSphere(pset.thisptr, prop.thisptr)
+ if 'center' in kw:
+ self.SetCenter(kw['center'])
+ del kw['center']
+ if 'radius' in kw:
+ self.SetRadius(kw['radius'])
+ del kw['radius']
+ super(CSPrimSphere, self).__init__(pset, prop, *args, **kw)
+
+ def SetCenter(self, coord):
+ """ SetRadius(val)
+
+ Set the sphere center point.
+
+ :param coord: (3,) array -- Set the sphere center point.
+ """
+ ptr = <_CSPrimSphere*>self.thisptr
+ assert len(coord)==3, "CSPrimSphere:SetCenter: length of array needs to be 3"
+ ptr.SetCenter(coord[0], coord[1], coord[2])
+
+ def GetCenter(self):
+ """
+ Get the sphere center point.
+
+ :returns: (3,) ndarray -- Center coordinate.
+ """
+ ptr = <_CSPrimSphere*>self.thisptr
+ coord = np.zeros(3)
+ for n in range(3):
+ coord[n] = ptr.GetCoord(n)
+ return coord
+
+ def SetRadius(self, val):
+ """ SetRadius(val)
+
+ Set the sphere radius
+
+ :param val: float -- Set the sphere radius
+ """
+ ptr = <_CSPrimSphere*>self.thisptr
+ ptr.SetRadius(val)
+
+ def GetRadius(self):
+ """
+ Get the sphere radius.
+
+ :returns: float -- Sphere radius.
+ """
+ ptr = <_CSPrimSphere*>self.thisptr
+ return ptr.GetRadius()
+
+###############################################################################
+cdef class CSPrimSphericalShell(CSPrimSphere):
+ """ Spherical Shell (hollow sphere) Primitive Class
+
+ A spherical shell is defined like a sphere with an additional shell width.
+
+ Parameters
+ ----------
+ shell_width : float
+ Width of the spherical shell
+
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimSphericalShell(pset.thisptr, prop.thisptr)
+ if 'shell_width' in kw:
+ self.SetShellWidth(kw['shell_width'])
+ del kw['shell_width']
+ super(CSPrimSphericalShell, self).__init__(pset, prop, *args, **kw)
+
+ def SetShellWidth(self, val):
+ """ SetShellWidth(val)
+
+ Set the sphere shell width.
+
+ :param val: float -- Set the sphere shell width
+ """
+ ptr = <_CSPrimSphericalShell*>self.thisptr
+ ptr.SetShellWidth(val)
+
+ def GetShellWidth(self):
+ """
+ Get the sphere shell width.
+
+ :returns: float -- sphere shell width.
+ """
+ ptr = <_CSPrimSphericalShell*>self.thisptr
+ return ptr.GetShellWidth()
+
+###############################################################################
+cdef class CSPrimPolygon(CSPrimitives):
+ """ Polygon Primitive
+
+ A polygon is a surface defined by a set of 2D points/coordinates.
+ To place the polygon in a 3D space, a normal direction (x/y/z) and an
+ elevation in this direction have to be specified.
+
+ Parameters
+ ----------
+ points : (N,2) array
+ Array of coordinates
+ norm_dir : float or str
+ Normal direction, either 0,1,2 or x/y/z respectively
+ elevation : float
+ Elevation in normal direciton
+
+ Examples
+ --------
+ Define a half circle as polygon
+
+ >>> polygon = CSPrimitives.CSPrimBox(pset, metal, norm_dir='z', elevation=1.0)
+ >>> ang = np.linspace(0, np.pi, 21)
+ >>> polygon.SetCoords(5*np.cos(ang), 5*np.sin(ang))
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimPolygon(pset.thisptr, prop.thisptr)
+ if 'points' in kw:
+ assert len(kw['points'])==2, 'points must be a list of length 2'
+ self.SetCoords(kw['points'][0], kw['points'][1])
+ del kw['points']
+ if 'norm_dir' in kw:
+ self.SetNormDir(kw['norm_dir'])
+ del kw['norm_dir']
+ if 'elevation' in kw:
+ self.SetElevation(kw['elevation'])
+ del kw['elevation']
+ super(CSPrimPolygon, self).__init__(pset, prop, *args, **kw)
+
+ def SetCoords(self, x0, x1):
+ """ SetCoords(x0, x1)
+
+ Set the coordinates for the polygon. This will clear all previous coordinates.
+
+ :param x0, x1: (N,), (N,) Two arrays for x0/x1 of the polygon coordinates.
+ """
+ assert len(x0)==len(x1), 'SetCoords: x0/x1 do not have the same length'
+ assert len(x0)>0, 'SetCoords: empty coordinates'
+
+ ptr = <_CSPrimPolygon*>self.thisptr
+ ptr.ClearCoords()
+ for n in range(len(x0)):
+ ptr.AddCoord(x0[n])
+ ptr.AddCoord(x1[n])
+
+ def GetCoords(self):
+ """
+ Get the coordinates for the polygon
+
+ :return x0, x1: (N,), (N,) Arrays for x0,x1 of the polygon coordinates
+ """
+ ptr = <_CSPrimPolygon*>self.thisptr
+ N = ptr.GetQtyCoords()
+ x0 = np.zeros(N)
+ x1 = np.zeros(N)
+ for n in range(N):
+ x0[n] = ptr.GetCoord(2*n)
+ x1[n] = ptr.GetCoord(2*n+1)
+ return x0, x1
+
+ def GetQtyCoords(self):
+ """
+ Get the number of coordinates for the polygon
+
+ :return val: int -- Number of polygon coordinates.
+ """
+ ptr = <_CSPrimPolygon*>self.thisptr
+ return ptr.GetQtyCoords()
+
+ def ClearCoords(self):
+ """
+ Remove all coordinates.
+ """
+ ptr = <_CSPrimPolygon*>self.thisptr
+ ptr.ClearCoords()
+
+ def SetNormDir(self, ny):
+ """ SetNormDir(ny)
+
+ Set the normal direction.
+
+ :param ny: int or string -- Normal direction, either 0/1/2 or 'x'/'y'/'z'
+ """
+ ptr = <_CSPrimPolygon*>self.thisptr
+ ptr.SetNormDir(CheckNyDir(ny))
+
+ def GetNormDir(self):
+ """
+ Get the normal direction.
+
+ :return ny: int -- Normal direction as 0, 1 or 2 meaning x,y or z
+ """
+ ptr = <_CSPrimPolygon*>self.thisptr
+ return ptr.GetNormDir()
+
+ def SetElevation(self, val):
+ """ SetElevation(val)
+
+ Set the elevation in normal direction.
+
+ :param val: float -- Elevation in normal direction.
+ """
+ ptr = <_CSPrimPolygon*>self.thisptr
+ ptr.SetElevation(val)
+
+ def GetElevation(self):
+ """
+ Get the elevation in normal direction.
+
+ :return val: float -- Get the elevation in normal direction.
+ """
+ ptr = <_CSPrimPolygon*>self.thisptr
+ return ptr.GetElevation()
+
+###############################################################################
+cdef class CSPrimLinPoly(CSPrimPolygon):
+ """ Linear Extruded Polygon
+
+ A linear extruded polygon is a polygon that is extruded in normal direction
+ for a certain length above the elevation.
+
+ Parameters
+ ----------
+ length : float
+ Extrusion length in normal direction
+
+ Examples
+ --------
+ Define a half circle with a height (in z direction) of 1
+
+ >>> linpoly = CSPrimitives.CSPrimLinPoly(pset, metal, norm_dir='z', elevation=0.5)
+ >>> ang = np.linspace(0, np.pi, 21)
+ >>> linpoly.SetCoords(5*np.cos(ang), 5*np.sin(ang))
+ >>> linpoly.SetLength(1.0)
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimLinPoly(pset.thisptr, prop.thisptr)
+ if 'length' in kw:
+ self.SetLength(kw['length'])
+ del kw['length']
+ super(CSPrimLinPoly, self).__init__(pset, prop, *args, **kw)
+
+ def SetLength(self, val):
+ """ SetLength(val)
+
+ Set the extrusion length in normal direction.
+
+ :param val: float -- Extrusion length in normal direction.
+ """
+ ptr = <_CSPrimLinPoly*>self.thisptr
+ ptr.SetLength(val)
+
+ def GetLength(self):
+ """
+ Get the extrusion length in normal direction.
+
+ :return val: float -- Get the extrusion length in normal direction.
+ """
+ ptr = <_CSPrimLinPoly*>self.thisptr
+ return ptr.GetLength()
+
+###############################################################################
+cdef class CSPrimRotPoly(CSPrimPolygon):
+ """ Rotation Extruded Polygon
+
+ A rotation extruded polygon is a polygon that is rotated around a Cartesian
+ axis with a given start and stop angle.
+
+ Parameters
+ ----------
+ rot_axis : float or str
+ Rotation axis direction, either 0,1,2 or x/y/z respectively.
+ angle : float, float
+ Start/Stop angle (rad) of rotation. Default is (0, 2*pi).
+
+ Examples
+ --------
+ Define a half circle on the xy-plane, rotated around the x axis
+
+ >>> rotpoly = CSPrimitives.CSPrimRotPoly(pset, metal, norm_dir='z')
+ >>> ang = np.linspace(0, np.pi, 21)
+ >>> rotpoly.SetCoords(5*np.cos(ang), 5*np.sin(ang))
+ >>> rotpoly.SetRotAxisDir('x')
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimRotPoly(pset.thisptr, prop.thisptr)
+ if 'rot_axis' in kw:
+ self.SetRotAxisDir(kw['rot_axis'])
+ del kw['rot_axis']
+ if 'angle' in kw:
+ assert len(kw['angle'])==2, 'angle must be a list/array of length 2'
+ self.SetRotAxisDir(kw['angle'][0],kw['angle'][1])
+ del kw['angle']
+ super(CSPrimRotPoly, self).__init__(pset, prop, *args, **kw)
+
+ def SetRotAxisDir(self, ny):
+ """ SetRotAxisDir(ny)
+
+ Set the rotation axis direction, either 0,1,2 or x/y/z respectively.
+
+ :param ny: int or str -- Rotation axis direction, either 0,1,2 or x/y/z respectively.
+ """
+ ptr = <_CSPrimRotPoly*>self.thisptr
+ ptr.SetRotAxisDir(CheckNyDir(ny))
+
+ def GetRotAxisDir(self):
+ """
+ Get the rotation axis direction
+
+ :returns ny: int -- Rotation axis direction as 0, 1 or 2 meaning x,y or z
+ """
+ ptr = <_CSPrimRotPoly*>self.thisptr
+ return ptr.GetRotAxisDir()
+
+ def SetAngle(self, a0, a1):
+ """ SetAngle(a0, a1)
+
+ Set the start/stop angle (rad) of rotation. Default is (0, 2*pi).
+
+ :param a0: float -- Start angle (rad) of rotation.
+ :param a1: float -- Stop angle (rad) of rotation.
+ """
+ ptr = <_CSPrimRotPoly*>self.thisptr
+ ptr.SetAngle(0, a0)
+ ptr.SetAngle(1, a1)
+
+ def GetAngle(self):
+ """
+ Get the start/stop angle (rad) of rotation.
+
+ :returns a0, a1: float, float -- Start/Stop angle (rad) of rotation.
+ """
+ ptr = <_CSPrimRotPoly*>self.thisptr
+ return ptr.GetAngle(0), ptr.GetAngle(1)
+
+###############################################################################
+cdef class CSPrimCurve(CSPrimitives):
+ """ Curve Primitive
+
+ A curve is a set of consequtive 3D coordinates.
+
+ Parameters
+ ----------
+ points : (3, N) array
+ Array of 3D coordinates.
+
+ Examples
+ --------
+
+ >>> x = np.array([0, 0, 1, 1]) + 1.5
+ >>> y = np.array([0, 1, 1, 0]) + 2.5
+ >>> z = np.array([0, 1, 3, 4])
+ >>> curve = CSPrimitives.CSPrimCurve(pset, metal, points=[x,y,z])
+ >>> curve.AddPoint([2, 0, 5])
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimCurve(pset.thisptr, prop.thisptr)
+ if 'points' in kw:
+ assert len(kw['points'])==3, 'points list not of length 3'
+ self.SetPoints(kw['points'][0], kw['points'][1], kw['points'][2])
+ del kw['points']
+ super(CSPrimCurve, self).__init__(pset, prop, *args, **kw)
+
+ def AddPoint(self, point):
+ """ AddPoint(point)
+
+ Add a single point to the list.
+
+ :param point: (3,) array -- Add a single 3D point
+ """
+ assert len(point)==3, "CSPrimSphere:SetCenter: length of array needs to be 3"
+ ptr = <_CSPrimCurve*>self.thisptr
+ cdef double dp[3]
+ for n in range(3):
+ dp[n] = point[n]
+ ptr.AddPoint(dp)
+
+ def SetPoints(self, x, y, z):
+ """ SetPoints(x, y, z)
+
+ Set an array of 3D coordinates
+
+ :param x,y,z: each (N,) array -- Array of 3D point components
+ """
+ assert len(x)==len(y)==len(z), 'SetPoints: each component must be of equal length'
+ assert len(x)>0, 'SetPoints: empty list!'
+ ptr = <_CSPrimCurve*>self.thisptr
+ ptr.ClearPoints()
+ cdef double dp[3]
+ for n in range(len(x)):
+ dp[0] = x[n]
+ dp[1] = y[n]
+ dp[2] = z[n]
+ ptr.AddPoint(dp)
+
+ def GetPoint(self, idx):
+ """ GetPoint(idx)
+
+ Get a point with a given index.
+
+ :param idx: int -- Index of point requested.
+ :return point: (3,) array -- Point coordinate at index `idx`
+ """
+ ptr = <_CSPrimCurve*>self.thisptr
+ cdef double dp[3]
+ assert ptr.GetPoint(idx, dp), 'GetPoint: invalid index'
+ point = np.zeros(3)
+ for n in range(3):
+ point[n] = dp[n]
+ return point
+
+ def ClearPoints(self):
+ """
+ Clear all points.
+ """
+ ptr = <_CSPrimCurve*>self.thisptr
+ ptr.ClearPoints()
+
+ def GetNumberOfPoints(self):
+ """
+ Get the number of points.
+
+ :return num: int -- Get the number of points.
+ """
+ ptr = <_CSPrimCurve*>self.thisptr
+ return ptr.GetNumberOfPoints()
+
+
+###############################################################################
+cdef class CSPrimWire(CSPrimCurve):
+ """ Wire Primitive
+
+ A wire is a curve with a given radius.
+
+ Parameters
+ ----------
+ radius : float
+ Wire radius
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimWire(pset.thisptr, prop.thisptr)
+ if 'radius' in kw:
+ self.SetWireRadius(kw['radius'])
+ del kw['radius']
+ super(CSPrimWire, self).__init__(pset, prop, *args, **kw)
+
+
+ def SetWireRadius(self, val):
+ """ SetWireRadius(val)
+
+ Set the wire radius
+
+ :param val: float -- Set the wire radius
+ """
+ ptr = <_CSPrimWire*>self.thisptr
+ ptr.SetWireRadius(val)
+
+ def GetWireRadius(self):
+ """
+ Get the wire radius.
+
+ :returns: float -- Wire radius.
+ """
+ ptr = <_CSPrimWire*>self.thisptr
+ return ptr.GetWireRadius()
+
+###############################################################################
+cdef class CSPrimPolyhedron(CSPrimitives):
+ """ Polyhedron Primitive
+
+ A polyhedron is a 3D solid with flat polygonal faces (currently only triangles).
+
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimPolyhedron(pset.thisptr, prop.thisptr)
+ super(CSPrimPolyhedron, self).__init__(pset, prop, *args, **kw)
+
+ def Reset(self):
+ """
+ Reset the polyhedron, that means removeing all faces.
+ """
+ ptr = <_CSPrimPolyhedron*>self.thisptr
+ ptr.Reset()
+
+ def AddVertex(self, x, y, z):
+ """ AddVertex(x, y, z)
+
+ Add a single 3D vertex.
+
+ :param x,y,z: float,float,float -- 3D vertex
+ """
+ ptr = <_CSPrimPolyhedron*>self.thisptr
+ ptr.AddVertex(x, y, z)
+
+ def GetVertex(self, idx):
+ """ GetVertex(idx)
+
+ Get the vertex with index `idx`.
+
+ :param idx: int -- Vertex index to return
+ :returns point: (3,) array -- Vertex coordinate at index `idx`
+ """
+ ptr = <_CSPrimPolyhedron*>self.thisptr
+ assert idx>=0 and idx<ptr.GetNumVertices(), "Error: invalid vertex index"
+ cdef float* p
+ p = ptr.GetVertex(idx)
+ assert p!=NULL
+ pyp = np.zeros(3)
+ for n in range(3):
+ pyp[n] = p[n]
+ return pyp
+
+ def GetNumVertices(self):
+ """
+ Get the number of vertices.
+
+ :returns num: int -- Number of vertices
+ """
+ ptr = <_CSPrimPolyhedron*>self.thisptr
+ return ptr.GetNumVertices()
+
+ def AddFace(self, verts):
+ """ AddFace(verts)
+
+ Add a face with a given list of vertices.
+ The vertices have to be added already.
+ Currently only triangle faces are possible.
+
+ :params verts: (N,) array -- Face with N vericies (currently N=3!)
+ """
+ assert len(verts)==3, 'AddFace: currently only triangles allowed as faces'
+ cdef int i_v[3]
+ for n in range(3):
+ i_v[n] = verts[n]
+ ptr = <_CSPrimPolyhedron*>self.thisptr
+ ptr.AddFace(len(verts), i_v)
+
+ def GetFace(self, idx):
+ """ GetFace(idx)
+
+ Get the face vertex indicies for the given face index `idx`
+
+ :param idx: int -- Face index to return
+ :returns: (N,) array -- Vertices array for face with index `idx`
+ """
+ ptr = <_CSPrimPolyhedron*>self.thisptr
+ assert idx>=0 and idx<ptr.GetNumFaces(), "Error: invalid face index"
+ cdef int *i_v
+ cdef unsigned int numVert=0
+ i_v = ptr.GetFace(idx, numVert)
+ assert i_v!=NULL
+ face = np.zeros(numVert, np.int)
+ for n in range(numVert):
+ face[n] = i_v[n]
+ return face
+
+ def GetNumFaces(self):
+ """
+ Get the number of faces.
+
+ :return num: int -- number of faces
+ """
+ ptr = <_CSPrimPolyhedron*>self.thisptr
+ return ptr.GetNumFaces()
+
+###############################################################################
+cdef class CSPrimPolyhedronReader(CSPrimPolyhedron):
+ """ Polyhedron Reader
+
+ This primives creates a polyhedron by reading a STL or PLY file.
+
+ Parameters
+ ----------
+ filename : str
+ File name to read
+ """
+ def __init__(self, ParameterSet pset, CSProperties prop, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = new _CSPrimPolyhedronReader(pset.thisptr, prop.thisptr)
+ if 'filename' in kw:
+ self.SetFilename(kw['filename'])
+ del kw['filename']
+ super(CSPrimPolyhedronReader, self).__init__(pset, prop, *args, **kw)
+
+ def SetFilename(self, fn):
+ """ SetFilename(fn)
+
+ Set the file name to read. This will try set the propper file type as well.
+
+ :param fn: str -- File name to read
+ """
+ ptr = <_CSPrimPolyhedronReader*>self.thisptr
+ if fn.endswith('.stl'):
+ self.SetFileType(1)
+ elif fn.endswith('.ply'):
+ self.SetFileType(2)
+ else:
+ self.SetFileType(0)
+ ptr.SetFilename(fn.encode('UTF-8'))
+
+ def GetFilename(self):
+ """
+ Get the file name.
+
+ :returns fn: str -- File name to read
+ """
+ ptr = <_CSPrimPolyhedronReader*>self.thisptr
+ return ptr.GetFilename()
+
+ def SetFileType(self, t):
+ """ SetFileType(t)
+
+ Set the file type. 1 --> STL-File, 2 --> PLY, 0 --> other/unknown
+
+ :param t: int -- File type (see above)
+ """
+ ptr = <_CSPrimPolyhedronReader*>self.thisptr
+ ptr.SetFileType(t)
+
+ def GetFileType(self):
+ """
+ Get the file type. 1 --> STL-File, 2 --> PLY, 0 --> other/unknown
+
+ :return t: int -- File type (see above)
+ """
+ ptr = <_CSPrimPolyhedronReader*>self.thisptr
+ return ptr.GetFileType()
+
+ def ReadFile(self):
+ """
+ Issue to read the file.
+
+ :return succ: bool -- True on successful read
+ """
+ ptr = <_CSPrimPolyhedronReader*>self.thisptr
+ return ptr.ReadFile()
diff --git a/CSXCAD/python/CSXCAD/CSProperties.pxd b/CSXCAD/python/CSXCAD/CSProperties.pxd
new file mode 100644
index 0000000..7b47e1a
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/CSProperties.pxd
@@ -0,0 +1,218 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from libcpp.string cimport string
+from libcpp.vector cimport vector
+from libcpp cimport bool
+
+from ParameterObjects cimport _ParameterSet, ParameterSet
+from CSPrimitives cimport _CSPrimitives, CSPrimitives
+from CSXCAD cimport ContinuousStructure
+
+cdef extern from "CSXCAD/CSProperties.h":
+ cpdef enum PropertyType "CSProperties::PropertyType":
+ ANY "CSProperties::ANY"
+ UNKNOWN "CSProperties::UNKNOWN"
+ MATERIAL "CSProperties::MATERIAL"
+ METAL "CSProperties::METAL"
+ EXCITATION "CSProperties::EXCITATION"
+ PROBEBOX "CSProperties::PROBEBOX"
+ RESBOX "CSProperties::RESBOX"
+ DUMPBOX "CSProperties::DUMPBOX"
+ DISPERSIVEMATERIAL "CSProperties::DISPERSIVEMATERIAL"
+ LORENTZMATERIAL "CSProperties::LORENTZMATERIAL"
+ DEBYEMATERIAL "CSProperties::DEBYEMATERIAL"
+ DISCRETE_MATERIAL "CSProperties::DISCRETE_MATERIAL"
+ LUMPED_ELEMENT "CSProperties::LUMPED_ELEMENT"
+ CONDUCTINGSHEET "CSProperties::CONDUCTINGSHEET"
+
+cdef extern from "CSXCAD/CSProperties.h":
+ cdef cppclass _CSProperties "CSProperties":
+ _CSProperties(_ParameterSet*) except +
+ int GetType()
+ string GetTypeString()
+
+ _ParameterSet* GetParameterSet()
+
+ void SetName(string name)
+ string GetName()
+
+ int GetQtyPrimitives()
+ _CSPrimitives* GetPrimitive(size_t index)
+
+ bool ExistAttribute(string name)
+ string GetAttributeValue(string name)
+ void AddAttribute(string name, string value)
+
+ void SetFillColor(unsigned char R, unsigned char G, unsigned char B, unsigned char a)
+ void SetEdgeColor(unsigned char R, unsigned char G, unsigned char B, unsigned char a)
+
+cdef class CSProperties:
+ cdef _CSProperties *thisptr
+ cdef __SetPtr(self, _CSProperties *ptr)
+ cdef __GetPrimitive(self, size_t index)
+ cdef readonly ContinuousStructure __CSX
+ cdef readonly ParameterSet __paraset
+ cdef readonly list __primitives
+
+##############################################################################
+cdef extern from "CSXCAD/CSPropMaterial.h":
+ cdef cppclass _CSPropMaterial "CSPropMaterial" (_CSProperties):
+ _CSPropMaterial(_ParameterSet*) except +
+ void SetEpsilon(double val, int ny)
+ double GetEpsilon(int ny)
+ int SetEpsilonWeightFunction(string fct, int ny)
+ string GetEpsilonWeightFunction(int ny)
+
+ void SetMue(double val, int ny)
+ double GetMue(int ny)
+ int SetMueWeightFunction(string fct, int ny)
+ string GetMueWeightFunction(int ny)
+
+ void SetKappa(double val, int ny)
+ double GetKappa(int ny)
+ int SetKappaWeightFunction(string fct, int ny)
+ string GetKappaWeightFunction(int ny)
+
+ void SetSigma(double val, int ny)
+ double GetSigma(int ny)
+ int SetSigmaWeightFunction(string fct, int ny)
+ string GetSigmaWeightFunction(int ny)
+
+ void SetDensity(double val)
+ double GetDensity()
+ int SetDensityWeightFunction(string fct)
+ string GetDensityWeightFunction()
+
+ void SetIsotropy(bool val)
+ bool GetIsotropy()
+
+cdef class CSPropMaterial(CSProperties):
+ pass
+
+##############################################################################
+cdef extern from "CSXCAD/CSPropLumpedElement.h":
+ cdef cppclass _CSPropLumpedElement "CSPropLumpedElement" (_CSProperties):
+ _CSPropLumpedElement(_ParameterSet*) except +
+ void SetResistance(double val)
+ double GetResistance()
+
+ void SetCapacity(double val)
+ double GetCapacity()
+
+ void SetInductance(double val)
+ double GetInductance()
+
+ void SetDirection(int ny)
+ int GetDirection()
+
+ void SetCaps(bool val)
+ int GetCaps()
+
+cdef class CSPropLumpedElement(CSProperties):
+ pass
+
+##############################################################################
+cdef extern from "CSXCAD/CSPropMetal.h":
+ cdef cppclass _CSPropMetal "CSPropMetal" (_CSProperties):
+ _CSPropMetal(_ParameterSet*) except +
+
+cdef class CSPropMetal(CSProperties):
+ pass
+
+##############################################################################
+cdef extern from "CSXCAD/CSPropConductingSheet.h":
+ cdef cppclass _CSPropConductingSheet "CSPropConductingSheet" (_CSPropMetal):
+ _CSPropConductingSheet(_ParameterSet*) except +
+ void SetConductivity(double val)
+ double GetConductivity()
+
+ void SetThickness(double val)
+ double GetThickness()
+
+cdef class CSPropConductingSheet(CSPropMetal):
+ pass
+
+##############################################################################
+cdef extern from "CSXCAD/CSPropExcitation.h":
+ cdef cppclass _CSPropExcitation "CSPropExcitation" (_CSProperties):
+ _CSPropExcitation(_ParameterSet*) except +
+ void SetExcitType(int val)
+ int GetExcitType()
+
+ void SetExcitation(double val, int Component)
+ double GetExcitation(int Component)
+
+ void SetPropagationDir(double val, int Component)
+ double GetPropagationDir(int Component)
+
+ int SetWeightFunction(string fct, int ny)
+ string GetWeightFunction(int ny)
+
+ void SetFrequency(double val)
+ double GetFrequency()
+
+ void SetDelay(double val)
+ double GetDelay()
+
+cdef class CSPropExcitation(CSProperties):
+ pass
+
+##############################################################################
+cdef extern from "CSXCAD/CSPropProbeBox.h":
+ cdef cppclass _CSPropProbeBox "CSPropProbeBox" (_CSProperties):
+ _CSPropProbeBox(_ParameterSet*) except +
+ void SetProbeType(int type)
+ int GetProbeType()
+
+ void SetWeighting(double weight)
+ double GetWeighting()
+
+ void SetNormalDir(unsigned int ndir)
+ int GetNormalDir()
+
+ size_t CountFDSamples()
+ vector[double]* GetFDSamples()
+ void ClearFDSamples()
+ void AddFDSample(double freq)
+
+cdef class CSPropProbeBox(CSProperties):
+ pass
+
+
+##############################################################################
+cdef extern from "CSXCAD/CSPropDumpBox.h":
+ cdef cppclass _CSPropDumpBox "CSPropDumpBox" (_CSPropProbeBox):
+ _CSPropDumpBox(_ParameterSet*) except +
+ void SetDumpType(int _type)
+ int GetDumpType()
+
+ void SetDumpMode(int mode)
+ int GetDumpMode()
+
+ void SetFileType(int ftype)
+ int GetFileType()
+
+ void SetOptResolution(int ny, double val)
+ double GetOptResolution(int ny)
+
+ void SetSubSampling(int ny, unsigned int val)
+ unsigned int GetSubSampling(int ny)
+
+cdef class CSPropDumpBox(CSPropProbeBox):
+ pass
diff --git a/CSXCAD/python/CSXCAD/CSProperties.pyx b/CSXCAD/python/CSXCAD/CSProperties.pyx
new file mode 100644
index 0000000..00b998c
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/CSProperties.pyx
@@ -0,0 +1,1163 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""
+Module for all Properties like metal, material, propes and dumps
+
+Notes
+-----
+Usually it is not meant to create properties manually, but instead
+use the ContinuousStructure object to create properties using the
+e.g. AddMaterial or AddMetal methods.
+
+
+Examples
+--------
+Create a metal property:
+
+>>> pset = ParameterObjects.ParameterSet()
+>>> metal = CSProperties.CSPropMetal(pset)
+"""
+
+import numpy as np
+from ParameterObjects cimport _ParameterSet, ParameterSet
+cimport CSProperties
+cimport CSPrimitives as c_CSPrimitives
+from CSPrimitives import CSPrimitives
+from Utilities import CheckNyDir
+
+def hex2color(color):
+ if color.startswith('#'):
+ color = color.lstrip('#')
+ rgb = tuple(int(color[i:i+2], 16) for i in (0, 2 ,4))
+ return rgb
+ else:
+ return None
+
+cdef class CSProperties:
+ """
+ Virtual base class for all properties, cannot be created!
+
+ """
+
+ @staticmethod
+ def fromType(p_type, pset, no_init=False, **kw):
+ """ fromType(p_type, pset, no_init=False, **kw)
+
+ Create a property specified by the `p_type`
+
+ :param p_type: Property type
+ :param pset: ParameterSet to assign to the new primitive
+ :param no_init: do not create an actual C++ instance
+ """
+ prop = None
+ if p_type == CONDUCTINGSHEET + METAL:
+ prop = CSPropConductingSheet(pset, no_init=no_init, **kw)
+ elif p_type == METAL:
+ prop = CSPropMetal(pset, no_init=no_init, **kw)
+ elif p_type == MATERIAL:
+ prop = CSPropMaterial(pset, no_init=no_init, **kw)
+ elif p_type == LUMPED_ELEMENT:
+ prop = CSPropLumpedElement(pset, no_init=no_init, **kw)
+ elif p_type == EXCITATION:
+ prop = CSPropExcitation(pset, no_init=no_init, **kw)
+ elif p_type == PROBEBOX:
+ prop = CSPropProbeBox(pset, no_init=no_init, **kw)
+ elif p_type == DUMPBOX:
+ prop = CSPropDumpBox(pset, no_init=no_init, **kw)
+
+ return prop
+
+ @staticmethod
+ def fromTypeName(type_str, pset, no_init=False, **kw):
+ """ fromTypeName(type_str, pset, no_init=False, **kw)
+
+ Create a property specified by the `type_str`
+
+ :param type_str: Property type name string
+ :param pset: ParameterSet to assign to the new primitive
+ :param no_init: do not create an actual C++ instance
+ """
+ prop = None
+ if type_str=='Material':
+ prop = CSPropMaterial(pset, no_init=no_init, **kw)
+ elif type_str=='LumpedElement':
+ prop = CSPropLumpedElement(pset, no_init=no_init, **kw)
+ elif type_str=='Metal':
+ prop = CSPropMetal(pset, no_init=no_init, **kw)
+ elif type_str=='ConductingSheet':
+ prop = CSPropConductingSheet(pset, no_init=no_init, **kw)
+ elif type_str=='Excitation':
+ prop = CSPropExcitation(pset, no_init=no_init, **kw)
+ elif type_str=='ProbeBox':
+ prop = CSPropProbeBox(pset, no_init=no_init, **kw)
+ elif type_str=='DumpBox':
+ prop = CSPropDumpBox(pset, no_init=no_init, **kw)
+ return prop
+
+ def __init__(self, ParameterSet pset, *args, no_init=False, **kw):
+ self.__CSX = None
+ # internal list of primitives
+ self.__primitives = []
+ if no_init:
+ self.thisptr = NULL
+ return
+ assert self.thisptr, "Error, cannot create CSProperties (protected)"
+
+ self.__paraset = ParameterSet(no_init=True)
+ self.__paraset.thisptr = self.thisptr.GetParameterSet()
+
+ assert len(kw)==0, 'Unknown keywords: {}'.format(kw)
+
+ cdef __SetPtr(self, _CSProperties *ptr):
+ self.thisptr = ptr
+
+ def GetQtyPrimitives(self):
+ """
+ Get the number of primitives assigned to this property
+
+ :returns: int -- Number of primitives
+ """
+ return self.thisptr.GetQtyPrimitives()
+
+ def GetPrimitive(self, index):
+ return self.__GetPrimitive(index)
+
+ def GetAllPrimitives(self):
+ return [self.GetPrimitive(n) for n in range(self.GetQtyPrimitives())]
+
+ cdef __GetPrimitive(self, size_t index):
+ cdef _CSPrimitives *_prim
+ cdef CSPrimitives prim
+ _prim = self.thisptr.GetPrimitive(index)
+ if self.__primitives is None:
+ self.__primitives = []
+ for p in self.__primitives:
+ prim = p
+ if prim.thisptr == _prim:
+ return p
+ prim = CSPrimitives.fromType(_prim.GetType(), pset=self.__paraset, prop=self, no_init=True)
+ prim.thisptr = _prim
+ self.__primitives.append(prim)
+ return prim
+
+ def GetType(self):
+ """ Get the type of the property
+
+ :returns: int -- Type ID of this property
+ """
+ return self.thisptr.GetType()
+
+ def GetTypeString(self):
+ """ Get the type of the property as a string
+
+ :returns: str -- Type name of this property type
+ """
+ return self.thisptr.GetTypeString().decode('UTF-8')
+
+ def GetParameterSet(self):
+ """
+ Get the parameter set assigned to this class
+ """
+ return self.__paraset
+
+ def SetName(self, name):
+ """ SetName(name)
+
+ Set the name of this property
+
+ :params name: str -- Name for this property
+ """
+ self.thisptr.SetName(name.encode('UTF-8'))
+
+ def GetName(self):
+ """
+ Get the name of this property
+
+ :returns: str -- Name for this property
+ """
+ return self.thisptr.GetName().decode('UTF-8')
+
+ def SetColor(self, color, alpha=255):
+ """ SetColor(color, alpha=255)
+
+ Set the fill and edge color for this property.
+
+ :param color: hex color value
+ :param alpha: transparency value
+ """
+ self.SetFillColor(color, alpha)
+ self.SetEdgeColor(color, alpha)
+
+ def SetFillColor(self, color, alpha=255):
+ """ SetFillColor(color, alpha=255)
+
+ Set the fill color for this property.
+
+ :param color: hex color value
+ :param alpha: transparency value
+ """
+ rgb = hex2color(color)
+ self.thisptr.SetFillColor(rgb[0], rgb[1], rgb[2], alpha)
+
+ def SetEdgeColor(self, color, alpha=255):
+ """ SetColor(color, alpha=255)
+
+ Set the edge color for this property.
+
+ :param color: hex color value
+ :param alpha: transparency value
+ """
+ rgb = hex2color(color)
+ self.thisptr.SetEdgeColor(rgb[0], rgb[1], rgb[2], alpha)
+
+ def ExistAttribute(self, name):
+ """ ExistAttribute(name)
+
+ Check if an attribute with the given `name` exists
+
+ :param name: str -- Attribute name
+ :returns: bool
+ """
+ return self.thisptr.ExistAttribute(name.encode('UTF-8'))
+
+ def GetAttributeValue(self, name):
+ """ GetAttributeValue(name)
+
+ Get the value of the attribute with the given `name`
+
+ :param name: str -- Attribute name
+ :returns: str -- Attribute value
+ """
+ return self.thisptr.GetAttributeValue(name.encode('UTF-8')).decode('UTF-8')
+
+ def AddAttribute(self, name, val):
+ """ AddAttribute(name, val)
+
+ Add an attribure and value
+
+ :param name: str -- Attribute name
+ :param val: str -- Attribute value
+ """
+ self.thisptr.AddAttribute(name.encode('UTF-8'), val.encode('UTF-8'))
+
+ def AddPoint(self, coord, **kw):
+ """ AddPoint(coord, **kw)
+
+ Add a point to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimPoint : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.POINT, coord=coord, **kw)
+
+ def AddBox(self, start, stop, **kw):
+ """ AddBox(start, stop, **kw)
+
+ Add a box to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimBox : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.BOX, start=start, stop=stop, **kw)
+
+ def AddCylinder(self, start, stop, radius, **kw):
+ """ AddCylinder(start, stop, radius, **kw)
+
+ Add a cylinder to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimCylinder : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.CYLINDER, start=start, stop=stop, radius=radius, **kw)
+
+ def AddCylindricalShell(self, start, stop, radius, shell_width, **kw):
+ """ AddCylindricalShell(start, stop, radius, shell_width, **kw)
+
+ Add a cylindrical shell to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimCylindricalShell : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.CYLINDRICALSHELL, start=start, stop=stop, radius=radius, shell_width=shell_width, **kw)
+
+ def AddSphere(self, center, radius, **kw):
+ """ AddSphere(center, radius, **kw)
+
+ Add a sphere to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimSphere : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.SPHERE, center=center, radius=radius, **kw)
+
+ def AddSphericalShell(self, center, radius, shell_width, **kw):
+ """ AddSphericalShell(center, radius, shell_width, **kw)
+
+ Add a spherical shell to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimSphericalShell : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.SPHERICALSHELL, center=center, radius=radius, shell_width=shell_width, **kw)
+
+ def AddPolygon(self, points, norm_dir, elevation, **kw):
+ """ AddPolygon(points, norm_dir, elevation, **kw)
+
+ Add a polygon to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimPolygon : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.POLYGON, points=points, norm_dir=norm_dir, elevation=elevation, **kw)
+
+ def AddLinPoly(self, points, norm_dir, elevation, length, **kw):
+ """ AddLinPoly(points, norm_dir, elevation, length, **kw)
+
+ Add a linear extruded polygon to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimLinPoly : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.LINPOLY, points=points, norm_dir=norm_dir, elevation=elevation, length=length, **kw)
+
+ def AddRotPoly(self, points, norm_dir, elevation, rot_axis, angle, **kw):
+ """ AddRotPoly(points, norm_dir, elevation, rot_axis, angle, **kw)
+
+ Add a rotated polygon to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimRotPoly : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.ROTPOLY, points=points, norm_dir=norm_dir, elevation=elevation, rot_axis=rot_axis, angle=angle, **kw)
+
+ def AddCurve(self, points, **kw):
+ """ AddCurve(points, **kw)
+
+ Add a curve to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimCurve : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.CURVE, points=points, **kw)
+
+ def AddWire(self, points, radius, **kw):
+ """ AddWire(points, radius, **kw)
+
+ Add a wire to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimWire : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.WIRE, points=points, radius=radius, **kw)
+
+ def AddPolyhedron(self, **kw):
+ """ AddPolyhedron(**kw)
+
+ Add a polyhedron to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimPolyhedron : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.POLYHEDRON, **kw)
+
+ def AddPolyhedronReader(self, filename, **kw):
+ """ AddPolyhedronReader(filename, **kw)
+
+ Add a polyhedron from file to this property.
+
+ See Also
+ --------
+ CSXCAD.CSPrimitives.CSPrimPolyhedronReader : See here for details on primitive arguments
+ """
+ return self.__CreatePrimitive(c_CSPrimitives.POLYHEDRONREADER, filename=filename, **kw)
+
+ def __CreatePrimitive(self, prim_type, **kw):
+ pset = self.GetParameterSet()
+ prim = CSPrimitives.fromType(prim_type, pset, self, **kw)
+ if prim is None:
+ raise Exception('CreatePrimitive: Unknown primitive type requested!')
+ self.__primitives.append(prim)
+ return prim
+
+###############################################################################
+cdef class CSPropMaterial(CSProperties):
+ """ General material property
+
+ This is a material with options to define relative electric permeability
+ (`eplsilon`), relative magnetic permittivity (`mue`), electric conductivity
+ (`kappa`), magnetic conductivity (`sigma`) and `density`.
+
+ :params epsilon: scalar or vector - relative electric permeability
+ :params mue: scalar or vector - relative magnetic permittivity
+ :params kappa: scalar or vector - relectric conductivity
+ :params sigma: scalar or vector - magnetic conductivity
+ :params density: float - Density
+ """
+ def __init__(self, ParameterSet pset, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = <_CSProperties*> new _CSPropMaterial(pset.thisptr)
+
+ self.SetMaterialProperty(**kw)
+ for k in list(kw.keys()):
+ if k in ['epsilon', 'mue', 'kappa', 'sigma', 'density']:
+ del kw[k]
+
+ super(CSPropMaterial, self).__init__(pset, *args, **kw)
+
+ def SetIsotropy(self, val):
+ """ SetIsotropy(val)
+
+ Set isotropy status for this material.
+
+ :param val: bool -- enable/disable isotropy
+ """
+ (<_CSPropMaterial*>self.thisptr).SetIsotropy(val)
+
+ def GetIsotropy(self):
+ """
+ Get isotropy status for this material.
+
+ :returns: bool -- isotropy status
+ """
+ return (<_CSPropMaterial*>self.thisptr).GetIsotropy()
+
+ def SetMaterialProperty(self, **kw):
+ """ SetMaterialProperty(**kw)
+ Set the material properties.
+
+ :params epsilon: scalar or vector - relative electric permeability
+ :params mue: scalar or vector - relative magnetic permittivity
+ :params kappa: scalar or vector - relectric conductivity
+ :params sigma: scalar or vector - magnetic conductivity
+ :params density: float - Density
+ """
+ for prop_name in kw:
+ val = kw[prop_name]
+ if prop_name == 'density':
+ (<_CSPropMaterial*>self.thisptr).SetDensity(val)
+ continue
+ if type(val)==float or type(val)==int:
+ self.__SetMaterialPropertyDir(prop_name, 0, val)
+ continue
+ assert len(val)==3, 'SetMaterialProperty: "{}" must be a list or array of length 3'.format(prop_name)
+ for n in range(3):
+ self.__SetMaterialPropertyDir(prop_name, n, val[n])
+
+ def __SetMaterialPropertyDir(self, prop_name, ny, val):
+ if prop_name=='epsilon':
+ return (<_CSPropMaterial*>self.thisptr).SetEpsilon(val, ny)
+ elif prop_name=='mue':
+ return (<_CSPropMaterial*>self.thisptr).SetMue(val, ny)
+ elif prop_name=='kappa':
+ return (<_CSPropMaterial*>self.thisptr).SetKappa(val, ny)
+ elif prop_name=='sigma':
+ return (<_CSPropMaterial*>self.thisptr).SetSigma(val, ny)
+ else:
+ raise Exception('SetMaterialPropertyDir: Error, unknown material property')
+
+ def SetMaterialWeight(self, **kw):
+ """ SetMaterialWeight(**kw)
+
+ Set the material weighting function(s)
+
+ The functions can use the variables:
+ `x`,`y`,`z`
+ `rho` for the distance to z-axis
+ `r` for the distance to origin
+ `a` for alpha or phi (as in cylindircal and spherical coord systems)
+ `t` for theta (as in the spherical coord system
+
+ all these variables are not weighted with the drawing unit defined by
+ the grid
+
+ :params epsilon: str or str-vector - relative electric permeability
+ :params mue: str or str-vector - relative magnetic permittivity
+ :params kappa: str or str-vector - relectric conductivity
+ :params sigma: str or str-vector - magnetic conductivity
+ :params density: str - Density
+ """
+ for prop_name in kw:
+ val = kw[prop_name]
+ if prop_name == 'density':
+ (<_CSPropMaterial*>self.thisptr).SetDensityWeightFunction(val.encode('UTF-8'))
+ continue
+ if type(val)==str:
+ self.__SetMaterialWeightDir(prop_name, 0, val)
+ continue
+ assert len(val)==3, 'SetMaterialWeight: "{}" must be a list or array of length 3'.format(prop_name)
+ for n in range(3):
+ self.__SetMaterialWeightDir(prop_name, n, val[n])
+
+ def __SetMaterialWeightDir(self, prop_name, ny, val):
+ val = val.encode('UTF-8')
+ if prop_name=='epsilon':
+ return (<_CSPropMaterial*>self.thisptr).SetEpsilonWeightFunction(val, ny)
+ elif prop_name=='mue':
+ return (<_CSPropMaterial*>self.thisptr).SetMueWeightFunction(val, ny)
+ elif prop_name=='kappa':
+ return (<_CSPropMaterial*>self.thisptr).SetKappaWeightFunction(val, ny)
+ elif prop_name=='sigma':
+ return (<_CSPropMaterial*>self.thisptr).SetSigmaWeightFunction(val, ny)
+ else:
+ raise Exception('SetMaterialWeightDir: Error, unknown material property')
+
+ def GetMaterialProperty(self, prop_name):
+ """ SetMaterialProperty(prop_name)
+ Get the material property with of type `prop_name`.
+
+ :params prop_name: str -- material property type
+ :returns: float for isotropic material and `density` or else (3,) array
+ """
+ if prop_name == 'density':
+ return (<_CSPropMaterial*>self.thisptr).GetDensity()
+ if (<_CSPropMaterial*>self.thisptr).GetIsotropy():
+ return self.__GetMaterialPropertyDir(prop_name, 0)
+ val = np.zeros(3)
+ for n in range(3):
+ val[n] = self.__GetMaterialPropertyDir(prop_name, n)
+ return val
+
+ def __GetMaterialPropertyDir(self, prop_name, ny):
+ if prop_name=='epsilon':
+ return (<_CSPropMaterial*>self.thisptr).GetEpsilon(ny)
+ elif prop_name=='mue':
+ return (<_CSPropMaterial*>self.thisptr).GetMue(ny)
+ elif prop_name=='kappa':
+ return (<_CSPropMaterial*>self.thisptr).GetKappa(ny)
+ elif prop_name=='sigma':
+ return (<_CSPropMaterial*>self.thisptr).GetSigma(ny)
+ else:
+ raise Exception('GetMaterialPropertyDir: Error, unknown material property')
+
+ def GetMaterialWeight(self, prop_name):
+ """ GetMaterialWeight(prop_name)
+ Get the material weighting function(s).
+
+ :params prop_name: str -- material property type
+ :returns: str for isotropic material and `density` or else str array
+ """
+ if prop_name == 'density':
+ return (<_CSPropMaterial*>self.thisptr).GetDensityWeightFunction().decode('UTF-8')
+ if (<_CSPropMaterial*>self.thisptr).GetIsotropy():
+ return self.__GetMaterialWeightDir(prop_name, 0).decode('UTF-8')
+ val = ['', '', '']
+ for n in range(3):
+ val[n] = self.__GetMaterialWeightDir(prop_name, n).decode('UTF-8')
+ return val
+
+ def __GetMaterialWeightDir(self, prop_name, ny):
+ if prop_name=='epsilon':
+ return (<_CSPropMaterial*>self.thisptr).GetEpsilonWeightFunction(ny)
+ elif prop_name=='mue':
+ return (<_CSPropMaterial*>self.thisptr).GetMueWeightFunction(ny)
+ elif prop_name=='kappa':
+ return (<_CSPropMaterial*>self.thisptr).GetKappaWeightFunction(ny)
+ elif prop_name=='sigma':
+ return (<_CSPropMaterial*>self.thisptr).GetSigmaWeightFunction(ny)
+ else:
+ raise Exception('GetMaterialWeightDir: Error, unknown material property')
+
+
+###############################################################################
+cdef class CSPropLumpedElement(CSProperties):
+ """
+ Lumped element property.
+
+ A lumped element can consist of a resitor `R`, capacitor `C` and inductance
+ `L` active in a given direction `ny`.
+ If Caps are enable, a small PEC plate is added to each
+ end of the lumped element to ensure contact to a connecting line
+
+ :param ny: int or str -- direction: 0,1,2 or 'x','y','z' for the orientation of the lumped element
+ :param caps: bool -- enable/disable caps
+ :param R: float -- lumped resitance value
+ :param C: float -- lumped capacitance value
+ :param L: float -- lumped inductance value
+ """
+ def __init__(self, ParameterSet pset, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = <_CSProperties*> new _CSPropLumpedElement(pset.thisptr)
+
+ for k in kw:
+ if k=='R':
+ self.SetResistance(kw[k])
+ elif k=='L':
+ self.SetInductance(kw[k])
+ elif k=='C':
+ self.SetCapacity(kw[k])
+ elif k=='ny':
+ self.SetDirection(kw[k])
+ elif k=='caps':
+ self.SetCaps(kw[k])
+ for k in ['R', 'L', 'C', 'ny', 'caps']:
+ if k in kw:
+ del kw[k]
+
+ super(CSPropLumpedElement, self).__init__(pset, *args, **kw)
+
+ def SetResistance(self, val):
+ """ SetResistance(val)
+ """
+ (<_CSPropLumpedElement*>self.thisptr).SetResistance(val)
+
+ def GetResistance(self):
+ """ GetResistance()
+ """
+ return (<_CSPropLumpedElement*>self.thisptr).GetResistance()
+
+ def SetCapacity(self, val):
+ """ SetCapacity(val)
+ """
+ (<_CSPropLumpedElement*>self.thisptr).SetCapacity(val)
+
+ def GetCapacity(self):
+ """ GetCapacity()
+ """
+ return (<_CSPropLumpedElement*>self.thisptr).GetCapacity()
+
+ def SetInductance(self, val):
+ """ SetInductance(val)
+ """
+ (<_CSPropLumpedElement*>self.thisptr).SetInductance(val)
+
+ def GetInductance(self):
+ """ GetInductance()
+ """
+ return (<_CSPropLumpedElement*>self.thisptr).GetInductance()
+
+ def SetDirection(self, ny):
+ """ SetDirection(ny)
+ """
+ (<_CSPropLumpedElement*>self.thisptr).SetDirection(CheckNyDir(ny))
+
+ def GetDirection(self):
+ """ GetDirection()
+ """
+ return (<_CSPropLumpedElement*>self.thisptr).GetDirection()
+
+ def SetCaps(self, val):
+ """ SetCaps(val)
+ """
+ (<_CSPropLumpedElement*>self.thisptr).SetCaps(val)
+
+ def GetCaps(self):
+ """ GetCaps()
+ """
+ return (<_CSPropLumpedElement*>self.thisptr).GetCaps()==1
+
+
+###############################################################################
+cdef class CSPropMetal(CSProperties):
+ """ Metal property
+
+ A metal property is usually modeled as a perfect electric conductor (PEC).
+ It does not have any further arguments.
+
+ See Also
+ --------
+ CSPropConductingSheet : For all lossy conductor model with a finite conductivity
+ """
+ def __init__(self, ParameterSet pset, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = <_CSProperties*> new _CSPropMetal(pset.thisptr)
+ super(CSPropMetal, self).__init__(pset, *args, **kw)
+
+###############################################################################
+cdef class CSPropConductingSheet(CSPropMetal):
+ """ Conducting sheet model property
+
+ A conducting sheet is a model for a thin conducting metal sheet.
+
+ Notes
+ -----
+ Only 2D primitives (sheets) should be added to this property
+
+ :param conductivity: float -- finite conductivity e.g. 56e6 (S/m)
+ :param thickness: float -- finite modeled thickness (e.g. 18e-6)
+ """
+ def __init__(self, ParameterSet pset, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = <_CSProperties*> new _CSPropConductingSheet(pset.thisptr)
+
+ if 'conductivity' in kw:
+ self.SetConductivity(kw['conductivity'])
+ del kw['conductivity']
+ if 'thickness' in kw:
+ self.SetThickness(kw['thickness'])
+ del kw['thickness']
+ super(CSPropConductingSheet, self).__init__(pset, *args, **kw)
+
+ def SetConductivity(self, val):
+ """ SetConductivity(val)
+ """
+ (<_CSPropConductingSheet*>self.thisptr).SetConductivity(val)
+
+ def GetConductivity(self):
+ """ GetConductivity()
+ """
+ return (<_CSPropConductingSheet*>self.thisptr).GetConductivity()
+
+ def SetThickness(self, val):
+ """ SetThickness(val)
+ """
+ (<_CSPropConductingSheet*>self.thisptr).SetThickness(val)
+
+ def GetThickness(self):
+ """ GetThickness()
+ """
+ return (<_CSPropConductingSheet*>self.thisptr).GetThickness()
+
+###############################################################################
+cdef class CSPropExcitation(CSProperties):
+ """ Excitation property
+
+ An excitation property is defined to define the (field) sources.
+
+ Depending on the EM modeling tool there exist different excitation types
+ with different meanings.
+
+ :param exc_type: int -- excitation type (see SetExcitation)
+ :param exc_val: (3,) array like -- set the excitation vector
+ :param delay: float -- excitation delay in seconds
+ """
+ def __init__(self, ParameterSet pset, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = <_CSProperties*> new _CSPropExcitation(pset.thisptr)
+
+ if 'exc_type' in kw:
+ self.SetExcitType(kw['exc_type'])
+ del kw['exc_type']
+ if 'exc_val' in kw:
+ self.SetExcitation(kw['exc_val'])
+ del kw['exc_val']
+ if 'delay' in kw:
+ self.SetDelay(kw['delay'])
+ del kw['delay']
+ super(CSPropExcitation, self).__init__(pset, *args, **kw)
+
+ def SetExcitType(self, val):
+ """ SetExcitType(val)
+
+ :param val: int -- excitation type (see above)
+ """
+ (<_CSPropExcitation*>self.thisptr).SetExcitType(val)
+
+ def GetExcitType(self):
+ """ GetExcitType()
+ Get the excitation type.
+
+ :return: int -- excitation type (see above)
+ """
+ return (<_CSPropExcitation*>self.thisptr).GetExcitType()
+
+ def SetExcitation(self, val):
+ """ SetExcitation(val)
+
+ openEMS excitation types:
+
+ * 0 : E-field soft excitation
+ * 1 : E-field hard excitation
+ * 2 : H-field soft excitation
+ * 3 : H-field hard excitation
+ * 10 : plane wave excitation
+
+ :param val: (3,) array -- excitation vector
+ """
+ assert len(val)==3, "Error, excitation vector must be of dimension 3"
+ for n in range(3):
+ (<_CSPropExcitation*>self.thisptr).SetExcitation(val[n], n)
+
+ def GetExcitation(self):
+ """ GetExcitation()
+
+ :returns: (3,) array -- excitation vector
+ """
+ val = np.zeros(3)
+ for n in range(3):
+ val[n] = (<_CSPropExcitation*>self.thisptr).GetExcitation(n)
+ return val
+
+ def SetPropagationDir(self, val):
+ """ SetPropagationDir(val)
+
+ Set the propagation direction, e.g. for a plane wave excitation
+
+ :param val: (3,) array -- propagation vector
+ """
+ assert len(val)==3, "Error, excitation vector must be of dimension 3"
+ for n in range(3):
+ (<_CSPropExcitation*>self.thisptr).SetPropagationDir(val[n], n)
+
+ def GetPropagationDir(self):
+ """ GetPropagationDir()
+
+ Get the propagation direction, e.g. of a plane wave excitation
+
+ :returns: (3,) array -- propagation vector
+ """
+ val = np.zeros(3)
+ for n in range(3):
+ val[n] = (<_CSPropExcitation*>self.thisptr).GetPropagationDir(n)
+ return val
+
+ def SetWeightFunction(self, func):
+ """SetWeightFunction(func)
+
+ Set the weigthing function for the excitation.
+
+ """
+
+ assert len(func)==3, 'Error, excitation weighting function must be an array of length 3'
+ for n in range(3):
+ assert type(func[n]) is str, 'Error, excitation weighting function must be a string'
+ (<_CSPropExcitation*>self.thisptr).SetWeightFunction(func[n].encode('UTF-8'), n)
+
+ def GetWeightFunction(self):
+ """GetWeightFunction()
+
+ Get the weigthing function for the excitation.
+
+ :returns: 3 element list of strings
+ """
+
+ func = [None]*3
+ for n in range(3):
+ func[n] = (<_CSPropExcitation*>self.thisptr).GetWeightFunction(n).decode('UTF-8')
+ return func
+
+ def SetFrequency(self, val):
+ """ SetFrequency(val)
+
+ Frequency for numerical phase velocity compensation (optional)
+
+ :param val: float -- Frequency
+ """
+ (<_CSPropExcitation*>self.thisptr).SetFrequency(val)
+
+ def GetFrequency(self):
+ """ GetFrequency()
+ """
+ return (<_CSPropExcitation*>self.thisptr).GetFrequency()
+
+ def SetDelay(self, val):
+ """ SetDelay(val)
+
+ Set signal delay for this property.
+
+ :param val: float -- Signal delay
+ """
+ (<_CSPropExcitation*>self.thisptr).SetDelay(val)
+
+ def GetDelay(self):
+ """ GetDelay()
+ """
+ return (<_CSPropExcitation*>self.thisptr).GetDelay()
+
+###############################################################################
+cdef class CSPropProbeBox(CSProperties):
+ """
+ Probe propery.
+
+ Depending on the EM modeling tool there exist different probe types
+ with different meanings.
+
+ openEMS probe types:
+
+ * 0 : for voltage probing
+ * 1 : for current probing
+ * 2 : for E-field probing
+ * 3 : for H-field probing
+ * 10 : for waveguide voltage mode matching
+ * 11 : for waveguide current mode matching
+
+ :param p_type: probe type (default is 0)
+ :param weight: weighting factor (default is 1)
+ :param frequency: dump in the frequency domain at the given samples (in Hz)
+ :param mode_function: A mode function (used only with type 3/4 in openEMS)
+ :param norm_dir: necessary for current probing box with dimension not 2
+ """
+ def __init__(self, ParameterSet pset, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = <_CSProperties*> new _CSPropProbeBox(pset.thisptr)
+
+ if 'p_type' in kw:
+ self.SetProbeType(kw['p_type'])
+ del kw['p_type']
+ if 'weight' in kw:
+ self.SetWeighting(kw['weight'])
+ del kw['weight']
+ if 'norm_dir' in kw:
+ self.SetNormalDir(kw['norm_dir'])
+ del kw['norm_dir']
+ if 'frequency' in kw:
+ self.SetFrequency(kw['frequency'])
+ del kw['frequency']
+ if 'mode_function' in kw:
+ self.SetModeFunction(kw['mode_function'])
+ del kw['mode_function']
+ super(CSPropProbeBox, self).__init__(pset, *args, **kw)
+
+ def SetProbeType(self, val):
+ """ SetProbeType(val)
+ """
+ (<_CSPropProbeBox*>self.thisptr).SetProbeType(val)
+
+ def GetProbeType(self):
+ """ GetProbeType()
+ """
+ return (<_CSPropProbeBox*>self.thisptr).GetProbeType()
+
+ def SetWeighting(self, val):
+ """ SetWeighting(val)
+ """
+ (<_CSPropProbeBox*>self.thisptr).SetWeighting(val)
+
+ def GetWeighting(self):
+ """ GetWeighting()
+ """
+ return (<_CSPropProbeBox*>self.thisptr).GetWeighting()
+
+ def SetNormalDir(self, val):
+ """ SetNormalDir(val)
+ """
+ (<_CSPropProbeBox*>self.thisptr).SetNormalDir(val)
+
+ def GetNormalDir(self):
+ """ GetNormalDir()
+ """
+ return (<_CSPropProbeBox*>self.thisptr).GetNormalDir()
+
+ def AddFrequency(self, freq):
+ """ AddFrequency(freq)
+ """
+ if np.isscalar(freq):
+ (<_CSPropProbeBox*>self.thisptr).AddFDSample(freq)
+ else:
+ for f in freq:
+ (<_CSPropProbeBox*>self.thisptr).AddFDSample(f)
+
+ def ClearFrequency(self):
+ """ ClearFrequency()
+ """
+ (<_CSPropProbeBox*>self.thisptr).ClearFDSamples()
+
+ def SetFrequency(self, freq):
+ """ SetFrequency(freq)
+ """
+ self.ClearFrequency()
+ self.AddFrequency(freq)
+
+ def GetFrequency(self):
+ """ GetFrequency
+ """
+ cdef vector[double]* _freq = (<_CSPropProbeBox*>self.thisptr).GetFDSamples()
+ Nf = _freq.size()
+ freq = np.zeros(Nf)
+ for n in range(Nf):
+ freq[n] = _freq.at(n)
+ return freq
+
+ def GetFrequencyCount(self):
+ """ GetFrequencyCount()
+ """
+ return (<_CSPropProbeBox*>self.thisptr).CountFDSamples()
+
+ def SetModeFunction(self, mode_fun):
+ """ SetModeFunction(mode_fun)
+ """
+ assert len(mode_fun)==3, 'SetModeFunction: mode_fun must be list of length 3'
+ self.AddAttribute('ModeFunctionX', str(mode_fun[0]))
+ self.AddAttribute('ModeFunctionY', str(mode_fun[1]))
+ self.AddAttribute('ModeFunctionZ', str(mode_fun[2]))
+
+###############################################################################
+cdef class CSPropDumpBox(CSPropProbeBox):
+ """
+ Dump property to create field dumps.
+
+ Depending on the EM modeling tool there exist different dump types, dump
+ modes and file types with different meanings.
+
+ openEMS dump types:
+
+ * 0 : for E-field time-domain dump (default)
+ * 1 : for H-field time-domain dump
+ * 2 : for electric current time-domain dump
+ * 3 : for total current density (rot(H)) time-domain dump
+
+ * 10 : for E-field frequency-domain dump
+ * 11 : for H-field frequency-domain dump
+ * 12 : for electric current frequency-domain dump
+ * 13 : for total current density (rot(H)) frequency-domain dump
+
+ * 20 : local SAR frequency-domain dump
+ * 21 : 1g averaging SAR frequency-domain dump
+ * 22 : 10g averaging SAR frequency-domain dump
+
+ * 29 : raw data needed for SAR calculations (electric field FD, cell volume, conductivity and density)
+
+ openEMS dump modes:
+
+ * 0 : no-interpolation
+ * 1 : node-interpolation (default, see warning below)
+ * 2 : cell-interpolation (see warning below)
+
+ openEMS file types:
+
+ * 0 : vtk-file (default)
+ * 1 : hdf5-file (easier to read by python, using h5py)
+
+ :param dump_type: dump type (see above)
+ :param dump_mode: dump mode (see above)
+ :param file_type: file type (see above)
+ :param frequency: specify a frequency vector (required for dump types >=10)
+ :param sub_sampling: field domain sub-sampling, e.g. '2,2,4'
+ :param opt_resolution: field domain dump resolution, e.g. '10' or '10,20,5'
+
+ Notes
+ -----
+ openEMS FDTD Interpolation abnormalities:
+
+ * no-interpolation:
+ fields are located in the mesh by the Yee-scheme, the mesh only
+ specifies E- or H-Yee-nodes --> use node- or cell-interpolation or
+ be aware of the offset
+ * E-field dump & node-interpolation:
+ normal electric fields on boundaries will have false amplitude due to
+ forward/backward interpolation in case of (strong) changes in material
+ permittivity or on metal surfaces
+ --> use no- or cell-interpolation
+ * H-field dump & cell-interpolation:
+ normal magnetic fields on boundaries will have false amplitude due to
+ forward/backward interpolation in case of (strong) changes in material
+ permeability --> use no- or node-interpolation
+ """
+ def __init__(self, ParameterSet pset, *args, no_init=False, **kw):
+ if no_init:
+ self.thisptr = NULL
+ return
+ if not self.thisptr:
+ self.thisptr = <_CSProperties*> new _CSPropDumpBox(pset.thisptr)
+
+ if 'dump_type' in kw:
+ self.SetDumpType(kw['dump_type'])
+ del kw['dump_type']
+ if 'dump_mode' in kw:
+ self.SetDumpMode(kw['dump_mode'])
+ del kw['dump_mode']
+ if 'file_type' in kw:
+ self.SetFileType(kw['file_type'])
+ del kw['file_type']
+ if 'opt_resolution' in kw:
+ self.SetOptResolution(kw['opt_resolution'])
+ del kw['opt_resolution']
+ if 'sub_sampling' in kw:
+ self.SetSubSampling(kw['sub_sampling'])
+ del kw['sub_sampling']
+ super(CSPropDumpBox, self).__init__(pset, *args, **kw)
+
+ def SetDumpType(self, val):
+ """ SetDumpType(val)
+ """
+ (<_CSPropDumpBox*>self.thisptr).SetDumpType(val)
+
+ def GetDumpType(self):
+ """ GetDumpType()
+ """
+ return (<_CSPropDumpBox*>self.thisptr).GetDumpType()
+
+ def SetDumpMode(self, val):
+ """ SetDumpMode(val)
+ """
+ (<_CSPropDumpBox*>self.thisptr).SetDumpMode(val)
+
+ def GetDumpMode(self):
+ """ GetDumpMode()
+ """
+ return (<_CSPropDumpBox*>self.thisptr).GetDumpMode()
+
+ def SetFileType(self, val):
+ """ SetFileType(val)
+ """
+ (<_CSPropDumpBox*>self.thisptr).SetFileType(val)
+
+ def GetFileType(self):
+ """ GetFileType()
+ """
+ return (<_CSPropDumpBox*>self.thisptr).GetFileType()
+
+ def SetOptResolution(self, val):
+ """ SetOptResolution(val)
+ """
+ assert len(val)==3, 'SetOptResolution: value must be list or array of length 3'
+ for n in range(3):
+ (<_CSPropDumpBox*>self.thisptr).SetOptResolution(n, val[n])
+
+ def GetOptResolution(self):
+ """ GetOptResolution()
+ """
+ val = np.zeros(3)
+ for n in range(3):
+ val[n] = (<_CSPropDumpBox*>self.thisptr).GetOptResolution(n)
+ return val
+
+ def SetSubSampling(self, val):
+ """ SetSubSampling(val)
+ """
+ assert len(val)==3, "SetSubSampling: 'val' must be a list or array of length 3"
+ for n in range(3):
+ (<_CSPropDumpBox*>self.thisptr).SetSubSampling(n, val[n])
+
+ def GetSubSampling(self):
+ """ GetSubSampling()
+ """
+ val = np.zeros(3)
+ for n in range(3):
+ val[n] = (<_CSPropDumpBox*>self.thisptr).GetSubSampling(n)
+ return val
diff --git a/CSXCAD/python/CSXCAD/CSRectGrid.pxd b/CSXCAD/python/CSXCAD/CSRectGrid.pxd
new file mode 100644
index 0000000..7ae344e
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/CSRectGrid.pxd
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from libcpp.string cimport string
+from libcpp cimport bool
+
+cdef extern from "CSXCAD/CSXCAD_Global.h":
+ cpdef enum CoordinateSystem "CoordinateSystem":
+ CARTESIAN "CARTESIAN"
+ CYLINDRICAL "CYLINDRICAL"
+ UNDEFINED_CS "UNDEFINED_CS"
+
+cdef extern from "CSXCAD/CSRectGrid.h":
+ cdef cppclass _CSRectGrid "CSRectGrid":
+ _CSRectGrid() except +
+ void AddDiscLine(int direct, double val)
+
+ void clear()
+ void ClearLines(int direct)
+
+ void SetDeltaUnit(double val)
+ double GetDeltaUnit()
+
+ void Sort(int direct)
+ double* GetLines(int direct, double *array, unsigned int &qty, bool sorted)
+ size_t GetQtyLines(int direct)
+ double GetLine(int direct, size_t Index)
+
+ unsigned int Snap2LineNumber(int ny, double value, bool &inside)
+
+ int GetDimension()
+ void SetMeshType(CoordinateSystem cs_type)
+ CoordinateSystem GetMeshType()
+
+ void IncreaseResolution(int nu, int factor)
+ double* GetSimArea()
+ bool isValid()
+
+cdef class CSRectGrid:
+ cdef _CSRectGrid *thisptr
+ cdef bool no_init
diff --git a/CSXCAD/python/CSXCAD/CSRectGrid.pyx b/CSXCAD/python/CSXCAD/CSRectGrid.pyx
new file mode 100644
index 0000000..d47467b
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/CSRectGrid.pyx
@@ -0,0 +1,222 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""
+Rectilinear Grid Class for CSXCAD
+"""
+
+import numpy as np
+cimport CSRectGrid
+from Utilities import CheckNyDir
+from SmoothMeshLines import SmoothMeshLines
+
+cdef class CSRectGrid:
+ """
+ Rectilinear Grid Class for CSXCAD. The grid can be defined e.g. as a Cartesian
+ or cylindrical mesh and can hold mesh lines in the 3 fundamental directions.
+ E.g. x,y and z for the Cartesian and rho, a and z for the cylindrical mesh.
+
+ :param CoordSystem: define the coordinate system (default 0 : Cartesian)
+ """
+ def __cinit__(self, *args, no_init=False, **kw):
+ self.no_init = no_init
+ if no_init==False:
+ self.thisptr = new _CSRectGrid()
+ if 'CoordSystem' in kw:
+ self.SetMeshType(kw['CoordSystem'])
+ del kw['CoordSystem']
+ elif 'cs_type' in kw:
+ self.SetMeshType(kw['cs_type'])
+ del kw['cs_type']
+ else:
+ self.thisptr = NULL
+
+ assert len(kw)==0, 'Unknown keyword arguments: "{}"'.format(kw)
+
+ def __dealloc__(self):
+ if not self.no_init:
+ del self.thisptr
+
+ def SetMeshType(self, cs_type):
+ """ SetMeshType(cs_type)
+
+ Set the coordinate system type (Cartesian or cylindrical) for this mesh.
+
+ :param cs_type: coordinate system (0 : Cartesian, 1 : Cylindrical)
+ """
+ assert cs_type in [CARTESIAN, CYLINDRICAL], 'Unknown coordinate system: {}'.format(cs_type)
+ self.thisptr.SetMeshType(cs_type)
+
+ def GetMeshType(self):
+ return self.thisptr.GetMeshType()
+
+ def SetLines(self, ny, lines):
+ """ SetLines(ny, lines)
+
+ Set an array of lines. This will clear all previous defined lines in
+ the given direction.
+
+ :param ny: int or str -- direction definition
+ :param lines: array -- list of lines to be set in the given direction
+ """
+ ny = CheckNyDir(ny)
+
+ assert len(lines)>0, 'SetLines: "lines" must be an array or list'
+ self.thisptr.ClearLines(ny)
+ for n in range(len(lines)):
+ self.thisptr.AddDiscLine(ny, lines[n])
+
+ def AddLine(self, ny, line):
+ """ AddLine(ny, lines)
+
+ Add an array of lines. This will *not* clear the previous defined lines in
+ the given direction.
+
+ :param ny: int or str -- direction definition
+ :param lines: array -- list of lines to be added in the given direction
+ """
+ ny = CheckNyDir(ny)
+ if np.isscalar(line):
+ self.thisptr.AddDiscLine(ny, line)
+ return
+ assert len(line)>0, 'AddLine: "lines" must be a float, array or list'
+ for n in range(len(line)):
+ self.thisptr.AddDiscLine(ny, line[n])
+
+ def GetQtyLines(self, ny):
+ """ GetQtyLines(ny)
+
+ :param ny: int or str -- direction definition
+ """
+ ny = CheckNyDir(ny)
+ return self.thisptr.GetQtyLines(ny)
+
+ def GetLine(self, ny, idx):
+ """ GetLine(ny, idx)
+
+ Get the line in a given direction `ny` and index
+
+ :param ny: int or str -- direction definition
+ :param idx: int -- line index
+ """
+ ny = CheckNyDir(ny)
+ return self.thisptr.GetLine(ny, idx)
+
+ def GetLines(self, ny, do_sort=False):
+ """ GetLines(ny, do_sort=False)
+
+ Get all lines in a given direction `ny`.
+
+ :param ny: int or str -- direction definition
+ :param do_sort: bool -- sort lines
+ """
+ ny = CheckNyDir(ny)
+ cdef unsigned int N = 0
+ cdef double* array = NULL
+ array = self.thisptr.GetLines(ny, array, N, do_sort)
+ lines = np.zeros(N)
+ for n in range(N):
+ lines[n] = array[n]
+ return lines
+
+ def ClearLines(self, ny):
+ """ ClearLines(ny)
+
+ Clear all lines in a given direction `ny`.
+
+ :param ny: int or str -- direction definition
+ """
+ ny = CheckNyDir(ny)
+ self.thisptr.ClearLines(ny)
+
+ def SmoothMeshLines(self, ny, max_res, ratio=1.5):
+ """ SmoothMeshLines(ny, max_res, ratio=1.5)
+
+ Smooth all mesh lines in the given direction with a max. allowed resolution.
+
+ :param ny: int or str -- direction definition or 'all' for all directions
+ :param max_res: float -- max. allowed resolution
+ :param ratio: float -- max. allowed ration of mesh smoothing de/increase
+ """
+ if ny=='all':
+ for n in range(3):
+ self.SmoothMeshLines(n, max_res, ratio)
+ else:
+ lines = self.GetLines(ny)
+ lines = SmoothMeshLines(lines, max_res, ratio)
+ self.SetLines(ny, lines)
+
+ def Clear(self):
+ """
+ Clear all lines and delta unit.
+ """
+ self.thisptr.clear()
+
+ def SetDeltaUnit(self, unit):
+ """ SetDeltaUnit(unit)
+
+ Set the drawing unit for all mesh lines. Default is 1 (m)
+ """
+ self.thisptr.SetDeltaUnit(unit)
+
+ def GetDeltaUnit(self):
+ """
+ Get the drawing unit for all mesh lines.
+ """
+ return self.thisptr.GetDeltaUnit()
+
+ def Sort(self, ny='all'):
+ """ Sort(ny='all')
+
+ Sort mesh lines in the given direction or all directions.
+ """
+ if ny=='all':
+ for n in range(3):
+ self.thisptr.Sort(n)
+ else:
+ ny = CheckNyDir(ny)
+ self.thisptr.Sort(ny)
+
+ def Snap2LineNumber(self, ny, value):
+ """ Snap2LineNumber(ny, value)
+
+ Find a fitting mesh line index for the given direction and value.
+ """
+ ny = CheckNyDir(ny)
+ cdef bool inside=False
+ pos = self.thisptr.Snap2LineNumber(ny, value, inside)
+ return pos, inside>0
+
+ def GetSimArea(self):
+ """
+ Get the simulation area as defined by the mesh.
+
+ :returns: (2,3) array -- Simulation domain box
+ """
+ bb = np.zeros([2,3])
+ cdef double *_bb = self.thisptr.GetSimArea()
+ for n in range(3):
+ bb[0,n] = _bb[2*n]
+ bb[1,n] = _bb[2*n+1]
+ return bb
+
+ def IsValid(self):
+ """
+ Check if the mesh is valid. That is at least 2 mesh lines in all directions.
+ """
+ return self.thisptr.isValid()
diff --git a/CSXCAD/python/CSXCAD/CSTransform.pxd b/CSXCAD/python/CSXCAD/CSTransform.pxd
new file mode 100644
index 0000000..05a43e2
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/CSTransform.pxd
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from libcpp.string cimport string
+from libcpp cimport bool
+from ParameterObjects cimport _ParameterSet
+
+cdef extern from "CSXCAD/CSTransform.h":
+ cdef cppclass _CSTransform "CSTransform":
+ _CSTransform() except +
+ _CSTransform(_ParameterSet*) except +
+
+ void Reset()
+
+ double* Transform(double *inCoord, double *outCoord)
+ double* InvertTransform(double *inCoord, double *outCoord)
+
+ double* GetMatrix()
+
+ bool HasTransform()
+
+ void Translate(double *translate, bool concatenate)
+
+ void SetMatrix(double *matrix, bool concatenate)
+
+ void RotateOrigin(double *vector, double angle, bool concatenate)
+ void RotateXYZ(int ny, double angle, bool concatenate)
+
+ void Scale(double scale, bool concatenate)
+ void Scale(double *scale, bool concatenate)
+
+ void SetPreMultiply()
+ void SetPostMultiply()
+
+ void SetAngleRadian()
+
+cdef class CSTransform:
+ cdef _CSTransform *thisptr \ No newline at end of file
diff --git a/CSXCAD/python/CSXCAD/CSTransform.pyx b/CSXCAD/python/CSXCAD/CSTransform.pyx
new file mode 100644
index 0000000..80b7b04
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/CSTransform.pyx
@@ -0,0 +1,225 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+"""
+Affine Transformations for primitives
+"""
+
+import numpy as np
+from ParameterObjects cimport _ParameterSet, ParameterSet
+cimport CSTransform
+from Utilities import CheckNyDir
+
+cdef class CSTransform:
+ """
+ This class can realize affine transformations for all CSPrimtivies.
+ Individual tranformations can be concatenated to the previous. As a result
+ the order of transformations is important.
+ """
+ def __cinit__(self, ParameterSet pset=None, no_init=False, **kw):
+ if no_init==False:
+ if pset is None:
+ self.thisptr = new _CSTransform()
+ else:
+ self.thisptr = new _CSTransform(pset.thisptr)
+ self.thisptr.SetAngleRadian()
+ else:
+ self.thisptr = NULL
+
+ def Reset(self):
+ """
+ Reset all transformations.
+ """
+ self.thisptr.Reset()
+
+ def HasTransform(self):
+ """
+ Check if any transformations are set.
+ """
+ return self.thisptr.HasTransform()
+
+ def Transform(self, coord, invers=False):
+ """ Transform(coord, invers)
+
+ Apply a transformation to the given coordinate.
+
+ :param coord: (3,) array -- coordinate to transform
+ :param invers: bool -- do an invers transformation
+ :returns: (3,) array -- transformed coordinates
+ """
+ cdef double[3] d_coord
+ cdef double[3] d_out
+ for n in range(3):
+ d_coord[n] = coord[n]
+
+ if not invers:
+ self.thisptr.Transform(d_coord, d_out)
+ else:
+ self.thisptr.InvertTransform(d_coord, d_out)
+ out = np.zeros((3,))
+ for n in range(3):
+ out[n] = d_out[n]
+ return out
+
+ def GetMatrix(self):
+ """
+ Get the full 4x4 transformation matrix used for transformation.
+
+ :returns: (4,4) array -- transformation matrix
+ """
+ cdef double *d_mat = NULL
+ d_mat = self.thisptr.GetMatrix()
+ mat = np.zeros([4,4])
+ for n in range(4):
+ for m in range(4):
+ mat[n][m] = d_mat[4*n + m]
+
+ return mat
+
+ def AddTransform(self, transform, *args, **kw):
+ """ AddTransform(transform, *args, **kw)
+
+ Add a transform by name and arguments.
+
+ Examples
+ --------
+ Add a translation and 30° rotation around the z-axis:
+
+ >>> tr = CSTransform()
+ >>> tr.AddTransform('Translate', [10, 4,6])
+ >>> tr.AddTransform('RotateAxis', 'z', 30)
+
+ Add a rotation around the axis=[1, 1, 0] by pi/3 (30°):
+
+ >>> tr = CSTransform()
+ >>> tr.AddTransform('RotateOrigin', [1, 1, 0], np.pi/3, deg=False)
+
+ Available Transformation keywords:
+
+ * RotateAxis : Rotate around x,y or z-axis
+ * RotateOrigin : Rotate around a given axis
+ * Translate : Translation vector
+ * Scale : Scale value or vector
+ * Matrix : A affine transformation matrix as (4,4) array
+
+ :param transform: str -- transformation name or keyword.
+ """
+ assert type(transform)==str, 'AddTransform, transform name must be a string'
+ if transform == 'RotateAxis':
+ self.RotateAxis(*args, **kw)
+ elif transform == 'RotateOrigin':
+ self.RotateOrigin(*args, **kw)
+ elif transform == 'Translate':
+ self.Translate(*args, **kw)
+ elif transform == 'Scale':
+ self.Scale(*args, **kw)
+ elif transform in ['Matrix', 'SetMatrix']:
+ self.SetMatrix(*args, **kw)
+ else:
+ raise Exception('AddTransform: Unkown transformation "{}"'.format(transform))
+
+ def Translate(self, vec, concatenate=True):
+ """ Translate(vec, concatenate=True)
+
+ Add a trsanslation transformation.
+
+ :param vec: (3,) array -- translation vector
+ """
+ assert len(vec)==3, 'Translate vector must be a list or array of length 3'
+ cdef double[3] d_vec;
+ for n in range(3):
+ d_vec[n] = vec[n]
+ self.thisptr.Translate(d_vec, concatenate)
+
+
+ def SetMatrix(self, mat, concatenate=True):
+ """ SetMatrix(mat, concatenate=True)
+
+ Add an arbitrary (invertable) trsanslation matrix.
+
+ :param mat: (3,) array -- translation vector
+ """
+ mat = np.array(mat)
+ assert mat.shape == (4,4), 'SetMatrix: matrix must be of shape (4,4)'
+ cdef double[16] d_mat;
+ for n in range(4):
+ for m in range(4):
+ d_mat[4*n + m] = mat[n][m]
+ self.thisptr.SetMatrix(d_mat, concatenate)
+
+ def RotateOrigin(self, vec, angle, deg=True, concatenate=True):
+ """ RotateOrigin(vec, angle, deg=True, concatenate=True)
+
+ Add a rotation transformation around an arbitrary axis.
+
+ :param vec: (3,) array -- translation axis vector.
+ :param angle: float -- rotation angle (default in degrees)
+ :param deg: bool -- set degree or radiant for angle (default True)
+ """
+ assert len(vec)==3, 'RotateOrigin: axis vector must be a list or array of length 3'
+ cdef double[3] d_vec;
+ for n in range(3):
+ d_vec[n] = vec[n]
+ if deg:
+ angle = np.deg2rad(angle)
+ self.thisptr.RotateOrigin(d_vec, angle, concatenate)
+
+ def RotateAxis(self, ny, angle, deg=True, concatenate=True):
+ """ RotateAxis(ny, angle, deg=True, concatenate=True)
+
+ Add a rotation transformation around a cartesian axis (x,y or z).
+
+ :param ny: int or str -- translation axis vector 0/1/2 or 'x'/'y'/'z.
+ :param angle: float -- rotation angle (default in degrees)
+ :param deg: bool -- set degree or radiant for angle (default True)
+ """
+ ny = CheckNyDir(ny)
+ if deg:
+ angle = np.deg2rad(angle)
+ self.thisptr.RotateXYZ(ny, angle, concatenate)
+
+ def Scale(self, scale, bool concatenate=True):
+ """ Scale(scale, concatenate=True)
+
+ Add a scaleing transformation.
+
+ :param scale: float or (3,) array -- Scaling factor
+ """
+ cdef double[3] d_scale;
+ if type(scale)==float or type(scale)==int:
+ d_scale[0] = scale
+ self.thisptr.Scale(d_scale[0], concatenate)
+ return
+
+ assert len(scale)==3, 'Scale: scale must be a float or array of length 3'
+ for n in range(3):
+ d_scale[n] = scale[n]
+ self.thisptr.Scale(d_scale, concatenate)
+
+ def SetPreMultiply(self):
+ """
+ Set all following transformations as pre multiply (default is post multiply)
+ """
+ self.thisptr.SetPreMultiply()
+
+ def SetPostMultiply(self):
+ """
+ Set all following transformations as post multiply (default)
+ """
+ self.thisptr.SetPostMultiply()
+
diff --git a/CSXCAD/python/CSXCAD/CSXCAD.pxd b/CSXCAD/python/CSXCAD/CSXCAD.pxd
new file mode 100644
index 0000000..b95b7c1
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/CSXCAD.pxd
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from libcpp.string cimport string
+from libcpp cimport bool
+from libcpp.vector cimport vector
+
+cimport CSPrimitives
+cimport CSProperties
+
+from CSPrimitives cimport _CSPrimitives, CSPrimitives, PrimitiveType
+from ParameterObjects cimport _ParameterSet, ParameterSet
+from CSProperties cimport _CSProperties, CSProperties, PropertyType
+from CSRectGrid cimport _CSRectGrid, CSRectGrid, CoordinateSystem
+
+cdef extern from "CSXCAD/ContinuousStructure.h":
+ cdef cppclass _ContinuousStructure "ContinuousStructure":
+ _ContinuousStructure() except +
+ bool Write2XML(string)
+ string ReadFromXML(string)
+ _ParameterSet* GetParameterSet()
+
+ _CSRectGrid* GetGrid()
+
+ void SetCoordInputType(CoordinateSystem cs_type)
+
+ void AddProperty(_CSProperties* prop)
+ _CSProperties* GetProperty(int index)
+ int GetQtyPrimitives(PropertyType prop_type)
+ int GetQtyProperties()
+
+ _CSProperties* GetPropertyByCoordPriority(const double* coord, PropertyType prop_type, bool markFoundAsUsed, _CSPrimitives** foundPrimitive)
+
+ vector[_CSPrimitives*] GetAllPrimitives(bool sort, PropertyType prop_type)
+
+ vector[_CSProperties*] GetPropertiesByName(string name)
+ vector[_CSProperties*] GetPropertyByType(PropertyType prop_type)
+
+ string Update()
+
+cdef class ContinuousStructure:
+ cdef _ContinuousStructure *thisptr # hold a C++ instance which we're wrapping
+ cdef readonly ParameterSet __paraset
+ cdef readonly CSRectGrid __grid
+ cdef _AddProperty(self, CSProperties prop)
+ cdef _GetProperty(self, int index)
+ cdef __GetPropertyByCoordPriority(self, double* coord, PropertyType prop_type, bool markFoundAsUsed)
+ cdef __GetAllPrimitives(self, bool sort, PropertyType prop_type)
+ cdef __GetPropertiesByName(self, string name)
+ cdef __GetPropertyByType(self, PropertyType prop_type) \ No newline at end of file
diff --git a/CSXCAD/python/CSXCAD/CSXCAD.pyx b/CSXCAD/python/CSXCAD/CSXCAD.pyx
new file mode 100644
index 0000000..a8d5fa7
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/CSXCAD.pyx
@@ -0,0 +1,385 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+
+"""
+This moduld contains the main class ContinuousStructure (CSX).
+
+
+Examples
+--------
+
+>>> CSX = CSXCAD.ContinuousStructure()
+>>> metal = CSX.AddMetal('metal') # create a metal property
+>>> box = CSX.AddBox(metal, [0,0,0, [10,10,10]) # assign a box to the metal property
+
+>>> mesh = CSX.GetGrid() # get a grid instance
+>>> mesh.AddLine('x', [-20, 0, 20]) # add some lines in x-direction
+>>> mesh.SmoothMeshLines('x', 2.5) # smooth the mesh
+"""
+
+cimport CSXCAD
+
+from CSProperties import CSPropMaterial, CSPropExcitation
+from CSProperties import CSPropMetal, CSPropConductingSheet
+from CSProperties import CSPropLumpedElement, CSPropProbeBox, CSPropDumpBox
+from CSPrimitives import CSPrimPoint, CSPrimBox, CSPrimCylinder, CSPrimCylindricalShell
+from CSPrimitives import CSPrimSphere, CSPrimSphericalShell
+from CSPrimitives import CSPrimPolygon, CSPrimLinPoly, CSPrimRotPoly
+from CSPrimitives import CSPrimCurve, CSPrimWire
+from CSPrimitives import CSPrimPolyhedron, CSPrimPolyhedronReader
+cimport CSProperties as c_CSProperties
+cimport CSRectGrid as c_CSRectGrid
+from CSProperties import CSProperties
+from ParameterObjects import ParameterSet
+
+from SmoothMeshLines import SmoothMeshLines
+
+cdef class ContinuousStructure:
+ """ ContinuousStructure
+
+ With this class different properties and primitives can be created and a
+ rectengular grid assigned.
+
+ See Also
+ --------
+ CSXCAD.CSProperties
+ CSXCAD.CSPrimitives
+ CSXCAD.CSRectGrid
+
+ Examples
+ --------
+ Create a metal box:
+
+ >>> CSX = CSXCAD.ContinuousStructure()
+ >>> metal = CSX.AddMetal('metal') # create a metal property with name "metal"
+ >>> start = [0,0,0]
+ >>> stop = [1,2,1]
+ >>> box = CSX.AddBox(metal, start, stop) # Assign a box to propety "metal"
+ """
+ def __cinit__(self, **kw):
+ self.thisptr = new _ContinuousStructure()
+ self.__paraset = ParameterSet(no_init=True)
+ self.__paraset.thisptr = self.thisptr.GetParameterSet()
+
+ self.__grid = CSRectGrid(no_init=True)
+ self.__grid.thisptr = self.thisptr.GetGrid()
+
+ if 'CoordSystem' in kw:
+ self.SetMeshType(kw['CoordSystem'])
+ del kw['CoordSystem']
+ elif 'cs_type' in kw:
+ self.SetMeshType(kw['cs_type'])
+ del kw['cs_type']
+
+ assert len(kw)==0, 'Unknown keyword arguments: "{}"'.format(kw)
+
+ def __dealloc__(self):
+ del self.thisptr
+
+ def Update(self):
+ return self.thisptr.Update().decode('UTF-8')
+
+ def Write2XML(self, fn):
+ """ Write2XML(fn)
+
+ Write geometry to an xml-file
+
+ :param fn: str -- file name
+ """
+ self.thisptr.Write2XML(fn.encode('UTF-8'))
+
+ def ReadFromXML(self, fn):
+ """ ReadFromXML(fn)
+
+ Read geometry from xml-file
+
+ :param fn: str -- file name
+ """
+ return self.thisptr.ReadFromXML(fn.encode('UTF-8')).decode('UTF-8')
+
+ def GetParameterSet(self):
+ """
+ Get the parameter set assigned to this class
+ """
+ return self.__paraset
+
+ def GetGrid(self):
+ """
+ Get the CSRectGrid assigned to this class.
+
+ See Also
+ --------
+ CSXCAD.CSRectGrid, DefineGrid
+ """
+ return self.__grid
+
+ def SetMeshType(self, cs_type):
+ self.__grid.SetMeshType(cs_type)
+ self.thisptr.SetCoordInputType(cs_type)
+
+ def DefineGrid(self, mesh, unit, smooth_mesh_res=None):
+ """ DefineGrid(mesh, unit, smooth_mesh_res=None)
+
+ Assign a mesh lines to the grid assigned to this property.
+
+ :param mesh: (3,) list of mesh lines
+ :param unit: float -- drawing unit
+ :param smooth_mesh_res: an optional mesh smoothing
+
+ See Also
+ --------
+ CSXCAD.CSRectGrid, GetGrid, CSXCAD.SmoothMeshLines.SmoothMeshLines
+
+ """
+ grid = self.GetGrid()
+ grid.Clear()
+ if smooth_mesh_res is not None:
+ for k in mesh:
+ mesh[k] = SmoothMeshLines(mesh[k], smooth_mesh_res)
+
+ for k in mesh:
+ grid.SetLines(k, mesh[k])
+
+ grid.SetDeltaUnit(unit)
+ return grid
+
+ def GetQtyProperties(self):
+ return self.thisptr.GetQtyProperties()
+
+ def GetQtyPrimitives(self, prop_type=c_CSProperties.ANY):
+ return self.thisptr.GetQtyPrimitives(prop_type)
+
+ def AddMaterial(self, name, **kw):
+ """ AddMaterial(name, **kw)
+
+ Add a material property with name `name`.
+
+ See Also
+ --------
+ CSXCAD.CSProperties.CSPropMaterial
+ """
+ return self.__CreateProperty('Material', name, **kw)
+
+ def AddLumpedElement(self, name, **kw):
+ """ AddLumpedElement(name, **kw)
+
+ Add a lumped element with name `name`.
+
+ See Also
+ --------
+ CSXCAD.CSProperties.CSPropLumpedElement
+ """
+ return self.__CreateProperty('LumpedElement', name, **kw)
+
+ def AddMetal(self, name):
+ """ AddMetal(name)
+
+ Add a metal property with name `name`.
+
+ See Also
+ --------
+ CSXCAD.CSProperties.CSPropMetal
+ """
+ return self.__CreateProperty('Metal', name)
+
+ def AddConductingSheet(self, name, **kw):
+ """ AddConductingSheet(name, **kw)
+
+ Add a conducting sheet with name `name`.
+
+ See Also
+ --------
+ CSXCAD.CSProperties.CSPropConductingSheet
+ """
+ return self.__CreateProperty('ConductingSheet', name, **kw)
+
+ def AddExcitation(self, name, exc_type, exc_val, **kw):
+ """ AddExcitation(name, exc_type, exc_val, **kw)
+
+ Add an excitation property with name `name`.
+
+ See Also
+ --------
+ CSXCAD.CSProperties.CSPropExcitation
+ """
+ return self.__CreateProperty('Excitation', name, exc_type=exc_type, exc_val=exc_val, **kw)
+
+ def AddProbe(self, name, p_type, **kw):
+ """ AddProbe(name, p_type, **kw)
+
+ Add a probe property with name `name`.
+
+ See Also
+ --------
+ CSXCAD.CSProperties.CSPropProbeBox
+ """
+ return self.__CreateProperty('ProbeBox', name, p_type=p_type, **kw)
+
+ def AddDump(self, name, **kw):
+ """ AddDump(name, **kw)
+
+ Add a dump property with name `name`.
+
+ See Also
+ --------
+ CSXCAD.CSProperties.CSPropDumpBox
+ """
+ return self.__CreateProperty('DumpBox', name, **kw)
+
+ def __CreateProperty(self, type_str, name, *args, **kw):
+ assert len(args)==0, 'CreateProperty does not support additional arguments'
+ prop = CSProperties.fromTypeName(type_str, self.__paraset, **kw)
+ if prop is None:
+ raise Exception('CreateProperty: Unknown property type requested: {}'.format(type_str))
+ prop.SetName(name)
+ self.AddProperty(prop)
+ return prop
+
+ def AddProperty(self, prop):
+ """ AddProperty(prop)
+
+ Add an already created property (`prop`) to this class.
+
+ Notes
+ -----
+ This class will take ownership of the property.
+ """
+ self._AddProperty(prop)
+
+ cdef _AddProperty(self, CSProperties prop):
+ prop.__CSX = self
+ self.thisptr.AddProperty(prop.thisptr)
+
+ def GetProperty(self, index):
+ """ GetProperty(index)
+
+ Get the property at the given index
+
+ See Also
+ --------
+ CSXCAD.GetQtyProperties
+ """
+ if index<0 or index >=self.GetQtyProperties():
+ raise IndexError('Index is out of range')
+ return self._GetProperty(index)
+
+ cdef _GetProperty(self, int index):
+ cdef _CSProperties* _prop
+ cdef CSProperties prop
+ _prop = self.thisptr.GetProperty(index)
+ prop = CSProperties.fromType(_prop.GetType(), pset=None, no_init=True)
+ prop.thisptr = _prop
+ return prop
+
+ def GetAllProperties(self):
+ """ GetAllProperties()
+
+ Get a list of all properties
+ """
+ props = []
+ for n in range(self.GetQtyProperties()):
+ props.append(self._GetProperty(n))
+ return props
+
+ def GetPropertiesByName(self, name):
+ """ GetPropertiesByName(name)
+
+ Get all the property specifed by their name
+ """
+ return self.__GetPropertiesByName(name.encode('UTF-8'))
+
+ cdef __GetPropertiesByName(self, string name):
+ cdef vector[_CSProperties*] vprop
+ vprop = self.thisptr.GetPropertiesByName(name)
+
+ cdef _CSProperties* _prop
+ cdef CSProperties prop
+ props = []
+ for n in range(vprop.size()):
+ _prop = vprop.at(n)
+ prop = CSProperties.fromType(_prop.GetType(), pset=None, no_init=True)
+ prop.thisptr = _prop
+ props.append(prop)
+
+ return props
+
+ def GetPropertyByType(self, prop_type):
+ """ GetPropertyByType(prop_type)
+
+ Get a list of properties specified by their type
+ """
+ return self.__GetPropertyByType(prop_type)
+
+ cdef __GetPropertyByType(self, PropertyType prop_type):
+ cdef vector[_CSProperties*] vprop
+ vprop = self.thisptr.GetPropertyByType(prop_type)
+
+ cdef _CSProperties* _prop
+ cdef CSProperties prop
+ props = []
+ for n in range(vprop.size()):
+ _prop = vprop.at(n)
+ prop = CSProperties.fromType(_prop.GetType(), pset=None, no_init=True)
+ prop.thisptr = _prop
+ props.append(prop)
+
+ return props
+
+ def GetPropertyByCoordPriority(self, coord, prop_type=c_CSProperties.ANY, markFoundAsUsed=False):
+ """ GetPropertyByCoordPriority(coord, prop_type=None, markFoundAsUsed=False)
+ """
+ cdef double _coord[3]
+ for n in range(3):
+ _coord[n] = coord[n]
+ return self.__GetPropertyByCoordPriority(_coord, prop_type, markFoundAsUsed)
+
+ cdef __GetPropertyByCoordPriority(self, double* coord, PropertyType prop_type, bool markFoundAsUsed):
+ cdef _CSPrimitives *prim
+ cdef _CSProperties *_prop = self.thisptr.GetPropertyByCoordPriority(coord, prop_type, markFoundAsUsed, &prim)
+
+ cdef CSProperties prop
+ if _prop==NULL:
+ return None
+ else:
+ prop = CSProperties.fromType(_prop.GetType(), pset=None, no_init=True)
+ prop.thisptr = _prop
+ return prop
+
+ def GetAllPrimitives(self, sort=False, prop_type=c_CSProperties.ANY):
+ """ GetAllPrimitives(sort, prop_type)
+
+ Get a list of all primitives.
+ """
+ return self.__GetAllPrimitives(sort, prop_type)
+
+ cdef __GetAllPrimitives(self, bool sort, PropertyType prop_type):
+ cdef vector[_CSPrimitives*] vprim
+ vprim = self.thisptr.GetAllPrimitives(sort, prop_type)
+
+ cdef _CSPrimitives* _prim
+ cdef CSPrimitives prim
+ prims = []
+ for n in range(vprim.size()):
+ _prim = vprim.at(n)
+ prim = CSPrimitives.fromType(_prim.GetType(), pset=None, prop=None, no_init=True)
+ prim.thisptr = _prim
+ prims.append(prim)
+
+ return prims
+
diff --git a/CSXCAD/python/CSXCAD/ParameterObjects.pxd b/CSXCAD/python/CSXCAD/ParameterObjects.pxd
new file mode 100644
index 0000000..e9baebb
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/ParameterObjects.pxd
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from libcpp cimport bool
+
+cdef extern from "CSXCAD/ParameterObjects.h":
+ cdef cppclass _ParameterSet "ParameterSet":
+ _ParameterSet() except +
+ void PrintSelf()
+ bool GetModified()
+
+cdef class ParameterSet:
+ cdef _ParameterSet *thisptr
+ cdef bool no_init
diff --git a/CSXCAD/python/CSXCAD/ParameterObjects.pyx b/CSXCAD/python/CSXCAD/ParameterObjects.pyx
new file mode 100644
index 0000000..3d02804
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/ParameterObjects.pyx
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from libcpp.string cimport string
+from libcpp cimport bool
+
+cimport ParameterObjects
+
+cdef class ParameterSet:
+ def __cinit__(self, no_init=False):
+ self.no_init = no_init
+ if no_init==True:
+ self.thisptr = NULL
+ else:
+ self.thisptr = new _ParameterSet()
+
+ def __dealloc__(self):
+ if not self.no_init:
+ del self.thisptr
diff --git a/CSXCAD/python/CSXCAD/SmoothMeshLines.py b/CSXCAD/python/CSXCAD/SmoothMeshLines.py
new file mode 100644
index 0000000..4da8d88
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/SmoothMeshLines.py
@@ -0,0 +1,266 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import numpy as np
+import pylab as plt
+
+def MeshLinesSymmetric(l, rel_tol=1e-6):
+ """
+ Internal function, do not use.
+ """
+ l = np.array(l)
+ N = len(l)
+ rng = l[-1]-l[0]
+ if N%2==0: # even
+ mid_val = 0.5*(l[0] + l[-1])
+ else: # off
+ mid_val = l[(N-1)/2]
+
+ for n in range(int(N/2)):
+ if np.abs(mid_val - np.sum((l[n], l[N-n-1])))>rng*rel_tol:
+ return False
+
+ return True
+
+def Unique(l, tol=1e-7):
+ """
+ Internal function, do not use.
+ """
+ l = np.unique(l)
+ dl = np.diff(l)
+ idx = np.where(dl<np.mean(dl)*tol)[0]
+ if len(idx)>0:
+ l = np.delete(l, idx)
+
+ return l
+
+def SmoothRange(start, stop, start_res, stop_res, max_res, ratio):
+ """
+ Internal function, do not use.
+ """
+ assert ratio>1
+ rng = (stop-start)
+
+ # very small range
+ if rng<max_res and rng<start_res*ratio and rng<stop_res*ratio:
+ return Unique([start, stop])
+
+ # very large range and easy start/stop res
+ if start_res>=(max_res/ratio) and stop_res>=(max_res/ratio):
+ N = np.ceil(rng/max_res)
+ return np.linspace(start, stop, N+1)
+
+ def one_side_taper(start_res, ratio, max_res):
+ res = start_res
+ pos = 0
+ N = 0
+ while res<max_res and pos<rng:
+ res *= ratio
+ pos += res
+ N += 1
+ if pos>rng:
+ l = np.zeros(N+1)
+ for n in range(N+1):
+ l[n] = np.sum(start_res * ratio ** np.arange(1,n+1))
+ return l * rng/pos
+
+ _ratio = np.e**((np.log(max_res) - np.log(start_res))/(N))
+
+ l = [0]
+ pos = 0
+ res = start_res
+ for n in range(N):
+ res *= _ratio
+ pos += res
+ l.append(pos)
+
+ while pos<rng:
+ pos += max_res
+ l.append(pos)
+
+ return np.array(l) * rng/l[-1]
+
+ # need to taper start
+ if start_res<(max_res/ratio) and stop_res>=(max_res/ratio):
+ return start + one_side_taper(start_res, ratio, max_res)
+
+ # need to taper stop
+ if start_res>=(max_res/ratio) and stop_res<(max_res/ratio):
+ return np.sort(stop - one_side_taper(stop_res, ratio, max_res))
+
+ # test if max taper on both sides is possible
+ pos1 = 0
+ N1 = 0
+ res = start_res
+ while res<max_res:
+ res *= ratio
+ pos1 += res
+ N1 += 1
+ ratio1 = np.e**((np.log(max_res) - np.log(start_res))/(N1))
+ pos1 = np.sum(start_res * ratio1 ** np.arange(1,N1+1))
+
+ pos2 = 0
+ N2 = 0
+ res = stop_res
+ while res<max_res:
+ res *= ratio
+ pos2 += res
+ N2 += 1
+ ratio2 = np.e**((np.log(max_res) - np.log(stop_res))/(N2))
+ pos2 = np.sum(stop_res * ratio2 ** np.arange(1,N2+1))
+
+ if (pos1+pos2)<rng:
+ l = [0]
+ for n in range(1,N1+1):
+ l.append(l[-1]+start_res*ratio1**n)
+ r = [0]
+ for n in range(1,N2+1):
+ r.append(r[-1]+stop_res*ratio2**n)
+
+ left = rng-pos1-pos2
+ N = int(np.ceil(left/max_res))
+
+ for n in range(N):
+ l.append(l[-1]+max_res)
+
+ length = l[-1]+r[-1]
+ c = Unique(np.r_[np.array(l), length-np.array(r)])
+ return start + c *rng/length
+
+ l = [0]
+ r = [0]
+ while l[-1]+r[-1]<rng:
+ if start_res==stop_res:
+ start_res *= ratio
+ l.append(l[-1]+start_res)
+ stop_res *= ratio
+ r.append(r[-1]+start_res)
+ elif start_res<stop_res:
+ start_res *= ratio
+ l.append(l[-1]+start_res)
+ else:
+ stop_res *= ratio
+ r.append(r[-1]+start_res)
+
+ length = l[-1]+r[-1]
+ c = Unique(np.r_[np.array(l), length-np.array(r)])
+ return start + c *rng/length
+
+def CheckSymmetry(lines):
+ tolerance = 1e-10
+ NP = len(lines)
+ if NP<=2:
+ return 0
+ line_range = lines[-1]-lines[0]
+ center = 0.5*(lines[-1]+lines[0])
+
+ # check all lines for symmetry
+ for n in range(int(NP/2)):
+ if (abs((center-lines[n])-(lines[-n-1]-center)) > line_range*tolerance):
+ return 0
+
+ # check central point to be symmetry-center
+ if NP%2==1:
+ if (abs(lines[int(NP/2)]-center) > line_range*tolerance):
+ return 0
+
+ # if all checks pass, return true
+ return 2 if NP%2==0 else 1
+
+def SmoothMeshLines(lines, max_res, ratio=1.5, **kw):
+ """This is the form of a docstring.
+
+ Parameters
+ ----------
+
+ lines : list
+ List of mesh lines to be smoothed
+ max_res : float
+ Maximum allowed resolution, resulting mesh will always stay below that value
+ ratio : float
+ Ratio of increase or decrease of neighboring mesh lines
+
+ """
+ out_l = Unique(lines)
+ sym = CheckSymmetry(out_l)
+ if sym==1:
+ center = 0.5*(out_l[-1]+out_l[0])
+ out_l = out_l[:int(len(out_l)/2)+1]
+ elif sym==2:
+ center = 0.5*(out_l[-1]+out_l[0])
+ out_l = out_l[:int(len(out_l)/2)]
+
+ dl = np.diff(out_l)
+
+ while len(np.where(dl>max_res)[0])>0:
+ N = len(out_l)
+ dl[dl<=max_res] = np.max(dl)*2
+ idx = np.argmin(dl)
+ dl = np.diff(out_l)
+ if idx>0:
+ start_res = dl[idx-1]
+ else:
+ start_res = max_res
+ if idx<len(dl)-1:
+ stop_res = dl[idx+1]
+ else:
+ stop_res = max_res
+ l = SmoothRange(out_l[idx], out_l[idx+1], start_res, stop_res, max_res, ratio)
+ out_l = Unique(np.r_[out_l, l])
+ dl = np.diff(out_l)
+
+ if len(out_l)==N:
+ break
+
+ if sym==1:
+ return Unique(np.r_[out_l, 2*center-out_l[:-1]])
+ elif sym==2:
+ l = SmoothRange(out_l[-1], 2*center-out_l[-1], dl[-1], dl[-1], max_res, ratio)
+ return Unique(np.r_[out_l, l, 2*center-out_l])
+ return Unique(out_l)
+
+
+if __name__ == "__main__":
+
+# print(SmoothRange(0., 1., 10., 50., 25., 1.5))
+# print(SmoothRange(0., 100., 1., 50., 25., 1.5))
+# print(SmoothRange(0., 100., 50., 1., 25., 1.5))
+# print(SmoothRange(0., 135., 5., 1.5, 25., 1.5))
+# print(SmoothRange(0., 10., 6., 6.5, 25., 1.5))
+
+# l = [-100, -50, 50, 100]
+# l = [ -50., 100., 0., 0.381, 0.762, 1.143, 1.524]
+#
+ l = [-100, -90, 0, 90, 100]
+
+ l = np.array([-6574.4, -6351.2, -4798.8, -4575.6, -1049.4, -826.198, 826.198, 1049.4, 4575.6, 4798.8, 6351.2, 6574.4])+6574.4
+ print (l)
+
+ print("sym: ", CheckSymmetry(l))
+# print(np.mean(l))
+#
+ plt.plot(l, l, 'k*')
+ ol = SmoothMeshLines(l, 892.809033532)
+ print(ol)
+ print("sym: ", CheckSymmetry(ol))
+# ol = SmoothMeshLines(l, 800)
+# print(np.mean(ol))
+# print(ol)
+
+ plt.plot(ol, ol, 'r*')
+ plt.show() \ No newline at end of file
diff --git a/CSXCAD/python/CSXCAD/Utilities.pyx b/CSXCAD/python/CSXCAD/Utilities.pyx
new file mode 100644
index 0000000..768da21
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/Utilities.pyx
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+def CheckNyDir(ny):
+ """ CheckNyDir(ny)
+
+ Translate directions like 'x'/'y' or 'z' into 0/1 or 2.
+ Raise an assertion error otherwise.
+
+ :param ny: int or str
+ :returns: int -- direction as 0/1/2
+ """
+ if ny in [0, 1, 2]:
+ return ny
+ elif ny in ['x','y','z']:
+ return ['x','y','z'].index(ny)
+ elif ny in ['r','a','z']:
+ return ['r','a','z'].index(ny)
+ else:
+ raise Exception('CheckNyDir: invalid direction: "{}"'.format(ny))
+
+def GetMultiDirs(dirs):
+ assert type(dirs)==str, 'GetMultiDirs: dirs must be of type str'
+ dirs = ''.join(sorted(dirs))
+ if dirs == 'all' or dirs == 'xyz' or dirs == 'raz':
+ return [0, 1, 2]
+ elif dirs == 'x' or dirs == 'r':
+ return [0,]
+ elif dirs == 'y' or dirs == 'a':
+ return [1,]
+ elif dirs == 'z':
+ return [2,]
+ elif dirs == 'xy' or dirs == 'ra':
+ return [0, 1]
+ elif dirs == 'yz' or dirs == 'az':
+ return [1, 2]
+ elif dirs == 'xz' or dirs == 'rz':
+ return [0, 2]
diff --git a/CSXCAD/python/CSXCAD/__init__.py b/CSXCAD/python/CSXCAD/__init__.py
new file mode 100644
index 0000000..d8ca9cc
--- /dev/null
+++ b/CSXCAD/python/CSXCAD/__init__.py
@@ -0,0 +1,7 @@
+# -*- coding: utf-8 -*-
+#
+# Shortcut CSXCAD import
+
+from __future__ import absolute_import
+
+from CSXCAD.CSXCAD import ContinuousStructure
diff --git a/CSXCAD/python/README.md b/CSXCAD/python/README.md
new file mode 100644
index 0000000..dfea3ba
--- /dev/null
+++ b/CSXCAD/python/README.md
@@ -0,0 +1,14 @@
+# CSXCAD python interface
+
+## Install
+* Simple version:
+```python
+python setup.py install
+```
+
+* Extended options, e.g. for custom install path at */opt/openEMS*:
+```python
+python setup.py build_ext -I/opt/openEMS/include -L/opt/openEMS/lib -R/opt/openEMS/lib"
+pyhton setup.py install
+```
+**Note:** The install command may require root on Linux, or add --user to install to ~/.local
diff --git a/CSXCAD/python/doc/CSPrimitives.rst b/CSXCAD/python/doc/CSPrimitives.rst
new file mode 100644
index 0000000..0417de0
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives.rst
@@ -0,0 +1,26 @@
+.. _csprimitives:
+
+CSPrimitives
+============
+
+.. automodule:: CSXCAD.CSPrimitives
+
+**List of Primitives:**
+
+.. toctree::
+
+ CSPrimitives/CSPrimitives
+ CSPrimitives/CSPrimPoint
+ CSPrimitives/CSPrimBox
+ CSPrimitives/CSPrimCylinder
+ CSPrimitives/CSPrimCylindricalShell
+ CSPrimitives/CSPrimSphere
+ CSPrimitives/CSPrimSphericalShell
+ CSPrimitives/CSPrimPolygon
+ CSPrimitives/CSPrimLinPoly
+ CSPrimitives/CSPrimRotPoly
+ CSPrimitives/CSPrimCurve
+ CSPrimitives/CSPrimWire
+ CSPrimitives/CSPrimPolyhedron
+ CSPrimitives/CSPrimPolyhedronReader
+
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimBox.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimBox.rst
new file mode 100644
index 0000000..7122770
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimBox.rst
@@ -0,0 +1,7 @@
+.. _csprimbox:
+
+CSPrimBox
+---------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimBox
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimCurve.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimCurve.rst
new file mode 100644
index 0000000..8125780
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimCurve.rst
@@ -0,0 +1,7 @@
+.. _csprimcurve:
+
+CSPrimCurve
+-----------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimCurve
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimCylinder.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimCylinder.rst
new file mode 100644
index 0000000..57c312d
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimCylinder.rst
@@ -0,0 +1,7 @@
+.. _csprimcylinder:
+
+CSPrimCylinder
+--------------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimCylinder
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimCylindricalShell.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimCylindricalShell.rst
new file mode 100644
index 0000000..31630c4
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimCylindricalShell.rst
@@ -0,0 +1,7 @@
+.. _csprimcylindricalshell:
+
+CSPrimCylindricalShell
+----------------------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimCylindricalShell
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimLinPoly.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimLinPoly.rst
new file mode 100644
index 0000000..236a9a0
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimLinPoly.rst
@@ -0,0 +1,8 @@
+.. _csprimlinpoly:
+
+CSPrimLinPoly
+-------------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimLinPoly
+ :members:
+ :show-inheritance:
+
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimPoint.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimPoint.rst
new file mode 100644
index 0000000..ca3cbdc
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimPoint.rst
@@ -0,0 +1,7 @@
+.. _csprimpoint:
+
+CSPrimPoint
+-----------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimPoint
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimPolygon.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimPolygon.rst
new file mode 100644
index 0000000..ffeaf22
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimPolygon.rst
@@ -0,0 +1,8 @@
+.. _csprimpolygon:
+
+CSPrimPolygon
+-------------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimPolygon
+ :members:
+ :show-inheritance:
+
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimPolyhedron.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimPolyhedron.rst
new file mode 100644
index 0000000..b7d01c9
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimPolyhedron.rst
@@ -0,0 +1,8 @@
+.. _csprimpolyhedron:
+
+CSPrimPolyhedron
+----------------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimPolyhedron
+ :members:
+ :show-inheritance:
+
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimPolyhedronReader.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimPolyhedronReader.rst
new file mode 100644
index 0000000..ed10b4a
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimPolyhedronReader.rst
@@ -0,0 +1,8 @@
+.. _csprimpolyhedronreader:
+
+CSPrimPolyhedronReader
+----------------------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimPolyhedronReader
+ :members:
+ :show-inheritance:
+
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimRotPoly.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimRotPoly.rst
new file mode 100644
index 0000000..cf1ca34
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimRotPoly.rst
@@ -0,0 +1,8 @@
+.. _csprimrotpoly:
+
+CSPrimRotPoly
+-------------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimRotPoly
+ :members:
+ :show-inheritance:
+
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimSphere.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimSphere.rst
new file mode 100644
index 0000000..245447e
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimSphere.rst
@@ -0,0 +1,7 @@
+.. _csprimsphere:
+
+CSPrimSphere
+------------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimSphere
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimSphericalShell.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimSphericalShell.rst
new file mode 100644
index 0000000..5c86259
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimSphericalShell.rst
@@ -0,0 +1,7 @@
+.. _csprimsphericalshell:
+
+CSPrimSphericalShell
+--------------------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimSphericalShell
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimWire.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimWire.rst
new file mode 100644
index 0000000..b0e2c56
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimWire.rst
@@ -0,0 +1,8 @@
+.. _csprimwire:
+
+CSPrimWire
+----------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimWire
+ :members:
+ :show-inheritance:
+
diff --git a/CSXCAD/python/doc/CSPrimitives/CSPrimitives.rst b/CSXCAD/python/doc/CSPrimitives/CSPrimitives.rst
new file mode 100644
index 0000000..b2406df
--- /dev/null
+++ b/CSXCAD/python/doc/CSPrimitives/CSPrimitives.rst
@@ -0,0 +1,7 @@
+.. _csprimitives_base:
+
+CSPrimitives (Base Class)
+-------------------------
+.. autoclass:: CSXCAD.CSPrimitives.CSPrimitives
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSProperties.rst b/CSXCAD/python/doc/CSProperties.rst
new file mode 100644
index 0000000..57705f7
--- /dev/null
+++ b/CSXCAD/python/doc/CSProperties.rst
@@ -0,0 +1,19 @@
+.. _csproperties:
+
+CSProperties
+============
+
+.. automodule:: CSXCAD.CSProperties
+
+**List of Properties:**
+
+.. toctree::
+
+ CSProperties/CSProperties
+ CSProperties/CSPropMaterial
+ CSProperties/CSPropLumpedElement
+ CSProperties/CSPropMetal
+ CSProperties/CSPropConductingSheet
+ CSProperties/CSPropExcitation
+ CSProperties/CSPropProbeBox
+ CSProperties/CSPropDumpBox
diff --git a/CSXCAD/python/doc/CSProperties/CSPropConductingSheet.rst b/CSXCAD/python/doc/CSProperties/CSPropConductingSheet.rst
new file mode 100644
index 0000000..2d0995a
--- /dev/null
+++ b/CSXCAD/python/doc/CSProperties/CSPropConductingSheet.rst
@@ -0,0 +1,7 @@
+.. _cspropconductingsheet:
+
+CSPropConductingSheet
+---------------------
+.. autoclass:: CSXCAD.CSProperties.CSPropConductingSheet
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSProperties/CSPropDumpBox.rst b/CSXCAD/python/doc/CSProperties/CSPropDumpBox.rst
new file mode 100644
index 0000000..228dc96
--- /dev/null
+++ b/CSXCAD/python/doc/CSProperties/CSPropDumpBox.rst
@@ -0,0 +1,7 @@
+.. _cspropdumpbox:
+
+CSPropDumpBox
+-------------
+.. autoclass:: CSXCAD.CSProperties.CSPropDumpBox
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSProperties/CSPropExcitation.rst b/CSXCAD/python/doc/CSProperties/CSPropExcitation.rst
new file mode 100644
index 0000000..6c34e39
--- /dev/null
+++ b/CSXCAD/python/doc/CSProperties/CSPropExcitation.rst
@@ -0,0 +1,7 @@
+.. _cspropexcitation:
+
+CSPropExcitation
+----------------
+.. autoclass:: CSXCAD.CSProperties.CSPropExcitation
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSProperties/CSPropLumpedElement.rst b/CSXCAD/python/doc/CSProperties/CSPropLumpedElement.rst
new file mode 100644
index 0000000..2b40907
--- /dev/null
+++ b/CSXCAD/python/doc/CSProperties/CSPropLumpedElement.rst
@@ -0,0 +1,7 @@
+.. _csproplumpedelement:
+
+CSPropLumpedElement
+-------------------
+.. autoclass:: CSXCAD.CSProperties.CSPropLumpedElement
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSProperties/CSPropMaterial.rst b/CSXCAD/python/doc/CSProperties/CSPropMaterial.rst
new file mode 100644
index 0000000..f176dae
--- /dev/null
+++ b/CSXCAD/python/doc/CSProperties/CSPropMaterial.rst
@@ -0,0 +1,7 @@
+.. _cspropmaterial:
+
+CSPropMaterial
+--------------
+.. autoclass:: CSXCAD.CSProperties.CSPropMaterial
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSProperties/CSPropMetal.rst b/CSXCAD/python/doc/CSProperties/CSPropMetal.rst
new file mode 100644
index 0000000..32e934f
--- /dev/null
+++ b/CSXCAD/python/doc/CSProperties/CSPropMetal.rst
@@ -0,0 +1,7 @@
+.. _cspropmetal:
+
+CSPropMetal
+-----------
+.. autoclass:: CSXCAD.CSProperties.CSPropMetal
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSProperties/CSPropProbeBox.rst b/CSXCAD/python/doc/CSProperties/CSPropProbeBox.rst
new file mode 100644
index 0000000..aca9bbe
--- /dev/null
+++ b/CSXCAD/python/doc/CSProperties/CSPropProbeBox.rst
@@ -0,0 +1,7 @@
+.. _cspropprobebox:
+
+CSPropProbeBox
+--------------
+.. autoclass:: CSXCAD.CSProperties.CSPropProbeBox
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSProperties/CSProperties.rst b/CSXCAD/python/doc/CSProperties/CSProperties.rst
new file mode 100644
index 0000000..76b19fd
--- /dev/null
+++ b/CSXCAD/python/doc/CSProperties/CSProperties.rst
@@ -0,0 +1,7 @@
+.. _cspropertiesbase:
+
+CSProperties (Base Class)
+-------------------------
+.. autoclass:: CSXCAD.CSProperties.CSProperties
+ :members:
+ :show-inheritance:
diff --git a/CSXCAD/python/doc/CSRectGrid.rst b/CSXCAD/python/doc/CSRectGrid.rst
new file mode 100644
index 0000000..e83cee0
--- /dev/null
+++ b/CSXCAD/python/doc/CSRectGrid.rst
@@ -0,0 +1,8 @@
+.. _csrectgrid:
+
+CSRectGrid
+----------
+
+.. automodule:: CSXCAD.CSRectGrid
+ :members:
+ :undoc-members:
diff --git a/CSXCAD/python/doc/CSTransform.rst b/CSXCAD/python/doc/CSTransform.rst
new file mode 100644
index 0000000..1879b8a
--- /dev/null
+++ b/CSXCAD/python/doc/CSTransform.rst
@@ -0,0 +1,9 @@
+.. _cstransform:
+
+CSTransform
+------------
+
+.. automodule:: CSXCAD.CSTransform
+ :members:
+ :undoc-members:
+
diff --git a/CSXCAD/python/doc/CSXCAD.rst b/CSXCAD/python/doc/CSXCAD.rst
new file mode 100644
index 0000000..0fedd2b
--- /dev/null
+++ b/CSXCAD/python/doc/CSXCAD.rst
@@ -0,0 +1,8 @@
+.. _csxcad:
+
+CSXCAD
+------
+
+.. automodule:: CSXCAD
+ :members: ContinuousStructure
+ :undoc-members:
diff --git a/CSXCAD/python/doc/CSXCAD_API.rst b/CSXCAD/python/doc/CSXCAD_API.rst
new file mode 100644
index 0000000..fea360b
--- /dev/null
+++ b/CSXCAD/python/doc/CSXCAD_API.rst
@@ -0,0 +1,13 @@
+CSXCAD Python Interface
+=======================
+
+.. toctree::
+ :maxdepth: 2
+
+ CSXCAD
+ CSProperties
+ CSPrimitives
+ CSTransform
+ CSRectGrid
+ Mesh
+ Utilities
diff --git a/CSXCAD/python/doc/Makefile b/CSXCAD/python/doc/Makefile
new file mode 100644
index 0000000..4dcdb4b
--- /dev/null
+++ b/CSXCAD/python/doc/Makefile
@@ -0,0 +1,225 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+# the i18n builder cannot share the environment and doctrees with the others
+I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " applehelp to make an Apple Help Book"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " epub3 to make an epub3"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " texinfo to make Texinfo files"
+ @echo " info to make Texinfo files and run them through makeinfo"
+ @echo " gettext to make PO message catalogs"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " xml to make Docutils-native XML files"
+ @echo " pseudoxml to make pseudoxml-XML files for display purposes"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+ @echo " coverage to run coverage check of the documentation (if enabled)"
+ @echo " dummy to check syntax errors of document sources"
+
+.PHONY: clean
+clean:
+ rm -rf $(BUILDDIR)/*
+
+.PHONY: html
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+.PHONY: dirhtml
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+.PHONY: singlehtml
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+.PHONY: pickle
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+.PHONY: json
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+.PHONY: htmlhelp
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+.PHONY: qthelp
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/CSXCAD.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/CSXCAD.qhc"
+
+.PHONY: applehelp
+applehelp:
+ $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
+ @echo
+ @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
+ @echo "N.B. You won't be able to view it unless you put it in" \
+ "~/Library/Documentation/Help or install it in your application" \
+ "bundle."
+
+.PHONY: devhelp
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/CSXCAD"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/CSXCAD"
+ @echo "# devhelp"
+
+.PHONY: epub
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+.PHONY: epub3
+epub3:
+ $(SPHINXBUILD) -b epub3 $(ALLSPHINXOPTS) $(BUILDDIR)/epub3
+ @echo
+ @echo "Build finished. The epub3 file is in $(BUILDDIR)/epub3."
+
+.PHONY: latex
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+.PHONY: latexpdf
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: latexpdfja
+latexpdfja:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through platex and dvipdfmx..."
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+.PHONY: text
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+.PHONY: man
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+.PHONY: texinfo
+texinfo:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
+ @echo "Run \`make' in that directory to run these through makeinfo" \
+ "(use \`make info' here to do that automatically)."
+
+.PHONY: info
+info:
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
+ @echo "Running Texinfo files through makeinfo..."
+ make -C $(BUILDDIR)/texinfo info
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
+
+.PHONY: gettext
+gettext:
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
+ @echo
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
+
+.PHONY: changes
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+.PHONY: linkcheck
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+.PHONY: doctest
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
+
+.PHONY: coverage
+coverage:
+ $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
+ @echo "Testing of coverage in the sources finished, look at the " \
+ "results in $(BUILDDIR)/coverage/python.txt."
+
+.PHONY: xml
+xml:
+ $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
+ @echo
+ @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
+
+.PHONY: pseudoxml
+pseudoxml:
+ $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
+ @echo
+ @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
+
+.PHONY: dummy
+dummy:
+ $(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILDDIR)/dummy
+ @echo
+ @echo "Build finished. Dummy builder generates no files."
diff --git a/CSXCAD/python/doc/Mesh.rst b/CSXCAD/python/doc/Mesh.rst
new file mode 100644
index 0000000..13a9978
--- /dev/null
+++ b/CSXCAD/python/doc/Mesh.rst
@@ -0,0 +1,12 @@
+.. _mesh:
+
+Mesh
+====
+
+SmoothMeshLines
+---------------
+
+.. automodule:: CSXCAD.SmoothMeshLines
+ :members:
+ :undoc-members:
+
diff --git a/CSXCAD/python/doc/Utilities.rst b/CSXCAD/python/doc/Utilities.rst
new file mode 100644
index 0000000..d192e0e
--- /dev/null
+++ b/CSXCAD/python/doc/Utilities.rst
@@ -0,0 +1,8 @@
+.. _utilities:
+
+Utilities
+---------
+
+.. automodule:: CSXCAD.Utilities
+ :members:
+ :undoc-members:
diff --git a/CSXCAD/python/doc/about.rst b/CSXCAD/python/doc/about.rst
new file mode 100644
index 0000000..9d14464
--- /dev/null
+++ b/CSXCAD/python/doc/about.rst
@@ -0,0 +1,21 @@
+.. _about:
+
+About
+=====
+
+CSXCAD (Continuous Structure XML) is a C++ library to describe geometrical objects and their physical or non-physical properties.
+
+It supports a Matlab/Octave and Python interface for high-level interaction.
+
+License
+-------
+
+CSXCAD is licensed under the terms of the LGPLv3.
+
+Further information
+-------------------
+
+:Website: http://openems.de/index.php/CSXCAD
+:Forum: http://openems.de/forum/
+:Tutorials: http://openems.de/index.php/Tutorials
+
diff --git a/CSXCAD/python/doc/conf.py b/CSXCAD/python/doc/conf.py
new file mode 100644
index 0000000..2d64e69
--- /dev/null
+++ b/CSXCAD/python/doc/conf.py
@@ -0,0 +1,348 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# CSXCAD documentation build configuration file, created by
+# sphinx-quickstart on Sun Aug 28 22:27:13 2016.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+import os
+import sys
+import sphinx_rtd_theme
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.intersphinx',
+ 'sphinx.ext.todo',
+ 'sphinx.ext.mathjax',
+ 'numpydoc',
+ 'sphinx.ext.autosummary',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#
+# source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'CSXCAD'
+copyright = '2016, Thorsten Liebig'
+author = 'Thorsten Liebig'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.6'
+# The full version, including alpha/beta/rc tags.
+release = '0.6.1'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#
+# today = ''
+#
+# Else, today_fmt is used as the format for a strftime call.
+#
+# today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#
+# default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#
+# add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#
+# add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#
+# show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+# modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+# keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = True
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'sphinx_rtd_theme'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+# html_theme_path = []
+
+# The name for this set of Sphinx documents.
+# "<project> v<release> documentation" by default.
+#
+# html_title = 'CSXCAD v0.6.1'
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#
+# html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#
+# html_logo = None
+
+# The name of an image file (relative to this directory) to use as a favicon of
+# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#
+# html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#
+# html_extra_path = []
+
+# If not None, a 'Last updated on:' timestamp is inserted at every page
+# bottom, using the given strftime format.
+# The empty string is equivalent to '%b %d, %Y'.
+#
+# html_last_updated_fmt = None
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#
+# html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#
+# html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#
+# html_additional_pages = {}
+
+# If false, no module index is generated.
+#
+# html_domain_indices = True
+
+# If false, no index is generated.
+#
+# html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#
+# html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#
+# html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#
+# html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#
+# html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#
+# html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+# html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
+# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr', 'zh'
+#
+# html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# 'ja' uses this config value.
+# 'zh' user can custom change `jieba` dictionary path.
+#
+# html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+#
+# html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'CSXCADdoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+ # The paper size ('letterpaper' or 'a4paper').
+ #
+ # 'papersize': 'letterpaper',
+
+ # The font size ('10pt', '11pt' or '12pt').
+ #
+ # 'pointsize': '10pt',
+
+ # Additional stuff for the LaTeX preamble.
+ #
+ # 'preamble': '',
+
+ # Latex figure (float) alignment
+ #
+ # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'CSXCAD.tex', 'CSXCAD Documentation',
+ 'Thorsten Liebig', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#
+# latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#
+# latex_use_parts = False
+
+# If true, show page references after internal links.
+#
+# latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#
+# latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#
+# latex_appendices = []
+
+# It false, will not define \strong, \code, itleref, \crossref ... but only
+# \sphinxstrong, ..., \sphinxtitleref, ... To help avoid clash with user added
+# packages.
+#
+# latex_keep_old_macro_names = True
+
+# If false, no module index is generated.
+#
+# latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'csxcad', 'CSXCAD Documentation',
+ [author], 1)
+]
+
+# If true, show URL addresses after external links.
+#
+# man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'CSXCAD', 'CSXCAD Documentation',
+ author, 'CSXCAD', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#
+# texinfo_appendices = []
+
+# If false, no module index is generated.
+#
+# texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#
+# texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#
+# texinfo_no_detailmenu = False
+
+numpydoc_show_class_members = False
diff --git a/CSXCAD/python/doc/index.rst b/CSXCAD/python/doc/index.rst
new file mode 100644
index 0000000..2a76ecb
--- /dev/null
+++ b/CSXCAD/python/doc/index.rst
@@ -0,0 +1,25 @@
+.. CSXCAD documentation master file, created by
+ sphinx-quickstart on Sun Aug 28 22:27:13 2016.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to CSXCAD's documentation!
+==================================
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+ about
+ install
+ CSXCAD_API
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/CSXCAD/python/doc/install.rst b/CSXCAD/python/doc/install.rst
new file mode 100644
index 0000000..f3b57ca
--- /dev/null
+++ b/CSXCAD/python/doc/install.rst
@@ -0,0 +1,31 @@
+.. _install:
+
+Install
+=======
+
+Instructions how to install the CSXCAD python interface.
+
+Linux
+-----
+
+* Make sure CSXCAD was build and installed correctly
+
+* Simple version:
+
+.. code-block:: console
+
+ python setup.py install
+
+* Extended options, e.g. for custom install path at */opt*:
+
+.. code-block:: console
+
+ python setup.py build_ext -I/opt/include -L/opt/lib -R/opt/lib"
+ pyhton setup.py install
+
+**Note:** The install command may require root on Linux, or add ``--user`` to install to *~/.local*
+
+Windows
+-------
+
+The python interface for CSXCAD currently does not support MS Windows.
diff --git a/CSXCAD/python/setup.py b/CSXCAD/python/setup.py
new file mode 100644
index 0000000..07c1608
--- /dev/null
+++ b/CSXCAD/python/setup.py
@@ -0,0 +1,37 @@
+from distutils.core import setup
+from distutils.extension import Extension
+from Cython.Build import cythonize
+
+import os
+
+extensions = [
+ Extension("*", [os.path.join(os.path.dirname(__file__), "CSXCAD","*.pyx")],
+ language="c++", # generate C++ code
+ libraries = ['CSXCAD',]),
+]
+
+setup(
+ name="CSXCAD",
+ version = '0.6.2',
+ description = "Python interface for the CSXCAD library",
+ classifiers = [
+ 'Development Status :: 3 - Alpha',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: Information Technology',
+ 'Intended Audience :: Science/Research',
+ 'License :: OSI Approved :: GNU Lesser General Public License v3 or later (LGPLv3+)',
+ 'Programming Language :: Python',
+ 'Topic :: Scientific/Engineering',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ 'Operating System :: POSIX :: Linux',
+ 'Operating System :: Microsoft :: Windows',
+ ],
+ author = 'Thorsten Liebig',
+ author_email = 'Thorsten.Liebig@gmx.de',
+ maintainer = 'Thorsten Liebig',
+ maintainer_email = 'Thorsten.Liebig@gmx.de',
+ url = 'http://openEMS.de',
+ packages=["CSXCAD", ],
+ package_data={'CSXCAD': ['*.pxd']},
+ ext_modules = cythonize(extensions)
+ )
diff --git a/CSXCAD/python/tests/sphere.ply b/CSXCAD/python/tests/sphere.ply
new file mode 100644
index 0000000..1e03e01
--- /dev/null
+++ b/CSXCAD/python/tests/sphere.ply
Binary files differ
diff --git a/CSXCAD/python/tests/sphere.stl b/CSXCAD/python/tests/sphere.stl
new file mode 100644
index 0000000..2afa4fd
--- /dev/null
+++ b/CSXCAD/python/tests/sphere.stl
Binary files differ
diff --git a/CSXCAD/python/tests/test_CSPrimitives.py b/CSXCAD/python/tests/test_CSPrimitives.py
new file mode 100644
index 0000000..ed9fc85
--- /dev/null
+++ b/CSXCAD/python/tests/test_CSPrimitives.py
@@ -0,0 +1,302 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Sun Dec 13 14:49:46 2015
+
+@author: thorsten
+"""
+
+import numpy as np
+
+from CSXCAD import ParameterObjects
+from CSXCAD import CSProperties
+from CSXCAD import CSPrimitives
+
+import unittest
+
+class Test_CSPrimMethods(unittest.TestCase):
+ def setUp(self):
+ self.pset = ParameterObjects.ParameterSet()
+ self.metal = CSProperties.CSPropMetal(self.pset)
+
+ def test_general(self):
+ box = CSPrimitives.CSPrimBox(self.pset, self.metal)
+
+ self.assertEqual(box.GetType(), 1)
+ self.assertEqual(box.GetTypeName(), 'Box')
+ self.assertEqual(box.GetPriority(), 0)
+
+ box.SetPriority(10)
+ self.assertEqual(box.GetPriority(), 10)
+
+ box.SetPriority(-10)
+ self.assertEqual(box.GetPriority(), -10)
+
+ box.SetStart([0,0,0])
+ box.SetStop([1,2,3])
+ self.assertTrue(box.Update())
+
+ self.assertTrue( (box.GetBoundBox() == np.array([[0,0,0],[1,2,3]])).all())
+ self.assertTrue( (box.GetStart() == np.array([0,0,0])).all())
+ self.assertTrue( (box.GetStop() == np.array([1,2,3])).all())
+
+ self.assertEqual(box.GetDimension(), 3)
+ self.assertTrue(box.IsInside([0,0,0]))
+ self.assertTrue(box.IsInside([0.5,0.5,0.5]))
+ self.assertFalse(box.IsInside([-0.5,0.5,0.5]))
+
+ tr = box.GetTransform()
+ self.assertFalse(tr.HasTransform())
+
+ box.AddTransform('Translate', [0, 1, 0])
+ self.assertTrue(tr.HasTransform())
+
+ self.assertEqual(box.GetCoordinateSystem(), None)
+
+ box.SetCoordinateSystem(0)
+ self.assertEqual(box.GetCoordinateSystem(), 0)
+
+ def test_point(self):
+ coord = [0,0.1,0.2]
+ point = CSPrimitives.CSPrimPoint(self.pset, self.metal, coord=coord)
+ self.assertTrue( (point.GetCoord() == coord).all())
+
+ coord = np.array(coord)*2
+ point.SetCoord(coord)
+ self.assertTrue( (point.GetCoord() == coord).all())
+
+ def test_box(self):
+ box = CSPrimitives.CSPrimBox(self.pset, self.metal)
+ tr = box.GetTransform()
+ self.assertFalse(tr.HasTransform())
+
+
+ def test_cylinder(self):
+ # TEST Cylinder
+ cyl = CSPrimitives.CSPrimCylinder(self.pset, self.metal)
+ start = [1,2,3]
+ cyl.SetStart(start)
+ self.assertTrue( (cyl.GetStart()==start).all() )
+
+ stop = np.array([5,6,7])
+ cyl.SetStop(stop)
+ self.assertTrue( (cyl.GetStop()==stop).all() )
+
+ self.assertTrue( cyl.GetType()==5 )
+ self.assertTrue( cyl.GetTypeName()=='Cylinder' )
+
+ self.assertTrue( cyl.GetPriority()==0 )
+
+ cyl.SetRadius(5)
+ self.assertTrue( cyl.GetRadius()==5.0 )
+
+ def test_cylinder_shell(self):
+ # TEST Cylinder-Shell
+ cyl_shell = CSPrimitives.CSPrimCylindricalShell(self.pset, self.metal)
+ start = [1,2,3]
+ cyl_shell.SetStart(start)
+ self.assertTrue( (cyl_shell.GetStart()==start).all() )
+
+ stop = np.array([5,6,7])
+ cyl_shell.SetStop(stop)
+ self.assertTrue( (cyl_shell.GetStop()==stop).all() )
+
+ self.assertTrue( cyl_shell.GetType()==6 )
+ self.assertTrue( cyl_shell.GetTypeName()=='CylindricalShell' )
+
+ self.assertTrue( cyl_shell.GetPriority()==0 )
+
+ cyl_shell.SetRadius(5)
+ self.assertTrue( cyl_shell.GetRadius()==5.0 )
+
+ cyl_shell.SetShellWidth(1.5)
+ self.assertTrue( cyl_shell.GetShellWidth()==1.5 )
+
+ def test_sphere(self):
+ # TEST Sphere
+ sphere = CSPrimitives.CSPrimSphere(self.pset, self.metal)
+ center = np.array([1.1,2.2,3.3])
+ sphere.SetCenter(center)
+ self.assertTrue( (sphere.GetCenter()==center).all() )
+
+ self.assertTrue( sphere.GetType()==3 )
+ self.assertTrue( sphere.GetTypeName()=='Sphere' )
+
+ self.assertTrue( sphere.GetPriority()==0 )
+
+ sphere.SetRadius(5)
+ self.assertTrue( sphere.GetRadius()==5.0 )
+
+ def test_sphere_shell(self):
+ # TEST Sphere-Shell
+ sphere_shell = CSPrimitives.CSPrimSphericalShell(self.pset, self.metal)
+ center = np.array([1.1,2.2,3.3])
+ sphere_shell.SetCenter(center)
+ self.assertTrue( (sphere_shell.GetCenter()==center).all() )
+
+ self.assertTrue( sphere_shell.GetType()==4 )
+ self.assertTrue( sphere_shell.GetTypeName()=='SphericalShell' )
+
+ self.assertTrue( sphere_shell.GetPriority()==0 )
+
+ sphere_shell.SetRadius(5)
+ self.assertTrue( sphere_shell.GetRadius()==5.0 )
+
+ sphere_shell.SetShellWidth(1.5)
+ self.assertTrue( sphere_shell.GetShellWidth()==1.5 )
+
+ def test_polygon(self):
+ # Test polygon
+ poly = CSPrimitives.CSPrimPolygon(self.pset, self.metal)
+ x0 = np.array([0, 0, 1, 1])
+ x1 = np.array([0, 1, 1, 0])
+ poly.SetCoords(x0, x1)
+ o0, o1 = poly.GetCoords()
+ self.assertTrue( (o0==x0).all() )
+ self.assertTrue( (o1==x1).all() )
+
+ self.assertTrue( poly.GetQtyCoords()==4 )
+ self.assertTrue( poly.GetNormDir()==0 )
+ poly.SetNormDir('y')
+ self.assertTrue( poly.GetNormDir()==1 )
+ poly.SetNormDir(2)
+ self.assertTrue( poly.GetNormDir()==2 )
+
+ poly.SetElevation(0.123)
+ self.assertTrue( poly.GetElevation()==0.123 )
+
+ def test_lin_poly(self):
+ # Test Lin-Polygon
+ linpoly = CSPrimitives.CSPrimLinPoly(self.pset, self.metal)
+ x0 = np.array([0, 0, 1, 1])
+ x1 = np.array([0, 1, 1, 0])
+ linpoly.SetCoords(x0, x1)
+ o0, o1 = linpoly.GetCoords()
+ self.assertTrue( (o0==x0).all() )
+ self.assertTrue( (o1==x1).all() )
+
+ self.assertTrue( linpoly.GetQtyCoords()==4 )
+ self.assertTrue( linpoly.GetNormDir()==0 )
+ linpoly.SetNormDir('y')
+ self.assertTrue( linpoly.GetNormDir()==1 )
+ linpoly.SetNormDir(2)
+ self.assertTrue( linpoly.GetNormDir()==2 )
+
+ linpoly.SetElevation(0.123)
+ self.assertTrue( linpoly.GetElevation()==0.123 )
+
+ linpoly.SetLength(11.23)
+ self.assertTrue( linpoly.GetLength()==11.23 )
+
+ def test_rot_poly(self):
+ # Test Rot-Polygon
+ rotpoly = CSPrimitives.CSPrimRotPoly(self.pset, self.metal)
+ x0 = np.array([0, 0, 1, 1]) + 1.5
+ x1 = np.array([0, 1, 1, 0]) + 2.5
+ rotpoly.SetCoords(x0, x1)
+ o0, o1 = rotpoly.GetCoords()
+ self.assertTrue( (o0==x0).all() )
+ self.assertTrue( (o1==x1).all() )
+
+ self.assertTrue( rotpoly.GetQtyCoords()==4 )
+ self.assertTrue( rotpoly.GetNormDir()==0 )
+ rotpoly.SetNormDir('y')
+ self.assertTrue( rotpoly.GetNormDir()==1 )
+ rotpoly.SetNormDir(0)
+ self.assertTrue( rotpoly.GetNormDir()==0 )
+
+ rotpoly.SetRotAxisDir('z')
+ self.assertTrue( rotpoly.GetRotAxisDir()==2 )
+
+ rotpoly.SetAngle(0, 2*np.pi)
+ self.assertTrue( (rotpoly.GetAngle() == np.array([0, 2*np.pi])).all() )
+
+ def test_curve(self):
+ # Test Curve
+ x = np.array([0, 0, 1, 1]) + 1.5
+ y = np.array([0, 1, 1, 0]) + 2.5
+ z = np.array([0, 1, 3, 4])
+ curve = CSPrimitives.CSPrimCurve(self.pset, self.metal)#, points=[x,y,z])
+ curve.SetPoints(x, y, z)
+
+ self.assertTrue( (curve.GetPoint(0)==np.array([1.5,2.5,0])).all() )
+ self.assertTrue( curve.GetNumberOfPoints()==4 )
+
+ curve.AddPoint([10, 10, 10.5])
+ self.assertTrue( curve.GetNumberOfPoints()==5 )
+
+ curve.ClearPoints()
+ self.assertTrue( curve.GetNumberOfPoints()==0 )
+
+ def test_wire(self):
+ # Test Wire
+ wire = CSPrimitives.CSPrimWire(self.pset, self.metal)
+ x = np.array([0, 0, 1, 1]) - 1.5
+ y = np.array([0, 1, 1, 0]) - 2.5
+ z = np.array([0, 1, 3, 4])
+ wire.SetPoints(x, y, z)
+
+ self.assertTrue( (wire.GetPoint(0)==np.array([-1.5,-2.5,0])).all() )
+ self.assertTrue( wire.GetNumberOfPoints()==4 )
+
+ wire.AddPoint([10, -10, 10.5])
+ self.assertTrue( wire.GetNumberOfPoints()==5 )
+
+ wire.SetWireRadius(1.5)
+ self.assertTrue( wire.GetWireRadius()==1.5 )
+
+ # Test CSPrimPolyhedron
+ ph = CSPrimitives.CSPrimPolyhedron(self.pset, self.metal)
+ self.assertTrue( ph.GetNumVertices()==0 )
+ self.assertTrue( ph.GetNumFaces()==0 )
+
+ ph.AddVertex(0,0,0)
+ ph.AddVertex(0,1,0)
+ ph.AddVertex(1,0,0)
+ self.assertTrue( ph.GetNumVertices()==3 )
+ self.assertTrue( (ph.GetVertex(0)==np.array([0,0,0])).all() )
+
+ ph.AddFace([0,1,2])
+ self.assertTrue( ph.GetNumFaces()==1 )
+ self.assertTrue( (ph.GetFace(0)==np.array([0,1,2])).all() )
+
+ def test_polyhedron(self):
+ ## Test CSPrimPolyhedron
+ ph = CSPrimitives.CSPrimPolyhedron(self.pset, self.metal)
+
+ # create pyramid
+ x0 = 0
+ y0 = 0
+ z0 = 0
+ width = 50
+ height = 150
+ ph.AddVertex(x0 , y0 , z0) #0
+ ph.AddVertex(x0+width , y0 , z0) #1
+ ph.AddVertex(x0+width , y0+width , z0) #2
+ ph.AddVertex(x0 , y0+width , z0) #3
+ ph.AddVertex(x0+width/2, y0+width/2, z0+height) #4 (tip)
+
+ ph.AddFace([0,1,2])
+ ph.AddFace([0,2,3])
+ ph.AddFace([1,0,4])
+ ph.AddFace([0,3,4])
+ ph.AddFace([3,2,4])
+ ph.AddFace([2,1,4])
+
+ self.assertTrue((ph.GetFace(1)==np.array([0,2,3])).all())
+ self.assertEqual(ph.GetNumVertices(), 5)
+ self.assertEqual(ph.GetNumFaces() , 6)
+
+ ph.Update()
+ self.assertTrue (ph.IsInside([x0+width/4, y0+width/4, z0+height/2]))
+ self.assertFalse(ph.IsInside([x0 , y0 , z0+height/2]))
+
+ def test_polyhedron_reader(self):
+ ## Test CSPrimPolyhedronReader
+ phr = CSPrimitives.CSPrimPolyhedronReader(self.pset, self.metal)
+ phr.SetFilename('sphere.stl')
+ self.assertTrue( phr.ReadFile() )
+ self.assertEqual(phr.GetNumVertices(), 50)
+ self.assertEqual(phr.GetNumFaces(), 96)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/CSXCAD/python/tests/test_CSProperties.py b/CSXCAD/python/tests/test_CSProperties.py
new file mode 100644
index 0000000..4703796
--- /dev/null
+++ b/CSXCAD/python/tests/test_CSProperties.py
@@ -0,0 +1,140 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Thu Dec 10 21:47:29 2015
+
+@author: thorsten
+"""
+
+import numpy as np
+
+from CSXCAD import ParameterObjects
+from CSXCAD import CSProperties, CSPrimitives
+
+import unittest
+
+class Test_CSPrimMethods(unittest.TestCase):
+ def setUp(self):
+ self.pset = ParameterObjects.ParameterSet()
+
+ def test_add_primitives(self):
+ prop = CSProperties.CSPropMetal(self.pset)
+ box = prop.AddBox(start= [0,0,0] , stop=[1,1,1])
+
+ self.assertEqual( prop.GetQtyPrimitives(), 1)
+ self.assertEqual( id(prop.GetPrimitive(0)), id(box))
+
+ self.assertEqual( prop.GetPrimitive(0).GetType(), CSPrimitives.BOX)
+ self.assertEqual( len(prop.GetAllPrimitives()), 1)
+ self.assertEqual( prop.GetAllPrimitives(), [box,])
+
+ prim = prop.AddCylinder(start= [0,0,0] , stop=[1,1,1], radius=0.5)
+ self.assertEqual( prop.GetQtyPrimitives(), 2)
+ self.assertEqual( prop.GetPrimitive(1).GetType(), CSPrimitives.CYLINDER)
+
+ prim = prop.AddCylindricalShell(start= [0,0,0] , stop=[1,1,1], radius=0.5, shell_width=0.1)
+ self.assertEqual( prop.GetQtyPrimitives(), 3)
+ self.assertEqual( prop.GetPrimitive(2).GetType(), CSPrimitives.CYLINDRICALSHELL)
+
+ prim = prop.AddSphere(center=[1,1,1], radius=0.5)
+ self.assertEqual( prop.GetQtyPrimitives(), 4)
+ self.assertEqual( prop.GetPrimitive(3).GetType(), CSPrimitives.SPHERE)
+
+ prim = prop.AddSphericalShell(center=[1,1,1], radius=0.5, shell_width=0.1)
+ self.assertEqual( prop.GetQtyPrimitives(), 5)
+ self.assertEqual( prop.GetPrimitive(4).GetType(), CSPrimitives.SPHERICALSHELL)
+
+ self.assertEqual( len(prop.GetAllPrimitives()), 5)
+
+ def test_metal(self):
+ prop = CSProperties.CSPropMetal(self.pset)
+
+ self.assertEqual( prop.GetType(), CSProperties.METAL)
+ self.assertEqual( prop.GetTypeString(), 'Metal')
+
+ def test_material(self):
+ prop = CSProperties.CSPropMaterial(self.pset, epsilon = 5.0)
+
+ self.assertEqual( prop.GetType(), CSProperties.MATERIAL)
+ self.assertEqual( prop.GetTypeString(), 'Material')
+
+ self.assertEqual( prop.GetMaterialProperty('epsilon'), 5.0)
+ self.assertEqual( prop.GetMaterialProperty('mue'), 1.0)
+
+# print(CSX.GetQtyProperties())
+
+ prop.SetMaterialProperty(epsilon=[1.0, 2.0, 3.0], mue=2.0)
+ self.assertEqual( prop.GetMaterialProperty('epsilon'), 1.0)
+ self.assertEqual( prop.GetMaterialProperty('mue'), 2.0)
+
+ prop.SetMaterialWeight(epsilon=['sin(x)', 'y', 'z'], mue='cos(y)', density='z*z')
+ self.assertEqual( prop.GetMaterialWeight('epsilon'), 'sin(x)')
+ self.assertEqual( prop.GetMaterialWeight('mue'), 'cos(y)')
+ self.assertEqual( prop.GetMaterialWeight('density'), 'z*z')
+
+ prop.SetIsotropy(False)
+ self.assertFalse( prop.GetIsotropy(),False)
+ self.assertTrue( (prop.GetMaterialProperty('epsilon')==[1.0, 2.0, 3.0]).all())
+
+ def test_lumped_elem(self):
+ prop = CSProperties.CSPropLumpedElement(self.pset, R = 50, C=1e-12, caps=True, ny='x')
+
+ self.assertEqual( prop.GetType(), CSProperties.LUMPED_ELEMENT)
+ self.assertEqual( prop.GetTypeString(), 'LumpedElement')
+
+ self.assertEqual( prop.GetResistance(), 50)
+ prop.SetResistance(55.0)
+ prop.SetDirection('x')
+ self.assertEqual( prop.GetResistance(), 55)
+ self.assertEqual( prop.GetCapacity(), 1e-12)
+ self.assertTrue( prop.GetCaps())
+ prop.SetCaps(False)
+ self.assertFalse( prop.GetCaps())
+ self.assertEqual( prop.GetDirection(), 0)
+
+ def test_cond_sheet(self):
+ prop = CSProperties.CSPropConductingSheet(self.pset, conductivity=56e6, thickness=35e-6)
+
+ self.assertEqual( prop.GetType(), CSProperties.CONDUCTINGSHEET + CSProperties.METAL)
+ self.assertEqual( prop.GetTypeString(), 'ConductingSheet')
+
+ self.assertEqual( prop.GetConductivity(), 56e6)
+ self.assertEqual( prop.GetThickness(), 35e-6)
+
+ def test_excitation(self):
+ prop = CSProperties.CSPropExcitation(self.pset, exc_type=1, exc_val=[-1.0, 0, 1.0], delay=1e-9)
+
+ self.assertEqual( prop.GetType(), CSProperties.EXCITATION)
+ self.assertEqual( prop.GetTypeString(), 'Excitation')
+
+ self.assertEqual( prop.GetExcitType(), 1)
+ self.assertTrue( (prop.GetExcitation()==[-1.0, 0, 1.0]).all() )
+ self.assertEqual( prop.GetDelay(),1e-9)
+
+ prop.SetWeightFunction(['y','x','z'])
+ self.assertEqual(prop.GetWeightFunction(), ['y','x','z'])
+
+ def test_probe(self):
+ prop = CSProperties.CSPropProbeBox(self.pset, frequency=[1e9, 2.4e9])
+
+ self.assertEqual( prop.GetType(), CSProperties.PROBEBOX)
+ self.assertEqual( prop.GetTypeString(), 'ProbeBox')
+
+ self.assertEqual(prop.GetFrequencyCount(), 2)
+ prop.AddFrequency(5e9)
+ self.assertEqual(prop.GetFrequencyCount(), 3)
+ self.assertTrue((prop.GetFrequency() == [1e9, 2.4e9, 5e9]).all())
+
+ prop.ClearFrequency()
+ self.assertEqual(prop.GetFrequencyCount(), 0)
+
+ prop.SetFrequency(np.linspace(1e9,2e9,11))
+ self.assertEqual(prop.GetFrequencyCount(), 11)
+
+ def test_dump(self):
+ prop = CSProperties.CSPropDumpBox(self.pset)
+
+ self.assertEqual( prop.GetType(), CSProperties.DUMPBOX)
+ self.assertEqual( prop.GetTypeString(), 'DumpBox')
+
+if __name__ == '__main__':
+ unittest.main() \ No newline at end of file
diff --git a/CSXCAD/python/tests/test_CSRectGrid.py b/CSXCAD/python/tests/test_CSRectGrid.py
new file mode 100644
index 0000000..ddefb9a
--- /dev/null
+++ b/CSXCAD/python/tests/test_CSRectGrid.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Sat Dec 12 22:04:58 2015
+
+@author: thorsten
+"""
+
+import numpy as np
+
+from CSXCAD import CSRectGrid
+
+import unittest
+
+class Test_CSRectGrid(unittest.TestCase):
+ def test_rect_grid(self):
+
+ grid = CSRectGrid.CSRectGrid(CoordSystem=0)
+
+ self.assertEqual( grid.GetMeshType(), 0 )
+
+ grid.SetMeshType(1)
+ self.assertEqual( grid.GetMeshType(), 1 )
+
+ grid.SetLines('x', [0, 1, 2])
+ grid.SetLines('y', [-2,0, 1])
+ self.assertEqual( grid.GetQtyLines('y'), 3 )
+ grid.AddLine('y',4)
+ self.assertEqual( grid.GetQtyLines('y'), 4 )
+ grid.AddLine('y',[4, 2, 5])
+ self.assertEqual( grid.GetQtyLines('y'), 7 )
+ self.assertTrue( (grid.GetLines('y')==np.array([-2., 0., 1., 4., 4., 2., 5.])).all() ) # check unsorted lines
+ grid.Sort('y')
+ self.assertTrue( (grid.GetLines('y')==np.array([-2., 0., 1., 2., 4., 5.])).all() )
+ self.assertEqual( grid.GetQtyLines('y'), 6 )
+
+ grid.SetLines('z', [10, 11, 12])
+
+ self.assertEqual( grid.GetLine('y', 1), 0.0 )
+
+ self.assertEqual( grid.GetQtyLines('x'), 3 )
+
+ grid.SetDeltaUnit(1e-3)
+ self.assertEqual( grid.GetDeltaUnit(), 1e-3 )
+
+ self.assertTrue( grid.IsValid() )
+
+ # check grid snapping
+ self.assertEqual( grid.Snap2LineNumber('y', 1), (2,True) )
+ self.assertEqual( grid.Snap2LineNumber('y', 1.1), (2,True) )
+ self.assertEqual( grid.Snap2LineNumber('y', 1.5), (3,True) )
+ self.assertEqual( grid.Snap2LineNumber('y', 1.6), (3,True) )
+ self.assertEqual( grid.Snap2LineNumber('y', 5.0), (5,True) )
+ self.assertEqual( grid.Snap2LineNumber('y', 5.01), (5,False) )
+
+ self.assertEqual( grid.Snap2LineNumber('y', -2.0), (0,True) )
+ self.assertEqual( grid.Snap2LineNumber('y', -2.01), (0,False) )
+
+ self.assertTrue( (grid.GetSimArea() == np.array([[0, -2, 10],[2, 5, 12]])).all() )
+
+ grid.ClearLines('x')
+ self.assertEqual( grid.GetQtyLines('x'), 0 )
+ self.assertEqual( grid.GetQtyLines('y'), 6 )
+ self.assertEqual( grid.GetQtyLines('z'), 3 )
+
+ self.assertFalse( grid.IsValid() )
+
+ grid.Clear()
+ self.assertEqual( grid.GetQtyLines('y'), 0 )
+
+ self.assertFalse( grid.IsValid() )
+
+if __name__ == '__main__':
+ unittest.main() \ No newline at end of file
diff --git a/CSXCAD/python/tests/test_CSTransform.py b/CSXCAD/python/tests/test_CSTransform.py
new file mode 100644
index 0000000..d2a35dd
--- /dev/null
+++ b/CSXCAD/python/tests/test_CSTransform.py
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Sep 2 21:42:50 2016
+
+@author: thorsten
+"""
+
+from CSXCAD import CSTransform
+import numpy as np
+
+import unittest
+
+def compare_coords(c1, c2):
+ c1 = np.array(c1)
+ c2 = np.array(c2)
+ return np.sum(np.abs(c1-c2))<1e-6
+
+
+class Test_CSTransform(unittest.TestCase):
+ def setUp(self):
+ self.tr = CSTransform.CSTransform()
+
+ def test_basics(self):
+ identity = np.identity(4)
+
+ self.assertFalse( self.tr.HasTransform() )
+ self.assertTrue( (self.tr.GetMatrix()==identity).all() )
+
+ self.tr.Translate([1,2,1])
+ self.assertTrue( self.tr.HasTransform() )
+ self.assertFalse((self.tr.GetMatrix()==identity).all() )
+
+ self.tr.Reset()
+ self.assertFalse( self.tr.HasTransform() )
+ self.assertTrue( (self.tr.GetMatrix()==identity).all() )
+
+ def test_translate(self):
+ test_pnt = np.array([1,1,1])/np.sqrt(3)
+
+ self.tr.Translate([1,2,1])
+ translate = np.identity(4)
+ translate[:3,3] = [1,2,1]
+ self.assertTrue( (self.tr.GetMatrix()==translate).all() )
+
+ self.assertTrue( compare_coords(self.tr.Transform(test_pnt), [ 1.57735027, 2.57735027, 1.57735027]) )
+
+ def test_rotate(self):
+ self.tr.RotateAxis('x', 45)
+ self.assertTrue( compare_coords(self.tr.Transform([0,np.sqrt(2),0]), [0, 1, 1]) )
+
+ self.tr.Reset()
+ self.tr.RotateAxis('x', -45)
+ self.assertTrue( compare_coords(self.tr.Transform([0,np.sqrt(2),0]), [0, 1, -1]) )
+
+ self.tr.Reset()
+ self.tr.RotateAxis('z', -90)
+ self.assertTrue( compare_coords(self.tr.Transform([1,0,0]), [0, -1, 0]) )
+ self.tr.RotateOrigin([0,0,1], 90)
+ self.assertTrue( compare_coords(self.tr.Transform([1,0,0]), [1, 0, 0]) )
+
+ self.tr.Reset()
+ self.tr.RotateOrigin([0,1,1], 90)
+ self.assertTrue( compare_coords(self.tr.Transform([1,0,0]), [0, 1/np.sqrt(2), -1/np.sqrt(2)]) )
+
+ def test_scale(self):
+ self.tr.Scale(3)
+ self.assertTrue( compare_coords(self.tr.Transform([1,0,0]), [3, 0, 0]) )
+
+ self.tr.Reset()
+ self.tr.Scale([1,2,3])
+ self.assertTrue( compare_coords(self.tr.Transform([1,1,1]), [1, 2, 3]) )
+
+ def test_matrix(self):
+ self.tr.RotateOrigin([1,1,1], 90)
+ mat = self.tr.GetMatrix()
+ self.tr.Reset()
+ self.tr.SetMatrix(mat)
+ self.assertTrue( (self.tr.GetMatrix()==mat).all() )
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/CSXCAD/python/tests/test_CSXCAD.py b/CSXCAD/python/tests/test_CSXCAD.py
new file mode 100644
index 0000000..062eb6c
--- /dev/null
+++ b/CSXCAD/python/tests/test_CSXCAD.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Dec 4 16:24:49 2015
+
+@author: thorsten
+"""
+
+import numpy as np
+
+from CSXCAD.CSXCAD import ContinuousStructure
+from CSXCAD import CSProperties
+
+from CSXCAD.CSProperties import CSPropMetal
+from CSXCAD import CSPrimitives
+csx = ContinuousStructure()
+pset = csx.GetParameterSet()
+grid = csx.GetGrid()
+
+##### Test Metal Prop
+metal = CSPropMetal(pset)
+assert metal.GetQtyPrimitives() == 0
+assert metal.GetTypeString()=='Metal'
+
+metal.SetName('metal')
+assert metal.GetName()=='metal'
+
+
+print(csx.GetQtyPrimitives(0))
+metal.AddBox([0,0,0], [1,1,1])
+
+ans = csx.AddProperty(metal)
+
+print(csx.GetQtyPrimitives(CSProperties.ANY))
+print(csx.GetQtyPrimitives(CSProperties.METAL))
+metal2 = csx.AddMetal('test')
+assert metal2.GetName()=='test'
+
+##### Test Excitation Prop
+exc_val = np.array([0,1,0])
+exc = csx.AddExcitation('excite', 0, exc_val)
+assert exc.GetName()=='excite'
+assert exc.GetExcitType() == 0
+assert (exc.GetExcitation()==exc_val).all()
+
+csx.Write2XML('test_CSXCAD.xml')
+
+del metal
+
+print("all ok") \ No newline at end of file
diff --git a/CSXCAD/src/CSPrimCylinder.cpp b/CSXCAD/src/CSPrimCylinder.cpp
index fb16262..453a851 100644
--- a/CSXCAD/src/CSPrimCylinder.cpp
+++ b/CSXCAD/src/CSPrimCylinder.cpp
@@ -153,8 +153,8 @@ bool CSPrimCylinder::Update(std::string *ErrStr)
EC=psRadius.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
bOK=false;
std::stringstream stream;
diff --git a/CSXCAD/src/CSPrimCylindricalShell.cpp b/CSXCAD/src/CSPrimCylindricalShell.cpp
index 0ca1701..481055d 100644
--- a/CSXCAD/src/CSPrimCylindricalShell.cpp
+++ b/CSXCAD/src/CSPrimCylindricalShell.cpp
@@ -136,8 +136,8 @@ bool CSPrimCylindricalShell::Update(std::string *ErrStr)
bool bOK=CSPrimCylinder::Update(ErrStr);
EC=psShellWidth.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
bOK=false;
std::stringstream stream;
diff --git a/CSXCAD/src/CSPrimLinPoly.cpp b/CSXCAD/src/CSPrimLinPoly.cpp
index 5ca3201..b03b9a9 100644
--- a/CSXCAD/src/CSPrimLinPoly.cpp
+++ b/CSXCAD/src/CSPrimLinPoly.cpp
@@ -95,8 +95,8 @@ bool CSPrimLinPoly::Update(std::string *ErrStr)
bool bOK = CSPrimPolygon::Update(ErrStr);
EC=extrudeLength.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
bOK=false;
std::stringstream stream;
diff --git a/CSXCAD/src/CSPrimMultiBox.cpp b/CSXCAD/src/CSPrimMultiBox.cpp
index e5547f0..51f1a5f 100644
--- a/CSXCAD/src/CSPrimMultiBox.cpp
+++ b/CSXCAD/src/CSPrimMultiBox.cpp
@@ -211,7 +211,7 @@ bool CSPrimMultiBox::Update(std::string *ErrStr)
for (size_t i=0;i<vCoords.size();++i)
{
EC=vCoords.at(i)->Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
if ((EC!=0) && (ErrStr!=NULL))
{
bOK=false;
diff --git a/CSXCAD/src/CSPrimPolygon.cpp b/CSXCAD/src/CSPrimPolygon.cpp
index 733fb0a..523857c 100644
--- a/CSXCAD/src/CSPrimPolygon.cpp
+++ b/CSXCAD/src/CSPrimPolygon.cpp
@@ -214,8 +214,8 @@ bool CSPrimPolygon::Update(std::string *ErrStr)
for (size_t i=1;i<vCoords.size();++i)
{
EC=vCoords[i].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
bOK=false;
std::stringstream stream;
@@ -226,8 +226,8 @@ bool CSPrimPolygon::Update(std::string *ErrStr)
}
EC=Elevation.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
bOK=false;
std::stringstream stream;
diff --git a/CSXCAD/src/CSPrimPolyhedron.cpp b/CSXCAD/src/CSPrimPolyhedron.cpp
index 9583b7e..129d238 100644
--- a/CSXCAD/src/CSPrimPolyhedron.cpp
+++ b/CSXCAD/src/CSPrimPolyhedron.cpp
@@ -268,6 +268,7 @@ bool CSPrimPolyhedron::IsInside(const double* Coord, double /*tol*/)
bool CSPrimPolyhedron::Update(std::string *ErrStr)
{
+ BuildTree();
//update local bounding box
m_BoundBoxValid = GetBoundBox(m_BoundBox);
return CSPrimitives::Update(ErrStr);
diff --git a/CSXCAD/src/CSPrimRotPoly.cpp b/CSXCAD/src/CSPrimRotPoly.cpp
index 705b08e..1411277 100644
--- a/CSXCAD/src/CSPrimRotPoly.cpp
+++ b/CSXCAD/src/CSPrimRotPoly.cpp
@@ -110,8 +110,8 @@ bool CSPrimRotPoly::Update(std::string *ErrStr)
bool bOK = CSPrimPolygon::Update(ErrStr);
EC=StartStopAngle[0].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
bOK=false;
std::stringstream stream;
@@ -121,8 +121,8 @@ bool CSPrimRotPoly::Update(std::string *ErrStr)
}
EC=StartStopAngle[1].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
bOK=false;
std::stringstream stream;
diff --git a/CSXCAD/src/CSPrimSphere.cpp b/CSXCAD/src/CSPrimSphere.cpp
index a372fe3..3d20308 100644
--- a/CSXCAD/src/CSPrimSphere.cpp
+++ b/CSXCAD/src/CSPrimSphere.cpp
@@ -126,8 +126,8 @@ bool CSPrimSphere::Update(std::string *ErrStr)
m_Center.SetCoordinateSystem(m_PrimCoordSystem, m_MeshType);
EC=psRadius.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
bOK=false;
std::stringstream stream;
diff --git a/CSXCAD/src/CSPrimSphericalShell.cpp b/CSXCAD/src/CSPrimSphericalShell.cpp
index 73f2d82..cb71cbd 100644
--- a/CSXCAD/src/CSPrimSphericalShell.cpp
+++ b/CSXCAD/src/CSPrimSphericalShell.cpp
@@ -92,8 +92,8 @@ bool CSPrimSphericalShell::Update(std::string *ErrStr)
bool bOK=CSPrimSphere::Update(ErrStr);
EC=psShellWidth.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
bOK=false;
std::stringstream stream;
diff --git a/CSXCAD/src/CSPrimUserDefined.cpp b/CSXCAD/src/CSPrimUserDefined.cpp
index 2cd5219..746e77e 100644
--- a/CSXCAD/src/CSPrimUserDefined.cpp
+++ b/CSXCAD/src/CSPrimUserDefined.cpp
@@ -190,8 +190,8 @@ bool CSPrimUserDefined::Update(std::string *ErrStr)
for (int i=0;i<3;++i)
{
EC=dPosShift[i].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
bOK=false;
std::ostringstream oss;
diff --git a/CSXCAD/src/CSPrimWire.cpp b/CSXCAD/src/CSPrimWire.cpp
index a182400..776e62d 100644
--- a/CSXCAD/src/CSPrimWire.cpp
+++ b/CSXCAD/src/CSPrimWire.cpp
@@ -116,8 +116,8 @@ bool CSPrimWire::Update(std::string *ErrStr)
CSPrimCurve::Update(ErrStr);
EC=wireRadius.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
bOK=false;
std::stringstream stream;
diff --git a/CSXCAD/src/CSPropConductingSheet.cpp b/CSXCAD/src/CSPropConductingSheet.cpp
index adce7fd..1fc5a53 100644
--- a/CSXCAD/src/CSPropConductingSheet.cpp
+++ b/CSXCAD/src/CSPropConductingSheet.cpp
@@ -39,8 +39,8 @@ bool CSPropConductingSheet::Update(std::string *ErrStr)
{
int EC=Conductivity.Evaluate();
bool bOK=true;
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in ConductingSheet-Property Conductivity-Value";
@@ -49,8 +49,8 @@ bool CSPropConductingSheet::Update(std::string *ErrStr)
}
EC=Thickness.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in ConductingSheet-Property Thickness-Value";
diff --git a/CSXCAD/src/CSPropDebyeMaterial.cpp b/CSXCAD/src/CSPropDebyeMaterial.cpp
index f12c261..b1809be 100644
--- a/CSXCAD/src/CSPropDebyeMaterial.cpp
+++ b/CSXCAD/src/CSPropDebyeMaterial.cpp
@@ -99,8 +99,8 @@ bool CSPropDebyeMaterial::Update(std::string *ErrStr)
for (int n=0;n<3;++n)
{
EC=EpsDelta[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Debye Material-Property epsilon Delta frequency value (ID: " << uiID << "): ";
@@ -109,8 +109,8 @@ bool CSPropDebyeMaterial::Update(std::string *ErrStr)
}
EC=WeightEpsDelta[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Debye Material-Property epsilon Delta frequency weighting function (ID: " << uiID << "): ";
@@ -119,8 +119,8 @@ bool CSPropDebyeMaterial::Update(std::string *ErrStr)
}
EC=EpsRelaxTime[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Debye Material-Property epsilon relaxation time value (ID: " << uiID << "): ";
@@ -129,8 +129,8 @@ bool CSPropDebyeMaterial::Update(std::string *ErrStr)
}
EC=WeightEpsRelaxTime[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Debye Material-Property epsilon relaxation time weighting function (ID: " << uiID << "): ";
diff --git a/CSXCAD/src/CSPropDumpBox.cpp b/CSXCAD/src/CSPropDumpBox.cpp
index 6cccce6..a16f92e 100644
--- a/CSXCAD/src/CSPropDumpBox.cpp
+++ b/CSXCAD/src/CSPropDumpBox.cpp
@@ -44,6 +44,7 @@ void CSPropDumpBox::SetSubSampling(int ny, unsigned int val)
{
if ((ny<0) || (ny>2)) return;
if (val<1) return;
+ m_SubSampling=true;
SubSampling[ny] = val;
}
@@ -56,7 +57,6 @@ void CSPropDumpBox::SetSubSampling(unsigned int val[])
void CSPropDumpBox::SetSubSampling(const char* vals)
{
if (vals==NULL) return;
- m_SubSampling=true;
std::vector<int> values = SplitString2Int(std::string(vals),',');
for (int ny=0;ny<3 && ny<(int)values.size();++ny)
SetSubSampling(ny,values.at(ny));
@@ -72,6 +72,7 @@ void CSPropDumpBox::SetOptResolution(int ny, double val)
{
if ((ny<0) || (ny>2)) return;
if (val<0) return;
+ m_OptResolution=true;
OptResolution[ny] = val;
}
@@ -84,7 +85,6 @@ void CSPropDumpBox::SetOptResolution(double val[])
void CSPropDumpBox::SetOptResolution(const char* vals)
{
if (vals==NULL) return;
- m_OptResolution=true;
std::vector<double> values = SplitString2Double(std::string(vals),',');
if (values.size()==1) //allow one resolution for all directions
{
diff --git a/CSXCAD/src/CSPropExcitation.cpp b/CSXCAD/src/CSPropExcitation.cpp
index 8d498ad..4089567 100644
--- a/CSXCAD/src/CSPropExcitation.cpp
+++ b/CSXCAD/src/CSPropExcitation.cpp
@@ -171,8 +171,8 @@ bool CSPropExcitation::Update(std::string *ErrStr)
for (unsigned int i=0;i<3;++i)
{
EC=Excitation[i].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Excitation-Property Excitaion-Value (ID: " << uiID << "): ";
@@ -180,8 +180,8 @@ bool CSPropExcitation::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=PropagationDir[i].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Excitation-Property PropagationDir-Value (ID: " << uiID << "): ";
@@ -190,8 +190,8 @@ bool CSPropExcitation::Update(std::string *ErrStr)
}
}
EC=m_Frequency.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Excitation-Property Frequency-Value";
@@ -199,8 +199,8 @@ bool CSPropExcitation::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=Delay.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Excitation-Property Delay-Value";
diff --git a/CSXCAD/src/CSPropLorentzMaterial.cpp b/CSXCAD/src/CSPropLorentzMaterial.cpp
index 73cda4a..763da66 100644
--- a/CSXCAD/src/CSPropLorentzMaterial.cpp
+++ b/CSXCAD/src/CSPropLorentzMaterial.cpp
@@ -163,8 +163,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
for (int n=0;n<3;++n)
{
EC=EpsPlasma[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property epsilon plasma frequency value (ID: " << uiID << "): ";
@@ -172,8 +172,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=MuePlasma[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property mue plasma frequency value (ID: " << uiID << "): ";
@@ -182,8 +182,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
}
EC=WeightEpsPlasma[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property epsilon plasma frequency weighting function (ID: " << uiID << "): ";
@@ -191,8 +191,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=WeightMuePlasma[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property mue plasma frequency value weighting function (ID: " << uiID << "): ";
@@ -201,8 +201,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
}
EC=EpsLorPole[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property epsilon lorentz pole frequency value (ID: " << uiID << "): ";
@@ -210,8 +210,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=MueLorPole[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property mue lorentz pole frequency value (ID: " << uiID << "): ";
@@ -220,8 +220,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
}
EC=WeightEpsLorPole[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property epsilon lorentz pole frequency weighting function (ID: " << uiID << "): ";
@@ -229,8 +229,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=WeightMueLorPole[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property mue lorentz pole frequency value weighting function (ID: " << uiID << "): ";
@@ -239,8 +239,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
}
EC=EpsRelaxTime[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property epsilon relaxation time value (ID: " << uiID << "): ";
@@ -248,8 +248,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=MueRelaxTime[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property mue relaxation time value (ID: " << uiID << "): ";
@@ -258,8 +258,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
}
EC=WeightEpsRelaxTime[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property epsilon relaxation time weighting function (ID: " << uiID << "): ";
@@ -267,8 +267,8 @@ bool CSPropLorentzMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=WeightMueRelaxTime[o][n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Lorentz Material-Property mue relaxation time value weighting function (ID: " << uiID << "): ";
diff --git a/CSXCAD/src/CSPropLumpedElement.cpp b/CSXCAD/src/CSPropLumpedElement.cpp
index f4dc602..f21f610 100644
--- a/CSXCAD/src/CSPropLumpedElement.cpp
+++ b/CSXCAD/src/CSPropLumpedElement.cpp
@@ -37,8 +37,8 @@ bool CSPropLumpedElement::Update(std::string *ErrStr)
{
int EC=m_R.Evaluate();
bool bOK=true;
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in LumpedElement-Property Resistance-Value";
@@ -48,8 +48,8 @@ bool CSPropLumpedElement::Update(std::string *ErrStr)
}
EC=m_C.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in LumpedElement-Property Capacitor-Value";
@@ -59,8 +59,8 @@ bool CSPropLumpedElement::Update(std::string *ErrStr)
}
EC=m_L.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in LumpedElement-Property Inductance-Value";
diff --git a/CSXCAD/src/CSPropMaterial.cpp b/CSXCAD/src/CSPropMaterial.cpp
index 7fd2415..21fc2dd 100644
--- a/CSXCAD/src/CSPropMaterial.cpp
+++ b/CSXCAD/src/CSPropMaterial.cpp
@@ -128,8 +128,8 @@ bool CSPropMaterial::Update(std::string *ErrStr)
for (int n=0;n<3;++n)
{
EC=Epsilon[n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Material-Property Epsilon-Value (ID: " << uiID << "): ";
@@ -137,8 +137,8 @@ bool CSPropMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=Mue[n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Material-Property Mue-Value (ID: " << uiID << "): ";
@@ -146,8 +146,8 @@ bool CSPropMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=Kappa[n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Material-Property Kappa-Value (ID: " << uiID << "): ";
@@ -155,8 +155,8 @@ bool CSPropMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=Sigma[n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Material-Property Sigma-Value (ID: " << uiID << "): ";
@@ -164,8 +164,8 @@ bool CSPropMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=WeightEpsilon[n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Material-Property Epsilon-Value weighting function (ID: " << uiID << "): ";
@@ -173,8 +173,8 @@ bool CSPropMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=WeightMue[n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Material-Property Mue-Value weighting function (ID: " << uiID << "): ";
@@ -182,8 +182,8 @@ bool CSPropMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=WeightKappa[n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Material-Property Kappa-Value weighting function (ID: " << uiID << "): ";
@@ -191,8 +191,8 @@ bool CSPropMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=WeightSigma[n].Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Material-Property Sigma-Value weighting function (ID: " << uiID << "): ";
@@ -202,8 +202,8 @@ bool CSPropMaterial::Update(std::string *ErrStr)
}
EC=Density.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Material-Property Density-Value (ID: " << uiID << "): ";
@@ -211,8 +211,8 @@ bool CSPropMaterial::Update(std::string *ErrStr)
PSErrorCode2Msg(EC,ErrStr);
}
EC=WeightDensity.Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in Material-Property Density weighting function (ID: " << uiID << "): ";
diff --git a/CSXCAD/src/CSPropProbeBox.cpp b/CSXCAD/src/CSPropProbeBox.cpp
index b7c87da..c9234f1 100644
--- a/CSXCAD/src/CSPropProbeBox.cpp
+++ b/CSXCAD/src/CSPropProbeBox.cpp
@@ -50,6 +50,7 @@ bool CSPropProbeBox::Write2XML(TiXmlNode& root, bool parameterised, bool sparse)
prop->SetAttribute("NormDir",(int)uiNumber);
prop->SetAttribute("Type",ProbeType);
prop->SetAttribute("Weight",m_weight);
+ prop->SetAttribute("NormDir",m_NormDir);
prop->SetAttribute("StartTime",startTime);
prop->SetAttribute("StopTime" ,stopTime );
diff --git a/CSXCAD/src/CSProperties.cpp b/CSXCAD/src/CSProperties.cpp
index 605b0be..6da7bf2 100644
--- a/CSXCAD/src/CSProperties.cpp
+++ b/CSXCAD/src/CSProperties.cpp
@@ -164,10 +164,12 @@ void CSProperties::AddAttribute(std::string name, std::string value)
size_t CSProperties::GetQtyPrimitives() {return vPrimitives.size();}
CSPrimitives* CSProperties::GetPrimitive(size_t index) {if (index<vPrimitives.size()) return vPrimitives.at(index); else return NULL;}
void CSProperties::SetFillColor(RGBa color) {FillColor.R=color.R;FillColor.G=color.G;FillColor.B=color.B;FillColor.a=color.a;}
+void CSProperties::SetFillColor(unsigned char R, unsigned char G, unsigned char B, unsigned char a) {FillColor.R=R;FillColor.G=G;FillColor.B=B;FillColor.a=a;}
RGBa CSProperties::GetFillColor() {return FillColor;}
RGBa CSProperties::GetEdgeColor() {return EdgeColor;}
void CSProperties::SetEdgeColor(RGBa color) {EdgeColor.R=color.R;EdgeColor.G=color.G;EdgeColor.B=color.B;EdgeColor.a=color.a;}
+void CSProperties::SetEdgeColor(unsigned char R, unsigned char G, unsigned char B, unsigned char a) {EdgeColor.R=R;EdgeColor.G=G;EdgeColor.B=B;EdgeColor.a=a;}
bool CSProperties::GetVisibility() {return bVisisble;}
void CSProperties::SetVisibility(bool val) {bVisisble=val;}
diff --git a/CSXCAD/src/CSProperties.h b/CSXCAD/src/CSProperties.h
index d8757ee..58b0085 100644
--- a/CSXCAD/src/CSProperties.h
+++ b/CSXCAD/src/CSProperties.h
@@ -76,7 +76,7 @@ public:
//! Enumeration of all possible sub-types of this base-class
enum PropertyType
{
- ANY = 0xfff, UNKNOWN = 0x001, MATERIAL = 0x002, METAL = 0x004, EXCITATION = 0x008, PROBEBOX = 0x010, RESBOX = 0x020, DUMPBOX = 0x040, /* unused = 0x080, */
+ ANY = 0xffff, UNKNOWN = 0x001, MATERIAL = 0x002, METAL = 0x004, EXCITATION = 0x008, PROBEBOX = 0x010, RESBOX = 0x020, DUMPBOX = 0x040, /* unused = 0x080, */
DISPERSIVEMATERIAL = 0x100, LORENTZMATERIAL = 0x200, DEBYEMATERIAL = 0x400,
DISCRETE_MATERIAL = 0x1000, LUMPED_ELEMENT = 0x2000, CONDUCTINGSHEET = 0x4000
};
@@ -89,6 +89,8 @@ public:
//! Get Property Type as a string. (default is the xml element name)
virtual const std::string GetTypeString() const {return GetTypeXMLString();}
+ ParameterSet* GetParameterSet() {return clParaSet;}
+
//! Check if Property is a physical material. Current PropertyType: MATERIAL & METAL
bool GetMaterial() {return bMaterial;}
//!Get ID of this property. Used for primitive-->property mapping. \sa SetID
@@ -138,11 +140,13 @@ public:
//! Set a fill-color for this property. \sa GetFillColor
void SetFillColor(RGBa color);
+ void SetFillColor(unsigned char R, unsigned char G, unsigned char B, unsigned char a);
//! Get a fill-color for this property. \sa SetFillColor \return RGBa color object.
RGBa GetFillColor();
//! Set a edge-color for this property. \sa SetEdgeColor
void SetEdgeColor(RGBa color);
+ void SetEdgeColor(unsigned char R, unsigned char G, unsigned char B, unsigned char a);
//! Get a fill-color for this property. \sa GetEdgeColor \return RGBa color object.
RGBa GetEdgeColor();
diff --git a/CSXCAD/src/CSRectGrid.cpp b/CSXCAD/src/CSRectGrid.cpp
index 5b36dc2..3a8dcf7 100644
--- a/CSXCAD/src/CSRectGrid.cpp
+++ b/CSXCAD/src/CSRectGrid.cpp
@@ -255,6 +255,7 @@ bool CSRectGrid::Write2XML(TiXmlNode &root, bool sorted)
TiXmlElement grid("RectilinearGrid");
grid.SetDoubleAttribute("DeltaUnit",dDeltaUnit);
+ grid.SetAttribute("CoordSystem",(int)this->GetMeshType());
TiXmlElement XLines("XLines");
XLines.SetAttribute("Qty",(int)Lines[0].size());
diff --git a/CSXCAD/src/CSXCAD_Global.h b/CSXCAD/src/CSXCAD_Global.h
index 15f1b32..6589ae9 100644
--- a/CSXCAD/src/CSXCAD_Global.h
+++ b/CSXCAD/src/CSXCAD_Global.h
@@ -20,7 +20,7 @@
#define _CSXCAD_LIB_NAME_ "CSXCAD-Lib: Continuous Structure XML - CAD"
#define _CSXCAD_LIB_NAME_SHORT_ "CSXCAD"
-#define _CSXCAD_AUTHOR_ "Thorsten Liebig (2008-2012)"
+#define _CSXCAD_AUTHOR_ "Thorsten Liebig (2008-2016)"
#define _CSXCAD_AUTHOR_MAIL_ "Thorsten.Liebig@gmx.de"
#define _CSXCAD_VERSION_ GIT_VERSION
#define _CSXCAD_LICENSE_ "LGPL v3"
diff --git a/CSXCAD/src/ContinuousStructure.cpp b/CSXCAD/src/ContinuousStructure.cpp
index a0c17a1..2882b04 100644
--- a/CSXCAD/src/ContinuousStructure.cpp
+++ b/CSXCAD/src/ContinuousStructure.cpp
@@ -373,11 +373,11 @@ bool ContinuousStructure::isGeometryValid()
return true;
}
-double* ContinuousStructure::GetObjectArea()
+double* ContinuousStructure::GetObjectArea(CSProperties::PropertyType type)
{
CSPrimitives* prim=NULL;
bool AccBound;
- std::vector<CSPrimitives*> vPrimitives=GetAllPrimitives();
+ std::vector<CSPrimitives*> vPrimitives=GetAllPrimitives(type);
for (size_t i=0;i<vPrimitives.size();++i)
{
prim=vPrimitives.at(i);
@@ -631,6 +631,11 @@ const char* ContinuousStructure::ReadFromXML(const char* file)
return ReadFromXML(&doc);
}
+std::string ContinuousStructure::ReadFromXML(std::string file)
+{
+ return ReadFromXML(file.c_str());
+}
+
void ContinuousStructure::UpdateIDs()
{
for (size_t i=0;i<vProperties.size();++i)
diff --git a/CSXCAD/src/ContinuousStructure.h b/CSXCAD/src/ContinuousStructure.h
index aa986c5..6d2b25b 100644
--- a/CSXCAD/src/ContinuousStructure.h
+++ b/CSXCAD/src/ContinuousStructure.h
@@ -78,7 +78,7 @@ public:
//! Get a primitive by its unique ID.
CSPrimitives* GetPrimitiveByID(unsigned int ID);
- //! Get all primitives with the given name
+ //! Get all properties with the given name
std::vector<CSProperties*> GetPropertiesByName(std::string name);
//! Get a property by its internal index number. \sa GetQtyProperties
@@ -135,7 +135,6 @@ public:
//! Get a primitives array of a certian type
std::vector<CSPrimitives*> GetPrimitivesByType(CSPrimitives::PrimitiveType type);
-
//! Get a primitives array inside a bounding box and with a certian property type (default is any)
std::vector<CSPrimitives*> GetPrimitivesByBoundBox(const double* boundbox, bool sorted=false, CSProperties::PropertyType type=CSProperties::ANY);
@@ -160,7 +159,7 @@ public:
std::string Update();
//! Get an array containing the absolute size of the current structure.
- double* GetObjectArea();
+ double* GetObjectArea(CSProperties::PropertyType type=CSProperties::ANY);
//! Delete and clear all objects includes. This will result in an empty structure.
void clear();
@@ -185,7 +184,9 @@ public:
\param file Filename to read this structure from.
*/
const char* ReadFromXML(const char* file);
- //! Read a structure from a given XML-node.
+ std::string ReadFromXML(std::string file);
+
+ //! Read a structure from a given XML-node.
/*!
\return Will return a string with possible error-messages!
\param rootNode XML-node to read this structure from.
diff --git a/CSXCAD/src/ParameterCoord.cpp b/CSXCAD/src/ParameterCoord.cpp
index 62da688..a79b1dc 100644
--- a/CSXCAD/src/ParameterCoord.cpp
+++ b/CSXCAD/src/ParameterCoord.cpp
@@ -210,8 +210,8 @@ bool ParameterCoord::Evaluate(std::string *ErrStr)
for (int i=0;i<3;++i)
{
EC=m_Coords[i]->Evaluate();
- if (EC!=ParameterScalar::NO_ERROR) bOK=false;
- if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL))
+ if (EC!=ParameterScalar::PS_NO_ERROR) bOK=false;
+ if ((EC!=ParameterScalar::PS_NO_ERROR) && (ErrStr!=NULL))
{
std::stringstream stream;
stream << std::endl << "Error in ParameterCoord (component: " << i << "): ";
diff --git a/CSXCAD/src/ParameterObjects.h b/CSXCAD/src/ParameterObjects.h
index 9e9da49..383999f 100644
--- a/CSXCAD/src/ParameterObjects.h
+++ b/CSXCAD/src/ParameterObjects.h
@@ -15,8 +15,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef _PARAMETEROBJECTS_H_
-#define _PARAMETEROBJECTS_H_
+#pragma once
+
/*
* Author: Thorsten Liebig
* Date: 03-12-2008
@@ -210,10 +210,10 @@ std::string PSErrorCode2Msg(int code);
class CSXCAD_EXPORT ParameterScalar
{
public:
- enum EvaluateErrorType
- {
- NO_ERROR
- };
+ enum EvaluateErrorType
+ {
+ PS_NO_ERROR
+ };
ParameterScalar();
ParameterScalar(ParameterSet* ParaSet, double value);
ParameterScalar(ParameterSet* ParaSet, const std::string value);
@@ -247,5 +247,3 @@ protected:
std::string sValue;
double dValue;
};
-
-#endif
diff --git a/QCSXCAD/CMakeLists.txt b/QCSXCAD/CMakeLists.txt
index 73b96a6..c0952a2 100644
--- a/QCSXCAD/CMakeLists.txt
+++ b/QCSXCAD/CMakeLists.txt
@@ -95,15 +95,7 @@ find_package(TinyXML REQUIRED)
ADD_DEFINITIONS( -DTIXML_USE_STL )
# vtk
-if (WIN32)
- find_package(VTK 6.1 REQUIRED)
-else()
- # prefer >=6.1, fallback to >=5.4
- find_package(VTK 6.1 COMPONENTS vtkGUISupportQt vtkRenderingLOD vtkRenderingOpenGL vtkIOXML vtkIOPLY vtkIOImage vtkInteractionWidgets NO_MODULE)
- IF (NOT ${VTK_FOUND})
- find_package(VTK REQUIRED)
- endif()
-endif()
+find_package(VTK REQUIRED)
message(STATUS "Found package VTK. Using version " ${VTK_VERSION})
include(${VTK_USE_FILE})
diff --git a/QCSXCAD/QVTKStructure.cpp b/QCSXCAD/QVTKStructure.cpp
index 8eea1e8..3239dea 100644
--- a/QCSXCAD/QVTKStructure.cpp
+++ b/QCSXCAD/QVTKStructure.cpp
@@ -19,7 +19,14 @@
#include "QVTKStructure.h"
-#include "QVTKWidget.h"
+#include "vtkCommand.h"
+#if VTK_MAJOR_VERSION>=8
+ #include "QVTKOpenGLWidget.h"
+ #include "vtkGenericOpenGLRenderWindow.h"
+#else
+ #include "QVTKWidget.h"
+
+#endif
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
@@ -50,7 +57,6 @@
#include "vtkDoubleArray.h"
#include "vtkActorCollection.h"
#include "vtkInteractorStyle.h"
-#include "vtkCommand.h"
#include "vtkCallbackCommand.h"
#include "vtkWindowToImageFilter.h"
#include "vtkPNGWriter.h"
@@ -93,7 +99,12 @@ QVTKStructure::QVTKStructure()
iResolution=32;
AllowUpdate=true;
+#if VTK_MAJOR_VERSION>=8
+ VTKWidget = new QVTKOpenGLWidget();
+ VTKWidget->SetRenderWindow(vtkGenericOpenGLRenderWindow::New());
+#else
VTKWidget= new QVTKWidget();
+#endif
ren = vtkRenderer::New();
VTKWidget->GetRenderWindow()->AddRenderer(ren);
diff --git a/QCSXCAD/QVTKStructure.h b/QCSXCAD/QVTKStructure.h
index 2809e8a..6719711 100644
--- a/QCSXCAD/QVTKStructure.h
+++ b/QCSXCAD/QVTKStructure.h
@@ -20,7 +20,12 @@
#include <QtGui>
-class QVTKWidget;
+#include "vtkCommand.h"
+#if VTK_MAJOR_VERSION>=8
+ class QVTKOpenGLWidget;
+#else
+ class QVTKWidget;
+#endif
class vtkRenderWindow;
class vtkRenderWindowInteractor;
class vtkRenderer;
@@ -95,7 +100,11 @@ protected:
unsigned int uID;
} VTKLayerStruct;
+#if VTK_MAJOR_VERSION>=8
+ QVTKOpenGLWidget *VTKWidget;
+#else
QVTKWidget *VTKWidget;
+#endif
//set to false if this widget is hidden
bool AllowUpdate;
diff --git a/debian/changelog b/debian/changelog
index f607a24..a4308ce 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,6 +1,75 @@
+openems (0.0.35+git20190103.6a75e98+dfsg.1-1) unstable; urgency=medium
+
+ * Upload to unstable
+
+ [ Gilles Filippini ]
+ * Fix FTBFS against HDF5 1.10.5 (Closes: #931539)
+
+ [ Ruben Undheim ]
+ * debian/control:
+ - New standards version 4.4.1 - no changes
+ - DH level 12
+ - Use debhelper-compat
+ * Drop Python 2 package
+
+ -- Ruben Undheim <ruben.undheim@gmail.com> Sat, 19 Oct 2019 19:20:44 +0200
+
+openems (0.0.35+dfsg.1-4) unstable; urgency=medium
+
+ * Team upload.
+ * Fix building against Octave 5
+
+ -- Sébastien Villemot <sebastien@debian.org> Mon, 07 Oct 2019 14:02:23 +0200
+
+openems (0.0.35+git20190103.6a75e98+dfsg.1-1~exp2) experimental; urgency=medium
+
+ * d/patches/0007-Fix-some-imports-to-make-python-interface-work.patch:
+ - Use 'from __future__ import absolute_import' instead to fix import in
+ Python2 package
+ * debian/control:
+ - Add missing install dependencies python3-matplotlib and
+ python-matplotlib.
+ * debian/gitlab-ci.yml:
+ - Enable continuous integration on salsa
+
+ -- Ruben Undheim <ruben.undheim@gmail.com> Thu, 21 Feb 2019 23:19:00 +0100
+
+openems (0.0.35+git20190103.6a75e98+dfsg.1-1~exp1) experimental; urgency=low
+
+ * New upstream GIT HEAD with Python interface support
+ - Refreshed patches
+ * debian/control:
+ - New standards version 4.3.0 - no changes
+ - New binary package: python-openems
+ - New binary package: python3-openems
+ - Depend on libvtk7-qt-dev instead of libvtk6-qt-dev
+ - More build-dependencies for Python interface:
+ - cython, cython3, dh-python, python-all, python3-all
+ * debian/libopenems.install:
+ - Install more header files
+ * Added debian/python-openems.install
+ * Added debian/python3-openems.install
+ * d/patches/0007-Fix-some-imports-to-make-python-interface-work.patch:
+ - Fix import for Python 2
+
+ -- Ruben Undheim <ruben.undheim@gmail.com> Sun, 10 Feb 2019 09:14:26 +0000
+
+openems (0.0.35+dfsg.1-3) unstable; urgency=medium
+
+ * debian/changelog:
+ - Fix typo
+ * debian/control:
+ - Do not build-depend on g++-7 anymore
+ * debian/rules:
+ - Now build with default g++ version
+ * debian/tests/octave-load:
+ - Handle case when run in a non-X11 environment
+
+ -- Ruben Undheim <ruben.undheim@gmail.com> Tue, 27 Nov 2018 18:59:05 +0100
+
openems (0.0.35+dfsg.1-2) unstable; urgency=medium
- * debian/patches0007-Guard-xmmintrin.h-include-so-it-is-only-used-when-ne.patch
+ * d/patches/0007-Guard-xmmintrin.h-include-so-it-is-only-used-when-ne.patch
- Cherry-pick fix from upstream: a5a1dca8324aa12dfbf8e268fbc06c2310b91c69
* debian/rules: Set -DSSE_CORRECT_DENORMALS=0
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index b4de394..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-11
diff --git a/debian/control b/debian/control
index 8b87ea3..4cf7148 100644
--- a/debian/control
+++ b/debian/control
@@ -3,22 +3,24 @@ Maintainer: Debian Science Maintainers <debian-science-maintainers@lists.alioth.
Uploaders: Ruben Undheim <ruben.undheim@gmail.com>
Section: electronics
Priority: optional
-Build-Depends: debhelper (>= 11),
+Build-Depends: debhelper-compat (= 12),
cmake,
libhdf5-dev,
libboost-all-dev,
libcgal-dev,
libcgal-qt5-dev,
libtinyxml-dev,
- libvtk6-qt-dev,
+ libvtk7-qt-dev,
libfparser-dev,
# It is called octave-pkg-dev in stretch
# and dh-octave in sid
dh-octave | octave-pkg-dev,
+ cython3,
chrpath,
- txt2man,
- g++-7
-Standards-Version: 4.2.1
+ dh-python,
+ python3-all,
+ txt2man
+Standards-Version: 4.4.1
Vcs-Browser: https://salsa.debian.org/science-team/openems
Vcs-Git: https://salsa.debian.org/science-team/openems.git
Homepage: http://openems.de
@@ -118,7 +120,7 @@ Package: octave-openems
Architecture: any
Depends: ${shlibs:Depends},
${misc:Depends},
- openems,
+ openems (= ${binary:Version}),
octave,
epstool,
transfig
@@ -129,3 +131,20 @@ Description: Octave interface for openems
.
openEMS is a simulator for electromagnetic problems using
the FDTD algorithm.
+
+Package: python3-openems
+Architecture: any
+Section: python
+Depends: ${shlibs:Depends},
+ ${misc:Depends},
+ ${python3:Depends},
+ openems (= ${binary:Version}),
+ python3,
+ python3-h5py,
+ python3-matplotlib
+Description: Python3 interface for openems
+ This package contains the Python-files needed for
+ openEMS (Python 3).
+ .
+ openEMS is a simulator for electromagnetic problems using
+ the FDTD algorithm.
diff --git a/debian/gitlab-ci.yml b/debian/gitlab-ci.yml
new file mode 100644
index 0000000..d9acd28
--- /dev/null
+++ b/debian/gitlab-ci.yml
@@ -0,0 +1,9 @@
+image: registry.salsa.debian.org/salsa-ci-team/ci-image-git-buildpackage:latest
+
+build:
+ artifacts:
+ paths:
+ - "*.deb"
+ expire_in: 1 day
+ script:
+ - gitlab-ci-git-buildpackage-all
diff --git a/debian/libopenems-dev.install b/debian/libopenems-dev.install
index 40ec33a..5da2d14 100644
--- a/debian/libopenems-dev.install
+++ b/debian/libopenems-dev.install
@@ -4,3 +4,4 @@ usr/lib/*/libope*.so
usr/lib/*/libnf*.so
usr/include/CSXCAD
usr/include/QCSXCAD
+usr/include/openEMS
diff --git a/debian/patches/0002-Spelling-fixes.patch b/debian/patches/0002-Spelling-fixes.patch
index 8ae0682..7604059 100644
--- a/debian/patches/0002-Spelling-fixes.patch
+++ b/debian/patches/0002-Spelling-fixes.patch
@@ -20,7 +20,7 @@ Subject: Spelling fixes
14 files changed, 36 insertions(+), 36 deletions(-)
diff --git a/CSXCAD/src/CSPrimPolyhedron.cpp b/CSXCAD/src/CSPrimPolyhedron.cpp
-index 7eac505..9583b7e 100644
+index 2454f28..129d238 100644
--- a/CSXCAD/src/CSPrimPolyhedron.cpp
+++ b/CSXCAD/src/CSPrimPolyhedron.cpp
@@ -183,11 +183,11 @@ bool CSPrimPolyhedron::BuildTree()
@@ -51,7 +51,7 @@ index ed224fd..c88c67e 100644
}
return CSPrimitives::Write2XML(elem,parameterised);
diff --git a/CSXCAD/src/CSRectGrid.cpp b/CSXCAD/src/CSRectGrid.cpp
-index 50f2947..5b36dc2 100644
+index 4f90bfe..3a8dcf7 100644
--- a/CSXCAD/src/CSRectGrid.cpp
+++ b/CSXCAD/src/CSRectGrid.cpp
@@ -78,7 +78,7 @@ std::string CSRectGrid::AddDiscLines(int direct, int numLines, double* vals, std
@@ -126,10 +126,10 @@ index 4cd4a74..b9ef094 100644
break;
}
diff --git a/QCSXCAD/QVTKStructure.cpp b/QCSXCAD/QVTKStructure.cpp
-index 9482dde..8eea1e8 100644
+index 7394bd9..3239dea 100644
--- a/QCSXCAD/QVTKStructure.cpp
+++ b/QCSXCAD/QVTKStructure.cpp
-@@ -295,7 +295,7 @@ void QVTKStructure::RenderGridDir(int dir, unsigned int plane_pos)
+@@ -306,7 +306,7 @@ void QVTKStructure::RenderGridDir(int dir, unsigned int plane_pos)
uiQty[n]=CSGrid->GetQtyLines(n);
if ((int)plane_pos>=uiQty[dir])
{
@@ -139,7 +139,7 @@ index 9482dde..8eea1e8 100644
}
diff --git a/openEMS/Common/processmodematch.cpp b/openEMS/Common/processmodematch.cpp
-index 620257d..7cd22f8 100644
+index 85d2d58..851912d 100644
--- a/openEMS/Common/processmodematch.cpp
+++ b/openEMS/Common/processmodematch.cpp
@@ -123,7 +123,7 @@ void ProcessModeMatch::InitProcess()
@@ -165,7 +165,7 @@ index fc46d85..d64c21c 100644
return false;
}
diff --git a/openEMS/FDTD/operator.cpp b/openEMS/FDTD/operator.cpp
-index a7582aa..2dec2d3 100644
+index 259b1fb..54d4aad 100644
--- a/openEMS/FDTD/operator.cpp
+++ b/openEMS/FDTD/operator.cpp
@@ -450,7 +450,7 @@ Grid_Path Operator::FindPath(double start[], double stop[])
@@ -179,7 +179,7 @@ index a7582aa..2dec2d3 100644
{
@@ -1397,7 +1397,7 @@ bool Operator::AverageMatCellCenter(int ny, const unsigned int* pos, double* Eff
for (int n=0; n<4; ++n)
- if (isnan(EffMat[n]) || isinf(EffMat[n]))
+ if (std::isnan(EffMat[n]) || std::isinf(EffMat[n]))
{
- cerr << "Operator::" << __func__ << ": Error, an effective material parameter is not a valid result, this should NOT have happend... exit..." << endl;
+ cerr << "Operator::" << __func__ << ": Error, an effective material parameter is not a valid result, this should NOT have happened... exit..." << endl;
@@ -188,7 +188,7 @@ index a7582aa..2dec2d3 100644
}
@@ -1510,7 +1510,7 @@ bool Operator::AverageMatQuarterCell(int ny, const unsigned int* pos, double* Ef
for (int n=0; n<4; ++n)
- if (isnan(EffMat[n]) || isinf(EffMat[n]))
+ if (std::isnan(EffMat[n]) || std::isinf(EffMat[n]))
{
- cerr << "Operator::" << __func__ << ": Error, An effective material parameter is not a valid result, this should NOT have happend... exit..." << endl;
+ cerr << "Operator::" << __func__ << ": Error, An effective material parameter is not a valid result, this should NOT have happened... exit..." << endl;
diff --git a/debian/patches/0003-More-things-to-fix-build.patch b/debian/patches/0003-More-things-to-fix-build.patch
index bf38fc7..cb407be 100644
--- a/debian/patches/0003-More-things-to-fix-build.patch
+++ b/debian/patches/0003-More-things-to-fix-build.patch
@@ -8,10 +8,10 @@ Subject: More things to fix build
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/CSXCAD/CMakeLists.txt b/CSXCAD/CMakeLists.txt
-index 9d516d5..d7670c1 100644
+index a2b0448..840f17d 100644
--- a/CSXCAD/CMakeLists.txt
+++ b/CSXCAD/CMakeLists.txt
-@@ -90,9 +90,9 @@ INCLUDE_DIRECTORIES( ${fparser_INCLUDE_DIR} )
+@@ -92,9 +92,9 @@ INCLUDE_DIRECTORIES( ${fparser_INCLUDE_DIR} )
find_package(TinyXML REQUIRED)
ADD_DEFINITIONS( -DTIXML_USE_STL )
@@ -24,7 +24,7 @@ index 9d516d5..d7670c1 100644
ADD_DEFINITIONS( -DH5_USE_16_API )
diff --git a/openEMS/CMakeLists.txt b/openEMS/CMakeLists.txt
-index 898f280..5504590 100644
+index 3325abb..e0a143a 100644
--- a/openEMS/CMakeLists.txt
+++ b/openEMS/CMakeLists.txt
@@ -108,7 +108,7 @@ find_package(TinyXML REQUIRED)
diff --git a/debian/patches/0004-link-more.patch b/debian/patches/0004-link-more.patch
index 2c95033..8035abf 100644
--- a/debian/patches/0004-link-more.patch
+++ b/debian/patches/0004-link-more.patch
@@ -8,22 +8,22 @@ Subject: link more
2 files changed, 2 insertions(+)
diff --git a/AppCSXCAD/CMakeLists.txt b/AppCSXCAD/CMakeLists.txt
-index d5a72c9..2d4b11b 100644
+index 3e235d1..09bba11 100644
--- a/AppCSXCAD/CMakeLists.txt
+++ b/AppCSXCAD/CMakeLists.txt
-@@ -157,6 +157,7 @@ TARGET_LINK_LIBRARIES( AppCSXCAD
+@@ -140,6 +140,7 @@ TARGET_LINK_LIBRARIES( AppCSXCAD
${HDF5_HL_LIBRARIES}
- ${QT_LIBRARIES}
- ${vtk_LIBS}
+ Qt5::Core Qt5::Widgets Qt5::Xml
+ ${VTK_LIBRARIES}
+ hdf5_serial_hl
)
#
diff --git a/openEMS/CMakeLists.txt b/openEMS/CMakeLists.txt
-index 5504590..794a498 100644
+index e0a143a..c98449b 100644
--- a/openEMS/CMakeLists.txt
+++ b/openEMS/CMakeLists.txt
-@@ -184,6 +184,7 @@ TARGET_LINK_LIBRARIES( openEMS
+@@ -176,6 +176,7 @@ TARGET_LINK_LIBRARIES( openEMS
${Boost_LIBRARIES}
${vtk_LIBS}
${MPI_LIBRARIES}
diff --git a/debian/patches/0007-Fix-some-imports-to-make-python-interface-work.patch b/debian/patches/0007-Fix-some-imports-to-make-python-interface-work.patch
new file mode 100644
index 0000000..a3fadc0
--- /dev/null
+++ b/debian/patches/0007-Fix-some-imports-to-make-python-interface-work.patch
@@ -0,0 +1,54 @@
+From: Ruben Undheim <ruben.undheim@gmail.com>
+Date: Sun, 10 Feb 2019 12:55:06 +0000
+Subject: Fix some imports to make python interface work
+
+---
+ openEMS/python/openEMS/__init__.py | 2 ++
+ openEMS/python/openEMS/nf2ff.py | 1 +
+ openEMS/python/openEMS/ports.py | 3 ++-
+ 3 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/openEMS/python/openEMS/__init__.py b/openEMS/python/openEMS/__init__.py
+index fb1ddb9..734aa76 100644
+--- a/openEMS/python/openEMS/__init__.py
++++ b/openEMS/python/openEMS/__init__.py
+@@ -1,4 +1,6 @@
+ # -*- coding: utf-8 -*-
+ #
+ # Shortcut openEMS import
++from __future__ import absolute_import
++
+ from openEMS.openEMS import openEMS
+diff --git a/openEMS/python/openEMS/nf2ff.py b/openEMS/python/openEMS/nf2ff.py
+index b6d38d0..b3792ff 100644
+--- a/openEMS/python/openEMS/nf2ff.py
++++ b/openEMS/python/openEMS/nf2ff.py
+@@ -15,6 +15,7 @@
+ # You should have received a copy of the GNU General Public License
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
+ #
++from __future__ import absolute_import
+
+ import os
+ import numpy as np
+diff --git a/openEMS/python/openEMS/ports.py b/openEMS/python/openEMS/ports.py
+index 1af1564..5b4fdc0 100644
+--- a/openEMS/python/openEMS/ports.py
++++ b/openEMS/python/openEMS/ports.py
+@@ -15,6 +15,7 @@
+ # You should have received a copy of the GNU General Public License
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
+ #
++from __future__ import absolute_import
+
+ import os
+ import numpy as np
+@@ -45,7 +46,7 @@ class UI_data:
+ self.ui_f_val.append(utilities.DFT_time2freq(tmp[:,0], tmp[:,1], freq, signal_type=signal_type))
+
+ # Port Base-Class
+-class Port:
++class Port(object):
+ """
+ The port base class.
+
diff --git a/debian/patches/0007-Guard-xmmintrin.h-include-so-it-is-only-used-when-ne.patch b/debian/patches/0007-Guard-xmmintrin.h-include-so-it-is-only-used-when-ne.patch
deleted file mode 100644
index 1fa3e9f..0000000
--- a/debian/patches/0007-Guard-xmmintrin.h-include-so-it-is-only-used-when-ne.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-From: =?utf-8?q?Stefan_Br=C3=BCns?= <stefan.bruens@rwth-aachen.de>
-Date: Tue, 27 Mar 2018 02:28:22 +0200
-Subject: Guard xmmintrin.h include so it is only used when necessary
-MIME-Version: 1.0
-Content-Type: text/plain; charset="utf-8"
-Content-Transfer-Encoding: 8bit
-
-The x86/SSE specific code for Flush-To-Zero is only used when
-SSE_CORRECT_DENORMALS is not defined. Guarding the include allows the
-code to compile on e.g. ARM.
-
-Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
----
- openEMS/FDTD/engine_multithread.cpp | 3 +++
- openEMS/FDTD/engine_sse.cpp | 3 +++
- 2 files changed, 6 insertions(+)
-
-diff --git a/openEMS/FDTD/engine_multithread.cpp b/openEMS/FDTD/engine_multithread.cpp
-index 7370198..7ebe0d7 100644
---- a/openEMS/FDTD/engine_multithread.cpp
-+++ b/openEMS/FDTD/engine_multithread.cpp
-@@ -32,7 +32,10 @@
- #include "boost/date_time/posix_time/posix_time.hpp"
- #include "boost/date_time/gregorian/gregorian.hpp"
- #include <iomanip>
-+
-+#ifndef SSE_CORRECT_DENORMALS
- #include <xmmintrin.h>
-+#endif
-
- //! \brief construct an Engine_Multithread instance
- //! it's the responsibility of the caller to free the returned pointer
-diff --git a/openEMS/FDTD/engine_sse.cpp b/openEMS/FDTD/engine_sse.cpp
-index 660e6d6..2e06685 100644
---- a/openEMS/FDTD/engine_sse.cpp
-+++ b/openEMS/FDTD/engine_sse.cpp
-@@ -15,7 +15,10 @@
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-+#ifndef SSE_CORRECT_DENORMALS
- #include <xmmintrin.h>
-+#endif
-+
- #include "engine_sse.h"
-
- //! \brief construct an Engine_sse instance
diff --git a/debian/patches/series b/debian/patches/series
index 5267054..073e8d4 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -4,4 +4,4 @@
0004-link-more.patch
0005-Deletede-CVS-dir-lintian.patch
0006-Don-t-exit-from-library.patch
-0007-Guard-xmmintrin.h-include-so-it-is-only-used-when-ne.patch
+0007-Fix-some-imports-to-make-python-interface-work.patch
diff --git a/debian/python3-openems.install b/debian/python3-openems.install
new file mode 100644
index 0000000..c305eb3
--- /dev/null
+++ b/debian/python3-openems.install
@@ -0,0 +1,2 @@
+openEMS/python/debian/tmp/usr/lib/python3* usr/lib/
+CSXCAD/python/debian/tmp/usr/lib/python3* usr/lib/
diff --git a/debian/rules b/debian/rules
index b1caee4..6329787 100755
--- a/debian/rules
+++ b/debian/rules
@@ -18,10 +18,12 @@ OCTAVE_HOSTTYPE = $(shell octave-config -p CANONICAL_HOST_TYPE)
OCTAVE_API_VERSION = $(shell octave-config -p API_VERSION)
OCTAVE_FULLBPATH = $(OCTAVE_BPATH)/openems-0.0.35/$(OCTAVE_HOSTTYPE)-$(OCTAVE_API_VERSION)
+PYTHON3VERSIONS := $(shell py3versions -s -v)
+
export CXXFLAGS := $(CXXFLAGS) -DSSE_CORRECT_DENORMALS=0
%:
- dh $@
+ dh $@ --with python3
# Since some sub-folders depend on other sub-folders to be installed before
@@ -31,27 +33,25 @@ override_dh_auto_configure:
override_dh_auto_build:
-# openEMS is currently being forced to build with g++-7. The reason is some yet unknown bug which
-# causes crash when simulating when building with g++-8
override_dh_auto_install:
- cd CSXCAD && mkdir -p build && cd build && CXX=/usr/bin/g++-7 cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_INSTALL_PREFIX=/usr -DLIB_SUFFIX=/$(DEB_HOST_MULTIARCH) .. && make && make install DESTDIR=../../debian/tmp
- cd QCSXCAD && mkdir -p build && cd build && CXX=/usr/bin/g++-7 cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_INSTALL_PREFIX=/usr -DCSXCAD_ROOT_DIR=../debian/tmp/usr -DLIB_SUFFIX=/$(DEB_HOST_MULTIARCH) .. && make && make install DESTDIR=../../debian/tmp
- cd openEMS && mkdir -p build && cd build && CXX=/usr/bin/g++-7 cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_INSTALL_PREFIX=/usr -DCSXCAD_ROOT_DIR=../debian/tmp/usr -DLIB_SUFFIX=/$(DEB_HOST_MULTIARCH) ..
+ cd CSXCAD && mkdir -p build && cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_INSTALL_PREFIX=/usr -DLIB_SUFFIX=/$(DEB_HOST_MULTIARCH) .. && make && make install DESTDIR=../../debian/tmp
+ cd QCSXCAD && mkdir -p build && cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_INSTALL_PREFIX=/usr -DCSXCAD_ROOT_DIR=../debian/tmp/usr -DLIB_SUFFIX=/$(DEB_HOST_MULTIARCH) .. && make && make install DESTDIR=../../debian/tmp
+ cd openEMS && mkdir -p build && cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_INSTALL_PREFIX=/usr -DCSXCAD_ROOT_DIR=../debian/tmp/usr -DLIB_SUFFIX=/$(DEB_HOST_MULTIARCH) ..
cd openEMS/build && make
cd openEMS/build && make install DESTDIR=../../debian/tmp
- cd AppCSXCAD && mkdir -p build && cd build && CXX=/usr/bin/g++-7 cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_INSTALL_PREFIX=/usr -DCSXCAD_ROOT_DIR=../debian/tmp/usr -DQCSXCAD_ROOT_DIR=../debian/tmp/usr -DLIB_SUFFIX=/$(DEB_HOST_MULTIARCH) ..
+ cd AppCSXCAD && mkdir -p build && cd build && cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_INSTALL_PREFIX=/usr -DCSXCAD_ROOT_DIR=../debian/tmp/usr -DQCSXCAD_ROOT_DIR=../debian/tmp/usr -DLIB_SUFFIX=/$(DEB_HOST_MULTIARCH) ..
cd AppCSXCAD/build && make
cd AppCSXCAD/build && make install DESTDIR=../../debian/tmp
- cd debian/tmp/usr/share/openEMS/matlab && CXX=/usr/bin/g++-7 CXXFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security" mkoctfile -lhdf5_cpp -DH5_USE_16_API -I/usr/include/hdf5/serial h5readatt_octave.cc
+ cd debian/tmp/usr/share/openEMS/matlab && CXXFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security" mkoctfile -L/usr/lib/$(DEB_HOST_MULTIARCH)/hdf5/serial -lhdf5_cpp -DH5_USE_16_API -I/usr/include/hdf5/serial h5readatt_octave.cc
mkdir -p debian/tmp/$(OCTAVE_FULLBPATH)
mv debian/tmp/usr/share/openEMS/matlab/h5readatt_octave.oct debian/tmp/$(OCTAVE_FULLBPATH)/
- rm debian/tmp/usr/share/openEMS/matlab/h5readatt_octave.o
rm debian/tmp/usr/share/openEMS/matlab/h5readatt_octave.cc
chrpath -d debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/*.so*
chrpath -d debian/tmp/usr/bin/AppCSXCAD
chrpath -d debian/tmp/usr/bin/nf2ff
chrpath -d debian/tmp/usr/bin/openEMS
-
+ cd CSXCAD/python && CPPFLAGS=-I../../debian/tmp/usr/include LDFLAGS=-L../../debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH) PYBUILD_VERSIONS="$(PYTHON3VERSIONS)" pybuild --build && PYBUILD_VERSIONS="$(PYTHON3VERSIONS)" pybuild --install
+ cd openEMS/python && CPPFLAGS=-I../../debian/tmp/usr/include LDFLAGS=-L../../debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH) PYBUILD_VERSIONS="$(PYTHON3VERSIONS)" pybuild --build && PYBUILD_VERSIONS="$(PYTHON3VERSIONS)" pybuild --install
override_dh_auto_clean:
dh_auto_clean
@@ -60,6 +60,14 @@ override_dh_auto_clean:
$(RM) -r openEMS/build || true
$(RM) -r AppCSXCAD/build || true
$(RM) debian/man/*.1
+ cd CSXCAD/python && PYBUILD_VERSIONS="$(PYTHON3VERSIONS)" pybuild --clean
+ cd openEMS/python && PYBUILD_VERSIONS="$(PYTHON3VERSIONS)" pybuild --clean
+ $(RM) -r CSXCAD/python/debian
+ $(RM) -r openEMS/python/debian
+ $(RM) CSXCAD/python/CSXCAD/*.cpp
+ $(RM) openEMS/python/openEMS/*.cpp
+ $(RM) -r CSXCAD/python/.pybuild/
+ $(RM) -r openEMS/python/.pybuild/
override_dh_installman:
cd debian/man ; CHANGELOG_DATE="$(CHANGELOG_DATE)" ./genmanpages.sh
diff --git a/debian/tests/control b/debian/tests/control
index 3392f2e..e5cda62 100644
--- a/debian/tests/control
+++ b/debian/tests/control
@@ -1,2 +1,2 @@
-Tests: octave-load
-Depends: octave-openems
+Tests: octave-load, python3-import
+Depends: octave-openems, python3-openems
diff --git a/debian/tests/octave-load b/debian/tests/octave-load
index 637edef..89933be 100755
--- a/debian/tests/octave-load
+++ b/debian/tests/octave-load
@@ -1,10 +1,10 @@
-#!/bin/sh
+#!/bin/bash
set -e
-octave --eval "pkg load openems"
+octave -W --eval "pkg load openems" 2>&1 >/dev/stdout | grep -v X11 || true | grep -v "disabling GUI" || true ; test ${PIPESTATUS[0]} -eq 0
echo "Successfully loaded openems"
-octave --eval "pkg load csxcad"
+octave -W --eval "pkg load csxcad" 2>&1 >/dev/stdout | grep -v X11 || true | grep -v "disabling GUI" || true ; test ${PIPESTATUS[0]} -eq 0
echo "Successfully loaded csxcad"
echo "done"
diff --git a/debian/tests/python3-import b/debian/tests/python3-import
new file mode 100755
index 0000000..02a5bb0
--- /dev/null
+++ b/debian/tests/python3-import
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+
+cd /
+python3 -c "import openEMS"
+echo "Successfully imported openEMS"
+python3 -c "import CSXCAD"
+echo "Successfully imported CSXCAD"
+
+echo "done"
diff --git a/openEMS/CMakeLists.txt b/openEMS/CMakeLists.txt
index 794a498..c98449b 100644
--- a/openEMS/CMakeLists.txt
+++ b/openEMS/CMakeLists.txt
@@ -122,15 +122,7 @@ find_package(Boost 1.46 COMPONENTS
)
# vtk
-if (WIN32)
- find_package(VTK 6.1 REQUIRED)
-else()
- # prefer >=6.1, fallback to >=5.4
- find_package(VTK 6.1 COMPONENTS vtkIOXML vtkIOGeometry vtkIOLegacy vtkIOPLY NO_MODULE)
- IF (NOT ${VTK_FOUND})
- find_package(VTK REQUIRED)
- endif()
-endif()
+find_package(VTK COMPONENTS vtkIOXML vtkIOGeometry vtkIOLegacy vtkIOPLY NO_MODULE REQUIRED)
message(STATUS "Found package VTK. Using version " ${VTK_VERSION})
if("${VTK_MAJOR_VERSION}" GREATER 5)
diff --git a/openEMS/Common/engine_interface_base.h b/openEMS/Common/engine_interface_base.h
index 6ce466b..15be488 100644
--- a/openEMS/Common/engine_interface_base.h
+++ b/openEMS/Common/engine_interface_base.h
@@ -56,6 +56,10 @@ public:
virtual double* GetJField(const unsigned int* pos, double* out) const =0;
//! Get the total current density field by rot(H) at \p pos. \sa SetInterpolationType
virtual double* GetRotHField(const unsigned int* pos, double* out) const =0;
+ //! Get the (interpolated) electric flux density field at \p pos. \sa SetInterpolationType
+ virtual double* GetDField(const unsigned int* pos, double* out) const =0;
+ //! Get the (interpolated) magnetic flux density field at \p pos. \sa SetInterpolationType
+ virtual double* GetBField(const unsigned int* pos, double* out) const =0;
//! Calculate the electric field integral along a given line
virtual double CalcVoltageIntegral(const unsigned int* start, const unsigned int* stop) const =0;
diff --git a/openEMS/Common/processfields.cpp b/openEMS/Common/processfields.cpp
index f52fc14..b486c32 100644
--- a/openEMS/Common/processfields.cpp
+++ b/openEMS/Common/processfields.cpp
@@ -71,6 +71,10 @@ string ProcessFields::GetFieldNameByType(DumpType type)
return "J-Field";
case ROTH_FIELD_DUMP:
return "RotH-Field";
+ case D_FIELD_DUMP:
+ return "D-Field";
+ case B_FIELD_DUMP:
+ return "B-Field";
case SAR_LOCAL_DUMP:
return "SAR-local";
case SAR_1G_DUMP:
@@ -95,6 +99,30 @@ bool ProcessFields::NeedConductivity() const
return false;
}
+bool ProcessFields::NeedPermittivity() const
+{
+ switch (m_DumpType)
+ {
+ case D_FIELD_DUMP:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
+bool ProcessFields::NeedPermeability() const
+{
+ switch (m_DumpType)
+ {
+ case B_FIELD_DUMP:
+ return true;
+ default:
+ return false;
+ }
+ return false;
+}
+
void ProcessFields::InitProcess()
{
if (Enabled==false) return;
@@ -333,6 +361,44 @@ FDTD_FLOAT**** ProcessFields::CalcField()
}
}
return field;
+ case D_FIELD_DUMP:
+ for (unsigned int i=0; i<numLines[0]; ++i)
+ {
+ pos[0]=posLines[0][i];
+ for (unsigned int j=0; j<numLines[1]; ++j)
+ {
+ pos[1]=posLines[1][j];
+ for (unsigned int k=0; k<numLines[2]; ++k)
+ {
+ pos[2]=posLines[2][k];
+
+ m_Eng_Interface->GetDField(pos,out);
+ field[0][i][j][k] = out[0];
+ field[1][i][j][k] = out[1];
+ field[2][i][j][k] = out[2];
+ }
+ }
+ }
+ return field;
+ case B_FIELD_DUMP:
+ for (unsigned int i=0; i<numLines[0]; ++i)
+ {
+ pos[0]=posLines[0][i];
+ for (unsigned int j=0; j<numLines[1]; ++j)
+ {
+ pos[1]=posLines[1][j];
+ for (unsigned int k=0; k<numLines[2]; ++k)
+ {
+ pos[2]=posLines[2][k];
+
+ m_Eng_Interface->GetBField(pos,out);
+ field[0][i][j][k] = out[0];
+ field[1][i][j][k] = out[1];
+ field[2][i][j][k] = out[2];
+ }
+ }
+ }
+ return field;
default:
cerr << "ProcessFields::CalcField(): Error, unknown dump type..." << endl;
return field;
diff --git a/openEMS/Common/processfields.h b/openEMS/Common/processfields.h
index 3d4085b..d954484 100644
--- a/openEMS/Common/processfields.h
+++ b/openEMS/Common/processfields.h
@@ -40,7 +40,7 @@ public:
Current dump types are electric field (E_FIELD_DUMP), magnetic field (H_FIELD_DUMP),
(conduction) electric current density (kappa*E) (J_FIELD_DUMP) and total current density (rotH)
*/
- enum DumpType { E_FIELD_DUMP=0, H_FIELD_DUMP=1, J_FIELD_DUMP=2, ROTH_FIELD_DUMP=3, SAR_LOCAL_DUMP=20, SAR_1G_DUMP=21, SAR_10G_DUMP=22, SAR_RAW_DATA=29};
+ enum DumpType { E_FIELD_DUMP=0, H_FIELD_DUMP=1, J_FIELD_DUMP=2, ROTH_FIELD_DUMP=3, D_FIELD_DUMP=4, B_FIELD_DUMP=5, SAR_LOCAL_DUMP=20, SAR_1G_DUMP=21, SAR_10G_DUMP=22, SAR_RAW_DATA=29};
virtual std::string GetProcessingName() const {return "common field processing";}
@@ -75,6 +75,8 @@ public:
static std::string GetFieldNameByType(DumpType type);
virtual bool NeedConductivity() const;
+ virtual bool NeedPermittivity() const;
+ virtual bool NeedPermeability() const;
protected:
DumpType m_DumpType;
diff --git a/openEMS/Common/processmodematch.cpp b/openEMS/Common/processmodematch.cpp
index 7cd22f8..851912d 100644
--- a/openEMS/Common/processmodematch.cpp
+++ b/openEMS/Common/processmodematch.cpp
@@ -174,7 +174,7 @@ void ProcessModeMatch::InitProcess()
for (int n=0; n<2; ++n)
{
m_ModeDist[n][posP][posPP] = m_ModeParser[n]->Eval(var); //calc mode template
- if ((isnan(m_ModeDist[n][posP][posPP])) || (isinf(m_ModeDist[n][posP][posPP])))
+ if ((std::isnan(m_ModeDist[n][posP][posPP])) || (std::isinf(m_ModeDist[n][posP][posPP])))
m_ModeDist[n][posP][posPP] = 0.0;
norm += pow(m_ModeDist[n][posP][posPP],2) * area;
}
diff --git a/openEMS/FDTD/engine_interface_fdtd.cpp b/openEMS/FDTD/engine_interface_fdtd.cpp
index b8fd9de..b5155fb 100644
--- a/openEMS/FDTD/engine_interface_fdtd.cpp
+++ b/openEMS/FDTD/engine_interface_fdtd.cpp
@@ -47,6 +47,11 @@ double* Engine_Interface_FDTD::GetJField(const unsigned int* pos, double* out) c
return GetRawInterpolatedField(pos, out, 1);
}
+double* Engine_Interface_FDTD::GetDField(const unsigned int* pos, double* out) const
+{
+ return GetRawInterpolatedField(pos, out, 3);
+}
+
double* Engine_Interface_FDTD::GetRotHField(const unsigned int* pos, double* out) const
{
return GetRawInterpolatedField(pos, out, 2);
@@ -117,6 +122,27 @@ double* Engine_Interface_FDTD::GetRawInterpolatedField(const unsigned int* pos,
double* Engine_Interface_FDTD::GetHField(const unsigned int* pos, double* out) const
{
+ return GetRawInterpolatedDualField(pos, out, 0);
+}
+
+double* Engine_Interface_FDTD::GetBField(const unsigned int* pos, double* out) const
+{
+ return GetRawInterpolatedDualField(pos, out, 1);
+}
+
+double Engine_Interface_FDTD::GetRawDualField(unsigned int n, const unsigned int* pos, int type) const
+{
+ double value = m_Eng->GetCurr(n,pos[0],pos[1],pos[2]);
+ double delta = m_Op->GetEdgeLength(n,pos,true);
+ if ((type==0) && (delta))
+ return value/delta;
+ if ((type==1) && (m_Op->m_mueR) && (delta))
+ return value*m_Op->m_mueR[n][pos[0]][pos[1]][pos[2]]/delta;
+ return 0.0;
+}
+
+double* Engine_Interface_FDTD::GetRawInterpolatedDualField(const unsigned int* pos, double* out, int type) const
+{
unsigned int iPos[] = {pos[0],pos[1],pos[2]};
int nP,nPP;
double delta;
@@ -124,9 +150,9 @@ double* Engine_Interface_FDTD::GetHField(const unsigned int* pos, double* out) c
{
default:
case NO_INTERPOLATION:
- out[0] = m_Eng->GetCurr(0,pos) / m_Op->GetEdgeLength(0,pos,true);
- out[1] = m_Eng->GetCurr(1,pos) / m_Op->GetEdgeLength(1,pos,true);
- out[2] = m_Eng->GetCurr(2,pos) / m_Op->GetEdgeLength(2,pos,true);
+ out[0] = GetRawDualField(0, pos, type);
+ out[1] = GetRawDualField(1, pos, type);
+ out[2] = GetRawDualField(2, pos, type);
break;
case NODE_INTERPOLATE:
for (int n=0; n<3; ++n)
@@ -138,13 +164,13 @@ double* Engine_Interface_FDTD::GetHField(const unsigned int* pos, double* out) c
out[n] = 0;
continue;
}
- out[n]=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true);
+ out[n] = GetRawDualField(n, iPos, type);
--iPos[nP];
- out[n]+=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true);
+ out[n]+= GetRawDualField(n, iPos, type);
--iPos[nPP];
- out[n]+=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true);
+ out[n]+= GetRawDualField(n, iPos, type);
++iPos[nP];
- out[n]+=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true);
+ out[n]+= GetRawDualField(n, iPos, type);
++iPos[nPP];
out[n]/=4;
}
@@ -153,7 +179,7 @@ double* Engine_Interface_FDTD::GetHField(const unsigned int* pos, double* out) c
for (int n=0; n<3; ++n)
{
delta = m_Op->GetEdgeLength(n,iPos,true);
- out[n] = m_Eng->GetCurr(n,iPos);
+ out[n] = GetRawDualField(n, iPos, type);
if ((pos[n]>=m_Op->GetNumberOfLines(n,true)-1))
{
out[n] = 0; //magnetic field on the outer boundaries is always zero
@@ -162,7 +188,7 @@ double* Engine_Interface_FDTD::GetHField(const unsigned int* pos, double* out) c
++iPos[n];
double deltaUp = m_Op->GetEdgeLength(n,iPos,true);
double deltaRel = delta / (delta+deltaUp);
- out[n] = out[n]*(1.0-deltaRel)/delta + (double)m_Eng->GetCurr(n,iPos)/deltaUp*deltaRel;
+ out[n] = out[n]*(1.0-deltaRel) + (double)GetRawDualField(n, iPos, type)*deltaRel;
--iPos[n];
}
break;
@@ -201,6 +227,8 @@ double Engine_Interface_FDTD::GetRawField(unsigned int n, const unsigned int* po
return value/delta;
if ((type==1) && (m_Op->m_kappa) && (delta))
return value*m_Op->m_kappa[n][pos[0]][pos[1]][pos[2]]/delta;
+ if ((type==3) && (m_Op->m_epsR) && (delta))
+ return value*m_Op->m_epsR[n][pos[0]][pos[1]][pos[2]]/delta;
if (type==2) //calc rot(H)
{
int nP = (n+1)%3;
diff --git a/openEMS/FDTD/engine_interface_fdtd.h b/openEMS/FDTD/engine_interface_fdtd.h
index 4e824ac..83281be 100644
--- a/openEMS/FDTD/engine_interface_fdtd.h
+++ b/openEMS/FDTD/engine_interface_fdtd.h
@@ -44,6 +44,8 @@ public:
virtual double* GetHField(const unsigned int* pos, double* out) const;
virtual double* GetJField(const unsigned int* pos, double* out) const;
virtual double* GetRotHField(const unsigned int* pos, double* out) const;
+ virtual double* GetDField(const unsigned int* pos, double* out) const;
+ virtual double* GetBField(const unsigned int* pos, double* out) const;
virtual double CalcVoltageIntegral(const unsigned int* start, const unsigned int* stop) const;
@@ -56,10 +58,15 @@ protected:
Operator* m_Op;
Engine* m_Eng;
- //! Internal method to get an interpolated field of a given type. (0: E, 1: J, 2: rotH)
+ //! Internal method to get an interpolated field of a given type. (0: E, 1: J, 2: rotH, 3: D)
virtual double* GetRawInterpolatedField(const unsigned int* pos, double* out, int type) const;
- //! Internal method to get a raw field of a given type. (0: E, 1: J, 2: rotH)
+ //! Internal method to get a raw field of a given type. (0: E, 1: J, 2: rotH, 3: D)
virtual double GetRawField(unsigned int n, const unsigned int* pos, int type) const;
+
+ //! Internal method to get an interpolated dual field of a given type. (0: H, 1: B)
+ virtual double* GetRawInterpolatedDualField(const unsigned int* pos, double* out, int type) const;
+ //! Internal method to get a raw dual field of a given type. (0: H, 1: B)
+ virtual double GetRawDualField(unsigned int n, const unsigned int* pos, int type) const;
};
#endif // ENGINE_INTERFACE_FDTD_H
diff --git a/openEMS/FDTD/excitation.cpp b/openEMS/FDTD/excitation.cpp
index 4e1ba85..b750c91 100644
--- a/openEMS/FDTD/excitation.cpp
+++ b/openEMS/FDTD/excitation.cpp
@@ -53,7 +53,7 @@ void Excitation::Reset( double timestep )
m_foi = 0;
}
-bool Excitation::SetupGaussianPulse(double f0, double fc)
+void Excitation::SetupGaussianPulse(double f0, double fc)
{
m_Excit_Type = Excitation::GaissianPulse;
m_f0 = f0;
@@ -62,7 +62,7 @@ bool Excitation::SetupGaussianPulse(double f0, double fc)
m_SignalPeriod = 0;
}
-bool Excitation::SetupSinusoidal(double f0)
+void Excitation::SetupSinusoidal(double f0)
{
m_Excit_Type = Excitation::Sinusoidal;
m_f0 = f0;
@@ -70,21 +70,21 @@ bool Excitation::SetupSinusoidal(double f0)
m_SignalPeriod = 1/f0;
}
-bool Excitation::SetupDiracPulse(double fmax)
+void Excitation::SetupDiracPulse(double fmax)
{
m_Excit_Type = Excitation::DiracPulse;
m_SignalPeriod = 0;
m_f_max = fmax;
}
-bool Excitation::SetupStepExcite(double fmax)
+void Excitation::SetupStepExcite(double fmax)
{
m_Excit_Type = Excitation::Step;
m_SignalPeriod = 0;
m_f_max = fmax;
}
-bool Excitation::SetupCustomExcite(string str, double f0, double fmax)
+void Excitation::SetupCustomExcite(string str, double f0, double fmax)
{
m_Excit_Type = Excitation::CustomExcite;
m_CustomExc_Str = str;
diff --git a/openEMS/FDTD/excitation.h b/openEMS/FDTD/excitation.h
index 8ae3a5b..b43ad28 100644
--- a/openEMS/FDTD/excitation.h
+++ b/openEMS/FDTD/excitation.h
@@ -31,11 +31,11 @@ public:
virtual void Reset( double timestep );
- bool SetupGaussianPulse(double f0, double fc);
- bool SetupSinusoidal(double f0);
- bool SetupDiracPulse(double fmax);
- bool SetupStepExcite(double fmax);
- bool SetupCustomExcite(std::string str, double f0, double fmax);
+ void SetupGaussianPulse(double f0, double fc);
+ void SetupSinusoidal(double f0);
+ void SetupDiracPulse(double fmax);
+ void SetupStepExcite(double fmax);
+ void SetupCustomExcite(std::string str, double f0, double fmax);
double GetCenterFreq() {return m_f0;}
double GetCutOffFreq() {return m_fc;}
diff --git a/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp b/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp
index 9f386fc..21ad184 100644
--- a/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp
+++ b/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp
@@ -225,6 +225,9 @@ bool Operator_Ext_LorentzMaterial::BuildExtension()
// CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord,(CSProperties::PropertyType)(CSProperties::METAL | CSProperties::MATERIAL), true);
CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, vPrims, true);
+
+ if (prop==NULL) continue;
+
if ((mat = prop->ToLorentzMaterial()))
{
w_plasma = mat->GetEpsPlasmaFreqWeighted(order,n,coord) * 2 * PI;
@@ -277,6 +280,9 @@ bool Operator_Ext_LorentzMaterial::BuildExtension()
// CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord,(CSProperties::PropertyType)(CSProperties::METAL | CSProperties::MATERIAL), true);
CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, vPrims, true);
+
+ if (prop==NULL) continue;
+
if ((mat = prop->ToLorentzMaterial()))
{
w_plasma = mat->GetMuePlasmaFreqWeighted(order,n,coord) * 2 * PI;
diff --git a/openEMS/FDTD/extensions/operator_ext_tfsf.cpp b/openEMS/FDTD/extensions/operator_ext_tfsf.cpp
index 663dc1f..62fd580 100644
--- a/openEMS/FDTD/extensions/operator_ext_tfsf.cpp
+++ b/openEMS/FDTD/extensions/operator_ext_tfsf.cpp
@@ -159,7 +159,7 @@ bool Operator_Ext_TFSF::BuildExtension()
else
m_PhVel=m_Op->CalcNumericPhaseVelocity(m_Start,m_Stop,m_PropDir,m_Frequency);
- if ((m_PhVel<0) || (m_PhVel>__C0__/ref_index) || isnan(m_PhVel))
+ if ((m_PhVel<0) || (m_PhVel>__C0__/ref_index) || std::isnan(m_PhVel))
{
cerr << "Operator_Ext_TFSF::BuildExtension: Warning, invalid phase velocity found, resetting to c0! " << endl;
m_PhVel = __C0__/ref_index;
diff --git a/openEMS/FDTD/operator.cpp b/openEMS/FDTD/operator.cpp
index 2dec2d3..54d4aad 100644
--- a/openEMS/FDTD/operator.cpp
+++ b/openEMS/FDTD/operator.cpp
@@ -1395,7 +1395,7 @@ bool Operator::AverageMatCellCenter(int ny, const unsigned int* pos, double* Eff
if (EffMat[3]) EffMat[3]=length / EffMat[3];
for (int n=0; n<4; ++n)
- if (isnan(EffMat[n]) || isinf(EffMat[n]))
+ if (std::isnan(EffMat[n]) || std::isinf(EffMat[n]))
{
cerr << "Operator::" << __func__ << ": Error, an effective material parameter is not a valid result, this should NOT have happened... exit..." << endl;
cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << "," << pos[2] << endl;
@@ -1508,7 +1508,7 @@ bool Operator::AverageMatQuarterCell(int ny, const unsigned int* pos, double* Ef
if (EffMat[3]) EffMat[3]=length / EffMat[3];
for (int n=0; n<4; ++n)
- if (isnan(EffMat[n]) || isinf(EffMat[n]))
+ if (std::isnan(EffMat[n]) || std::isinf(EffMat[n]))
{
cerr << "Operator::" << __func__ << ": Error, An effective material parameter is not a valid result, this should NOT have happened... exit..." << endl;
cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << "," << pos[2] << endl;
@@ -1555,7 +1555,7 @@ bool Operator::Calc_LumpedElements()
if (R<0)
R = NAN;
- if ((isnan(R)) && (isnan(C)))
+ if ((std::isnan(R)) && (std::isnan(C)))
{
cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element R or C not specified! skipping. "
<< " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl;
diff --git a/openEMS/FDTD/operator_sse.cpp b/openEMS/FDTD/operator_sse.cpp
index 8a1b21b..214bf3a 100644
--- a/openEMS/FDTD/operator_sse.cpp
+++ b/openEMS/FDTD/operator_sse.cpp
@@ -41,11 +41,11 @@ Operator_sse::~Operator_sse()
Delete();
}
-Engine* Operator_sse::CreateEngine() const
+Engine* Operator_sse::CreateEngine()
{
//! create a special sse-engine
- Engine_sse* eng = Engine_sse::New(this);
- return eng;
+ m_Engine = Engine_sse::New(this);
+ return m_Engine;
}
void Operator_sse::Init()
diff --git a/openEMS/FDTD/operator_sse.h b/openEMS/FDTD/operator_sse.h
index 317ea72..c0a698a 100644
--- a/openEMS/FDTD/operator_sse.h
+++ b/openEMS/FDTD/operator_sse.h
@@ -29,7 +29,7 @@ public:
static Operator_sse* New();
virtual ~Operator_sse();
- virtual Engine* CreateEngine() const;
+ virtual Engine* CreateEngine();
inline virtual FDTD_FLOAT GetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_vv[n][x][y][z%numVectors].f[z/numVectors]; }
inline virtual FDTD_FLOAT GetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_vi[n][x][y][z%numVectors].f[z/numVectors]; }
diff --git a/openEMS/FDTD/operator_sse_compressed.cpp b/openEMS/FDTD/operator_sse_compressed.cpp
index 5214892..ce3e8e3 100644
--- a/openEMS/FDTD/operator_sse_compressed.cpp
+++ b/openEMS/FDTD/operator_sse_compressed.cpp
@@ -42,16 +42,14 @@ Operator_SSE_Compressed::~Operator_SSE_Compressed()
Delete();
}
-Engine* Operator_SSE_Compressed::CreateEngine() const
+Engine* Operator_SSE_Compressed::CreateEngine()
{
if (!m_Use_Compression)
- {
//! create a default sse-engine
- Engine_sse* eng = Engine_sse::New(this);
- return eng;
- }
- Engine_SSE_Compressed* eng = Engine_SSE_Compressed::New(this);
- return eng;
+ m_Engine = Engine_sse::New(this);
+ else
+ m_Engine = Engine_SSE_Compressed::New(this);
+ return m_Engine;
}
int Operator_SSE_Compressed::CalcECOperator( DebugFlags debugFlags )
diff --git a/openEMS/FDTD/operator_sse_compressed.h b/openEMS/FDTD/operator_sse_compressed.h
index 5d3454f..f9b12a2 100644
--- a/openEMS/FDTD/operator_sse_compressed.h
+++ b/openEMS/FDTD/operator_sse_compressed.h
@@ -43,7 +43,7 @@ public:
static Operator_SSE_Compressed* New();
virtual ~Operator_SSE_Compressed();
- virtual Engine* CreateEngine() const;
+ virtual Engine* CreateEngine();
inline virtual FDTD_FLOAT GetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { if (m_Use_Compression) return f4_vv_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors]; else return Operator_sse::GetVV(n,x,y,z);}
inline virtual FDTD_FLOAT GetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { if (m_Use_Compression) return f4_vi_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors]; else return Operator_sse::GetVI(n,x,y,z);}
diff --git a/openEMS/matlab/DelayFidelity.m b/openEMS/matlab/DelayFidelity.m
index 3cc0ae2..48d5975 100644
--- a/openEMS/matlab/DelayFidelity.m
+++ b/openEMS/matlab/DelayFidelity.m
@@ -1,5 +1,5 @@
function [delay, fidelity, nf2ff_out] = DelayFidelity(nf2ff, port, path, weight_theta, weight_phi, theta, phi, f_0, f_c, varargin)
-% [delay, fidelity] = DelayFidelity(nf2ff, port, path, theta, phi, f_lo, f_hi, varargin)
+% [delay, fidelity] = DelayFidelity(nf2ff, port, path, weight_theta, weight_phi, theta, phi, f_lo, f_hi, varargin)
%
%
% This function calculates the time delay from the source port to the phase center of the antenna and the fidelity.
@@ -11,8 +11,8 @@ function [delay, fidelity, nf2ff_out] = DelayFidelity(nf2ff, port, path, weight_
% nf2ff: return value of CreateNF2FFBox.
% port: return value of AddLumpedPort
% path: path of the simulation results.
-% weight_theta: weight if the E_theta component
-% weight_phi: eight of the E_phi component
+% weight_theta: weight of the E_theta component
+% weight_phi: weight of the E_phi component
% -> with both (possibly complex) parameters any polarization can be examined
% theta: theta values to be simulated
% phi: phi values to be simulated
@@ -27,7 +27,8 @@ function [delay, fidelity, nf2ff_out] = DelayFidelity(nf2ff, port, path, weight_
% example:
% theta = [-180:10:180] * pi / 180;
% phi = [0, 90] * pi / 180;
-% [delay, fidelity] = DelayFidelity2(nf2ff, port, Sim_Path, sin(tilt), cos(tilt), theta, phi, f_0, f_c, 'Mode', 1);
+% % use circular right handed polarization
+% [delay, fidelity] = DelayFidelity2(nf2ff, port, Sim_Path, -1i, 1, theta, phi, f_0, f_c, 'Mode', 1);
% figure
% polar(theta.', delay(:,1) * 3e11); % delay in mm
% figure
diff --git a/openEMS/matlab/RunOpenEMS.m b/openEMS/matlab/RunOpenEMS.m
index 3894adc..21a9876 100644
--- a/openEMS/matlab/RunOpenEMS.m
+++ b/openEMS/matlab/RunOpenEMS.m
@@ -170,11 +170,11 @@ if (enable_ssh)
warning('openEMS:RunOpenEMS','remote cleanup failed!');
end
else
- args = [Sim_File ' ' opts];
+ args = ['"' Sim_File '" ' opts]
if isfield(Settings,'LogFile') && isfield(Settings,'Silent')
- invoke_openEMS(args,Settings.LogFile,Settings.Silent);
+ invoke_openEMS(args,['"' Settings.LogFile '"'],Settings.Silent);
elseif isfield(Settings,'LogFile')
- invoke_openEMS(args,Settings.LogFile);
+ invoke_openEMS(args,['"' Settings.LogFile '"']);
elseif isfield(Settings,'Silent')
invoke_openEMS(args,[],Settings.Silent);
else
diff --git a/openEMS/matlab/plotRefl.m b/openEMS/matlab/plotRefl.m
index 5f88631..441c336 100644
--- a/openEMS/matlab/plotRefl.m
+++ b/openEMS/matlab/plotRefl.m
@@ -18,9 +18,11 @@ function h = plotRefl(port, varargin)
% for the frequency (always in MHz), default is 0
% 'threshold': - Threshold value (in dB) for the upper and lower
% cutoff frequency, default is -3
+% 'fmarkers': - set lower and upper frequency marker in Hz manually,
+% like so: [4e9, 6.5e9]
% example:
% myport = calcPort(myport, Sim_Path, linspace(f_0-f_c, f_0+f_c, 200));
-% plotRefl(myport);
+% plotRefl(myport, 'fmarkers', [4e9, 6.5e9]);
%
% See also calcPort
%
@@ -31,14 +33,16 @@ function h = plotRefl(port, varargin)
%defaults
precision = 0;
threshold = -3;
-
+fmarkers = [];
for n=1:2:numel(varargin)
if (strcmp(varargin{n},'precision')==1);
precision = varargin{n+1};
elseif (strcmp(varargin{n},'threshold')==1);
threshold = varargin{n+1};
- else
+ elseif (strcmp(varargin{n},'fmarkers')==1);
+ fmarkers = varargin{n+1};
+ else
warning('openEMS:polarFF',['unknown argument key: ''' varargin{n} '''']);
end
end
@@ -111,8 +115,14 @@ text (real (rho), imag (rho), '0');
s11dB = 20*log10(abs(s11));
+if(isempty(fmarkers))
upperind = s11dB(1:end-1) < threshold & s11dB(2:end) > threshold;
lowerind = s11dB(1:end-1) > threshold & s11dB(2:end) < threshold;
+else
+upperind = [nthargout(2, @min, abs(fmarkers(2)-port.f))];
+lowerind = [nthargout(2, @min, abs(fmarkers(1)-port.f))];
+end
+
minind = nthargout(2, @min, s11dB);
handle1 = plot(s11(lowerind),['<','b']);
handle2 = plot(s11(upperind),['>','b']);
@@ -120,6 +130,7 @@ handle3 = plot(s11(minind),['*', 'b']);
llegend = num2str(port.f(lowerind)(1)/1e6, ffmt);
ulegend = num2str(port.f(upperind)(1)/1e6, ffmt);
+
if nnz(lowerind) > 1
for i= 2:nnz(lowerind)
llegend = strjoin({llegend, num2str(port.f(lowerind)(i)/1e6, ffmt)}, ', ');
@@ -142,4 +153,4 @@ if (nargout == 0)
clear h;
end
-end \ No newline at end of file
+end
diff --git a/openEMS/matlab/setup.m b/openEMS/matlab/setup.m
index e208ad4..fc13ded 100644
--- a/openEMS/matlab/setup.m
+++ b/openEMS/matlab/setup.m
@@ -19,14 +19,14 @@ if isOctave()
fflush(stdout);
if isunix
[res, fn_so] = unix('find /usr/lib -name libhdf5.so');
- [res, fn_h] = unix('find /usr/include -name hdf5.h');
+ [res, fn_h] = unix('find /usr/include -name hdf5.h | head -1');
if length(fn_so)>0 && length(fn_h)>0
- [hdf5lib_dir, hdf5lib_fn] = fileparts(fn_so);
+ [hdf5lib_dir, hdf5lib_fn, ext] = fileparts(fn_so);
disp(["HDF5 library path found at: " hdf5lib_dir])
- [hdf5inc_dir, hdf5inc_fn] = fileparts(fn_h);
+ [hdf5inc_dir, hdf5inc_fn, ext] = fileparts(fn_h);
disp(["HDF5 include path found at: " hdf5inc_dir])
- mkoctfile(["-L" hdf5lib_dir " -I" hdf5inc_dir],"-lhdf5", "h5readatt_octave.cc")
+ mkoctfile("h5readatt_octave.cc", ["-L" hdf5lib_dir], ["-I" hdf5inc_dir], "-L hdf5")
else
mkoctfile -lhdf5 h5readatt_octave.cc
end
diff --git a/openEMS/nf2ff/nf2ff_calc.cpp b/openEMS/nf2ff/nf2ff_calc.cpp
index 335dd9a..9c2aa4f 100644
--- a/openEMS/nf2ff/nf2ff_calc.cpp
+++ b/openEMS/nf2ff/nf2ff_calc.cpp
@@ -313,6 +313,10 @@ bool nf2ff_calc::AddPlane(float **lines, unsigned int* numLines, complex<float>*
if ((m_MirrorType[n]!=MIRROR_OFF) && (m_MirrorType[nP]==MIRROR_OFF) && (m_MirrorType[nPP]==MIRROR_OFF))
{
this->AddMirrorPlane(n, lines, numLines, E_field, H_field, MeshType);
+
+ for (unsigned int i=0;i<numLines[n];++i)
+ lines[n][i] = 2.0*m_MirrorPos[n] - lines[n][i];
+
break;
}
//check if two planes are on
@@ -321,6 +325,10 @@ bool nf2ff_calc::AddPlane(float **lines, unsigned int* numLines, complex<float>*
this->AddMirrorPlane(nP, lines, numLines, E_field, H_field, MeshType);
this->AddMirrorPlane(nPP, lines, numLines, E_field, H_field, MeshType);
this->AddMirrorPlane(nP, lines, numLines, E_field, H_field, MeshType);
+
+ for (unsigned int i=0;i<numLines[nPP];++i)
+ lines[nPP][i] = 2.0*m_MirrorPos[nPP] - lines[nPP][i];
+
break;
}
}
@@ -334,6 +342,10 @@ bool nf2ff_calc::AddPlane(float **lines, unsigned int* numLines, complex<float>*
this->AddMirrorPlane(0, lines, numLines, E_field, H_field, MeshType);
this->AddMirrorPlane(1, lines, numLines, E_field, H_field, MeshType);
this->AddMirrorPlane(0, lines, numLines, E_field, H_field, MeshType);
+
+ for (unsigned int i=0;i<numLines[2];++i)
+ lines[2][i] = 2.0*m_MirrorPos[2] - lines[2][i];
+
}
//cleanup E- & H-Fields
@@ -496,7 +508,7 @@ bool nf2ff_calc::AddSinglePlane(float **lines, unsigned int* numLines, complex<f
m_H_theta[tn][pn] += factor*(Np[tn][pn] - Lt[tn][pn]/Z0);
m_H_phi[tn][pn] -= factor*(Nt[tn][pn] + Lp[tn][pn]/Z0);
- m_P_rad[tn][pn] = m_radius*m_radius/(2*fZ0) * abs((m_E_theta[tn][pn]*conj(m_E_theta[tn][pn])+m_E_phi[tn][pn]*conj(m_E_phi[tn][pn])));
+ m_P_rad[tn][pn] = abs((m_E_theta[tn][pn]*conj(m_E_theta[tn][pn])+m_E_phi[tn][pn]*conj(m_E_phi[tn][pn])))/(2*fZ0);
if (m_P_rad[tn][pn]>P_max)
P_max = m_P_rad[tn][pn];
}
diff --git a/openEMS/openems.cpp b/openEMS/openems.cpp
index 1d08ef7..4e32bf8 100644
--- a/openEMS/openems.cpp
+++ b/openEMS/openems.cpp
@@ -182,13 +182,13 @@ bool openEMS::parseCommandLineArgument( const char *argv )
else if (strcmp(argv,"--debug-PEC")==0)
{
cout << "openEMS - dumping PEC info to 'PEC_dump.vtk'" << endl;
- m_debugPEC = true;
+ DebugPEC();
return true;
}
else if (strcmp(argv,"--debug-CSX")==0)
{
cout << "openEMS - dumping CSX geometry to 'debugCSX.xml'" << endl;
- m_debugCSX = true;
+ DebugCSX();
return true;
}
else if (strcmp(argv,"--engine=basic")==0)
@@ -217,7 +217,7 @@ bool openEMS::parseCommandLineArgument( const char *argv )
}
else if (strncmp(argv,"--numThreads=",13)==0)
{
- m_engine_numThreads = atoi(argv+13);
+ this->SetNumberOfThreads(atoi(argv+13));
cout << "openEMS - fixed number of threads: " << m_engine_numThreads << endl;
return true;
}
@@ -284,7 +284,7 @@ void openEMS::WelcomeScreen()
cout << " ---------------------------------------------------------------------- " << endl;
cout << " | openEMS " << bits << " -- version " GIT_VERSION << endl;
- cout << " | (C) 2010-2016 Thorsten Liebig <thorsten.liebig@gmx.de> GPL license" << endl;
+ cout << " | (C) 2010-2018 Thorsten Liebig <thorsten.liebig@gmx.de> GPL license" << endl;
cout << " ---------------------------------------------------------------------- " << endl;
cout << openEMS::GetExtLibsInfo("\t") << endl;
}
@@ -472,9 +472,9 @@ bool openEMS::SetupProcessing()
CSPropDumpBox* db = DumpProps.at(i)->ToDumpBox();
if (db)
{
- if ((db->GetDumpType()>=0) && (db->GetDumpType()<=3))
+ if ((db->GetDumpType()>=0) && (db->GetDumpType()<=5))
ProcField = new ProcessFieldsTD(NewEngineInterface(db->GetMultiGridLevel()));
- else if ((db->GetDumpType()>=10) && (db->GetDumpType()<=13))
+ else if ((db->GetDumpType()>=10) && (db->GetDumpType()<=15))
ProcField = new ProcessFieldsFD(NewEngineInterface(db->GetMultiGridLevel()));
else if ( ((db->GetDumpType()>=20) && (db->GetDumpType()<=22)) || (db->GetDumpType()==29) )
{
@@ -518,8 +518,12 @@ bool openEMS::SetupProcessing()
ProcField->SetDumpType(ProcessFields::SAR_RAW_DATA);
//SetupMaterialStorages() has previewed storage needs... refresh here to prevent cleanup!!!
- if ( ProcField->NeedConductivity() && Enable_Dumps )
+ if ( ProcField->NeedPermittivity() && Enable_Dumps)
+ FDTD_Op->SetMaterialStoreFlags(0,true);
+ if ( ProcField->NeedConductivity() && Enable_Dumps)
FDTD_Op->SetMaterialStoreFlags(1,true);
+ if ( ProcField->NeedPermeability() && Enable_Dumps)
+ FDTD_Op->SetMaterialStoreFlags(2,true);
ProcField->SetDumpMode((Engine_Interface_Base::InterpolationType)db->GetDumpMode());
ProcField->SetFileType((ProcessFields::FileType)db->GetFileType());
@@ -567,6 +571,10 @@ bool openEMS::SetupMaterialStorages()
(db->GetDumpType()==20) || (db->GetDumpType()==21) || (db->GetDumpType()==22)) && // SAR dump types
Enable_Dumps )
FDTD_Op->SetMaterialStoreFlags(1,true); //tell operator to store kappa material data
+ if ( ((db->GetDumpType()==4) || (db->GetDumpType()==14)) || Enable_Dumps) // electric flux density storage
+ FDTD_Op->SetMaterialStoreFlags(0,true); //tell operator to store epsR material data
+ if ( ((db->GetDumpType()==5) || (db->GetDumpType()==15)) || Enable_Dumps) // magnetic flux density storage
+ FDTD_Op->SetMaterialStoreFlags(2,true); //tell operator to store mueR material data
}
return true;
}
diff --git a/openEMS/openems.h b/openEMS/openems.h
index d194050..6600e06 100644
--- a/openEMS/openems.h
+++ b/openEMS/openems.h
@@ -70,9 +70,13 @@ public:
void SetTimeStepFactor(double val) {m_TS_fac=val;}
void SetMaxTime(double val) {m_maxTime=val;}
+ void SetNumberOfThreads(unsigned int val) {m_engine_numThreads = val;}
+
void DebugMaterial() {DebugMat=true;}
void DebugOperator() {DebugOp=true;}
void DebugBox() {m_debugBox=true;}
+ void DebugPEC() {m_debugPEC=true;}
+ void DebugCSX() {m_debugCSX=true;}
void Set_BC_Type(int idx, int type);
int Get_BC_Type(int idx);
diff --git a/openEMS/python/README.md b/openEMS/python/README.md
new file mode 100644
index 0000000..887e9da
--- /dev/null
+++ b/openEMS/python/README.md
@@ -0,0 +1,14 @@
+# openEMS python interface
+
+## Install
+* Simple version:
+```python
+python setup.py install
+```
+
+* Extended options, e.g. for custom install path at */opt/openEMS*:
+```python
+python setup.py build_ext -I/opt/openEMS/include -L/opt/openEMS/lib -R/opt/openEMS/lib"
+python setup.py install
+```
+**Note:** The install command may require root on Linux, or add --user to install to ~/.local
diff --git a/openEMS/python/Tutorials/Bent_Patch_Antenna.py b/openEMS/python/Tutorials/Bent_Patch_Antenna.py
new file mode 100644
index 0000000..ef2cb0e
--- /dev/null
+++ b/openEMS/python/Tutorials/Bent_Patch_Antenna.py
@@ -0,0 +1,198 @@
+# -*- coding: utf-8 -*-
+"""
+ Bent Patch Antenna Tutorial
+
+ Tested with
+ - python 3.4
+ - openEMS v0.0.33+
+
+ (C) 2016 Thorsten Liebig <thorsten.liebig@gmx.de>
+
+"""
+
+### Import Libraries
+import os, tempfile
+from pylab import *
+from mpl_toolkits.mplot3d import Axes3D
+
+from CSXCAD import CSXCAD
+
+from openEMS.openEMS import openEMS
+from openEMS.physical_constants import *
+
+
+### Setup the simulation
+Sim_Path = os.path.join(tempfile.gettempdir(), 'Bent_Patch')
+
+post_proc_only = False
+
+unit = 1e-3 # all length in mm
+
+f0 = 2.4e9 # center frequency, frequency of interest!
+lambda0 = round(C0/f0/unit) # wavelength in mm
+fc = 0.5e9 # 20 dB corner frequency
+
+# patch width in alpha-direction
+patch_width = 32 # resonant length in alpha-direction
+patch_radius = 50 # radius
+patch_length = 40 # patch length in z-direction
+
+#substrate setup
+substrate_epsR = 3.38
+substrate_kappa = 1e-3 * 2*pi*2.45e9 * EPS0*substrate_epsR
+substrate_width = 80
+substrate_length = 90
+substrate_thickness = 1.524
+substrate_cells = 4
+
+#setup feeding
+feed_pos = -5.5 #feeding position in x-direction
+feed_width = 2 #feeding port width
+feed_R = 50 #feed resistance
+
+# size of the simulation box
+SimBox_rad = 2*100
+SimBox_height = 1.5*200
+
+### Setup FDTD parameter & excitation function
+FDTD = openEMS(CoordSystem=1) # init a cylindrical FDTD
+f0 = 2e9 # center frequency
+fc = 1e9 # 20 dB corner frequency
+FDTD.SetGaussExcite(f0, fc)
+FDTD.SetBoundaryCond(['MUR', 'MUR', 'MUR', 'MUR', 'MUR', 'MUR']) # boundary conditions
+
+### Setup the Geometry & Mesh
+# init a cylindrical mesh
+CSX = CSXCAD.ContinuousStructure(CoordSystem=1)
+FDTD.SetCSX(CSX)
+mesh = CSX.GetGrid()
+mesh.SetDeltaUnit(unit)
+
+### Setup the geometry using cylindrical coordinates
+# calculate some width as an angle in radiant
+patch_ang_width = patch_width/(patch_radius+substrate_thickness)
+substr_ang_width = substrate_width/patch_radius
+feed_angle = feed_pos/patch_radius
+
+# create patch
+patch = CSX.AddMetal('patch') # create a perfect electric conductor (PEC)
+start = [patch_radius+substrate_thickness, -patch_ang_width/2, -patch_length/2 ]
+stop = [patch_radius+substrate_thickness, patch_ang_width/2, patch_length/2 ]
+CSX.AddBox(patch, priority=10, start=start, stop=stop, edges2grid='all') # add a box-primitive to the metal property 'patch'
+
+# create substrate
+substrate = CSX.AddMaterial('substrate', epsilon=substrate_epsR, kappa=substrate_kappa )
+start = [patch_radius , -substr_ang_width/2, -substrate_length/2]
+stop = [patch_radius+substrate_thickness, substr_ang_width/2, substrate_length/2]
+substrate.AddBox(start=start, stop=stop, edges2grid='all')
+
+# save current density oon the patch
+jt_patch = CSX.AddDump('Jt_patch', dump_type=3, file_type=1)
+start = [patch_radius+substrate_thickness, -substr_ang_width/2, -substrate_length/2]
+stop = [patch_radius+substrate_thickness, +substr_ang_width/2, substrate_length/2]
+jt_patch.AddBox(start=start, stop=stop)
+
+# create ground
+gnd = CSX.AddMetal('gnd') # create a perfect electric conductor (PEC)
+start = [patch_radius, -substr_ang_width/2, -substrate_length/2]
+stop = [patch_radius, +substr_ang_width/2, +substrate_length/2]
+gnd.AddBox(priority=10, start=start, stop=stop, edges2grid='all')
+
+# apply the excitation & resist as a current source
+start = [patch_radius , feed_angle, 0]
+stop = [patch_radius+substrate_thickness, feed_angle, 0]
+port = FDTD.AddLumpedPort(1 ,feed_R, start, stop, 'r', 1.0, priority=50, edges2grid='all')
+
+### Finalize the Mesh
+# add the simulation domain size
+mesh.AddLine('r', patch_radius+np.array([-20, SimBox_rad]))
+mesh.AddLine('a', [-0.75*pi, 0.75*pi])
+mesh.AddLine('z', [-SimBox_height/2, SimBox_height/2])
+
+# add some lines for the substrate
+mesh.AddLine('r', patch_radius+np.linspace(0,substrate_thickness,substrate_cells))
+
+# generate a smooth mesh with max. cell size: lambda_min / 20
+max_res = C0 / (f0+fc) / unit / 20
+max_ang = max_res/(SimBox_rad+patch_radius) # max res in radiant
+mesh.SmoothMeshLines(0, max_res, 1.4)
+mesh.SmoothMeshLines(1, max_ang, 1.4)
+mesh.SmoothMeshLines(2, max_res, 1.4)
+
+## Add the nf2ff recording box
+nf2ff = FDTD.CreateNF2FFBox()
+
+### Run the simulation
+if 0: # debugging only
+ CSX_file = os.path.join(Sim_Path, 'bent_patch.xml')
+ if not os.path.exists(Sim_Path):
+ os.mkdir(Sim_Path)
+ CSX.Write2XML(CSX_file)
+ os.system(r'AppCSXCAD "{}"'.format(CSX_file))
+
+
+if not post_proc_only:
+ FDTD.Run(Sim_Path, verbose=3, cleanup=True)
+
+### Postprocessing & plotting
+f = np.linspace(max(1e9,f0-fc),f0+fc,401)
+port.CalcPort(Sim_Path, f)
+Zin = port.uf_tot / port.if_tot
+s11 = port.uf_ref/port.uf_inc
+s11_dB = 20.0*np.log10(np.abs(s11))
+
+figure()
+plot(f/1e9, s11_dB)
+grid()
+ylabel('s11 (dB)')
+xlabel('frequency (GHz)')
+
+P_in = 0.5*np.real(port.uf_tot * np.conj(port.if_tot)) # antenna feed power
+
+# plot feed point impedance
+figure()
+plot( f/1e6, real(Zin), 'k-', linewidth=2, label=r'$\Re(Z_{in})$' )
+grid()
+plot( f/1e6, imag(Zin), 'r--', linewidth=2, label=r'$\Im(Z_{in})$' )
+title( 'feed point impedance' )
+xlabel( 'frequency (MHz)' )
+ylabel( 'impedance ($\Omega$)' )
+legend( )
+
+
+idx = np.where((s11_dB<-10) & (s11_dB==np.min(s11_dB)))[0]
+if not len(idx)==1:
+ print('No resonance frequency found for far-field calulation')
+else:
+ f_res = f[idx[0]]
+ theta = np.arange(-180.0, 180.0, 2.0)
+ print("Calculate NF2FF")
+ nf2ff_res_phi0 = nf2ff.CalcNF2FF(Sim_Path, f_res, theta, 0, center=np.array([patch_radius+substrate_thickness, 0, 0])*unit, read_cached=True, outfile='nf2ff_xz.h5')
+
+ figure(figsize=(15, 7))
+ ax = subplot(121, polar=True)
+ E_norm = 20.0*np.log10(nf2ff_res_phi0.E_norm/np.max(nf2ff_res_phi0.E_norm)) + nf2ff_res_phi0.Dmax
+ ax.plot(np.deg2rad(theta), 10**(np.squeeze(E_norm)/20), linewidth=2, label='xz-plane')
+ ax.grid(True)
+ ax.set_xlabel('theta (deg)')
+ ax.set_theta_zero_location('N')
+ ax.set_theta_direction(-1)
+ ax.legend(loc=3)
+
+ phi = theta
+ nf2ff_res_theta90 = nf2ff.CalcNF2FF(Sim_Path, f_res, 90, phi, center=np.array([patch_radius+substrate_thickness, 0, 0])*unit, read_cached=True, outfile='nf2ff_xy.h5')
+
+ ax = subplot(122, polar=True)
+ E_norm = 20.0*np.log10(nf2ff_res_theta90.E_norm/np.max(nf2ff_res_theta90.E_norm)) + nf2ff_res_theta90.Dmax
+ ax.plot(np.deg2rad(phi), 10**(np.squeeze(E_norm)/20), linewidth=2, label='xy-plane')
+ ax.grid(True)
+ ax.set_xlabel('phi (deg)')
+ suptitle('Bent Patch Anteanna Pattern\nFrequency: {} GHz'.format(f_res/1e9), fontsize=14)
+ ax.legend(loc=3)
+
+ print( 'radiated power: Prad = {:.2e} Watt'.format(nf2ff_res_theta90.Prad[0]))
+ print( 'directivity: Dmax = {:.1f} ({:.1f} dBi)'.format(nf2ff_res_theta90.Dmax[0], 10*np.log10(nf2ff_res_theta90.Dmax[0])))
+ print( 'efficiency: nu_rad = {:.1f} %'.format(100*nf2ff_res_theta90.Prad[0]/real(P_in[idx[0]])))
+
+show()
+
diff --git a/openEMS/python/Tutorials/CRLH_Extraction.py b/openEMS/python/Tutorials/CRLH_Extraction.py
new file mode 100644
index 0000000..4e1850e
--- /dev/null
+++ b/openEMS/python/Tutorials/CRLH_Extraction.py
@@ -0,0 +1,239 @@
+# -*- coding: utf-8 -*-
+"""
+ Tutorials / CRLH_Extraction
+
+ Describtion at:
+ http://openems.de/index.php/Tutorial:_CRLH_Extraction
+
+ Tested with
+ - python 3.4
+ - openEMS v0.0.34+
+
+ (C) 2016 Thorsten Liebig <thorsten.liebig@gmx.de>
+"""
+
+
+### Import Libraries
+import os, tempfile
+from pylab import *
+
+from CSXCAD import ContinuousStructure
+from openEMS import openEMS
+from openEMS.physical_constants import *
+
+### Class to represent single CRLH unit cells
+class CRLH_Cells:
+ def __init__(self, LL, LW, Top, Bot, GLT, GLB, SL, SW, VR):
+ self.LL = LL # Line length
+ self.LW = LW # Line width
+ self.Top = Top # top signal height
+ self.Bot = Bot # bottom signal height
+ self.GLT = GLT # gap length top
+ self.GLB = GLB # gap length bottom
+ self.SL = SL # stub length
+ self.SW = SW # stub width
+ self.VR = VR # via radius
+ self.props = dict() # property dictionary
+ self.edge_resolution = None
+
+ def createProperties(self, CSX):
+ for p in ['metal_top', 'metal_bot', 'via']:
+ self.props[p] = CSX.AddMetal(p)
+
+ def setEdgeResolution(self, res):
+ self.edge_resolution = res
+
+ def createCell(self, translate = [0,0,0]):
+ def append_mesh(mesh1, mesh2):
+ for n in range(3):
+ if mesh1[n] is None:
+ mesh1[n] = mesh2[n]
+ elif mesh2[n] is None:
+ continue
+ else:
+ mesh1[n] += mesh2[n]
+ return mesh1
+ translate = array(translate)
+ start = [-self.LL/2 , -self.LW/2, self.Top] + translate
+ stop = [-self.GLT/2, self.LW/2, self.Top] + translate
+ box = self.props['metal_top'].AddBox(start, stop, priority=10)
+ mesh = box.GetGridHint('x', metal_edge_res=self.edge_resolution, down_dir=False)
+ append_mesh(mesh, box.GetGridHint('y', metal_edge_res=self.edge_resolution) )
+
+ start = [+self.LL/2 , -self.LW/2, self.Top] + translate
+ stop = [+self.GLT/2, self.LW/2, self.Top] + translate
+ box = self.props['metal_top'].AddBox(start, stop, priority=10)
+ append_mesh(mesh, box.GetGridHint('x', metal_edge_res=self.edge_resolution, up_dir=False) )
+
+ start = [-(self.LL-self.GLB)/2, -self.LW/2, self.Bot] + translate
+ stop = [+(self.LL-self.GLB)/2, self.LW/2, self.Bot] + translate
+ box = self.props['metal_bot'].AddBox(start, stop, priority=10)
+ append_mesh(mesh, box.GetGridHint('x', metal_edge_res=self.edge_resolution) )
+
+ start = [-self.SW/2, -self.LW/2-self.SL, self.Bot] + translate
+ stop = [+self.SW/2, self.LW/2+self.SL, self.Bot] + translate
+ box = self.props['metal_bot'].AddBox(start, stop, priority=10)
+ append_mesh(mesh, box.GetGridHint('xy', metal_edge_res=self.edge_resolution) )
+
+ start = [0, -self.LW/2-self.SL+self.SW/2, 0 ] + translate
+ stop = [0, -self.LW/2-self.SL+self.SW/2, self.Bot] + translate
+
+ self.props['via'].AddCylinder(start, stop, radius=self.VR, priority=10)
+
+ start[1] *= -1
+ stop [1] *= -1
+ self.props['via'].AddCylinder(start, stop, radius=self.VR, priority=10)
+
+ return mesh
+
+
+if __name__ == '__main__':
+ ### Setup the simulation
+ Sim_Path = os.path.join(tempfile.gettempdir(), 'CRLH_Extraction')
+ post_proc_only = False
+
+ unit = 1e-6 # specify everything in um
+
+ feed_length = 30000
+
+ substrate_thickness = [1524, 101 , 254 ]
+ substrate_epsr = [3.48, 3.48, 3.48]
+
+ CRLH = CRLH_Cells(LL = 14e3, LW = 4e3, GLB = 1950, GLT = 4700, SL = 7800, SW = 1000, VR = 250 , \
+ Top = sum(substrate_thickness), \
+ Bot = sum(substrate_thickness[:-1]))
+
+ # frequency range of interest
+ f_start = 0.8e9
+ f_stop = 6e9
+
+ ### Setup FDTD parameters & excitation function
+ CSX = ContinuousStructure()
+ FDTD = openEMS(EndCriteria=1e-5)
+ FDTD.SetCSX(CSX)
+ mesh = CSX.GetGrid()
+ mesh.SetDeltaUnit(unit)
+
+ CRLH.createProperties(CSX)
+
+ FDTD.SetGaussExcite((f_start+f_stop)/2, (f_stop-f_start)/2 )
+ BC = {'PML_8' 'PML_8' 'MUR' 'MUR' 'PEC' 'PML_8'}
+ FDTD.SetBoundaryCond( ['PML_8', 'PML_8', 'MUR', 'MUR', 'PEC', 'PML_8'] )
+
+ ### Setup a basic mesh and create the CRLH unit cell
+ resolution = C0/(f_stop*sqrt(max(substrate_epsr)))/unit /30 # resolution of lambda/30
+ CRLH.setEdgeResolution(resolution/4)
+
+ mesh.SetLines('x', [-feed_length-CRLH.LL/2, 0, feed_length+CRLH.LL/2])
+ mesh.SetLines('y', [-30000, 0, 30000])
+
+ substratelines = cumsum(substrate_thickness)
+ mesh.SetLines('z', [0, 20000])
+ mesh.AddLine('z', cumsum(substrate_thickness))
+ mesh.AddLine('z', linspace(substratelines[-2],substratelines[-1],4))
+
+ # create the CRLH unit cell (will define additional fixed mesh lines)
+ mesh_hint = CRLH.createCell()
+ mesh.AddLine('x', mesh_hint[0])
+ mesh.AddLine('y', mesh_hint[1])
+
+ # Smooth the given mesh
+ mesh.SmoothMeshLines('all', resolution, 1.2)
+
+ ### Setup the substrate layer
+ substratelines = [0] + substratelines.tolist()
+ start, stop = mesh.GetSimArea()
+
+ for n in range(len(substrate_thickness)):
+ sub = CSX.AddMaterial( 'substrate_{}'.format(n), epsilon=substrate_epsr[n] )
+ start[2] = substratelines[n]
+ stop [2] = substratelines[n+1]
+
+ sub.AddBox( start, stop )
+
+ ### Add the feeding MSL ports
+ pec = CSX.AddMetal( 'PEC' )
+ port = [None, None]
+ x_lines = mesh.GetLines('x')
+ portstart = [ x_lines[0], -CRLH.LW/2, substratelines[-1]]
+ portstop = [ -CRLH.LL/2, CRLH.LW/2, 0]
+ port[0] = FDTD.AddMSLPort( 1, pec, portstart, portstop, 'x', 'z', excite=-1, FeedShift=10*resolution, MeasPlaneShift=feed_length/2, priority=10)
+
+
+ portstart = [ x_lines[-1], -CRLH.LW/2, substratelines[-1]]
+ portstop = [ +CRLH.LL/2 , CRLH.LW/2, 0]
+ port[1] = FDTD.AddMSLPort( 2, pec, portstart, portstop, 'x', 'z', MeasPlaneShift=feed_length/2, priority=10)
+
+ ### Run the simulation
+ if 1: # debugging only
+ CSX_file = os.path.join(Sim_Path, 'CRLH_Extraction.xml')
+ if not os.path.exists(Sim_Path):
+ os.mkdir(Sim_Path)
+ CSX.Write2XML(CSX_file)
+ os.system(r'AppCSXCAD "{}"'.format(CSX_file))
+
+ if not post_proc_only:
+ FDTD.Run(Sim_Path, verbose=3, cleanup=True)
+
+ ### Post-Processing
+ f = linspace( f_start, f_stop, 1601 )
+ for p in port:
+ p.CalcPort( Sim_Path, f, ref_impedance = 50, ref_plane_shift = feed_length)
+
+ # calculate and plot scattering parameter
+ s11 = port[0].uf_ref / port[0].uf_inc
+ s21 = port[1].uf_ref / port[0].uf_inc
+
+ plot(f/1e9,20*log10(abs(s11)),'k-' , linewidth=2, label='$S_{11}$')
+ plot(f/1e9,20*log10(abs(s21)),'r--', linewidth=2, label='$S_{21}$')
+ grid()
+ legend(loc=3)
+ ylabel('S-Parameter (dB)')
+ xlabel('frequency (GHz)')
+ ylim([-40, 2])
+
+ ### Extract CRLH parameter form ABCD matrix
+ A = ((1+s11)*(1-s11) + s21*s21)/(2*s21)
+ C = ((1-s11)*(1-s11) - s21*s21)/(2*s21) / port[1].Z_ref
+
+ Y = C
+ Z = 2*(A-1)/C
+
+ iZ = imag(Z)
+ iY = imag(Y)
+
+ fse = interp(0, iZ, f)
+ fsh = interp(0, iY, f)
+
+ df = f[1]-f[0]
+ fse_idx = np.where(f>fse)[0][0]
+ fsh_idx = np.where(f>fsh)[0][0]
+
+ LR = 0.5*(iZ[fse_idx]-iZ[fse_idx-1])/(2*pi*df)
+ CL = 1/(2*pi*fse)**2/LR
+
+ CR = 0.5*(iY[fsh_idx]-iY[fsh_idx-1])/(2*pi*df)
+ LL = 1/(2*pi*fsh)**2/CR
+
+ print(' Series tank: CL = {:.2f} pF, LR = {:.2f} nH -> f_se = {:.2f} GHz '.format(CL*1e12, LR*1e9, fse*1e-9))
+ print(' Shunt tank: CR = {:.2f} pF, LL = {:.2f} nH -> f_sh = {:.2f} GHz '.format(CR*1e12, LL*1e9, fsh*1e-9))
+
+ ### Calculate analytical wave-number of an inf-array of cells
+ w = 2*pi*f
+ wse = 2*pi*fse
+ wsh = 2*pi*fsh
+ beta_calc = real(arccos(1-(w**2-wse**2)*(w**2-wsh**2)/(2*w**2/CR/LR)))
+
+ # plot
+ figure()
+ beta = -angle(s21)/CRLH.LL/unit
+ plot(abs(beta)*CRLH.LL*unit/pi,f*1e-9,'k-', linewidth=2, label=r'$\beta_{CRLH,\ 1\ cell}$' )
+ grid()
+ plot(beta_calc/pi,f*1e-9,'c--', linewidth=2, label=r'$\beta_{CRLH,\ \infty\ cells}$')
+ plot(real(port[1].beta)*CRLH.LL*unit/pi,f*1e-9,'g-', linewidth=2, label=r'$\beta_{MSL}$')
+ ylim([1, 6])
+ xlabel(r'$|\beta| p / \pi$')
+ ylabel('frequency (GHz)')
+ legend(loc=2)
+
+ show() \ No newline at end of file
diff --git a/openEMS/python/Tutorials/Helical_Antenna.py b/openEMS/python/Tutorials/Helical_Antenna.py
new file mode 100644
index 0000000..3211ec8
--- /dev/null
+++ b/openEMS/python/Tutorials/Helical_Antenna.py
@@ -0,0 +1,191 @@
+# -*- coding: utf-8 -*-
+"""
+ Helical Antenna Tutorial
+
+ Tested with
+ - python 3.4
+ - openEMS v0.0.33+
+
+ (C) 2015-2016 Thorsten Liebig <thorsten.liebig@gmx.de>
+
+"""
+
+### Import Libraries
+import os, tempfile
+from pylab import *
+
+from CSXCAD import CSXCAD
+
+from openEMS import openEMS
+from openEMS.physical_constants import *
+
+
+### Setup the simulation
+Sim_Path = os.path.join(tempfile.gettempdir(), 'Helical_Ant')
+post_proc_only = False
+
+unit = 1e-3 # all length in mm
+
+f0 = 2.4e9 # center frequency, frequency of interest!
+lambda0 = round(C0/f0/unit) # wavelength in mm
+fc = 0.5e9 # 20 dB corner frequency
+
+Helix_radius = 20 # --> diameter is ~ lambda/pi
+Helix_turns = 10 # --> expected gain is G ~ 4 * 10 = 40 (16dBi)
+Helix_pitch = 30 # --> pitch is ~ lambda/4
+Helix_mesh_res = 3
+
+gnd_radius = lambda0/2
+
+# feeding
+feed_heigth = 3
+feed_R = 120 #feed impedance
+
+# size of the simulation box
+SimBox = array([1, 1, 1.5])*2.0*lambda0
+
+### Setup FDTD parameter & excitation function
+FDTD = openEMS(EndCriteria=1e-4)
+FDTD.SetGaussExcite( f0, fc )
+FDTD.SetBoundaryCond( ['MUR', 'MUR', 'MUR', 'MUR', 'MUR', 'PML_8'] )
+
+### Setup Geometry & Mesh
+CSX = CSXCAD.ContinuousStructure()
+FDTD.SetCSX(CSX)
+mesh = CSX.GetGrid()
+mesh.SetDeltaUnit(unit)
+
+max_res = floor(C0 / (f0+fc) / unit / 20) # cell size: lambda/20
+
+# create helix mesh
+mesh.AddLine('x', [-Helix_radius, 0, Helix_radius])
+mesh.SmoothMeshLines('x', Helix_mesh_res)
+# add the air-box
+mesh.AddLine('x', [-SimBox[0]/2-gnd_radius, SimBox[0]/2+gnd_radius])
+# create a smooth mesh between specified fixed mesh lines
+mesh.SmoothMeshLines('x', max_res, ratio=1.4)
+
+# copy x-mesh to y-direction
+mesh.SetLines('y', mesh.GetLines('x'))
+
+# create helix mesh in z-direction
+mesh.AddLine('z', [0, feed_heigth, Helix_turns*Helix_pitch+feed_heigth])
+mesh.SmoothMeshLines('z', Helix_mesh_res)
+
+# add the air-box
+mesh.AddLine('z', [-SimBox[2]/2, max(mesh.GetLines('z'))+SimBox[2]/2 ])
+# create a smooth mesh between specified fixed mesh lines
+mesh.SmoothMeshLines('z', max_res, ratio=1.4)
+
+### Create the Geometry
+## * Create the metal helix using the wire primitive.
+## * Create a metal gorund plane as cylinder.
+# create a perfect electric conductor (PEC)
+helix_metal = CSX.AddMetal('helix' )
+
+ang = linspace(0,2*pi,21)
+coil_x = Helix_radius*cos(ang)
+coil_y = Helix_radius*sin(ang)
+coil_z = ang/2/pi*Helix_pitch
+
+Helix_x=np.array([])
+Helix_y=np.array([])
+Helix_z=np.array([])
+zpos = feed_heigth
+for n in range(Helix_turns-1):
+ Helix_x = r_[Helix_x, coil_x]
+ Helix_y = r_[Helix_y, coil_y]
+ Helix_z = r_[Helix_z ,coil_z+zpos]
+ zpos = zpos + Helix_pitch
+
+p = np.array([Helix_x, Helix_y, Helix_z])
+helix_metal.AddCurve(p)
+
+# create ground circular ground
+gnd = CSX.AddMetal( 'gnd' ) # create a perfect electric conductor (PEC)
+
+# add a box using cylindrical coordinates
+start = [0, 0, -0.1]
+stop = [0, 0, 0.1]
+gnd.AddCylinder(start, stop, radius=gnd_radius)
+
+# apply the excitation & resist as a current source
+start = [Helix_radius, 0, 0]
+stop = [Helix_radius, 0, feed_heigth]
+port = FDTD.AddLumpedPort(1 ,feed_R, start, stop, 'z', 1.0, priority=5)
+
+# nf2ff calc
+nf2ff = FDTD.CreateNF2FFBox(opt_resolution=[lambda0/15]*3)
+
+### Run the simulation
+if 0: # debugging only
+ CSX_file = os.path.join(Sim_Path, 'helix.xml')
+ if not os.path.exists(Sim_Path):
+ os.mkdir(Sim_Path)
+ CSX.Write2XML(CSX_file)
+ os.system(r'AppCSXCAD "{}"'.format(CSX_file))
+
+if not post_proc_only:
+ FDTD.Run(Sim_Path, verbose=3, cleanup=True)
+
+### Postprocessing & plotting
+freq = linspace( f0-fc, f0+fc, 501 )
+port.CalcPort(Sim_Path, freq)
+
+Zin = port.uf_tot / port.if_tot
+s11 = port.uf_ref / port.uf_inc
+
+## Plot the feed point impedance
+figure()
+plot( freq/1e6, real(Zin), 'k-', linewidth=2, label=r'$\Re(Z_{in})$' )
+grid()
+plot( freq/1e6, imag(Zin), 'r--', linewidth=2, label=r'$\Im(Z_{in})$' )
+title( 'feed point impedance' )
+xlabel( 'frequency (MHz)' )
+ylabel( 'impedance ($\Omega$)' )
+legend( )
+
+## Plot reflection coefficient S11
+figure()
+plot( freq/1e6, 20*log10(abs(s11)), 'k-', linewidth=2 )
+grid()
+title( 'reflection coefficient $S_{11}$' )
+xlabel( 'frequency (MHz)' )
+ylabel( 'reflection coefficient $|S_{11}|$' )
+
+### Create the NFFF contour
+## * calculate the far field at phi=0 degrees and at phi=90 degrees
+theta = arange(0.,180.,1.)
+phi = arange(-180,180,2)
+disp( 'calculating the 3D far field...' )
+
+nf2ff_res = nf2ff.CalcNF2FF(Sim_Path, f0, theta, phi, read_cached=True, verbose=True )
+
+Dmax_dB = 10*log10(nf2ff_res.Dmax[0])
+E_norm = 20.0*log10(nf2ff_res.E_norm[0]/np.max(nf2ff_res.E_norm[0])) + 10*log10(nf2ff_res.Dmax[0])
+
+theta_HPBW = theta[ np.where(squeeze(E_norm[:,phi==0])<Dmax_dB-3)[0][0] ]
+
+## * Display power and directivity
+print('radiated power: Prad = {} W'.format(nf2ff_res.Prad[0]))
+print('directivity: Dmax = {} dBi'.format(Dmax_dB))
+print('efficiency: nu_rad = {} %'.format(100*nf2ff_res.Prad[0]/interp(f0, freq, port.P_acc)))
+print('theta_HPBW = {} °'.format(theta_HPBW))
+
+E_norm = 20.0*log10(nf2ff_res.E_norm[0]/np.max(nf2ff_res.E_norm[0])) + 10*log10(nf2ff_res.Dmax[0])
+E_CPRH = 20.0*log10(np.abs(nf2ff_res.E_cprh[0])/np.max(nf2ff_res.E_norm[0])) + 10*log10(nf2ff_res.Dmax[0])
+E_CPLH = 20.0*log10(np.abs(nf2ff_res.E_cplh[0])/np.max(nf2ff_res.E_norm[0])) + 10*log10(nf2ff_res.Dmax[0])
+
+## * Plot the pattern
+figure()
+plot(theta, E_norm[:,phi==0],'k-' , linewidth=2, label='$|E|$')
+plot(theta, E_CPRH[:,phi==0],'g--', linewidth=2, label='$|E_{CPRH}|$')
+plot(theta, E_CPLH[:,phi==0],'r-.', linewidth=2, label='$|E_{CPLH}|$')
+grid()
+xlabel('theta (deg)')
+ylabel('directivity (dBi)')
+title('Frequency: {} GHz'.format(nf2ff_res.freq[0]/1e9))
+legend()
+
+show()
+
diff --git a/openEMS/python/Tutorials/MSL_NotchFilter.py b/openEMS/python/Tutorials/MSL_NotchFilter.py
new file mode 100644
index 0000000..f036e0f
--- /dev/null
+++ b/openEMS/python/Tutorials/MSL_NotchFilter.py
@@ -0,0 +1,123 @@
+# -*- coding: utf-8 -*-
+"""
+ Microstrip Notch Filter Tutorial
+
+ Describtion at:
+ http://openems.de/doc/openEMS/Tutorials.html#microstrip-notch-filter
+
+ Tested with
+ - python 3.4
+ - openEMS v0.0.34+
+
+ (C) 2016 Thorsten Liebig <thorsten.liebig@gmx.de>
+
+"""
+
+### Import Libraries
+import os, tempfile
+from pylab import *
+
+from CSXCAD import ContinuousStructure
+from openEMS import openEMS
+from openEMS.physical_constants import *
+
+
+### Setup the simulation
+Sim_Path = os.path.join(tempfile.gettempdir(), 'NotchFilter')
+post_proc_only = False
+
+unit = 1e-6 # specify everything in um
+MSL_length = 50000
+MSL_width = 600
+substrate_thickness = 254
+substrate_epr = 3.66
+stub_length = 12e3
+f_max = 7e9
+
+### Setup FDTD parameters & excitation function
+FDTD = openEMS()
+FDTD.SetGaussExcite( f_max/2, f_max/2 )
+FDTD.SetBoundaryCond( ['PML_8', 'PML_8', 'MUR', 'MUR', 'PEC', 'MUR'] )
+
+### Setup Geometry & Mesh
+CSX = ContinuousStructure()
+FDTD.SetCSX(CSX)
+mesh = CSX.GetGrid()
+mesh.SetDeltaUnit(unit)
+
+resolution = C0/(f_max*sqrt(substrate_epr))/unit/50 # resolution of lambda/50
+third_mesh = array([2*resolution/3, -resolution/3])/4
+
+## Do manual meshing
+mesh.AddLine('x', 0)
+mesh.AddLine('x', MSL_width/2+third_mesh)
+mesh.AddLine('x', -MSL_width/2-third_mesh)
+mesh.SmoothMeshLines('x', resolution/4)
+
+mesh.AddLine('x', [-MSL_length, MSL_length])
+mesh.SmoothMeshLines('x', resolution)
+
+mesh.AddLine('y', 0)
+mesh.AddLine('y', MSL_width/2+third_mesh)
+mesh.AddLine('y', -MSL_width/2-third_mesh)
+mesh.SmoothMeshLines('y', resolution/4)
+
+mesh.AddLine('y', [-15*MSL_width, 15*MSL_width+stub_length])
+mesh.AddLine('y', (MSL_width/2+stub_length)+third_mesh)
+mesh.SmoothMeshLines('y', resolution)
+
+mesh.AddLine('z', linspace(0,substrate_thickness,5))
+mesh.AddLine('z', 3000)
+mesh.SmoothMeshLines('z', resolution)
+
+## Add the substrate
+substrate = CSX.AddMaterial( 'RO4350B', epsilon=substrate_epr)
+start = [-MSL_length, -15*MSL_width, 0]
+stop = [+MSL_length, +15*MSL_width+stub_length, substrate_thickness]
+substrate.AddBox(start, stop )
+
+## MSL port setup
+port = [None, None]
+pec = CSX.AddMetal( 'PEC' )
+portstart = [ -MSL_length, -MSL_width/2, substrate_thickness]
+portstop = [ 0, MSL_width/2, 0]
+port[0] = FDTD.AddMSLPort( 1, pec, portstart, portstop, 'x', 'z', excite=-1, FeedShift=10*resolution, MeasPlaneShift=MSL_length/3, priority=10)
+
+portstart = [MSL_length, -MSL_width/2, substrate_thickness]
+portstop = [0 , MSL_width/2, 0]
+port[1] = FDTD.AddMSLPort( 2, pec, portstart, portstop, 'x', 'z', MeasPlaneShift=MSL_length/3, priority=10 )
+
+## Filter-Stub Definition
+start = [-MSL_width/2, MSL_width/2, substrate_thickness]
+stop = [ MSL_width/2, MSL_width/2+stub_length, substrate_thickness]
+pec.AddBox(start, stop, priority=10 )
+
+### Run the simulation
+if 0: # debugging only
+ CSX_file = os.path.join(Sim_Path, 'notch.xml')
+ if not os.path.exists(Sim_Path):
+ os.mkdir(Sim_Path)
+ CSX.Write2XML(CSX_file)
+ os.system(r'AppCSXCAD "{}"'.format(CSX_file))
+
+
+if not post_proc_only:
+ FDTD.Run(Sim_Path, verbose=3, cleanup=True)
+
+### Post-processing and plotting
+f = linspace( 1e6, f_max, 1601 )
+for p in port:
+ p.CalcPort( Sim_Path, f, ref_impedance = 50)
+
+s11 = port[0].uf_ref / port[0].uf_inc
+s21 = port[1].uf_ref / port[0].uf_inc
+
+plot(f/1e9,20*log10(abs(s11)),'k-',linewidth=2 , label='$S_{11}$')
+grid()
+plot(f/1e9,20*log10(abs(s21)),'r--',linewidth=2 , label='$S_{21}$')
+legend()
+ylabel('S-Parameter (dB)')
+xlabel('frequency (GHz)')
+ylim([-40, 2])
+
+show()
diff --git a/openEMS/python/Tutorials/RCS_Sphere.py b/openEMS/python/Tutorials/RCS_Sphere.py
new file mode 100644
index 0000000..df801ce
--- /dev/null
+++ b/openEMS/python/Tutorials/RCS_Sphere.py
@@ -0,0 +1,126 @@
+# -*- coding: utf-8 -*-
+"""
+ Tutorials / radar cross section of a metal sphere
+
+ Tested with
+ - python 3.4
+ - openEMS v0.0.34+
+
+ (C) 2016 Thorsten Liebig <thorsten.liebig@gmx.de>
+"""
+
+### Import Libraries
+import os, tempfile
+from pylab import *
+
+from CSXCAD import ContinuousStructure
+from openEMS import openEMS
+from openEMS.physical_constants import *
+from openEMS.ports import UI_data
+
+### Setup the simulation
+Sim_Path = os.path.join(tempfile.gettempdir(), 'RCS_Sphere')
+post_proc_only = False
+
+unit = 1e-3 # all length in mm
+
+sphere_rad = 200
+
+inc_angle = 0 #incident angle (to x-axis) in deg
+
+# size of the simulation box
+SimBox = 1200
+PW_Box = 750
+
+### Setup FDTD parameters & excitation function
+FDTD = openEMS(EndCriteria=1e-5)
+
+f_start = 50e6 # start frequency
+f_stop = 1000e6 # stop frequency
+f0 = 500e6
+FDTD.SetGaussExcite( 0.5*(f_start+f_stop), 0.5*(f_stop-f_start) )
+
+FDTD.SetBoundaryCond( ['PML_8', 'PML_8', 'PML_8', 'PML_8', 'PML_8', 'PML_8'] )
+
+### Setup Geometry & Mesh
+CSX = ContinuousStructure()
+FDTD.SetCSX(CSX)
+mesh = CSX.GetGrid()
+mesh.SetDeltaUnit(unit)
+
+#create mesh
+mesh.SetLines('x', [-SimBox/2, 0, SimBox/2])
+mesh.SmoothMeshLines('x', C0 / f_stop / unit / 20) # cell size: lambda/20
+mesh.SetLines('y', mesh.GetLines('x'))
+mesh.SetLines('z', mesh.GetLines('x'))
+
+### Create a metal sphere and plane wave source
+sphere_metal = CSX.AddMetal( 'sphere' ) # create a perfect electric conductor (PEC)
+sphere_metal.AddSphere(priority=10, center=[0, 0, 0], radius=sphere_rad)
+
+# plane wave excitation
+k_dir = [cos(inc_angle), sin(inc_angle), 0] # plane wave direction
+E_dir = [0, 0, 1] # plane wave polarization --> E_z
+
+pw_exc = CSX.AddExcitation('plane_wave', exc_type=10, exc_val=E_dir)
+pw_exc.SetPropagationDir(k_dir)
+pw_exc.SetFrequency(f0)
+
+start = np.array([-PW_Box/2, -PW_Box/2, -PW_Box/2])
+stop = -start
+pw_exc.AddBox(start, stop)
+
+# nf2ff calc
+nf2ff = FDTD.CreateNF2FFBox()
+
+### Run the simulation
+if 0: # debugging only
+ CSX_file = os.path.join(Sim_Path, 'RCS_Sphere.xml')
+ if not os.path.exists(Sim_Path):
+ os.mkdir(Sim_Path)
+ CSX.Write2XML(CSX_file)
+ os.system(r'AppCSXCAD "{}"'.format(CSX_file))
+
+
+if not post_proc_only:
+ FDTD.Run(Sim_Path, verbose=3, cleanup=True)
+
+### Postprocessing & plotting
+# get Gaussian pulse stength at frequency f0
+ef = UI_data('et', Sim_Path, freq=f0)
+
+Pin = 0.5*norm(E_dir)**2/Z0 * abs(ef.ui_f_val[0])**2
+#
+nf2ff_res = nf2ff.CalcNF2FF(Sim_Path, f0, 90, arange(-180, 180.1, 2))
+RCS = 4*pi/Pin[0]*nf2ff_res.P_rad[0]
+
+fig = figure()
+ax = fig.add_subplot(111, polar=True)
+ax.plot( nf2ff_res.phi, RCS[0], 'k-', linewidth=2 )
+ax.grid(True)
+
+# calculate RCS over frequency
+freq = linspace(f_start,f_stop,100)
+ef = UI_data( 'et', Sim_Path, freq ) # time domain/freq domain voltage
+Pin = 0.5*norm(E_dir)**2/Z0 * abs(np.array(ef.ui_f_val[0]))**2
+
+nf2ff_res = nf2ff.CalcNF2FF(Sim_Path, freq, 90, 180+inc_angle, outfile='back_nf2ff.h5')
+
+back_scat = np.array([4*pi/Pin[fn]*nf2ff_res.P_rad[fn][0][0] for fn in range(len(freq))])
+
+figure()
+plot(freq/1e6,back_scat, linewidth=2)
+grid()
+xlabel('frequency (MHz)')
+ylabel('RCS ($m^2$)')
+title('radar cross section')
+
+figure()
+semilogy(sphere_rad*unit/C0*freq,back_scat/(pi*sphere_rad*unit*sphere_rad*unit), linewidth=2)
+ylim([10^-2, 10^1])
+grid()
+xlabel('sphere radius / wavelength')
+ylabel('RCS / ($\pi a^2$)')
+title('normalized radar cross section')
+
+show() \ No newline at end of file
diff --git a/openEMS/python/Tutorials/Rect_Waveguide.py b/openEMS/python/Tutorials/Rect_Waveguide.py
new file mode 100644
index 0000000..5d38115
--- /dev/null
+++ b/openEMS/python/Tutorials/Rect_Waveguide.py
@@ -0,0 +1,125 @@
+# -*- coding: utf-8 -*-
+"""
+ Rectangular Waveguide Tutorial
+
+ Describtion at:
+ http://openems.de/doc/openEMS/Tutorials.html#rectangular-waveguide
+
+ Tested with
+ - python 3.4
+ - openEMS v0.0.34+
+
+ (C) 2015-2016 Thorsten Liebig <thorsten.liebig@gmx.de>
+
+"""
+
+### Import Libraries
+import os, tempfile
+from pylab import *
+
+from CSXCAD import ContinuousStructure
+from openEMS import openEMS
+from openEMS.physical_constants import *
+
+### Setup the simulation
+Sim_Path = os.path.join(tempfile.gettempdir(), 'Rect_WG')
+
+post_proc_only = False
+unit = 1e-6; #drawing unit in um
+
+# waveguide dimensions
+# WR42
+a = 10700; #waveguide width
+b = 4300; #waveguide heigth
+length = 50000;
+
+# frequency range of interest
+f_start = 20e9;
+f_0 = 24e9;
+f_stop = 26e9;
+lambda0 = C0/f_0/unit;
+
+#waveguide TE-mode definition
+TE_mode = 'TE10';
+
+#targeted mesh resolution
+mesh_res = lambda0/30
+
+### Setup FDTD parameter & excitation function
+FDTD = openEMS(NrTS=1e4);
+FDTD.SetGaussExcite(0.5*(f_start+f_stop),0.5*(f_stop-f_start));
+
+# boundary conditions
+FDTD.SetBoundaryCond([0, 0, 0, 0, 3, 3]);
+
+### Setup geometry & mesh
+CSX = ContinuousStructure()
+FDTD.SetCSX(CSX)
+mesh = CSX.GetGrid()
+mesh.SetDeltaUnit(unit)
+
+mesh.AddLine('x', [0, a])
+mesh.AddLine('y', [0, b])
+mesh.AddLine('z', [0, length])
+
+## Apply the waveguide port
+ports = []
+start=[0, 0, 10*mesh_res];
+stop =[a, b, 15*mesh_res];
+mesh.AddLine('z', [start[2], stop[2]])
+ports.append(FDTD.AddRectWaveGuidePort( 0, start, stop, 'z', a*unit, b*unit, TE_mode, 1))
+
+start=[0, 0, length-10*mesh_res];
+stop =[a, b, length-15*mesh_res];
+mesh.AddLine('z', [start[2], stop[2]])
+ports.append(FDTD.AddRectWaveGuidePort( 1, start, stop, 'z', a*unit, b*unit, TE_mode))
+
+mesh.SmoothMeshLines('all', mesh_res, ratio=1.4)
+
+### Define dump box...
+Et = CSX.AddDump('Et', file_type=0, sub_sampling=[2,2,2])
+start = [0, 0, 0];
+stop = [a, b, length];
+Et.AddBox(start, stop);
+
+### Run the simulation
+if 0: # debugging only
+ CSX_file = os.path.join(Sim_Path, 'rect_wg.xml')
+ if not os.path.exists(Sim_Path):
+ os.mkdir(Sim_Path)
+ CSX.Write2XML(CSX_file)
+ os.system(r'AppCSXCAD "{}"'.format(CSX_file))
+
+if not post_proc_only:
+ FDTD.Run(Sim_Path, verbose=3, cleanup=True)
+
+### Postprocessing & plotting
+freq = linspace(f_start,f_stop,201)
+for port in ports:
+ port.CalcPort(Sim_Path, freq)
+
+s11 = ports[0].uf_ref / ports[0].uf_inc
+s21 = ports[1].uf_ref / ports[0].uf_inc
+ZL = ports[0].uf_tot / ports[0].if_tot
+ZL_a = ports[0].ZL # analytic waveguide impedance
+
+## Plot s-parameter
+figure()
+plot(freq*1e-6,20*log10(abs(s11)),'k-',linewidth=2, label='$S_{11}$')
+grid()
+plot(freq*1e-6,20*log10(abs(s21)),'r--',linewidth=2, label='$S_{21}$')
+legend();
+ylabel('S-Parameter (dB)')
+xlabel(r'frequency (MHz) $\rightarrow$')
+
+## Compare analytic and numerical wave-impedance
+figure()
+plot(freq*1e-6,real(ZL), linewidth=2, label='$\Re\{Z_L\}$')
+grid()
+plot(freq*1e-6,imag(ZL),'r--', linewidth=2, label='$\Im\{Z_L\}$')
+plot(freq*1e-6,ZL_a,'g-.',linewidth=2, label='$Z_{L, analytic}$')
+ylabel('ZL $(\Omega)$')
+xlabel(r'frequency (MHz) $\rightarrow$')
+legend()
+
+show()
diff --git a/openEMS/python/Tutorials/Simple_Patch_Antenna.py b/openEMS/python/Tutorials/Simple_Patch_Antenna.py
new file mode 100644
index 0000000..cd80f78
--- /dev/null
+++ b/openEMS/python/Tutorials/Simple_Patch_Antenna.py
@@ -0,0 +1,151 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Fri Dec 18 20:56:53 2015
+
+@author: thorsten
+"""
+
+### Import Libraries
+import os, tempfile
+from pylab import *
+
+from CSXCAD import ContinuousStructure
+from openEMS import openEMS
+from openEMS.physical_constants import *
+
+### General parameter setup
+Sim_Path = os.path.join(tempfile.gettempdir(), 'Simp_Patch')
+
+post_proc_only = False
+
+# patch width (resonant length) in x-direction
+patch_width = 32 #
+# patch length in y-direction
+patch_length = 40
+
+#substrate setup
+substrate_epsR = 3.38
+substrate_kappa = 1e-3 * 2*pi*2.45e9 * EPS0*substrate_epsR
+substrate_width = 60
+substrate_length = 60
+substrate_thickness = 1.524
+substrate_cells = 4
+
+#setup feeding
+feed_pos = -6 #feeding position in x-direction
+feed_R = 50 #feed resistance
+
+# size of the simulation box
+SimBox = np.array([200, 200, 150])
+
+# setup FDTD parameter & excitation function
+f0 = 2e9 # center frequency
+fc = 1e9 # 20 dB corner frequency
+
+### FDTD setup
+## * Limit the simulation to 30k timesteps
+## * Define a reduced end criteria of -40dB
+FDTD = openEMS(NrTS=30000, EndCriteria=1e-4)
+FDTD.SetGaussExcite( f0, fc )
+FDTD.SetBoundaryCond( ['MUR', 'MUR', 'MUR', 'MUR', 'MUR', 'MUR'] )
+
+
+CSX = ContinuousStructure()
+FDTD.SetCSX(CSX)
+mesh = CSX.GetGrid()
+mesh.SetDeltaUnit(1e-3)
+mesh_res = C0/(f0+fc)/1e-3/20
+
+### Generate properties, primitives and mesh-grid
+#initialize the mesh with the "air-box" dimensions
+mesh.AddLine('x', [-SimBox[0]/2, SimBox[0]/2])
+mesh.AddLine('y', [-SimBox[1]/2, SimBox[1]/2] )
+mesh.AddLine('z', [-SimBox[2]/3, SimBox[2]*2/3] )
+
+# create patch
+patch = CSX.AddMetal( 'patch' ) # create a perfect electric conductor (PEC)
+start = [-patch_width/2, -patch_length/2, substrate_thickness]
+stop = [ patch_width/2 , patch_length/2, substrate_thickness]
+patch.AddBox(priority=10, start=start, stop=stop) # add a box-primitive to the metal property 'patch'
+FDTD.AddEdges2Grid(dirs='xy', properties=patch, metal_edge_res=mesh_res/2)
+
+# create substrate
+substrate = CSX.AddMaterial( 'substrate', epsilon=substrate_epsR, kappa=substrate_kappa)
+start = [-substrate_width/2, -substrate_length/2, 0]
+stop = [ substrate_width/2, substrate_length/2, substrate_thickness]
+substrate.AddBox( priority=0, start=start, stop=stop )
+
+# add extra cells to discretize the substrate thickness
+mesh.AddLine('z', linspace(0,substrate_thickness,substrate_cells+1))
+
+# create ground (same size as substrate)
+gnd = CSX.AddMetal( 'gnd' ) # create a perfect electric conductor (PEC)
+start[2]=0
+stop[2] =0
+gnd.AddBox(start, stop, priority=10)
+
+FDTD.AddEdges2Grid(dirs='xy', properties=gnd)
+
+# apply the excitation & resist as a current source
+start = [feed_pos, 0, 0]
+stop = [feed_pos, 0, substrate_thickness]
+port = FDTD.AddLumpedPort(1, feed_R, start, stop, 'z', 1.0, priority=5, edges2grid='xy')
+
+mesh.SmoothMeshLines('all', mesh_res, 1.4)
+
+# Add the nf2ff recording box
+nf2ff = FDTD.CreateNF2FFBox()
+
+### Run the simulation
+if 0: # debugging only
+ CSX_file = os.path.join(Sim_Path, 'simp_patch.xml')
+ if not os.path.exists(Sim_Path):
+ os.mkdir(Sim_Path)
+ CSX.Write2XML(CSX_file)
+ os.system(r'AppCSXCAD "{}"'.format(CSX_file))
+
+if not post_proc_only:
+ FDTD.Run(Sim_Path, verbose=3, cleanup=True)
+
+
+### Post-processing and plotting
+f = np.linspace(max(1e9,f0-fc),f0+fc,401)
+port.CalcPort(Sim_Path, f)
+s11 = port.uf_ref/port.uf_inc
+s11_dB = 20.0*np.log10(np.abs(s11))
+figure()
+plot(f/1e9, s11_dB, 'k-', linewidth=2, label='$S_{11}$')
+grid()
+legend()
+ylabel('S-Parameter (dB)')
+xlabel('Frequency (GHz)')
+
+idx = np.where((s11_dB<-10) & (s11_dB==np.min(s11_dB)))[0]
+if not len(idx)==1:
+ print('No resonance frequency found for far-field calulation')
+else:
+ f_res = f[idx[0]]
+ theta = np.arange(-180.0, 180.0, 2.0)
+ phi = [0., 90.]
+ nf2ff_res = nf2ff.CalcNF2FF(Sim_Path, f_res, theta, phi, center=[0,0,1e-3])
+
+ figure()
+ E_norm = 20.0*np.log10(nf2ff_res.E_norm[0]/np.max(nf2ff_res.E_norm[0])) + nf2ff_res.Dmax[0]
+ plot(theta, np.squeeze(E_norm[:,0]), 'k-', linewidth=2, label='xz-plane')
+ plot(theta, np.squeeze(E_norm[:,1]), 'r--', linewidth=2, label='yz-plane')
+ grid()
+ ylabel('Directivity (dBi)')
+ xlabel('Theta (deg)')
+ title('Frequency: {} GHz'.format(f_res/1e9))
+ legend()
+
+Zin = port.uf_tot/port.if_tot
+figure()
+plot(f/1e9, np.real(Zin), 'k-', linewidth=2, label='$\Re\{Z_{in}\}$')
+plot(f/1e9, np.imag(Zin), 'r--', linewidth=2, label='$\Im\{Z_{in}\}$')
+grid()
+legend()
+ylabel('Zin (Ohm)')
+xlabel('Frequency (GHz)')
+
+show()
diff --git a/openEMS/python/doc/Tutorials/Antenna_Tutorials.rst b/openEMS/python/doc/Tutorials/Antenna_Tutorials.rst
new file mode 100644
index 0000000..4a5927a
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/Antenna_Tutorials.rst
@@ -0,0 +1,9 @@
+Antennas
+--------
+
+.. toctree::
+ :maxdepth: 1
+
+ Simple_Patch_Antenna
+ Helical_Antenna
+ Bent_Patch_Antenna
diff --git a/openEMS/python/doc/Tutorials/Bent_Patch_Antenna.rst b/openEMS/python/doc/Tutorials/Bent_Patch_Antenna.rst
new file mode 100644
index 0000000..9582563
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/Bent_Patch_Antenna.rst
@@ -0,0 +1,35 @@
+Bent Patch Antenna
+==================
+
+* Setup & Simulate a bent patch antenna using a cylindrical mesh
+
+Introduction
+-------------
+**This tutorial covers:**
+
+* Setup of a Bent Patch Antenna (see for comparison: :ref:`simple_patch_antenna`)
+* setup of a *cylindrical FDTD mesh*.
+* Calculate the S-Parameter and input impedance
+* Calculate far-field pattern 2D/3D
+
+
+Python Script
+-------------
+Get the latest version `from git <http://www.openems.de/gitweb/?p=openEMS.git;a=blob_plain;f=matlab/Tutorials/Bent_Patch_Antenna.m;hb=refs/heads/master>`_.
+
+.. include:: ./__Bent_Patch_Antenna.txt
+
+Images
+-------------
+.. figure:: images/Bent_Patch.png
+ :width: 49%
+ :alt: alternate text
+
+ 3D view of the Bent Patch Antenna (AppCSXCAD)
+
+.. figure:: images/Bent_Patch_Pattern.png
+ :width: 80%
+ :alt: Farfield pattern
+
+ Farfield pattern on an xy- and xz-plane
+
diff --git a/openEMS/python/doc/Tutorials/CRLH_Extraction.rst b/openEMS/python/doc/Tutorials/CRLH_Extraction.rst
new file mode 100644
index 0000000..156cf73
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/CRLH_Extraction.rst
@@ -0,0 +1,40 @@
+CRLH Parameter Extraction
+=========================
+
+* Setup a composite-right/left-handed (CRLH) unit cell and extract the equivalent circuit parameter.
+
+Introduction
+-------------
+**This tutorial covers:**
+
+* Setup a feeding mircostrip line & port
+* Apply an inhomogeneous mesh used for improved accuracy and simulation speed
+* Use an internal clss to setup a CRLH unit cell
+* Use the port voltages and currents to extract the unit cell equivalent circuit parameter
+
+.. figure:: images/CRLH_cell.png
+ :width: 80%
+ :alt: CRLH unit cell with feeding MSL.
+
+ CRLH unit cell with feeding MSL.
+
+Python Script
+-------------
+Get the latest version `from git <http://www.openems.de/gitweb/?p=openEMS.git;a=blob_plain;f=matlab/Tutorials/Bent_Patch_Antenna.m;hb=refs/heads/master>`_.
+
+.. include:: ./__CRLH_Extraction.txt
+
+Images
+-------------
+
+.. figure:: images/CRLH_Spara.png
+ :width: 80%
+ :alt: CRLH cell S-parameter
+
+ CRLH cell S-parameter
+
+.. figure:: images/CRLH_dispersion.png
+ :width: 80%
+ :alt: CRLH unit cell dispersion diagram
+
+ CRLH unit cell dispersion diagram
diff --git a/openEMS/python/doc/Tutorials/Helical_Antenna.rst b/openEMS/python/doc/Tutorials/Helical_Antenna.rst
new file mode 100644
index 0000000..6a94081
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/Helical_Antenna.rst
@@ -0,0 +1,32 @@
+Helical Antenna
+===============
+
+Introduction
+-------------
+**This tutorial covers:**
+
+* setup of a helix using the wire primitive
+* setup a lumped feeding port (R_in = 120 Ohms)
+* adding a near-field to far-field (nf2ff) box using an efficient subsampling
+* calculate the S-Parameter of the antenna
+* calculate and plot the far-field pattern
+
+Python Script
+-------------
+Get the latest version `from git <http://www.openems.de/gitweb/?p=openEMS.git;a=blob_plain;f=matlab/Tutorials/Helical_Antenna.m;hb=refs/heads/master>`_.
+
+.. include:: ./__Helical_Antenna.txt
+
+Images
+-------------
+.. figure:: images/Helix_Ant.png
+ :width: 49%
+ :alt: alternate text
+
+ 3D view of the Helical Antenna (AppCSXCAD)
+
+.. figure:: images/Helix_Ant_Pattern.png
+ :width: 49%
+ :alt: alternate text
+
+ Far-Field pattern showing a right-handed circular polarization.
diff --git a/openEMS/python/doc/Tutorials/Intro_Tutorials.rst b/openEMS/python/doc/Tutorials/Intro_Tutorials.rst
new file mode 100644
index 0000000..8126f33
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/Intro_Tutorials.rst
@@ -0,0 +1,10 @@
+.. _intro_tutorials:
+
+Introductional Tutorials
+------------------------
+
+
+.. toctree::
+
+ Rect_Waveguide
+ RCS_Sphere
diff --git a/openEMS/python/doc/Tutorials/MSL_NotchFilter.rst b/openEMS/python/doc/Tutorials/MSL_NotchFilter.rst
new file mode 100644
index 0000000..c84883e
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/MSL_NotchFilter.rst
@@ -0,0 +1,27 @@
+Microstrip Notch Filter
+=======================
+
+ * A straight MSL line with a open-ended stub to create a simple microwave filter.
+
+Introduction
+-------------
+**This tutorial covers:**
+
+
+* Setup a mircostrip line (MSL) and MSL port
+* Apply an inhomogeneous mesh used for improved accuracy and simulation speed
+* Calculate the S-Parameter of the filter
+
+Python Script
+-------------
+Get the latest version `from git <http://openems.de/gitweb/?p=openEMS.git;a=blob_plain;f=matlab/Tutorials/MSL_NotchFilter.m;hb=HEAD>`_.
+
+.. include:: ./__MSL_NotchFilter.txt
+
+Images
+-------------
+.. figure:: images/Notch_Filter_SPara.png
+ :width: 49%
+ :alt: S-Parameter over Frequency
+
+ S-Parameter over Frequency
diff --git a/openEMS/python/doc/Tutorials/MicroWave_Tutorials.rst b/openEMS/python/doc/Tutorials/MicroWave_Tutorials.rst
new file mode 100644
index 0000000..92fc0ce
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/MicroWave_Tutorials.rst
@@ -0,0 +1,10 @@
+.. _microwave_tutorials:
+
+Micro Wave Tutorials
+--------------------
+
+
+.. toctree::
+
+ MSL_NotchFilter
+ CRLH_Extraction
diff --git a/openEMS/python/doc/Tutorials/RCS_Sphere.rst b/openEMS/python/doc/Tutorials/RCS_Sphere.rst
new file mode 100644
index 0000000..1cbced8
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/RCS_Sphere.rst
@@ -0,0 +1,32 @@
+Metal Sphere Radar Cross Section
+================================
+
+ * A 3D simulation demonstrating a the total-field/scattered-field approach on a metallic sphere with a RCS (radar cross section) calculation.
+
+Introduction
+-------------
+**This tutorial covers:**
+
+
+* The total-field/scattered-field approach
+* Calculation of a radar cross section (RCS)
+
+Python Script
+-------------
+Get the latest version `from git <https://raw.githubusercontent.com/thliebig/openEMS/master/python/Tutorials/RCS_Sphere.py>`_.
+
+.. include:: ./__RCS_Sphere.txt
+
+Images
+-------------
+.. figure:: images/RCS_pattern.png
+ :width: 49%
+ :alt: Radar cross section pattern
+
+ Radar cross section pattern
+
+.. figure:: images/RCS_norm.png
+ :width: 49%
+ :alt: normalized radar cross section
+
+ Normalized radar cross Section over normalized wavelength
diff --git a/openEMS/python/doc/Tutorials/Rect_Waveguide.rst b/openEMS/python/doc/Tutorials/Rect_Waveguide.rst
new file mode 100644
index 0000000..8b955ac
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/Rect_Waveguide.rst
@@ -0,0 +1,27 @@
+Rectangular Waveguide
+=====================
+
+ * A simple rectangular waveguide, showing the openEMS mode profile capabilities.
+
+Introduction
+-------------
+**This tutorial covers:**
+
+* Setup a mode profile excitation
+* Create voltage and current probes using the mode profile
+* Calculate the waveguide impedance and S-Parameter
+
+
+Python Script
+-------------
+Get the latest version `from git <http://openems.de/gitweb/?p=openEMS.git;a=blob_plain;f=matlab/Tutorials/Rect_Waveguide.m;hb=HEAD>`_.
+
+.. include:: ./__Rect_Waveguide.txt
+
+Images
+-------------
+.. figure:: images/Rect_WG_SPara.png
+ :width: 49%
+ :alt: S-Parameter over Frequency
+
+ S-Parameter over Frequency
diff --git a/openEMS/python/doc/Tutorials/Simple_Patch_Antenna.rst b/openEMS/python/doc/Tutorials/Simple_Patch_Antenna.rst
new file mode 100644
index 0000000..4345c56
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/Simple_Patch_Antenna.rst
@@ -0,0 +1,42 @@
+.. _simple_patch_antenna:
+
+Simple Patch Antenna
+====================
+
+Introduction
+------------
+A simple patch antenna for 2.4 GHz.
+
+**This tutorial covers:**
+
+* Setup a patch, substrate and ground.
+* Setup of a lumped feeding port.
+* Adding a near-field to far-field (nf2ff) recording box.
+* Calculate the S-Parameter of the antenna.
+* Calculate and plot the far-field pattern
+
+Python Script
+-------------
+Get the latest version `from git <http://www.openems.de/gitweb/?p=openEMS.git;a=blob_plain;f=matlab/Tutorials/Simple_Patch_Antenna.m;hb=refs/heads/master>`_.
+
+.. include:: ./__Simple_Patch_Antenna.txt
+
+Images
+------
+.. figure:: images/Simp_Patch_S11.png
+ :width: 49%
+ :alt: S11 over Frequency
+
+ S-Parameter over Frequency
+
+.. figure:: images/Simp_Patch_Zin.png
+ :width: 49%
+ :alt: Input Impedance
+
+ Antenna Input Impedance
+
+.. figure:: images/Simp_Patch_Pattern.png
+ :width: 49%
+ :alt: Farfield pattern
+
+ Farfield pattern for the xy- and yz-plane.
diff --git a/openEMS/python/doc/Tutorials/images/Bent_Patch.png b/openEMS/python/doc/Tutorials/images/Bent_Patch.png
new file mode 100644
index 0000000..0beddf9
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/Bent_Patch.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/Bent_Patch_Pattern.png b/openEMS/python/doc/Tutorials/images/Bent_Patch_Pattern.png
new file mode 100644
index 0000000..4fc3211
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/Bent_Patch_Pattern.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/Bent_Patch_SPara.png b/openEMS/python/doc/Tutorials/images/Bent_Patch_SPara.png
new file mode 100644
index 0000000..d3970fb
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/Bent_Patch_SPara.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/CRLH_Spara.png b/openEMS/python/doc/Tutorials/images/CRLH_Spara.png
new file mode 100644
index 0000000..d0f4a3b
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/CRLH_Spara.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/CRLH_cell.png b/openEMS/python/doc/Tutorials/images/CRLH_cell.png
new file mode 100644
index 0000000..85ae9b7
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/CRLH_cell.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/CRLH_dispersion.png b/openEMS/python/doc/Tutorials/images/CRLH_dispersion.png
new file mode 100644
index 0000000..65fc163
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/CRLH_dispersion.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/Helix_Ant.png b/openEMS/python/doc/Tutorials/images/Helix_Ant.png
new file mode 100644
index 0000000..16c532c
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/Helix_Ant.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/Helix_Ant_Pattern.png b/openEMS/python/doc/Tutorials/images/Helix_Ant_Pattern.png
new file mode 100644
index 0000000..020aae1
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/Helix_Ant_Pattern.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/Notch_Filter_SPara.png b/openEMS/python/doc/Tutorials/images/Notch_Filter_SPara.png
new file mode 100644
index 0000000..9d1d7be
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/Notch_Filter_SPara.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/RCS_norm.png b/openEMS/python/doc/Tutorials/images/RCS_norm.png
new file mode 100644
index 0000000..57712ba
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/RCS_norm.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/RCS_pattern.png b/openEMS/python/doc/Tutorials/images/RCS_pattern.png
new file mode 100644
index 0000000..b3d9d23
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/RCS_pattern.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/Rect_WG_SPara.png b/openEMS/python/doc/Tutorials/images/Rect_WG_SPara.png
new file mode 100644
index 0000000..0c0ff27
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/Rect_WG_SPara.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/Simp_Patch_Pattern.png b/openEMS/python/doc/Tutorials/images/Simp_Patch_Pattern.png
new file mode 100644
index 0000000..2cd90d4
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/Simp_Patch_Pattern.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/Simp_Patch_S11.png b/openEMS/python/doc/Tutorials/images/Simp_Patch_S11.png
new file mode 100644
index 0000000..381bb3c
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/Simp_Patch_S11.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/images/Simp_Patch_Zin.png b/openEMS/python/doc/Tutorials/images/Simp_Patch_Zin.png
new file mode 100644
index 0000000..bbabe54
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/images/Simp_Patch_Zin.png
Binary files differ
diff --git a/openEMS/python/doc/Tutorials/index.rst b/openEMS/python/doc/Tutorials/index.rst
new file mode 100644
index 0000000..fd5c5dc
--- /dev/null
+++ b/openEMS/python/doc/Tutorials/index.rst
@@ -0,0 +1,12 @@
+.. _tutorials:
+
+#########
+Tutorials
+#########
+
+.. toctree::
+ :maxdepth: 2
+
+ Intro_Tutorials
+ MicroWave_Tutorials
+ Antenna_Tutorials
diff --git a/openEMS/python/doc/conf.py b/openEMS/python/doc/conf.py
new file mode 100644
index 0000000..b5c7b76
--- /dev/null
+++ b/openEMS/python/doc/conf.py
@@ -0,0 +1,297 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# openEMS documentation build configuration file, created by
+# sphinx-quickstart on Thu Sep 8 20:42:18 2016.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys
+import os
+import sphinx_rtd_theme
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+ 'sphinx.ext.autodoc',
+ 'sphinx.ext.intersphinx',
+ 'sphinx.ext.todo',
+ 'sphinx.ext.mathjax',
+ 'numpydoc',
+ 'sphinx.ext.autosummary',
+]
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'openEMS'
+copyright = '2016, Thorsten Liebig'
+author = 'Thorsten Liebig'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.0.34'
+# The full version, including alpha/beta/rc tags.
+release = '0.0.34'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all
+# documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+# If true, keep warnings as "system message" paragraphs in the built documents.
+#keep_warnings = False
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = True
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'sphinx_rtd_theme'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (relative to this directory) to use as a favicon of
+# the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Add any extra paths that contain custom files (such as robots.txt or
+# .htaccess) here, relative to this directory. These files are copied
+# directly to the root of the documentation.
+#html_extra_path = []
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Language to be used for generating the HTML full-text search index.
+# Sphinx supports the following languages:
+# 'da', 'de', 'en', 'es', 'fi', 'fr', 'h', 'it', 'ja'
+# 'nl', 'no', 'pt', 'ro', 'r', 'sv', 'tr'
+#html_search_language = 'en'
+
+# A dictionary with options for the search language support, empty by default.
+# Now only 'ja' uses this config value
+#html_search_options = {'type': 'default'}
+
+# The name of a javascript file (relative to the configuration directory) that
+# implements a search results scorer. If empty, the default will be used.
+#html_search_scorer = 'scorer.js'
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'openEMSdoc'
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+# The paper size ('letterpaper' or 'a4paper').
+#'papersize': 'letterpaper',
+
+# The font size ('10pt', '11pt' or '12pt').
+#'pointsize': '10pt',
+
+# Additional stuff for the LaTeX preamble.
+#'preamble': '',
+
+# Latex figure (float) alignment
+#'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'openEMS.tex', 'openEMS Documentation',
+ 'Thorsten Liebig', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'openems', 'openEMS Documentation',
+ [author], 1)
+]
+
+# If true, show URL addresses after external links.
+#man_show_urls = False
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'openEMS', 'openEMS Documentation',
+ author, 'openEMS', 'One line description of project.',
+ 'Miscellaneous'),
+]
+
+# Documents to append as an appendix to all manuals.
+#texinfo_appendices = []
+
+# If false, no module index is generated.
+#texinfo_domain_indices = True
+
+# How to display URL addresses: 'footnote', 'no', or 'inline'.
+#texinfo_show_urls = 'footnote'
+
+# If true, do not generate a @detailmenu in the "Top" node's menu.
+#texinfo_no_detailmenu = False
+
+numpydoc_show_class_members = False
+
+# Example configuration for intersphinx: refer to the Python standard library.
+intersphinx_mapping = {'CSXCAD': ('http://openems.de/doc/CSXCAD/', None)}
diff --git a/openEMS/python/doc/convert_tutorials.py b/openEMS/python/doc/convert_tutorials.py
new file mode 100755
index 0000000..009937b
--- /dev/null
+++ b/openEMS/python/doc/convert_tutorials.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+"""
+Created on Sat Sep 10 17:12:53 2016
+
+@author: thorsten
+"""
+
+import os
+import glob
+
+DOC_DIR = os.path.dirname(__file__)
+ROOT_DIR = os.path.join(DOC_DIR, '..')
+
+def main():
+ in_path = os.path.join(ROOT_DIR, 'Tutorials')
+
+ fns = glob.glob(os.path.join(in_path, '*.py'))
+
+ for fn in fns:
+ bn = os.path.basename(fn)
+ out_fn = os.path.join(DOC_DIR, 'Tutorials', '__' + bn.replace('.py', '.txt'))
+
+ in_code_block = False
+ in_ignore_block = False
+ out_fh = open(out_fn, 'w')
+ for line in open(fn, 'r'):
+ if in_ignore_block==False and line.startswith('"""'):
+ in_ignore_block = True
+ in_code_block = False
+ continue
+ elif in_ignore_block==True and line.startswith('"""'):
+ in_ignore_block = False
+ in_code_block = False
+ continue
+ elif in_ignore_block==True:
+ in_code_block = False
+ continue
+ elif line.startswith('# -*-'):
+ continue
+ elif not line.startswith('##'):
+ if not in_code_block:
+ if len(line.strip())==0:
+ continue
+ out_fh.write('\n.. code-block:: python\n\n')
+ in_code_block = True
+ out_fh.write(' ' + line)
+ elif line.startswith('###'):
+ if in_code_block:
+ out_fh.write('\n')
+ in_code_block = False
+ line = line.replace('#','').strip()
+ out_fh.write('**' + line + '**\n\n')
+# out_fh.write('"'*len(line) + '\n')
+ elif line.startswith('##'):
+ if in_code_block:
+ out_fh.write('\n')
+ in_code_block = False
+ out_fh.write(line.replace('#','').strip() + '\n')
+ out_fh.close()
+
+if __name__ == '__main__':
+ main()
diff --git a/openEMS/python/doc/index.rst b/openEMS/python/doc/index.rst
new file mode 100644
index 0000000..f4cb9ea
--- /dev/null
+++ b/openEMS/python/doc/index.rst
@@ -0,0 +1,24 @@
+.. openEMS documentation master file, created by
+ sphinx-quickstart on Thu Sep 8 20:42:18 2016.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to openEMS's documentation!
+===================================
+
+Contents:
+
+.. toctree::
+ :maxdepth: 3
+
+ Tutorials/index
+ openEMS_API
+
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/openEMS/python/doc/nf2ff.rst b/openEMS/python/doc/nf2ff.rst
new file mode 100644
index 0000000..c4fbb01
--- /dev/null
+++ b/openEMS/python/doc/nf2ff.rst
@@ -0,0 +1,16 @@
+.. _nf2ff:
+
+NF2FF
+-----
+
+.. automodule:: openEMS.nf2ff
+
+ NF2FF
+ -----
+ .. autoclass:: nf2ff
+ :members:
+
+ NF2FF Results
+ -----------------
+ .. autoclass:: nf2ff_results
+ :members:
diff --git a/openEMS/python/doc/openEMS.rst b/openEMS/python/doc/openEMS.rst
new file mode 100644
index 0000000..c73dece
--- /dev/null
+++ b/openEMS/python/doc/openEMS.rst
@@ -0,0 +1,8 @@
+.. _openems:
+
+openEMS
+-------
+
+.. automodule:: openEMS
+ :members: openEMS
+ :undoc-members:
diff --git a/openEMS/python/doc/openEMS_API.rst b/openEMS/python/doc/openEMS_API.rst
new file mode 100644
index 0000000..ae7e381
--- /dev/null
+++ b/openEMS/python/doc/openEMS_API.rst
@@ -0,0 +1,11 @@
+.. _openems_api:
+
+openEMS Python Interface
+========================
+
+.. toctree::
+
+ openEMS
+ ports
+ nf2ff
+
diff --git a/openEMS/python/doc/ports.rst b/openEMS/python/doc/ports.rst
new file mode 100644
index 0000000..79971e6
--- /dev/null
+++ b/openEMS/python/doc/ports.rst
@@ -0,0 +1,37 @@
+.. _ports:
+
+Ports
+-----
+
+.. automodule:: openEMS.ports
+
+ Port (Base Class)
+ -----------------
+ .. autoclass:: Port
+ :members:
+ :show-inheritance:
+
+ Lumped Port
+ -----------
+ .. autoclass:: LumpedPort
+ :members:
+ :show-inheritance:
+
+ MSL Port
+ --------
+ .. autoclass:: MSLPort
+ :members:
+ :show-inheritance:
+
+ Waveguide Port
+ --------------
+ .. autoclass:: WaveguidePort
+ :members:
+ :show-inheritance:
+
+ Rect Waveguide Port
+ -------------------
+ .. autoclass:: RectWGPort
+ :members:
+ :show-inheritance:
+
diff --git a/openEMS/python/openEMS/__init__.py b/openEMS/python/openEMS/__init__.py
new file mode 100644
index 0000000..734aa76
--- /dev/null
+++ b/openEMS/python/openEMS/__init__.py
@@ -0,0 +1,6 @@
+# -*- coding: utf-8 -*-
+#
+# Shortcut openEMS import
+from __future__ import absolute_import
+
+from openEMS.openEMS import openEMS
diff --git a/openEMS/python/openEMS/_nf2ff.pxd b/openEMS/python/openEMS/_nf2ff.pxd
new file mode 100644
index 0000000..7e1b764
--- /dev/null
+++ b/openEMS/python/openEMS/_nf2ff.pxd
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from libcpp.string cimport string
+from libcpp.vector cimport vector
+from libcpp.complex cimport complex
+from libcpp cimport bool
+cimport cython.numeric
+
+cdef extern from "openEMS/nf2ff.h":
+ cdef cppclass cpp_nf2ff "nf2ff":
+ cpp_nf2ff(vector[float] freq, vector[float] theta, vector[float] phi, vector[float] center, unsigned int numThreads) except +
+
+ bool AnalyseFile(string E_Field_file, string H_Field_file)
+
+ void SetRadius(float radius)
+ void SetPermittivity(vector[float] permittivity);
+ void SetPermeability(vector[float] permeability);
+
+ void SetMirror(int _type, int _dir, float pos);
+
+ double GetTotalRadPower(size_t f_idx)
+ double GetMaxDirectivity(size_t f_idx)
+
+ complex[double]** GetETheta(size_t f_idx)
+ complex[double]** GetEPhi(size_t f_idx)
+ double** GetRadPower(size_t f_idx)
+
+ bool Write2HDF5(string filename)
+
+ void SetVerboseLevel(int level)
+
+cdef class _nf2ff:
+ cdef cpp_nf2ff *thisptr
diff --git a/openEMS/python/openEMS/_nf2ff.pyx b/openEMS/python/openEMS/_nf2ff.pyx
new file mode 100644
index 0000000..8016694
--- /dev/null
+++ b/openEMS/python/openEMS/_nf2ff.pyx
@@ -0,0 +1,59 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+cimport _nf2ff
+import numpy as np
+import os
+from CSXCAD.Utilities import CheckNyDir
+
+cdef class _nf2ff:
+ def __cinit__(self, freq, theta, phi, center, numThreads=0, **kw):
+ if type(freq) in [float, int]:
+ freq = list(float(freq))
+ if type(theta) in [float, int]:
+ theta = list(float(theta))
+ if type(phi) in [float, int]:
+ phi = list(float(phi))
+ self.thisptr = new cpp_nf2ff(freq, theta, phi, center, numThreads)
+
+ if 'verbose' in kw:
+ self.SetVerboseLevel(kw['verbose'])
+ del kw['verbose']
+
+ assert len(kw)==0, 'Unknown keyword(s): {}'.format(kw)
+
+ def AnalyseFile(self, e_file, h_file):
+ assert os.path.exists(e_file)
+ assert os.path.exists(h_file)
+ return self.thisptr.AnalyseFile(e_file.encode('UTF-8'), h_file.encode('UTF-8'))
+
+ def SetMirror(self, mirr_type, ny, pos):
+ if mirr_type<=0:
+ return
+ assert mirr_type<3
+ ny = CheckNyDir(ny)
+ self.thisptr.SetMirror(mirr_type, ny, pos)
+
+ def SetRadius(self, radius):
+ self.thisptr.SetRadius(radius)
+
+ def Write2HDF5(self, filename):
+ return self.thisptr.Write2HDF5(filename.encode('UTF-8'))
+
+ def SetVerboseLevel(self, level):
+ self.thisptr.SetVerboseLevel(level)
diff --git a/openEMS/python/openEMS/automesh.py b/openEMS/python/openEMS/automesh.py
new file mode 100644
index 0000000..93472fa
--- /dev/null
+++ b/openEMS/python/openEMS/automesh.py
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Sun Feb 19 20:29:25 2017
+
+@author: thorsten
+"""
+
+import sys
+import numpy as np
+
+from CSXCAD import CSPrimitives
+from CSXCAD.Utilities import CheckNyDir, GetMultiDirs
+
+def mesh_hint_from_primitive(primitive, dirs, **kw):
+ if primitive.GetType() is CSPrimitives.POINT:
+ return mesh_hint_from_point(primitive, dirs, **kw)
+ if primitive.GetType() is CSPrimitives.BOX:
+ return mesh_hint_from_box(primitive, dirs, **kw)
+ else:
+ return None
+
+def mesh_hint_from_point(point, dirs, **kw):
+ """ mesh_hint_from_point(point, dirs)
+
+ Get a grid hint for the coordinates of the point.
+
+ :param dirs: str -- 'x','y','z' or 'xy', 'yz' or 'xyz' or 'all'
+ :returns: (3,) list of mesh hints
+ """
+ hint = [None, None, None]
+ coord = point.GetCoord()
+ for ny in GetMultiDirs(dirs):
+ hint[ny] = [coord[ny],]
+ return hint
+
+def mesh_hint_from_box(box, dirs, **kw):
+ """ mesh_hint_from_box(box, dirs, metal_edge_res=None, **kw)
+
+ Get a grid hint for the edges of the given box with an an optional 2D metal
+ edge resolution.
+
+ :param dirs: str -- 'x','y','z' or 'xy', 'yz' or 'xyz' or 'all'
+ :param metal_edge_res: float -- 2D flat edge resolution
+ :returns: (3,) list of mesh hints
+ """
+ metal_edge_res = kw.get('metal_edge_res', None)
+ up_dir = kw.get('up_dir' , True)
+ down_dir = kw.get('down_dir', True)
+
+ if metal_edge_res is None:
+ mer = 0
+ else:
+ mer = np.array([-1.0, 2.0])/3 * metal_edge_res
+ if box.HasTransform():
+ sys.stderr.write('FDTD::automesh: Warning, cannot add edges to grid with transformations enabled\n')
+ return
+ hint = [None, None, None]
+ start = np.fmin(box.GetStart(), box.GetStop())
+ stop = np.fmax(box.GetStart(), box.GetStop())
+ for ny in GetMultiDirs(dirs):
+ hint[ny] = []
+ if metal_edge_res is not None and stop[ny]-start[ny]>metal_edge_res:
+ if down_dir:
+ hint[ny].append(start[ny]-mer[0])
+ hint[ny].append(start[ny]-mer[1])
+ if up_dir:
+ hint[ny].append(stop[ny]+mer[0])
+ hint[ny].append(stop[ny]+mer[1])
+ elif stop[ny]-start[ny]:
+ if down_dir:
+ hint[ny].append(start[ny])
+ if up_dir:
+ hint[ny].append(stop[ny])
+ else:
+ hint[ny].append(start[ny])
+ return hint
+
diff --git a/openEMS/python/openEMS/nf2ff.py b/openEMS/python/openEMS/nf2ff.py
new file mode 100644
index 0000000..b3792ff
--- /dev/null
+++ b/openEMS/python/openEMS/nf2ff.py
@@ -0,0 +1,211 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import
+
+import os
+import numpy as np
+import h5py
+from openEMS import _nf2ff
+from openEMS import utilities
+
+class nf2ff:
+ """
+ Create an nf2ff recording box. The nf2ff can either record in time-domain
+ or frequency-domain. Further more certain directions and boundary condition
+ mirroring can be enabled/disabled.
+
+ :param name: str -- Name for this recording box.
+ :param start/stop: (3,) array -- Box start/stop coordinates.
+ :param directions: (6,) bool array -- Enable/Disables directions.
+ :param mirror: (6,) int array -- 0 (Off), 1 (PEC) or 2 (PMC) boundary mirroring
+ :param frequency: array like -- List of frequencies (FD-domain recording)
+ """
+ def __init__(self, CSX, name, start, stop, **kw):
+ self.CSX = CSX
+ self.name = name
+ self.start = start
+ self.stop = stop
+
+ self.freq = None
+ self.theta = None
+ self.phi = None
+ self.center = None
+
+ self.directions = [True]*6 # all directions by default
+ if 'directions' in kw:
+ self.directions = kw['directions']
+ del kw['directions']
+ assert len(self.directions)==6
+
+ self.mirror = [0]*6
+ if 'mirror' in kw:
+ self.mirror = kw['mirror']
+ del kw['mirror']
+ assert len(self.mirror)==6
+
+ self.dump_type = 0 # default Et/Ht
+ self.dump_mode = 1 # default cell interpolated
+
+ self.freq = None # broadband recording by defualt
+ if 'frequency' in kw:
+ self.freq = kw['frequency']
+ del kw['frequency']
+ self.dump_type = 10 # Ef/Hf
+
+ if np.isscalar(self.freq):
+ self.freq = [self.freq]
+
+ self.e_file = '{}_E'.format(self.name)
+ self.h_file = '{}_H'.format(self.name)
+
+ self.e_dump = CSX.AddDump(self.e_file, dump_type=self.dump_type , dump_mode=self.dump_mode, file_type=1, **kw)
+ self.h_dump = CSX.AddDump(self.h_file, dump_type=self.dump_type+1, dump_mode=self.dump_mode, file_type=1, **kw)
+ if self.freq is not None:
+ self.e_dump.SetFrequency(self.freq)
+ self.h_dump.SetFrequency(self.freq)
+
+# print(self.directions)
+ for ny in range(3):
+ pos = 2*ny
+ if self.directions[pos]:
+ l_start = np.array(start)
+ l_stop = np.array(stop)
+ l_stop[ny] = l_start[ny]
+ self.e_dump.AddBox(l_start, l_stop)
+ self.h_dump.AddBox(l_start, l_stop)
+ if self.directions[pos+1]:
+ l_start = np.array(start)
+ l_stop = np.array(stop)
+ l_start[ny] = l_stop[ny]
+ self.e_dump.AddBox(l_start, l_stop)
+ self.h_dump.AddBox(l_start, l_stop)
+
+ def CalcNF2FF(self, sim_path, freq, theta, phi, radius=1, center=[0,0,0], outfile=None, read_cached=False, verbose=0):
+ """ CalcNF2FF(sim_path, freq, theta, phi, center=[0,0,0], outfile=None, read_cached=True, verbose=0):
+
+ Calculate the far-field after the simulation is done.
+
+ :param sim_path: str -- Simulation path
+ :param freq: array like -- list of frequency for transformation
+ :param theta/phi: array like -- Theta/Phi angles to calculate the far-field
+ :param radius: float -- Radius to calculate the far-field (default is 1m)
+ :param center: (3,) array -- phase center, must be inside the recording box
+ :param outfile: str -- File to save results in. (defaults to recording name)
+ :param read_cached: bool -- enable/disable read already existing results (default off)
+ :param verbose: int -- set verbose level (default 0)
+
+ :returns: nf2ff_results class instance
+ """
+ if np.isscalar(freq):
+ freq = [freq]
+ self.freq = freq
+ if np.isscalar(theta):
+ theta = [theta]
+ self.theta = theta
+ if np.isscalar(phi):
+ phi = [phi]
+ self.phi = phi
+ self.center = center
+
+ if outfile is None:
+ fn = os.path.join(sim_path, self.name + '.h5')
+ else:
+ fn = os.path.join(sim_path, outfile)
+ if not read_cached or not os.path.exists(fn):
+ nfc = _nf2ff._nf2ff(self.freq, np.deg2rad(theta), np.deg2rad(phi), center, verbose=verbose)
+
+ for ny in range(3):
+ nfc.SetMirror(self.mirror[2*ny] , ny, self.start[ny])
+ nfc.SetMirror(self.mirror[2*ny+1], ny, self.stop[ny])
+
+ nfc.SetRadius(radius)
+
+ for n in range(6):
+ fn_e = os.path.join(sim_path, self.e_file + '_{}.h5'.format(n))
+ fn_h = os.path.join(sim_path, self.h_file + '_{}.h5'.format(n))
+ if os.path.exists(fn_e) and os.path.exists(fn_h):
+ assert nfc.AnalyseFile(fn_e, fn_h)
+
+ nfc.Write2HDF5(fn)
+
+ result = nf2ff_results(fn)
+ if result.phi is not None:
+ assert np.abs((result.r-radius)/radius)<1e-6, 'Radius does not match. Did you read an invalid chached result? Try "read_cached=False"'
+ assert utilities.Check_Array_Equal(np.rad2deg(result.theta), self.theta, 1e-4), 'Theta array does not match. Did you read an invalid chached result? Try "read_cached=False"'
+ assert utilities.Check_Array_Equal(np.rad2deg(result.phi), self.phi, 1e-4), 'Phi array does not match. Did you read an invalid chached result? Try "read_cached=False"'
+ assert utilities.Check_Array_Equal(result.freq, self.freq, 1e-6, relative=True), 'Frequency array does not match. Did you read an invalid chached result? Try "read_cached=False"'
+ return result
+
+class nf2ff_results:
+ """
+ nf2ff result class containing all results obtained by the nf2ff calculation.
+ Usueally returned from nf2ff.CalcNF2FF
+
+ Available attributes:
+
+ * `fn` : file name
+ * `theta`: theta angles
+ * `phi` : phi angles
+ * `r` : radius
+ * `freq` : frequencies
+ * `Dmax` : directivity over frequency
+ * `Prad` : total radiated power over frequency
+
+ * `E_theta` : theta component of electric field over frequency/theta/phi
+ * `E_phi` : phi component of electric field over frequency/theta/phi
+ * `E_norm` : abs component of electric field over frequency/theta/phi
+ * `E_cprh` : theta component of electric field over frequency/theta/phi
+ * `E_cplh` : theta component of electric field over frequency/theta/phi
+ * `P_rad` : radiated power (S) over frequency/theta/phi
+ """
+ def __init__(self, fn):
+ self.fn = fn
+ h5_file = h5py.File(fn, 'r')
+ mesh_grp = h5_file['Mesh']
+ self.phi = np.array(mesh_grp['phi'])
+ self.theta = np.array(mesh_grp['theta'])
+ self.r = np.array(mesh_grp['r'])
+
+ data = h5_file['nf2ff']
+ self.freq = np.array(data.attrs['Frequency'])
+
+ self.Dmax = np.array(data.attrs['Dmax'])
+ self.Prad = np.array(data.attrs['Prad'])
+
+ THETA, PHI = np.meshgrid(self.theta, self.phi, indexing='ij')
+ cos_phi = np.cos(PHI)
+ sin_phi = np.sin(PHI)
+
+ self.E_theta = []
+ self.E_phi = []
+ self.P_rad = []
+ self.E_norm = []
+ self.E_cprh = []
+ self.E_cplh = []
+ for n in range(len(self.freq)):
+ E_theta = np.array(h5_file['/nf2ff/E_theta/FD/f{}_real'.format(n)]) + 1j*np.array(h5_file['/nf2ff/E_theta/FD/f{}_imag'.format(n)])
+ E_theta = np.swapaxes(E_theta, 0, 1)
+ E_phi = np.array(h5_file['/nf2ff/E_phi/FD/f{}_real'.format(n)]) + 1j*np.array(h5_file['/nf2ff/E_phi/FD/f{}_imag'.format(n)])
+ E_phi = np.swapaxes(E_phi, 0, 1)
+ self.P_rad .append(np.swapaxes(np.array(h5_file['/nf2ff/P_rad/FD/f{}'.format(n)]), 0, 1))
+
+ self.E_theta.append(E_theta)
+ self.E_phi .append(E_phi)
+ self.E_norm .append(np.sqrt(np.abs(E_theta)**2 + np.abs(E_phi)**2))
+ self.E_cprh .append((cos_phi+1j*sin_phi) * (E_theta+1j*E_phi)/np.sqrt(2.0))
+ self.E_cplh .append((cos_phi-1j*sin_phi) * (E_theta-1j*E_phi)/np.sqrt(2.0))
diff --git a/openEMS/python/openEMS/openEMS.pxd b/openEMS/python/openEMS/openEMS.pxd
new file mode 100644
index 0000000..a307152
--- /dev/null
+++ b/openEMS/python/openEMS/openEMS.pxd
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+from libcpp.string cimport string
+from libcpp cimport bool
+
+from CSXCAD.CSXCAD cimport _ContinuousStructure, ContinuousStructure
+
+cdef extern from "openEMS/openems.h":
+ cdef cppclass _openEMS "openEMS":
+ _openEMS() except +
+ void SetNumberOfTimeSteps(unsigned int val)
+ void SetCSX(_ContinuousStructure* csx)
+
+ void SetEndCriteria(double val)
+ void SetOverSampling(int val)
+ void SetCellConstantMaterial(bool val)
+
+ void SetCylinderCoords(bool val)
+ void SetupCylinderMultiGrid(string val)
+
+ void SetTimeStepMethod(int val)
+ void SetTimeStep(double val)
+ void SetTimeStepFactor(double val)
+ void SetMaxTime(double val)
+
+ void SetNumberOfThreads(int val)
+
+ void Set_BC_Type(int idx, int _type)
+ int Get_BC_Type(int idx)
+ void Set_BC_PML(int idx, unsigned int size)
+ int Get_PML_Size(int idx)
+ void Set_Mur_PhaseVel(int idx, double val)
+
+ void SetGaussExcite(double f0, double fc)
+
+ void SetVerboseLevel(int level)
+ void DebugPEC()
+ void DebugMaterial()
+ void DebugCSX()
+
+ int SetupFDTD()
+ void RunFDTD()
+
+ @staticmethod
+ void WelcomeScreen()
+
+cdef class openEMS:
+ cdef _openEMS *thisptr
+ cdef readonly ContinuousStructure __CSX # hold a C++ instance which we're wrapping
diff --git a/openEMS/python/openEMS/openEMS.pyx b/openEMS/python/openEMS/openEMS.pyx
new file mode 100644
index 0000000..bb41bff
--- /dev/null
+++ b/openEMS/python/openEMS/openEMS.pyx
@@ -0,0 +1,447 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os, sys, shutil
+import numpy as np
+cimport openEMS
+from . import ports, nf2ff, automesh
+
+from CSXCAD.Utilities import GetMultiDirs
+
+cdef class openEMS:
+ """ openEMS
+
+ This class is the main control class for the FDTD options and setup and
+ to run the final simulation.
+
+ Examples
+ --------
+
+ >>> CSX = CSXCAD.ContinuousStructure()
+ >>>
+ >>> grid = CSX.GetGrid()
+ >>> grid.SetLines('x', np.arange(-50,50,1))
+ >>> grid.SetLines('y', np.arange(-50,50,1))
+ >>> grid.SetLines('z', np.arange(-2,2.1,1))
+ >>> grid.SetDeltaUnit(1e-3)
+ >>>
+ >>> FDTD = openEMS(NrTS=1e4, EndCriteria=1e-4)
+ >>>
+ >>> FDTD.SetCSX(CSX)
+ >>> FDTD.SetBoundaryCond(['PML_8', 'PML_8', 'PML_8', 'PML_8', 'PEC', 'PEC'])
+ >>> FDTD.SetGaussExcite(0, 10e9)
+ >>>
+ >>> FDTD.AddLumpedPort(port_nr=1, R=50, start=[10, 0, -2], stop=[10, 0, 2], p_dir='z', excite=1)
+ >>>
+ >>> FDTD.Run(sim_path='/tmp/test')
+
+ :param NrTS: max. number of timesteps to simulate (e.g. default=1e9)
+ :param EndCriteria: end criteria, e.g. 1e-5, simulations stops if energy has decayed by this value (<1e-4 is recommended, default=1e-5)
+ :param MaxTime: max. real time in seconds to simulate
+ :param OverSampling: nyquist oversampling of time domain dumps
+ :param CoordSystem: choose coordinate system (0 Cartesian, 1 Cylindrical)
+ :param MultiGrid: define a cylindrical sub-grid radius
+ :param TimeStep: force to use a given timestep (dangerous!)
+ :param TimeStepFactor: reduce the timestep by a given factor (>0 to <=1)
+ :param TimeStepMethod: 1 or 3 chose timestep method (1=CFL, 3=Rennigs (default))
+ :param CellConstantMaterial: set to 1 to assume a material is constant inside a cell (material probing in cell center)
+ """
+ @staticmethod
+ def WelcomeScreen():
+ """
+ Show the openEMS welcome screen.
+ """
+ _openEMS.WelcomeScreen()
+
+ def __cinit__(self, *args, **kw):
+ self.thisptr = new _openEMS()
+ self.__CSX = None
+
+ if 'NrTS' in kw:
+ self.SetNumberOfTimeSteps(kw['NrTS'])
+ del kw['NrTS']
+ else:
+ self.SetNumberOfTimeSteps(1e9)
+ if 'EndCriteria' in kw:
+ self.SetEndCriteria(kw['EndCriteria'])
+ del kw['EndCriteria']
+ if 'MaxTime' in kw:
+ self.SetMaxTime(kw['MaxTime'])
+ del kw['MaxTime']
+ if 'OverSampling' in kw:
+ self.SetOverSampling(kw['OverSampling'])
+ del kw['OverSampling']
+ if 'CoordSystem' in kw:
+ self.SetCoordSystem(kw['CoordSystem'])
+ del kw['CoordSystem']
+ if 'TimeStep' in kw:
+ self.SetTimeStep(kw['TimeStep'])
+ del kw['TimeStep']
+ if 'TimeStepFactor' in kw:
+ self.SetTimeStepFactor(kw['TimeStepFactor'])
+ del kw['TimeStepFactor']
+ if 'TimeStepMethod' in kw:
+ self.SetTimeStepMethod(kw['TimeStepMethod'])
+ del kw['TimeStepMethod']
+ if 'CellConstantMaterial' in kw:
+ self.SetCellConstantMaterial(kw['CellConstantMaterial'])
+ del kw['CellConstantMaterial']
+ if 'MultiGrid' in kw:
+ self.SetMultiGrid(kw['MultiGrid'])
+ del kw['MultiGrid']
+
+ assert len(kw)==0, 'Unknown keyword arguments: "{}"'.format(kw)
+
+ def __dealloc__(self):
+ del self.thisptr
+ if self.__CSX is not None:
+ self.__CSX.thisptr = NULL
+
+ def SetNumberOfTimeSteps(self, val):
+ """ SetNumberOfTimeSteps(val)
+
+ Set the number of timesteps. E.g. 5e4 (default is 1e9)
+ """
+ self.thisptr.SetNumberOfTimeSteps(val)
+
+ def SetEndCriteria(self, val):
+ """ SetEndCriteria(val)
+
+ Set the end critera value. E.g. 1e-6 for -60dB
+ """
+ self.thisptr.SetEndCriteria(val)
+
+ def SetOverSampling(self, val):
+ """ SetOverSampling(val)
+
+ Set the time domain signal oversampling as multiple of the Nyquist-rate.
+ """
+ self.thisptr.SetOverSampling(val)
+
+ def SetCellConstantMaterial(self, val):
+ """ SetCellConstantMaterial(val)
+
+ Set cell material averaging to assume constant material inside each primary cell. (Advanced option)
+
+ :param val: bool -- Enable or Disable (default disabled)
+ """
+ self.thisptr.SetCellConstantMaterial(val)
+
+ def SetCoordSystem(self, val):
+ """ SetCoordSystem(val)
+
+ Set the coordinate system. 0 --> Cartesian (default), 1 --> cylindrical
+ """
+ assert (val==0 or val==1), 'SetCoordSystem: Invalid coordinate system'
+ if val==0:
+ self.thisptr.SetCylinderCoords(False)
+ elif val==1:
+ self.thisptr.SetCylinderCoords(True)
+
+ def SetMultiGrid(self, radii):
+ """ SetMultiGrid(radii)
+
+ Define radii at which a cylindrical multi grid should be defined.
+
+ :param radii: array like, multigrid radii
+
+ See Also
+ --------
+ openEMS.SetCylinderCoords
+ """
+ assert len(radii)>0, 'SetMultiGrid: invalid multi grid definition'
+
+ grid_str = ','.join(['{}'.format(x) for x in radii])
+ self.thisptr.SetupCylinderMultiGrid(grid_str.encode('UTF-8'))
+
+ def SetCylinderCoords(self):
+ """ SetCylinderCoords()
+
+ Enable use of cylindircal coordinates.
+
+ See Also
+ --------
+ openEMS.SetMultiGrid
+ """
+ self.thisptr.SetCylinderCoords(True)
+
+ def SetTimeStepMethod(self, val):
+ """ SetTimeStepMethod(val)
+
+ Set the time step calculation method. (Advanced option)
+
+ Options:
+
+ * 1: CFL criteria
+ * 3: Advanced Rennings criteria (default)
+
+ :param val: int -- 1 or 3 (See above)
+ """
+ self.thisptr.SetTimeStepMethod(val)
+
+ def SetTimeStep(self, val):
+ """ SetTimeStep(val)
+
+ Set/force the timestep. (Advanced option)
+
+ It is highly recommended to not use this method! You may use the
+ SetTimeStepFactor instead to reduce the time step if necessary!
+ """
+ self.thisptr.SetTimeStep(val)
+
+ def SetTimeStepFactor(self, val):
+ """ SetTimeStepFactor(val)
+
+ Set a time step factor (>0..1) to increase FDTD stability.
+
+ :param val: float -- >0..1
+ """
+ self.thisptr.SetTimeStepFactor(val)
+
+ def SetMaxTime(self, val):
+ """ SetMaxTime(val)
+
+ Set max simulation time for a max. number of timesteps.
+ """
+ self.thisptr.SetMaxTime(val)
+
+ def SetGaussExcite(self, f0, fc):
+ """ SetGaussExcite(f0, fc)
+
+ Set a Gaussian pulse as excitation signal.
+
+ :param f0: float -- Center frequency in Hz.
+ :param fc: float -- -20dB bandwidth in Hz.
+ """
+ self.thisptr.SetGaussExcite(f0, fc)
+
+
+ def SetBoundaryCond(self, BC):
+ """ SetBoundaryCond(BC)
+
+ Set the boundary conditions for all six FDTD directions.
+
+ Options:
+
+ * 0 or 'PEC' : perfect electric conductor (default)
+ * 1 or 'PMC' : perfect magnetic conductor, useful for symmetries
+ * 2 or 'MUR' : simple MUR absorbing boundary conditions
+ * 3 or 'PML-8' : PML absorbing boundary conditions
+
+ :param BC: (8,) array or list -- see options above
+ """
+ assert len(BC)==6
+ for n in range(len(BC)):
+ if type(BC[n])==int:
+ self.thisptr.Set_BC_Type(n, BC[n])
+ continue
+ if BC[n] in ['PEC', 'PMC', 'MUR']:
+ self.thisptr.Set_BC_Type(n, ['PEC', 'PMC', 'MUR'].index(BC[n]))
+ continue
+ if BC[n].startswith('PML_'):
+ size = int(BC[n].strip('PML_'))
+ self.thisptr.Set_BC_PML(n, size)
+ continue
+ raise Exception('Unknown boundary condition')
+
+ def AddLumpedPort(self, port_nr, R, start, stop, p_dir, excite=0, **kw):
+ """ AddLumpedPort(port_nr, R, start, stop, p_dir, excite=0, **kw)
+
+ Add a lumped port wit the given values and location.
+
+ See Also
+ --------
+ openEMS.ports.LumpedPort
+ """
+ assert self.__CSX is not None, 'AddLumpedPort: CSX is not set!'
+ port = ports.LumpedPort(self.__CSX, port_nr, R, start, stop, p_dir, excite, **kw)
+ edges2grid = kw.get('edges2grid', None)
+ if edges2grid is not None:
+ grid = self.__CSX.GetGrid()
+ for n in GetMultiDirs(edges2grid):
+ grid.AddLine(n, start[n])
+ if start[n] != stop[n]:
+ grid.AddLine(n, stop[n])
+ return port
+
+ def AddWaveGuidePort(self, port_nr, start, stop, p_dir, E_func, H_func, kc, excite=0, **kw):
+ """ AddWaveGuidePort(self, port_nr, start, stop, p_dir, E_func, H_func, kc, excite=0, **kw)
+
+ Add a arbitrary waveguide port.
+
+ See Also
+ --------
+ openEMS.ports.WaveguidePort
+ """
+ assert self.__CSX is not None, 'AddWaveGuidePort: CSX is not set!'
+ return ports.WaveguidePort(self.__CSX, port_nr, start, stop, p_dir, E_func, H_func, kc, excite, **kw)
+
+ def AddRectWaveGuidePort(self, port_nr, start, stop, p_dir, a, b, mode_name, excite=0, **kw):
+ """ AddRectWaveGuidePort(port_nr, start, stop, p_dir, a, b, mode_name, excite=0, **kw)
+
+ Add a rectilinear waveguide port.
+
+ See Also
+ --------
+ openEMS.ports.RectWGPort
+ """
+ assert self.__CSX is not None, 'AddRectWaveGuidePort: CSX is not set!'
+ return ports.RectWGPort(self.__CSX, port_nr, start, stop, p_dir, a, b, mode_name, excite, **kw)
+
+ def AddMSLPort(self, port_nr, metal_prop, start, stop, prop_dir, exc_dir, excite=0, **kw):
+ """ AddMSLPort(port_nr, metal_prop, start, stop, prop_dir, exc_dir, excite=0, **kw)
+
+ Add a microstrip transmission line port.
+
+ See Also
+ --------
+ openEMS.ports.MSLPort
+ """
+ assert self.__CSX is not None, 'AddMSLPort: CSX is not set!'
+ return ports.MSLPort(self.__CSX, port_nr, metal_prop, start, stop, prop_dir, exc_dir, excite, **kw)
+
+ def CreateNF2FFBox(self, name='nf2ff', start=None, stop=None, **kw):
+ """ CreateNF2FFBox(name='nf2ff', start=None, stop=None, **kw)
+
+ Create a near-field to far-field box.
+
+ This method will automatically adept the recording box to the current
+ FDTD grid and boundary conditions.
+
+ Notes
+ -----
+ * Make sure the mesh grid and all boundary conditions are finially defined.
+
+ See Also
+ --------
+ openEMS.nf2ff.nf2ff
+ """
+ assert self.__CSX is not None, 'CreateNF2FFBox: CSX is not set!'
+ directions = [True]*6
+ mirror = [0]*6
+ BC_size = [0]*6
+ BC_type = [0]*6
+ for n in range(6):
+ BC_type[n] = self.thisptr.Get_BC_Type(n)
+ if BC_type[n]==0:
+ directions[n]= False
+ mirror[n] = 1 # PEC mirror
+ elif BC_type[n]==1:
+ directions[n]= False
+ mirror[n] = 2 # PMC mirror
+ elif BC_type[n]==2:
+ BC_size[n] = 2
+ elif BC_type[n]==3:
+ BC_size[n] = self.thisptr.Get_PML_Size(n)+1
+
+ if start is None or stop is None:
+ grid = self.__CSX.GetGrid()
+ assert grid.IsValid(), 'Error::CreateNF2FFBox: Grid is invalid'
+ start = np.zeros(3)
+ stop = np.zeros(3)
+ for n in range(3):
+ l = grid.GetLines(n)
+ BC_type = self.thisptr.Get_BC_Type(2*n)
+ assert len(l)>(BC_size[2*n]+BC_size[2*n+1]), 'Error::CreateNF2FFBox: not enough lines in some direction'
+ start[n] = l[BC_size[2*n]]
+ stop[n] = l[-1*BC_size[2*n+1]-1]
+ return nf2ff.nf2ff(self.__CSX, name, start, stop, directions=directions, mirror=mirror, **kw)
+
+ def SetCSX(self, ContinuousStructure CSX):
+ """ SetCSX(CSX)
+
+ Set the CSXCAD Continuous Structure for CAD data handling.
+
+ See Also
+ --------
+ CSXCAD.ContinuousStructure
+ """
+ self.__CSX = CSX
+ self.thisptr.SetCSX(CSX.thisptr)
+
+ def GetCSX(self):
+ return self.__CSX
+
+ def AddEdges2Grid(self, dirs, primitives=None, properties=None, **kw):
+ """ AddEdges2Grid(primitives, dirs, **kw)
+
+ Add the edges of the given primitives to the FDTD grid.
+
+ :param dirs: primitives -- one or more primitives
+ :param dirs: str -- 'x','y','z' or 'xy', 'yz' or 'xyz' or 'all'
+ """
+ csx = self.GetCSX()
+ if csx is None:
+ raise Exception('AddEdges2Grid: Unable to access CSX!')
+ prim_list = []
+ if primitives is not None and type(primitives) is not list:
+ prim_list.append(primitives)
+ elif primitives is not None:
+ prim_list += primitives
+
+ if properties is not None and type(properties) is not list:
+ prim_list += properties.GetAllPrimitives()
+ elif properties is not None:
+ for prop in properties:
+ prim_list += prop.GetAllPrimitives()
+
+ grid = csx.GetGrid()
+ for prim in prim_list:
+ hint = automesh.mesh_hint_from_primitive(prim, dirs, **kw)
+ if hint is None:
+ continue
+ for n in range(3):
+ if hint[n] is None:
+ continue
+ grid.AddLine(n, hint[n])
+
+ def Run(self, sim_path, cleanup=False, setup_only=False, debug_pec=False, verbose=None, **kw):
+ """ Run(sim_path, cleanup=False, setup_only=False, verbose=None)
+
+ Run the openEMS FDTD simulation.
+
+ :param sim_path: str -- path to run in and create result data
+ :param cleanup: bool -- remove exisiting sim_path to cleanup old results
+ :param setup_only: bool -- only perform FDTD setup, do not run simulation
+ :param verbose: int -- set the openEMS verbosity level 0..3
+
+ Additional keyword parameter:
+ :param numThreads: int -- set the number of threads (default 0 --> max)
+ """
+ if cleanup and os.path.exists(sim_path):
+ shutil.rmtree(sim_path)
+ os.mkdir(sim_path)
+ if not os.path.exists(sim_path):
+ os.mkdir(sim_path)
+ cwd = os.getcwd()
+ os.chdir(sim_path)
+ if verbose is not None:
+ self.thisptr.SetVerboseLevel(verbose)
+ if debug_pec:
+ self.thisptr.DebugPEC()
+ if 'numThreads' in kw:
+ self.thisptr.SetNumberOfThreads(int(kw['numThreads']))
+ assert os.getcwd() == sim_path
+ _openEMS.WelcomeScreen()
+ cdef int EC
+ EC = self.thisptr.SetupFDTD()
+ if EC!=0:
+ print('Run: Setup failed, error code: {}'.format(EC))
+ if setup_only or EC!=0:
+ return EC
+ self.thisptr.RunFDTD()
diff --git a/openEMS/python/openEMS/physical_constants.py b/openEMS/python/openEMS/physical_constants.py
new file mode 100644
index 0000000..8f014b5
--- /dev/null
+++ b/openEMS/python/openEMS/physical_constants.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import numpy as np
+
+C0 = 299792458 # m/s
+MUE0 = 4e-7*np.pi # N/A^2
+EPS0 = 1/(MUE0*C0**2) # F/m
+
+# free space wave impedance
+Z0 = np.sqrt(MUE0/EPS0) # Ohm
diff --git a/openEMS/python/openEMS/ports.py b/openEMS/python/openEMS/ports.py
new file mode 100644
index 0000000..5b4fdc0
--- /dev/null
+++ b/openEMS/python/openEMS/ports.py
@@ -0,0 +1,434 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+from __future__ import absolute_import
+
+import os
+import numpy as np
+from CSXCAD.Utilities import CheckNyDir
+from openEMS import utilities
+
+from openEMS.physical_constants import *
+
+class UI_data:
+ def __init__(self, fns, path, freq, signal_type='pulse', **kw):
+ self.path = path
+ if type(fns)==str:
+ fns = [fns]
+ self.fns = fns
+
+ if np.isscalar(freq):
+ freq = [freq]
+ self.freq = freq
+
+ self.ui_time = []
+ self.ui_val = []
+ self.ui_f_val = []
+
+ for fn in fns:
+ tmp = np.loadtxt(os.path.join(path, fn),comments='%')
+ self.ui_time.append(tmp[:,0])
+ self.ui_val.append(tmp[:,1])
+ self.ui_f_val.append(utilities.DFT_time2freq(tmp[:,0], tmp[:,1], freq, signal_type=signal_type))
+
+# Port Base-Class
+class Port(object):
+ """
+ The port base class.
+
+ :param CSX: Continuous Structure
+ :param port_nr: int -- port number
+ :param R: float -- port reference impedance, e.g. 50 (Ohms)
+ :param start, stop: (3,) array -- Start/Stop box coordinates
+ :param p_dir: int -- port direction
+ :param excite: float -- port excitation amplitude
+ :param priority: int -- priority of all contained primtives
+ :param PortNamePrefix: str -- a prefix for all ports-names
+ :param delay: float -- a positiv delay value to e.g. emulate a phase shift
+ """
+ def __init__(self, CSX, port_nr, start, stop, excite, **kw):
+ self.CSX = CSX
+ self.number = port_nr
+ self.excite = excite
+ self.start = np.array(start, np.float)
+ self.stop = np.array(stop, np.float)
+ self.Z_ref = None
+ self.U_filenames = kw.get('U_filenames', [])
+ self.I_filenames = kw.get('I_filenames', [])
+
+ self.priority = 0
+ if 'priority' in kw:
+ self.priority = kw['priority']
+
+ self.prefix = ''
+ if 'PortNamePrefix' in kw:
+ self.prefix = kw['PortNamePrefix']
+ self.delay = 0
+
+ if 'delay' in kw:
+ self.delay = kw['delay']
+
+ self.lbl_temp = self.prefix + 'port_{}' + '_{}'.format(self.number)
+
+ def ReadUIData(self, sim_path, freq, signal_type ='pulse'):
+ self.u_data = UI_data(self.U_filenames, sim_path, freq, signal_type )
+ self.uf_tot = 0
+ self.ut_tot = 0
+ for n in range(len(self.U_filenames)):
+ self.uf_tot += self.u_data.ui_f_val[n]
+ self.ut_tot += self.u_data.ui_val[n]
+
+ self.i_data = UI_data(self.I_filenames, sim_path, freq, signal_type )
+ self.if_tot = 0
+ self.it_tot = 0
+ for n in range(len(self.U_filenames)):
+ self.if_tot += self.i_data.ui_f_val[n]
+ self.it_tot += self.i_data.ui_val[n]
+
+
+ def CalcPort(self, sim_path, freq, ref_impedance=None, ref_plane_shift=None, signal_type='pulse'):
+ self.ReadUIData(sim_path, freq, signal_type)
+
+ if ref_impedance is not None:
+ self.Z_ref = ref_impedance
+ assert self.Z_ref is not None
+
+ if ref_plane_shift is not None:
+ assert hasattr(self, 'beta')
+ shift = ref_plane_shift
+ if self.measplane_shift:
+ shift -= self.measplane_shift
+ shift *= self.CSX.GetGrid().GetDeltaUnit()
+ phase = np.real(self.beta)*shift
+ uf_tot = self.uf_tot * np.cos(-phase) + 1j * self.if_tot * self.Z_ref * np.sin(-phase)
+ if_tot = self.if_tot * np.cos(-phase) + 1j * self.uf_tot / self.Z_ref * np.sin(-phase)
+ self.uf_tot = uf_tot
+ self.if_tot = if_tot
+
+ self.uf_inc = 0.5 * ( self.uf_tot + self.if_tot * self.Z_ref )
+ self.if_inc = 0.5 * ( self.if_tot + self.uf_tot / self.Z_ref )
+ self.uf_ref = self.uf_tot - self.uf_inc
+ self.if_ref = self.if_inc - self.if_tot
+
+ if type(self.Z_ref) == float:
+ self.ut_inc = 0.5 * ( self.ut_tot + self.it_tot * self.Z_ref )
+ self.it_inc = 0.5 * ( self.it_tot + self.ut_tot / self.Z_ref )
+ self.ut_ref = self.ut_tot - self.ut_inc
+ self.it_ref = self.it_inc - self.it_tot
+
+ # calc some more port parameter
+ # incoming power
+ self.P_inc = 0.5*np.real(self.uf_inc*np.conj(self.if_inc))
+ # reflected power
+ self.P_ref = 0.5*np.real(self.uf_ref*np.conj(self.if_ref))
+ # accepted power (incoming - reflected)
+ self.P_acc = 0.5*np.real(self.uf_tot*np.conj(self.if_tot))
+
+class LumpedPort(Port):
+ """
+ The lumped port.
+
+ See Also
+ --------
+ Port
+ """
+ def __init__(self, CSX, port_nr, R, start, stop, exc_dir, excite=0, **kw):
+ super(LumpedPort, self).__init__(CSX, port_nr=port_nr, start=start, stop=stop, excite=excite, **kw)
+ self.R = R
+ self.exc_ny = CheckNyDir(exc_dir)
+
+ self.direction = np.sign(self.stop[self.exc_ny]-self.start[self.exc_ny])
+ assert self.start[self.exc_ny]!=self.stop[self.exc_ny], 'LumpedPort: start and stop may not be identical in excitation direction'
+
+ if self.R > 0:
+ lumped_R = CSX.AddLumpedElement(self.lbl_temp.format('resist'), ny=self.exc_ny, caps=True, R=self.R)
+ elif self.R==0:
+ lumped_R = CSX.AddMetal(self.lbl_temp.format('resist'))
+
+ lumped_R.AddBox(self.start, self.stop, priority=self.priority)
+
+ if excite!=0:
+ exc_vec = np.zeros(3)
+ exc_vec[self.exc_ny] = -1*self.direction*excite
+ exc = CSX.AddExcitation(self.lbl_temp.format('excite'), exc_type=0, exc_val=exc_vec, delay=self.delay)
+ exc.AddBox(self.start, self.stop, priority=self.priority)
+
+ self.U_filenames = [self.lbl_temp.format('ut'), ]
+ u_start = 0.5*(self.start+self.stop)
+ u_start[self.exc_ny] = self.start[self.exc_ny]
+ u_stop = 0.5*(self.start+self.stop)
+ u_stop[self.exc_ny] = self.stop[self.exc_ny]
+ u_probe = CSX.AddProbe(self.U_filenames[0], p_type=0, weight=-1*self.direction)
+ u_probe.AddBox(u_start, u_stop)
+
+ self.I_filenames = [self.lbl_temp.format('it'), ]
+ i_start = np.array(self.start)
+ i_start[self.exc_ny] = 0.5*(self.start[self.exc_ny]+self.stop[self.exc_ny])
+ i_stop = np.array(self.stop)
+ i_stop[self.exc_ny] = 0.5*(self.start[self.exc_ny]+self.stop[self.exc_ny])
+ i_probe = CSX.AddProbe(self.I_filenames[0], p_type=1, weight=self.direction, norm_dir=self.exc_ny)
+ i_probe.AddBox(i_start, i_stop)
+
+ def CalcPort(self, sim_path, freq, ref_impedance=None, ref_plane_shift=None, signal_type='pulse'):
+ if ref_impedance is None:
+ self.Z_ref = self.R
+ if ref_plane_shift is not None:
+ Warning('A lumped port does not support a reference plane shift! Ignoring...')
+ super(LumpedPort, self).CalcPort(sim_path, freq, ref_impedance, ref_plane_shift, signal_type)
+
+class MSLPort(Port):
+ """
+ The microstrip transmission line port.
+
+ :param prop_dir: int/str -- direction of propagation
+
+ See Also
+ --------
+ Port
+ """
+ def __init__(self, CSX, port_nr, metal_prop, start, stop, prop_dir, exc_dir, excite=0, **kw):
+ super(MSLPort, self).__init__(CSX, port_nr=port_nr, start=start, stop=stop, excite=excite, **kw)
+ self.exc_ny = CheckNyDir(exc_dir)
+ self.prop_ny = CheckNyDir(prop_dir)
+ self.direction = np.sign(stop[self.prop_ny]-start[self.prop_ny])
+ self.upside_down = np.sign(stop[self.exc_ny] -start[self.exc_ny])
+ assert (self.start!=self.stop).all()
+# assert stop[self.prop_ny]!=start[self.prop_ny], 'port length in propergation direction may not be zero!'
+# assert stop[self.exc_ny] !=start[self.exc_ny], 'port length in propergation direction may not be zero!'
+ assert self.exc_ny!=self.prop_ny
+
+ self.feed_shift = 0
+ if 'FeedShift' in kw:
+ self.feed_shift = kw['FeedShift']
+ self.measplane_shift = 0.5*np.abs(self.start[self.prop_ny]-self.stop[self.prop_ny])
+ if 'MeasPlaneShift' in kw:
+ self.measplane_shift = kw['MeasPlaneShift']
+ self.measplane_pos = self.start[self.prop_ny] + self.measplane_shift*self.direction
+ self.feed_R = np.inf
+ if 'Feed_R' in kw:
+ self.feed_R = kw['Feed_R']
+
+ # add metal msl-plane
+ MSL_start = np.array(self.start)
+ MSL_stop = np.array(self.stop)
+ MSL_stop[self.exc_ny] = MSL_start[self.exc_ny]
+ metal_prop.AddBox(MSL_start, MSL_stop, priority=self.priority )
+
+ mesh = CSX.GetGrid()
+ prop_lines = mesh.GetLines(self.prop_ny)
+ assert len(prop_lines)>5, 'At least 5 lines in propagation direction required!'
+ meas_pos_idx = np.argmin(np.abs(prop_lines-self.measplane_pos))
+ if meas_pos_idx==0:
+ meas_pos_idx=1
+ if meas_pos_idx>=len(prop_lines)-1:
+ meas_pos_idx=len(prop_lines)-2
+ self.measplane_shift = np.abs(self.start[self.prop_ny]-prop_lines[meas_pos_idx])
+ prope_idx = np.array([meas_pos_idx-1, meas_pos_idx, meas_pos_idx+1], np.int)
+ if self.direction<0:
+ prope_idx = np.flipud(prope_idx)
+ u_prope_pos = prop_lines[prope_idx]
+ self.U_filenames = []
+ self.U_delta = np.diff(u_prope_pos)
+ suffix = ['A', 'B', 'C']
+ for n in range(len(prope_idx)):
+ u_start = 0.5*(self.start+self.stop)
+ u_stop = 0.5*(self.start+self.stop)
+ u_start[self.prop_ny] = u_prope_pos[n]
+ u_stop[self.prop_ny] = u_prope_pos[n]
+ u_start[self.exc_ny] = self.start[self.exc_ny]
+ u_stop[self.exc_ny] = self.stop [self.exc_ny]
+ u_name = self.lbl_temp.format('ut') + suffix[n]
+ self.U_filenames.append(u_name)
+ u_probe = CSX.AddProbe(u_name, p_type=0, weight=self.upside_down)
+ u_probe.AddBox(u_start, u_stop)
+
+ i_prope_pos = u_prope_pos[0:2] + np.diff(u_prope_pos)/2.0
+ self.I_filenames = []
+ self.I_delta = np.diff(i_prope_pos)
+ i_start = np.array(self.start)
+ i_stop = np.array(self.stop)
+ i_stop[self.exc_ny] = self.start[self.exc_ny]
+ for n in range(len(i_prope_pos)):
+ i_start[self.prop_ny] = i_prope_pos[n]
+ i_stop[self.prop_ny] = i_prope_pos[n]
+ i_name = self.lbl_temp.format('it') + suffix[n]
+ self.I_filenames.append(i_name)
+ i_probe = CSX.AddProbe(i_name, p_type=1, weight=self.direction, norm_dir=self.prop_ny)
+ i_probe.AddBox(i_start, i_stop)
+
+ if excite!=0:
+ excide_pos_idx = np.argmin(np.abs(prop_lines-(self.start[self.prop_ny] + self.feed_shift*self.direction)))
+ exc_start = np.array(self.start)
+ exc_stop = np.array(self.stop)
+ exc_start[self.prop_ny] = prop_lines[excide_pos_idx]
+ exc_stop [self.prop_ny] = prop_lines[excide_pos_idx]
+ exc_vec = np.zeros(3)
+ exc_vec[self.exc_ny] = -1*self.upside_down*excite
+ exc = CSX.AddExcitation(self.lbl_temp.format('excite'), exc_type=0, exc_val=exc_vec, delay=self.delay)
+ exc.AddBox(exc_start, exc_stop, priority=self.priority)
+
+ if self.feed_R>=0 and not np.isinf(self.feed_R):
+ R_start = np.array(self.start)
+ R_stop = np.array(self.stop)
+ R_stop [self.prop_ny] = R_start[self.prop_ny]
+ if self.feed_R==0:
+ metal_prop.AddBox(R_start, R_stop)
+ else:
+ lumped_R = CSX.AddLumpedElement(self.lbl_temp.format('resist'), ny=self.exc_ny, caps=True, R=self.feed_R)
+ lumped_R.AddBox(R_start, R_stop)
+
+ def ReadUIData(self, sim_path, freq, signal_type ='pulse'):
+ self.u_data = UI_data(self.U_filenames, sim_path, freq, signal_type )
+ self.uf_tot = self.u_data.ui_f_val[1]
+
+ self.i_data = UI_data(self.I_filenames, sim_path, freq, signal_type )
+ self.if_tot = 0.5*(self.i_data.ui_f_val[0]+self.i_data.ui_f_val[1])
+
+ unit = self.CSX.GetGrid().GetDeltaUnit()
+ Et = self.u_data.ui_f_val[1]
+ dEt = (self.u_data.ui_f_val[2] - self.u_data.ui_f_val[0]) / (np.sum(np.abs(self.U_delta)) * unit)
+ Ht = self.if_tot # space averaging: Ht is now defined at the same pos as Et
+ dHt = (self.i_data.ui_f_val[1] - self.i_data.ui_f_val[0]) / (np.abs(self.I_delta[0]) * unit)
+
+ beta = np.sqrt( - dEt * dHt / (Ht * Et) )
+ beta[np.real(beta) < 0] *= -1 # determine correct sign (unlike the paper)
+ self.beta = beta
+
+ # determine ZL
+ self.Z_ref = np.sqrt(Et * dEt / (Ht * dHt))
+
+class WaveguidePort(Port):
+ """
+ Base class for any waveguide port.
+
+ See Also
+ --------
+ Port, RectWGPort
+
+ """
+ def __init__(self, CSX, port_nr, start, stop, exc_dir, E_WG_func, H_WG_func, kc, excite=0, **kw):
+ super(WaveguidePort, self).__init__(CSX, port_nr=port_nr, start=start, stop=stop, excite=excite, **kw)
+ self.exc_ny = CheckNyDir(exc_dir)
+ self.ny_P = (self.exc_ny+1)%3
+ self.ny_PP = (self.exc_ny+2)%3
+ self.direction = np.sign(stop[self.exc_ny]-start[self.exc_ny])
+ self.ref_index = 1
+
+ assert not (self.excite!=0 and stop[self.exc_ny]==start[self.exc_ny]), 'port length in excitation direction may not be zero if port is excited!'
+
+ self.kc = kc
+ self.E_func = E_WG_func
+ self.H_func = H_WG_func
+
+ if excite!=0:
+ e_start = np.array(start)
+ e_stop = np.array(stop)
+ e_stop[self.exc_ny] = e_start[self.exc_ny]
+ e_vec = np.ones(3)
+ e_vec[self.exc_ny]=0
+ exc = CSX.AddExcitation(self.lbl_temp.format('excite'), exc_type=0, exc_val=e_vec, delay=self.delay)
+ exc.SetWeightFunction([str(x) for x in self.E_func])
+ exc.AddBox(e_start, e_stop, priority=self.priority)
+
+ # voltage/current planes
+ m_start = np.array(start)
+ m_stop = np.array(stop)
+ m_start[self.exc_ny] = m_stop[self.exc_ny]
+ self.measplane_shift = np.abs(stop[self.exc_ny] - start[self.exc_ny])
+
+ self.U_filenames = [self.lbl_temp.format('ut'), ]
+
+ u_probe = CSX.AddProbe(self.U_filenames[0], p_type=10, mode_function=self.E_func)
+ u_probe.AddBox(m_start, m_stop)
+
+ self.I_filenames = [self.lbl_temp.format('it'), ]
+ i_probe = CSX.AddProbe(self.I_filenames[0], p_type=11, weight=self.direction, mode_function=self.H_func)
+ i_probe.AddBox(m_start, m_stop)
+
+
+ def CalcPort(self, sim_path, freq, ref_impedance=None, ref_plane_shift=None, signal_type='pulse'):
+ k = 2.0*np.pi*freq/C0*self.ref_index
+ self.beta = np.sqrt(k**2 - self.kc**2)
+ self.ZL = k * Z0 / self.beta #analytic waveguide impedance
+ if ref_impedance is None:
+ self.Z_ref = self.ZL
+ super(WaveguidePort, self).CalcPort(sim_path, freq, ref_impedance, ref_plane_shift, signal_type)
+
+class RectWGPort(WaveguidePort):
+ """
+ Rectangular waveguide port.
+
+ :param a,b: float -- Width/Height of rectangular waveguide port
+
+ See Also
+ --------
+ Port, WaveguidePort
+
+ """
+ def __init__(self, CSX, port_nr, start, stop, exc_dir, a, b, mode_name, excite=0, **kw):
+ Port.__init__(self, CSX, port_nr, start, stop, excite=0, **kw)
+ self.exc_ny = CheckNyDir(exc_dir)
+ self.ny_P = (self.exc_ny+1)%3
+ self.ny_PP = (self.exc_ny+2)%3
+ self.WG_size = [a, b]
+
+ self.WG_mode = mode_name
+ assert len(self.WG_mode)==4, 'Invalid mode definition'
+ self.unit = self.CSX.GetGrid().GetDeltaUnit()
+ if self.WG_mode.startswith('TE'):
+ self.TE = True
+ self.TM = False
+ else:
+ self.TE = False
+ self.TM = True
+ self.M = float(self.WG_mode[2])
+ self.N = float(self.WG_mode[3])
+
+ assert self.TE, 'Currently only TE-modes are supported! Mode found: {}'.format(self.WG_mode)
+
+ # values by David M. Pozar, Microwave Engineering, third edition
+ a = self.WG_size[0]
+ b = self.WG_size[1]
+
+ xyz = 'xyz'
+ if self.start[self.ny_P]!=0:
+ name_P = '({}-{})'.format(xyz[self.ny_P], self.start[self.ny_P])
+ else:
+ name_P = xyz[self.ny_P]
+ if self.start[self.ny_PP]!=0:
+ name_PP = '({}-{})'.format(xyz[self.ny_P], self.start[self.ny_P])
+ else:
+ name_PP = xyz[self.ny_P]
+
+ kc = np.sqrt((self.M*np.pi/a)**2 + (self.N*np.pi/b)**2)
+
+ a /= self.unit
+ b /= self.unit
+ E_func = [0,0,0]
+ H_func = [0,0,0]
+ if self.N>0:
+ E_func[self.ny_P] = '{}*cos({}*{})*sin({}*{})'.format(self.N/b , self.M*np.pi/a, name_P, self.N*np.pi/b, name_PP)
+ if self.M>0:
+ E_func[self.ny_PP] = '{}*sin({}*{})*cos({}*{})'.format(-1*self.M/a, self.M*np.pi/a, name_P, self.N*np.pi/b, name_PP)
+
+ if self.M>0:
+ H_func[self.ny_P] = '{}*sin({}*{})*cos({}*{})'.format(self.M/a, self.M*np.pi/a, name_P, self.N*np.pi/b, name_PP)
+ if self.N>0:
+ H_func[self.ny_PP] = '{}*cos({}*{})*sin({}*{})'.format(self.N/b, self.M*np.pi/a, name_P, self.N*np.pi/b, name_PP)
+
+ super(RectWGPort, self).__init__(CSX, port_nr=port_nr, start=start, stop=stop, exc_dir=exc_dir, E_WG_func=E_func, H_WG_func=H_func, kc=kc, excite=excite, **kw)
+
diff --git a/openEMS/python/openEMS/utilities.py b/openEMS/python/openEMS/utilities.py
new file mode 100644
index 0000000..22bfbf6
--- /dev/null
+++ b/openEMS/python/openEMS/utilities.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2015,20016 Thorsten Liebig (Thorsten.Liebig@gmx.de)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import numpy as np
+
+def DFT_time2freq( t, val, freq, signal_type='pulse'):
+ assert len(t)==len(val)
+ assert len(freq)>0
+ f_val = np.zeros(len(freq))*1j
+ for n_f in range(len(freq)):
+ f_val[n_f] = np.sum( val*np.exp( -1j*2*np.pi*freq[n_f] * t ) )
+
+ if signal_type == 'pulse':
+ f_val *= t[1]-t[0]
+ elif signal_type == 'periodic':
+ f_val /= len(t)
+ else:
+ raise Exception('Unknown signal type: "{}"'.format(signal_type))
+
+ return 2*f_val # single-sided spectrum
+
+def Check_Array_Equal(a,b, tol, relative=False):
+ a = np.array(a)
+ b = np.array(b)
+ if a.shape!=b.shape:
+ return False
+ if tol==0:
+ return (a==b).all()
+ if relative:
+ d = np.abs((a-b)/a)
+ else:
+ d = np.abs((a-b))
+ return np.max(d)<tol
+
+if __name__=="__main__":
+ import pylab as plt
+
+ t = np.linspace(0,2,201)
+
+ s = np.sin(2*np.pi*2*t)
+ plt.plot(t,s)
+
+ f = np.linspace(0,3,101)
+ sf = DFT_time2freq(t, s, f, 'periodic')
+
+ plt.figure()
+ plt.plot(f, np.abs(sf))
+
+ plt.show()
+
+
diff --git a/openEMS/python/setup.py b/openEMS/python/setup.py
new file mode 100644
index 0000000..ef06160
--- /dev/null
+++ b/openEMS/python/setup.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Sun Dec 13 23:48:22 2015
+
+@author: thorsten
+"""
+
+from distutils.core import setup
+from distutils.extension import Extension
+from Cython.Build import cythonize
+
+import os, sys
+ROOT_DIR = os.path.dirname(__file__)
+
+sys.path.append(os.path.join(ROOT_DIR,'..','..','CSXCAD','python'))
+
+extensions = [
+ Extension("*", [os.path.join(os.path.dirname(__file__), "openEMS","*.pyx")],
+ language="c++", # generate C++ code
+ libraries = ['CSXCAD','openEMS', 'nf2ff']),
+]
+
+setup(
+ name="openEMS",
+ version = '0.0.33',
+ description = "Python interface for the openEMS FDTD library",
+ classifiers = [
+ 'Development Status :: 3 - Alpha',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: Information Technology',
+ 'Intended Audience :: Science/Research',
+ 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
+ 'Programming Language :: Python',
+ 'Topic :: Scientific/Engineering',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ 'Operating System :: POSIX :: Linux',
+ 'Operating System :: Microsoft :: Windows',
+ ],
+ author = 'Thorsten Liebig',
+ author_email = 'Thorsten.Liebig@gmx.de',
+ maintainer = 'Thorsten Liebig',
+ maintainer_email = 'Thorsten.Liebig@gmx.de',
+ url = 'http://openEMS.de',
+ packages=["openEMS", ],
+ package_data={'openEMS': ['*.pxd']},
+ ext_modules = cythonize(extensions)
+ )
diff --git a/openEMS/tools/sar_calculation.cpp b/openEMS/tools/sar_calculation.cpp
index 343aa07..e135aca 100644
--- a/openEMS/tools/sar_calculation.cpp
+++ b/openEMS/tools/sar_calculation.cpp
@@ -292,7 +292,7 @@ int SAR_Calculation::FindFittingCubicalMass(unsigned int pos[3], float box_size,
bool SAR_Calculation::GetCubicalMass(unsigned int pos[3], double box_size, unsigned int start[3], unsigned int stop[3],
float partial_start[3], float partial_stop[3], double &mass, double &volume, double &bg_ratio, int disabledFace)
{
- if ((box_size<=0) || isnan(box_size) || isinf(box_size))
+ if ((box_size<=0) || std::isnan(box_size) || std::isinf(box_size))
{
cerr << "SAR_Calculation::GetCubicalMass: critical error: invalid averaging box size!! EXIT" << endl;
exit(-1);