From 059219617d2a39e9969ff459891ebc1023747e86 Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Sun, 2 Sep 2018 01:07:06 +0200 Subject: Import openems_0.0.35+dfsg.1-1.debian.tar.xz [dgit import tarball openems 0.0.35+dfsg.1-1 openems_0.0.35+dfsg.1-1.debian.tar.xz] --- CSXCAD.packinfo/DESCRIPTION | 7 + CSXCAD.packinfo/INDEX | 1 + CSXCAD.packinfo/NEWS | 1 + FIXME | 2 + README.source | 3 + changelog | 5 + compat | 1 + control | 131 ++++++++ copyright | 162 ++++++++++ gbp.conf | 2 + libcsxcad0.install | 1 + libcsxcad0.shlibs | 1 + libnf2ff0.install | 1 + libnf2ff0.shlibs | 1 + libopenems-dev.install | 6 + libopenems0.install | 1 + libopenems0.shlibs | 1 + libqcsxcad0.install | 1 + libqcsxcad0.shlibs | 1 + man/AppCSXCAD.txt | 19 ++ man/genmanpages.sh | 6 + man/nf2ff.txt | 16 + man/openEMS.txt | 21 ++ octave-openems.install | 5 + openEMS.packinfo/DESCRIPTION | 7 + openEMS.packinfo/INDEX | 1 + openEMS.packinfo/NEWS | 1 + openems.install | 3 + openems.manpages | 1 + patches/0001-Fix-path-to-binaries-for-Debian.patch | 90 ++++++ patches/0002-Spelling-fixes.patch | 338 +++++++++++++++++++++ patches/0003-More-things-to-fix-build.patch | 38 +++ patches/0004-link-more.patch | 33 ++ patches/0005-Deletede-CVS-dir-lintian.patch | 73 +++++ patches/0006-Don-t-exit-from-library.patch | 57 ++++ patches/series | 6 + rules | 64 ++++ source/format | 1 + tests/control | 2 + tests/octave-load | 10 + watch | 4 + 41 files changed, 1125 insertions(+) create mode 100644 CSXCAD.packinfo/DESCRIPTION create mode 100644 CSXCAD.packinfo/INDEX create mode 100644 CSXCAD.packinfo/NEWS create mode 100644 FIXME create mode 100644 README.source create mode 100644 changelog create mode 100644 compat create mode 100644 control create mode 100644 copyright create mode 100644 gbp.conf create mode 100644 libcsxcad0.install create mode 100644 libcsxcad0.shlibs create mode 100644 libnf2ff0.install create mode 100644 libnf2ff0.shlibs create mode 100644 libopenems-dev.install create mode 100644 libopenems0.install create mode 100644 libopenems0.shlibs create mode 100644 libqcsxcad0.install create mode 100644 libqcsxcad0.shlibs create mode 100644 man/AppCSXCAD.txt create mode 100755 man/genmanpages.sh create mode 100644 man/nf2ff.txt create mode 100644 man/openEMS.txt create mode 100644 octave-openems.install create mode 100644 openEMS.packinfo/DESCRIPTION create mode 100644 openEMS.packinfo/INDEX create mode 100644 openEMS.packinfo/NEWS create mode 100644 openems.install create mode 100644 openems.manpages create mode 100644 patches/0001-Fix-path-to-binaries-for-Debian.patch create mode 100644 patches/0002-Spelling-fixes.patch create mode 100644 patches/0003-More-things-to-fix-build.patch create mode 100644 patches/0004-link-more.patch create mode 100644 patches/0005-Deletede-CVS-dir-lintian.patch create mode 100644 patches/0006-Don-t-exit-from-library.patch create mode 100644 patches/series create mode 100755 rules create mode 100644 source/format create mode 100644 tests/control create mode 100755 tests/octave-load create mode 100644 watch diff --git a/CSXCAD.packinfo/DESCRIPTION b/CSXCAD.packinfo/DESCRIPTION new file mode 100644 index 0000000..8419e33 --- /dev/null +++ b/CSXCAD.packinfo/DESCRIPTION @@ -0,0 +1,7 @@ +Name: csxcad +Version: 0.0.35 +Date: 2016-07-06 +Author: various authors +Maintainer: Ruben Undheim +Title: Electromagnetic field solver +Description: Signal processing tools, including filtering, windowing and display functions. diff --git a/CSXCAD.packinfo/INDEX b/CSXCAD.packinfo/INDEX new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/CSXCAD.packinfo/INDEX @@ -0,0 +1 @@ + diff --git a/CSXCAD.packinfo/NEWS b/CSXCAD.packinfo/NEWS new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/CSXCAD.packinfo/NEWS @@ -0,0 +1 @@ + diff --git a/FIXME b/FIXME new file mode 100644 index 0000000..6530c87 --- /dev/null +++ b/FIXME @@ -0,0 +1,2 @@ +For some reason, it works fine when built in stretch, but fails with a segfault when built in sid. +Figure out why. diff --git a/README.source b/README.source new file mode 100644 index 0000000..c6f5a31 --- /dev/null +++ b/README.source @@ -0,0 +1,3 @@ +The bundled library fparser has been removed from the source package. + +Also a few .HYP files for which the license was not found, have been removed. diff --git a/changelog b/changelog new file mode 100644 index 0000000..ea08ac1 --- /dev/null +++ b/changelog @@ -0,0 +1,5 @@ +openems (0.0.35+dfsg.1-1) unstable; urgency=low + + * Initial release (Closes: #830109) + + -- Ruben Undheim Sun, 02 Sep 2018 01:07:06 +0200 diff --git a/compat b/compat new file mode 100644 index 0000000..b4de394 --- /dev/null +++ b/compat @@ -0,0 +1 @@ +11 diff --git a/control b/control new file mode 100644 index 0000000..8b87ea3 --- /dev/null +++ b/control @@ -0,0 +1,131 @@ +Source: openems +Maintainer: Debian Science Maintainers +Uploaders: Ruben Undheim +Section: electronics +Priority: optional +Build-Depends: debhelper (>= 11), + cmake, + libhdf5-dev, + libboost-all-dev, + libcgal-dev, + libcgal-qt5-dev, + libtinyxml-dev, + libvtk6-qt-dev, + libfparser-dev, +# It is called octave-pkg-dev in stretch +# and dh-octave in sid + dh-octave | octave-pkg-dev, + chrpath, + txt2man, + g++-7 +Standards-Version: 4.2.1 +Vcs-Browser: https://salsa.debian.org/science-team/openems +Vcs-Git: https://salsa.debian.org/science-team/openems.git +Homepage: http://openems.de + +Package: openems +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + libopenems0 (= ${binary:Version}), + libcsxcad0 (= ${binary:Version}), + libqcsxcad0 (= ${binary:Version}), + libnf2ff0 (= ${binary:Version}) +Recommends: octave-openems +Description: Electromagnetic simulator + This is a simulator for electromagnetic problems using the FDTD + (Finite-difference time-domain method) algorithm. + . + The FDTD algorithm is a popular algorithm for solving electromagnetic problems + in the time domain. + +Package: libopenems0 +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, + ${misc:Depends} +Pre-Depends: ${misc:Pre-Depends} +Multi-Arch: same +Description: Library for the electromagnetic simulator using the FDTD method + The finite difference time domain method is a popular numerical algorithm + for solving electromagnetic problems. + . + This package contains the library used by openEMS. + +Package: libcsxcad0 +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, + ${misc:Depends} +Pre-Depends: ${misc:Pre-Depends} +Multi-Arch: same +Description: Continuous Structure XML library for openEMS + A C++ library to describe geometrical objects and their physical or + non-physical properties. + . + openEMS is a simulator for electromagnetic problems using + the FDTD algorithm. + +Package: libqcsxcad0 +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, + ${misc:Depends} +Pre-Depends: ${misc:Pre-Depends} +Multi-Arch: same +Description: QT Gui Library for Visualization of Continuous Structure XML + Continuous structure XML (libcsxcad) is a way to describe geometrical objects + and their physical or non-physical properties. This library provides + functions to show this in a GUI. + . + openEMS is a simulator for electromagnetic problems using + the FDTD algorithm. + +Package: libnf2ff0 +Architecture: any +Section: libs +Depends: ${shlibs:Depends}, + ${misc:Depends} +Pre-Depends: ${misc:Pre-Depends} +Multi-Arch: same +Description: Near-field to far-field transform library + This is a library for the near-field to far-field transform used + by openEMS. + . + It is needed by the nf2ff utility. + . + openEMS is a simulator for electromagnetic problems using + the FDTD algorithm. + +Package: libopenems-dev +Architecture: any +Section: libdevel +Depends: ${misc:Depends}, + libopenems0 (= ${binary:Version}), + libcsxcad0 (= ${binary:Version}), + libqcsxcad0 (= ${binary:Version}), + libnf2ff0 (= ${binary:Version}), + libfparser-dev +Multi-Arch: same +Description: Development files for openems + This package contains the development files for all + the libraries provided by openEMS. + . + openEMS is a simulator for electromagnetic problems using + the FDTD algorithm. + +Package: octave-openems +Architecture: any +Depends: ${shlibs:Depends}, + ${misc:Depends}, + openems, + octave, + epstool, + transfig +Description: Octave interface for openems + This package contains the octave-files needed for + openEMS. The are installed such that they can be used + after running "pkg load openems" or "pkg load csxcad". + . + openEMS is a simulator for electromagnetic problems using + the FDTD algorithm. diff --git a/copyright b/copyright new file mode 100644 index 0000000..90f3977 --- /dev/null +++ b/copyright @@ -0,0 +1,162 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: openEMS +Source: https://github.com/thliebig/openEMS +Files-Excluded: fparser + hyp2mat/eagle/hairpinfilter/hairpinfilter.HYP + hyp2mat/eagle/notchfilter/notchfilter.HYP + hyp2mat/eagle/tutorial/msl.HYP + +Files: * +Copyright: 2010-2016 Thorsten Liebig +License: GPL-3+ + +Files: CSXCAD/* + QCSXCAD/* +Copyright: 2010-2016 Thorsten Liebig +License: LGPL-3+ + +Files: hyp2mat/* +Copyright: 2012,2014 Koen De Vleeschauwer +License: GPL-3+ + +Files: openEMS/FDTD/engine_multithread.* + openEMS/FDTD/operator_sse.* + openEMS/tools/aligned_allocator.h + openEMS/tools/global.* +Copyright: 2010 Sebastian Held +License: GPL-3+ + +Files: QCSXCAD/export_pov.* + QCSXCAD/export_x3d.* +Copyright: 2010 Sebastian Held (sebastian.held@gmx.de) +License: LGPL-3+ + +Files: AppCSXCAD/linux/AppCSXCAD.spec + CSXCAD/linux/CSXCAD.spec + QCSXCAD/linux/QCSXCAD.spec + openEMS/linux/openEMS.spec +Copyright: 2010 SUSE LINUX Products GmbH, Nuernberg, Germany. +License: MIT or GPL-3+ + +Files: hyp2mat/eagle/hairpinfilter/demo_hairpin.m + hyp2mat/eagle/notchfilter/demo_notch.m + hyp2mat/eagle/tutorial/GetEpsilon.m + hyp2mat/eagle/tutorial/GetUnits.m + hyp2mat/eagle/tutorial/tutorial_hyp2mat.m +Copyright: 2011,2012 Thorsten Liebig + 2012 Koen De Vleeschauwer +License: GPL-3+ + +Files: hyp2mat/lib/clipper.cpp +Copyright: 2010-2013 Angus Johnson +License: Boost_ver_1 + +Files: CTB/* +Copyright: 2006-2013 Sebastian Held, Thorsten Liebig +License: BSD-2-clause + +Files: debian/* +Copyright: 2016,2018 Ruben Undheim +License: GPL-3+ + + +License: GPL-3+ + This package 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 . + . + On Debian systems, the complete text of the GNU General + Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". + + +License: LGPL-3+ + 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 . + . + On Debian systems, the complete text of the GNU Lesser General + Public License version 3 can be found in "/usr/share/common-licenses/LGPL-3". + + +License: Boost_ver_1 + Permission is hereby granted, free of charge, to any person or organization + obtaining a copy of the software and accompanying documentation covered by + this license (the "Software") to use, reproduce, display, distribute, + execute, and transmit the Software, and to prepare derivative works of the + Software, and to permit third-parties to whom the Software is furnished to + do so, all subject to the following: + . + The copyright notices in the Software and this entire statement, including + the above license grant, this restriction and the following disclaimer, + must be included in all copies of the Software, in whole or in part, and + all derivative works of the Software, unless such copies or derivative + works are solely in the form of machine-executable object code generated by + a source language processor. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT + SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE + FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + +License: MIT + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + . + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + . + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + +License: BSD-2-clause + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + . + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + . + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/gbp.conf b/gbp.conf new file mode 100644 index 0000000..cec628c --- /dev/null +++ b/gbp.conf @@ -0,0 +1,2 @@ +[DEFAULT] +pristine-tar = True diff --git a/libcsxcad0.install b/libcsxcad0.install new file mode 100644 index 0000000..5bcae99 --- /dev/null +++ b/libcsxcad0.install @@ -0,0 +1 @@ +usr/lib/*/libCSXCAD.so.* diff --git a/libcsxcad0.shlibs b/libcsxcad0.shlibs new file mode 100644 index 0000000..d1cd130 --- /dev/null +++ b/libcsxcad0.shlibs @@ -0,0 +1 @@ +libCSXCAD 0 libcsxcad0 diff --git a/libnf2ff0.install b/libnf2ff0.install new file mode 100644 index 0000000..6224d65 --- /dev/null +++ b/libnf2ff0.install @@ -0,0 +1 @@ +usr/lib/*/libnf2ff.so.* diff --git a/libnf2ff0.shlibs b/libnf2ff0.shlibs new file mode 100644 index 0000000..f919eb6 --- /dev/null +++ b/libnf2ff0.shlibs @@ -0,0 +1 @@ +libnf2ff 0 libnf2ff0 diff --git a/libopenems-dev.install b/libopenems-dev.install new file mode 100644 index 0000000..40ec33a --- /dev/null +++ b/libopenems-dev.install @@ -0,0 +1,6 @@ +usr/lib/*/libCS*.so +usr/lib/*/libQCS*.so +usr/lib/*/libope*.so +usr/lib/*/libnf*.so +usr/include/CSXCAD +usr/include/QCSXCAD diff --git a/libopenems0.install b/libopenems0.install new file mode 100644 index 0000000..881bdfe --- /dev/null +++ b/libopenems0.install @@ -0,0 +1 @@ +usr/lib/*/libopenEMS.so.* diff --git a/libopenems0.shlibs b/libopenems0.shlibs new file mode 100644 index 0000000..d2fd3b9 --- /dev/null +++ b/libopenems0.shlibs @@ -0,0 +1 @@ +libopenEMS 0 libopenems0 diff --git a/libqcsxcad0.install b/libqcsxcad0.install new file mode 100644 index 0000000..342e622 --- /dev/null +++ b/libqcsxcad0.install @@ -0,0 +1 @@ +usr/lib/*/libQCSXCAD.so.* diff --git a/libqcsxcad0.shlibs b/libqcsxcad0.shlibs new file mode 100644 index 0000000..eaf208a --- /dev/null +++ b/libqcsxcad0.shlibs @@ -0,0 +1 @@ +libQCSXCAD 0 libqcsxcad0 diff --git a/man/AppCSXCAD.txt b/man/AppCSXCAD.txt new file mode 100644 index 0000000..13f4324 --- /dev/null +++ b/man/AppCSXCAD.txt @@ -0,0 +1,19 @@ +NAME + AppCSXCAD - GUI for looking at geometries for openEMS + +SYNOPSIS + AppCSXCAD + +DESCRIPTION + + Running the command launches a GUI + +OPTIONS + + + +AUTHOR + This manual page was written by Ruben Undheim for the Debian project (and may be used by others). + + + diff --git a/man/genmanpages.sh b/man/genmanpages.sh new file mode 100755 index 0000000..5ecfefd --- /dev/null +++ b/man/genmanpages.sh @@ -0,0 +1,6 @@ +#!/bin/bash + + +txt2man -d "${CHANGELOG_DATE}" -t OPENEMS -s 1 openEMS.txt > openEMS.1 +txt2man -d "${CHANGELOG_DATE}" -t NF2FF -s 1 nf2ff.txt > nf2ff.1 +txt2man -d "${CHANGELOG_DATE}" -t APPCSXCAD -s 1 AppCSXCAD.txt > AppCSXCAD.1 diff --git a/man/nf2ff.txt b/man/nf2ff.txt new file mode 100644 index 0000000..341e1dd --- /dev/null +++ b/man/nf2ff.txt @@ -0,0 +1,16 @@ +NAME + nf2ff - Near-field to Far-field Transformation for openEMS + +SYNOPSIS + nf2ff + +DESCRIPTION + + + + +AUTHOR + This manual page was written by Ruben Undheim for the Debian project (and may be used by others). + + + diff --git a/man/openEMS.txt b/man/openEMS.txt new file mode 100644 index 0000000..2e7a1e2 --- /dev/null +++ b/man/openEMS.txt @@ -0,0 +1,21 @@ +NAME + openEMS - Electromagnetic simulator using the FDTD algorithm + +SYNOPSIS + openEMS [...] + +DESCRIPTION + + +OPTIONS + + --disable-dumps Disable all field dumps for faster simulation + --debug-material Dump material distribution to a vtk file for debugging + + + +AUTHOR + This manual page was written by Ruben Undheim for the Debian project (and may be used by others). + + + diff --git a/octave-openems.install b/octave-openems.install new file mode 100644 index 0000000..09821d2 --- /dev/null +++ b/octave-openems.install @@ -0,0 +1,5 @@ +usr/share/openEMS/matlab/* /usr/share/octave/packages/openems-0.0.35/ +usr/lib/*/octave +usr/share/CSXCAD/matlab/* /usr/share/octave/packages/csxcad-0.0.35/ +debian/openEMS.packinfo/* /usr/share/octave/packages/openems-0.0.35/packinfo/ +debian/CSXCAD.packinfo/* /usr/share/octave/packages/csxcad-0.0.35/packinfo/ diff --git a/openEMS.packinfo/DESCRIPTION b/openEMS.packinfo/DESCRIPTION new file mode 100644 index 0000000..9490323 --- /dev/null +++ b/openEMS.packinfo/DESCRIPTION @@ -0,0 +1,7 @@ +Name: openems +Version: 0.0.35 +Date: 2016-07-06 +Author: various authors +Maintainer: Ruben Undheim +Title: Electromagnetic field solver +Description: Signal processing tools, including filtering, windowing and display functions. diff --git a/openEMS.packinfo/INDEX b/openEMS.packinfo/INDEX new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/openEMS.packinfo/INDEX @@ -0,0 +1 @@ + diff --git a/openEMS.packinfo/NEWS b/openEMS.packinfo/NEWS new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/openEMS.packinfo/NEWS @@ -0,0 +1 @@ + diff --git a/openems.install b/openems.install new file mode 100644 index 0000000..cf3de4f --- /dev/null +++ b/openems.install @@ -0,0 +1,3 @@ +usr/bin/AppCSXCAD +usr/bin/nf2ff +usr/bin/openEMS diff --git a/openems.manpages b/openems.manpages new file mode 100644 index 0000000..13cdaf4 --- /dev/null +++ b/openems.manpages @@ -0,0 +1 @@ +debian/man/*.1 diff --git a/patches/0001-Fix-path-to-binaries-for-Debian.patch b/patches/0001-Fix-path-to-binaries-for-Debian.patch new file mode 100644 index 0000000..542589b --- /dev/null +++ b/patches/0001-Fix-path-to-binaries-for-Debian.patch @@ -0,0 +1,90 @@ +From: Ruben Undheim +Date: Wed, 6 Jul 2016 18:24:09 +0200 +Subject: Fix path to binaries for Debian + +--- + CSXCAD/matlab/CSXGeomPlot.m | 16 +++++++++------- + openEMS/matlab/CalcNF2FF.m | 15 ++++++++------- + openEMS/matlab/private/invoke_openEMS.m | 16 +++++++++------- + 3 files changed, 26 insertions(+), 21 deletions(-) + +diff --git a/CSXCAD/matlab/CSXGeomPlot.m b/CSXCAD/matlab/CSXGeomPlot.m +index df33c94..034f1a1 100644 +--- a/CSXCAD/matlab/CSXGeomPlot.m ++++ b/CSXCAD/matlab/CSXGeomPlot.m +@@ -27,13 +27,15 @@ end + filename = mfilename('fullpath'); + dir = fileparts( filename ); + +-if isunix +- AppCSXCAD_bin = searchBinary('AppCSXCAD.sh', ... +- {[dir filesep '..' filesep '..' filesep 'AppCSXCAD' filesep], ... +- [dir filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}); +-else % assume windows +- AppCSXCAD_bin = searchBinary('AppCSXCAD.exe',[dir filesep '..' filesep]); +-end ++%if isunix ++% AppCSXCAD_bin = searchBinary('AppCSXCAD.sh', ... ++% {[dir filesep '..' filesep '..' filesep 'AppCSXCAD' filesep], ... ++% [dir filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}); ++%else % assume windows ++% AppCSXCAD_bin = searchBinary('AppCSXCAD.exe',[dir filesep '..' filesep]); ++%end ++ ++AppCSXCAD_bin = '/usr/bin/AppCSXCAD'; + + command = [AppCSXCAD_bin ' --disableEdit ' args_string ' ' CSX_filename]; + disp( ['invoking AppCSXCAD, exit to continue script...'] ); +diff --git a/openEMS/matlab/CalcNF2FF.m b/openEMS/matlab/CalcNF2FF.m +index c80b52e..07cc849 100644 +--- a/openEMS/matlab/CalcNF2FF.m ++++ b/openEMS/matlab/CalcNF2FF.m +@@ -98,13 +98,14 @@ struct_2_xml(nf2ff.xml,nf2ff_xml,'nf2ff'); + m_filename = mfilename('fullpath'); + dir_name = fileparts( m_filename ); + +-if isunix +- nf2ff_bin = searchBinary('nf2ff', ... +- {[dir_name filesep '..' filesep 'nf2ff' filesep], ... +- [dir_name filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}, 0); +-else +- nf2ff_bin = searchBinary('nf2ff.exe',[dir_name filesep '..' filesep], 0); +-end ++%if isunix ++% nf2ff_bin = searchBinary('nf2ff', ... ++% {[dir_name filesep '..' filesep 'nf2ff' filesep], ... ++% [dir_name filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}, 0); ++%else ++% nf2ff_bin = searchBinary('nf2ff.exe',[dir_name filesep '..' filesep], 0); ++%end ++nf2ff_bin = '/usr/bin/nf2ff'; + + if ((exist(nf2ff.hdf5,'file') && (mode==0)) || (mode==2)) + disp('CalcNF2FF: Reading nf2ff data only...') +diff --git a/openEMS/matlab/private/invoke_openEMS.m b/openEMS/matlab/private/invoke_openEMS.m +index afb2b46..8c4d79b 100644 +--- a/openEMS/matlab/private/invoke_openEMS.m ++++ b/openEMS/matlab/private/invoke_openEMS.m +@@ -26,13 +26,15 @@ end + filename = mfilename('fullpath'); + dir = fileparts( filename ); + +-if isunix +- openEMS_bin = searchBinary('openEMS.sh', ... +- {[dir filesep '..' filesep '..' filesep], ... % try devel path +- [dir filesep '..' filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}); % try (default) install path +-else % assume windows +- openEMS_bin = searchBinary('openEMS.exe', [dir filesep '..' filesep '..' filesep]); +-end ++%if isunix ++% openEMS_bin = searchBinary('openEMS.sh', ... ++% {[dir filesep '..' filesep '..' filesep], ... % try devel path ++% [dir filesep '..' filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}); % try (default) install path ++%else % assume windows ++% openEMS_bin = searchBinary('openEMS.exe', [dir filesep '..' filesep '..' filesep]); ++%end ++ ++openEMS_bin = '/usr/bin/openEMS'; + + command = [openEMS_bin ' ' opts]; + diff --git a/patches/0002-Spelling-fixes.patch b/patches/0002-Spelling-fixes.patch new file mode 100644 index 0000000..8ae0682 --- /dev/null +++ b/patches/0002-Spelling-fixes.patch @@ -0,0 +1,338 @@ +From: Ruben Undheim +Date: Sat, 9 Jul 2016 11:12:02 +0200 +Subject: Spelling fixes + +--- + CSXCAD/src/CSPrimPolyhedron.cpp | 4 ++-- + CSXCAD/src/CSPrimPolyhedronReader.cpp | 2 +- + CSXCAD/src/CSRectGrid.cpp | 4 ++-- + QCSXCAD/QCSGridEditor.cpp | 2 +- + QCSXCAD/QCSXCAD.cpp | 8 ++++---- + QCSXCAD/QVTKStructure.cpp | 2 +- + openEMS/Common/processmodematch.cpp | 2 +- + openEMS/FDTD/extensions/operator_ext_upml.cpp | 2 +- + openEMS/FDTD/operator.cpp | 6 +++--- + openEMS/tools/AdrOp.cpp | 22 +++++++++++----------- + openEMS/tools/ErrorMsg.cpp | 10 +++++----- + openEMS/tools/ExpenseLog.h | 2 +- + openEMS/tools/useful.cpp | 2 +- + openEMS/tools/vtk_file_writer.cpp | 4 ++-- + 14 files changed, 36 insertions(+), 36 deletions(-) + +diff --git a/CSXCAD/src/CSPrimPolyhedron.cpp b/CSXCAD/src/CSPrimPolyhedron.cpp +index 7eac505..9583b7e 100644 +--- a/CSXCAD/src/CSPrimPolyhedron.cpp ++++ b/CSXCAD/src/CSPrimPolyhedron.cpp +@@ -183,11 +183,11 @@ bool CSPrimPolyhedron::BuildTree() + { + m_Dimension = 2; + +- //if structure is not closed due to invalud faces, mark it as 3D ++ //if structure is not closed due to invalid faces, mark it as 3D + if (m_InvalidFaces>0) + { + m_Dimension = 3; +- std::cerr << "CSPrimPolyhedron::BuildTree: Warning, found polyhedron has invalud faces and is not a closed surface, setting to 3D solid anyway!" << std::endl; ++ std::cerr << "CSPrimPolyhedron::BuildTree: Warning, found polyhedron has invalid faces and is not a closed surface, setting to 3D solid anyway!" << std::endl; + } + } + +diff --git a/CSXCAD/src/CSPrimPolyhedronReader.cpp b/CSXCAD/src/CSPrimPolyhedronReader.cpp +index ed224fd..c88c67e 100644 +--- a/CSXCAD/src/CSPrimPolyhedronReader.cpp ++++ b/CSXCAD/src/CSPrimPolyhedronReader.cpp +@@ -77,7 +77,7 @@ bool CSPrimPolyhedronReader::Write2XML(TiXmlElement &elem, bool parameterised) + elem.SetAttribute("FileType","PLY"); + break; + default: +- elem.SetAttribute("FileType","Unkown"); ++ elem.SetAttribute("FileType","Unknown"); + break; + } + return CSPrimitives::Write2XML(elem,parameterised); +diff --git a/CSXCAD/src/CSRectGrid.cpp b/CSXCAD/src/CSRectGrid.cpp +index 50f2947..5b36dc2 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 + } + fParse.Parse(DistFunction,dirVar); + if (fParse.GetParseErrorType()!=FunctionParser::FP_NO_ERROR) +- return std::string("An error occured parsing f(") + dirVar + std::string(") - Parser message:\n") + std::string(fParse.ErrorMsg()); ++ return std::string("An error occurred parsing f(") + dirVar + std::string(") - Parser message:\n") + std::string(fParse.ErrorMsg()); + + double dValue=0; + bool error=false; +@@ -88,7 +88,7 @@ std::string CSRectGrid::AddDiscLines(int direct, int numLines, double* vals, std + if (fParse.EvalError()!=0) error=true; + AddDiscLine(direct,dValue); + } +- if (error) return std::string("An error occured evaluation the grid function f(") + dirVar + std::string(")!"); ++ if (error) return std::string("An error occurred evaluation the grid function f(") + dirVar + std::string(")!"); + } + return ""; + } +diff --git a/QCSXCAD/QCSGridEditor.cpp b/QCSXCAD/QCSGridEditor.cpp +index 4e2210c..17d8ffe 100644 +--- a/QCSXCAD/QCSGridEditor.cpp ++++ b/QCSXCAD/QCSGridEditor.cpp +@@ -237,7 +237,7 @@ void QCSGridEditor::BuildInHomogenDisc() + // if (fParse.EvalError()!=0) error=true; + // clGrid->AddDiscLine(i,dValue); + // } +-// if (error) QMessageBox::warning(HomogenDisc,tr("Error evaluation grid function!"),QString(tr("An error occured evaluation the grid function f(%1)!").arg(coordVars.at(i)))); ++// if (error) QMessageBox::warning(HomogenDisc,tr("Error evaluation grid function!"),QString(tr("An error occurred evaluation the grid function f(%1)!").arg(coordVars.at(i)))); + // } + // clGrid->Sort(i); + // } +diff --git a/QCSXCAD/QCSXCAD.cpp b/QCSXCAD/QCSXCAD.cpp +index 4cd4a74..b9ef094 100644 +--- a/QCSXCAD/QCSXCAD.cpp ++++ b/QCSXCAD/QCSXCAD.cpp +@@ -299,7 +299,7 @@ bool QCSXCAD::ReadNode(TiXmlNode* root) + if (root==NULL) return false; + clear(); + QString msg(ReadFromXML(root)); +- if (msg.isEmpty()==false) QMessageBox::warning(this,tr("Geometry read error"),tr("An geometry read error occured!!\n\n")+msg,QMessageBox::Ok,QMessageBox::NoButton); ++ if (msg.isEmpty()==false) QMessageBox::warning(this,tr("Geometry read error"),tr("An geometry read error occurred!!\n\n")+msg,QMessageBox::Ok,QMessageBox::NoButton); + CSTree->UpdateTree(); + CSTree->expandAll(); + setModified(); +@@ -336,7 +336,7 @@ bool QCSXCAD::ReadFile(QString filename) + // QString msg(ReadFromXML(filename.toLatin1().constData())); + QString msg(ReadFromXML(root)); + if (msg.isEmpty()==false) +- QMessageBox::warning(this,tr("Geometry read error"),tr("An geometry read error occured!!\n\n")+msg,QMessageBox::Ok,QMessageBox::NoButton); ++ QMessageBox::warning(this,tr("Geometry read error"),tr("An geometry read error occurred!!\n\n")+msg,QMessageBox::Ok,QMessageBox::NoButton); + + CSTree->UpdateTree(); + CSTree->expandAll(); +@@ -720,7 +720,7 @@ void QCSXCAD::ExportGeometry() + if (qFilename==NULL) return; + if (!qFilename.endsWith(".xml")) qFilename+=".xml"; + +- if (Write2XML(qFilename.toLatin1().data())==false) QMessageBox::warning(this,tr("Geometry Export"),tr("Unknown error occured! Geometry Export failed"),1,0); ++ if (Write2XML(qFilename.toLatin1().data())==false) QMessageBox::warning(this,tr("Geometry Export"),tr("Unknown error occurred! Geometry Export failed"),1,0); + } + + void QCSXCAD::ExportGeometry_Povray() +@@ -802,7 +802,7 @@ void QCSXCAD::ExportGeometry(QString dirname, int type) + StructureVTK->ExportProperty2PLY(uID,filename,clGrid.GetDeltaUnit()); + break; + default: +- QMessageBox::warning(this, "Export Dialog","Unkown export type, skipping..."); ++ QMessageBox::warning(this, "Export Dialog","Unknown export type, skipping..."); + return; + break; + } +diff --git a/QCSXCAD/QVTKStructure.cpp b/QCSXCAD/QVTKStructure.cpp +index 9482dde..8eea1e8 100644 +--- a/QCSXCAD/QVTKStructure.cpp ++++ b/QCSXCAD/QVTKStructure.cpp +@@ -295,7 +295,7 @@ void QVTKStructure::RenderGridDir(int dir, unsigned int plane_pos) + uiQty[n]=CSGrid->GetQtyLines(n); + if ((int)plane_pos>=uiQty[dir]) + { +- cerr << "QVTKStructure::RenderGridDir: requested plane postion is out of range, resetting to max value!" << endl; ++ cerr << "QVTKStructure::RenderGridDir: requested plane position is out of range, resetting to max value!" << endl; + plane_pos = uiQty[dir]-1; + } + +diff --git a/openEMS/Common/processmodematch.cpp b/openEMS/Common/processmodematch.cpp +index 620257d..7cd22f8 100644 +--- a/openEMS/Common/processmodematch.cpp ++++ b/openEMS/Common/processmodematch.cpp +@@ -123,7 +123,7 @@ void ProcessModeMatch::InitProcess() + int res = m_ModeParser[n]->Parse(m_ModeFunction[ny], "x,y,z,rho,a,r,t"); + if (res >= 0) + { +- cerr << "ProcessModeMatch::InitProcess(): Warning, an error occured parsing the mode matching function (see below) ..." << endl; ++ cerr << "ProcessModeMatch::InitProcess(): Warning, an error occurred parsing the mode matching function (see below) ..." << endl; + cerr << m_ModeFunction[ny] << "\n" << string(res, ' ') << "^\n" << m_ModeParser[n]->ErrorMsg() << "\n"; + SetEnable(false); + Reset(); +diff --git a/openEMS/FDTD/extensions/operator_ext_upml.cpp b/openEMS/FDTD/extensions/operator_ext_upml.cpp +index fc46d85..d64c21c 100644 +--- a/openEMS/FDTD/extensions/operator_ext_upml.cpp ++++ b/openEMS/FDTD/extensions/operator_ext_upml.cpp +@@ -280,7 +280,7 @@ bool Operator_Ext_UPML::SetGradingFunction(string func) + int res = m_GradingFunction->Parse(m_GradFunc.c_str(), "D,dl,W,Z,N"); + if (res < 0) return true; + +- cerr << "Operator_Ext_UPML::SetGradingFunction: Warning, an error occured parsing the pml grading function (see below) ..." << endl; ++ cerr << "Operator_Ext_UPML::SetGradingFunction: Warning, an error occurred parsing the pml grading function (see below) ..." << endl; + cerr << func << "\n" << string(res, ' ') << "^\n" << m_GradingFunction->ErrorMsg() << "\n"; + return false; + } +diff --git a/openEMS/FDTD/operator.cpp b/openEMS/FDTD/operator.cpp +index a7582aa..2dec2d3 100644 +--- a/openEMS/FDTD/operator.cpp ++++ b/openEMS/FDTD/operator.cpp +@@ -450,7 +450,7 @@ Grid_Path Operator::FindPath(double start[], double stop[]) + currPos[minDir]+=-1; + minPos[minDir]-=1; + } +- //check validity of current postion ++ //check validity of current position + for (int n=0;n<3;++n) + if (currPos[n]>=numLines[n]) + { +@@ -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])) + { +- 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; + cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << "," << pos[2] << endl; + exit(0); + } +@@ -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])) + { +- 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; + cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << "," << pos[2] << endl; + exit(0); + } +diff --git a/openEMS/tools/AdrOp.cpp b/openEMS/tools/AdrOp.cpp +index 228f8de..23a7e87 100644 +--- a/openEMS/tools/AdrOp.cpp ++++ b/openEMS/tools/AdrOp.cpp +@@ -28,15 +28,15 @@ AdrOp::AdrOp(unsigned int muiImax, unsigned int muiJmax, unsigned int muiKmax, u + fprintf(stderr,"Memory allocation failed!! exiting..."); + exit(1); + } +- error->SetMsg(1,"Adress Operator: Memory allocation failed!! exiting..."); +- error->SetMsg(2,"Adress Operator: Invalid Adress requested!! exiting..."); +- error->SetMsg(3,"Adress Operator: Invalid Position set!! exiting..."); +- error->SetMsg(4,"Adress Operator: Invalid jump or passing end of iteration!! exiting..."); +- error->SetMsg(5,"Adress Operator: 4D not yet implemented!! exiting..."); +- error->SetMsg(6,"Adress Operator: Position not set!! exiting..."); +- error->SetMsg(7,"Adress Operator: Cells not added to Adress Operator!! exiting..."); +- error->SetMsg(8,"Adress Operator: Invalid Node!! exiting..."); +- error->SetMsg(9,"Adress Operator: Grid invalid!! exiting..."); ++ error->SetMsg(1,"Address Operator: Memory allocation failed!! exiting..."); ++ error->SetMsg(2,"Address Operator: Invalid Address requested!! exiting..."); ++ error->SetMsg(3,"Address Operator: Invalid Position set!! exiting..."); ++ error->SetMsg(4,"Address Operator: Invalid jump or passing end of iteration!! exiting..."); ++ error->SetMsg(5,"Address Operator: 4D not yet implemented!! exiting..."); ++ error->SetMsg(6,"Address Operator: Position not set!! exiting..."); ++ error->SetMsg(7,"Address Operator: Cells not added to Address Operator!! exiting..."); ++ error->SetMsg(8,"Address Operator: Invalid Node!! exiting..."); ++ error->SetMsg(9,"Address Operator: Grid invalid!! exiting..."); + + //if (muiImax<0) muiImax=0; + //if (muiJmax<0) muiJmax=0; +@@ -50,7 +50,7 @@ AdrOp::AdrOp(unsigned int muiImax, unsigned int muiJmax, unsigned int muiKmax, u + else exit(-2); + if (muiKmax>0) uiDimension++; + if ( (muiLmax>0) && (muiKmax>0) ) uiDimension++; +-// cout << "\n-----Adress Operator created: Dimension: " << uiDimension << "----" <0) && (nr<=NoMsg)) + { + if (Msg[nr-1]!=NULL) fprintf(stderr,"%s",Msg[nr-1]); +- else fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); ++ else fprintf(stderr,"unknown error occurred!! Error code: %d exiting...",nr); + if (chAddMsg!=NULL) fprintf(stderr,"%s",chAddMsg); + getchar(); + exit(nr); + } + else + { +- fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); ++ fprintf(stderr,"unknown error occurred!! Error code: %d exiting...",nr); + getchar(); + exit(nr); + } +@@ -78,14 +78,14 @@ void ErrorMsg::Error(unsigned int nr,int addNr) + if ((nr>0) && (nr<=NoMsg)) + { + if (Msg[nr-1]!=NULL) fprintf(stderr,"%s",Msg[nr-1]); +- else fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); ++ else fprintf(stderr,"unknown error occurred!! Error code: %d exiting...",nr); + fprintf(stderr,"%d",addNr); + getchar(); + exit(nr); + } + else + { +- fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); ++ fprintf(stderr,"unknown error occurred!! Error code: %d exiting...",nr); + getchar(); + exit(nr); + } +@@ -93,6 +93,6 @@ void ErrorMsg::Error(unsigned int nr,int addNr) + + void ErrorMsg::ownError(void) + { +- fprintf(stdout," Error occured by using Error Message class!! ... exiting..."); ++ fprintf(stdout," Error occurred by using Error Message class!! ... exiting..."); + exit(-1); + } +diff --git a/openEMS/tools/ExpenseLog.h b/openEMS/tools/ExpenseLog.h +index f8cc1ba..8aa1438 100644 +--- a/openEMS/tools/ExpenseLog.h ++++ b/openEMS/tools/ExpenseLog.h +@@ -14,7 +14,7 @@ using namespace std; + ExpenseLog EL; \ + ExpenseModule* EngineExpense=EL.AddModule("Static Engine Expenses"); \ + ExpenseModule* PPExpense=EL.AddModule("Static Post Processing"); \ +-ExpenseModule* AdrOpExpense=EL.AddModule("Adress Operator"); ++ExpenseModule* AdrOpExpense=EL.AddModule("Address Operator"); + #define EXTERN_EXPENSE_DEFINE extern ExpenseLog EL; + #define ENGINEEXPENSE_DEFINE extern ExpenseModule* EngineExpense; + #define POSTPROCEXPENSE_DEFINE extern ExpenseModule* PPExpense; +diff --git a/openEMS/tools/useful.cpp b/openEMS/tools/useful.cpp +index 50aacfb..8e548f0 100644 +--- a/openEMS/tools/useful.cpp ++++ b/openEMS/tools/useful.cpp +@@ -63,7 +63,7 @@ std::vector AssignJobs2Threads(unsigned int jobs, unsigned int nrT + } + + if (jobs>0) +- std::cerr << "AssignJobs2Threads: Error, " << jobs << " remain to be assigned, this should not have happend..." << std::endl; ++ std::cerr << "AssignJobs2Threads: Error, " << jobs << " remain to be assigned, this should not have happened..." << std::endl; + + if (RemoveEmpty) + { +diff --git a/openEMS/tools/vtk_file_writer.cpp b/openEMS/tools/vtk_file_writer.cpp +index 79c40f3..be6586f 100644 +--- a/openEMS/tools/vtk_file_writer.cpp ++++ b/openEMS/tools/vtk_file_writer.cpp +@@ -70,7 +70,7 @@ void VTK_File_Writer::SetMeshLines(double const* const* lines, unsigned int cons + vtkRectilinearGrid* RectGrid = dynamic_cast(m_GridData); + if (RectGrid==NULL) + { +- cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happend! " << endl; ++ cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happened! " << endl; + exit(1); + } + RectGrid->SetDimensions(count[0],count[1],count[2]); +@@ -97,7 +97,7 @@ void VTK_File_Writer::SetMeshLines(double const* const* lines, unsigned int cons + vtkStructuredGrid* StructGrid = dynamic_cast(m_GridData); + if (StructGrid==NULL) + { +- cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happend! " << endl; ++ cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happened! " << endl; + exit(1); + } + diff --git a/patches/0003-More-things-to-fix-build.patch b/patches/0003-More-things-to-fix-build.patch new file mode 100644 index 0000000..bf38fc7 --- /dev/null +++ b/patches/0003-More-things-to-fix-build.patch @@ -0,0 +1,38 @@ +From: Ruben Undheim +Date: Sun, 20 Nov 2016 22:01:42 +0000 +Subject: More things to fix build + +--- + CSXCAD/CMakeLists.txt | 4 ++-- + openEMS/CMakeLists.txt | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/CSXCAD/CMakeLists.txt b/CSXCAD/CMakeLists.txt +index 9d516d5..d7670c1 100644 +--- a/CSXCAD/CMakeLists.txt ++++ b/CSXCAD/CMakeLists.txt +@@ -90,9 +90,9 @@ INCLUDE_DIRECTORIES( ${fparser_INCLUDE_DIR} ) + find_package(TinyXML REQUIRED) + ADD_DEFINITIONS( -DTIXML_USE_STL ) + +-find_package(HDF5 1.8 COMPONENTS C HL REQUIRED) ++find_package(HDF5 1.8 COMPONENTS CXX HL REQUIRED) + INCLUDE_DIRECTORIES (${HDF5_INCLUDE_DIRS}) +-link_directories(${HDF5_LIBRARY_DIRS}) ++link_directories(${HDF5_LIBRARIES}) + # hdf5 compat + ADD_DEFINITIONS( -DH5_USE_16_API ) + +diff --git a/openEMS/CMakeLists.txt b/openEMS/CMakeLists.txt +index 898f280..5504590 100644 +--- a/openEMS/CMakeLists.txt ++++ b/openEMS/CMakeLists.txt +@@ -108,7 +108,7 @@ find_package(TinyXML REQUIRED) + ADD_DEFINITIONS( -DTIXML_USE_STL ) + + # hdf5 +-find_package(HDF5 1.8 COMPONENTS C HL REQUIRED) ++find_package(HDF5 1.8 COMPONENTS CXX HL REQUIRED) + INCLUDE_DIRECTORIES (${HDF5_INCLUDE_DIRS}) + link_directories(${HDF5_LIBRARIES}) + diff --git a/patches/0004-link-more.patch b/patches/0004-link-more.patch new file mode 100644 index 0000000..2c95033 --- /dev/null +++ b/patches/0004-link-more.patch @@ -0,0 +1,33 @@ +From: Ruben Undheim +Date: Sun, 20 Nov 2016 22:40:17 +0000 +Subject: link more + +--- + AppCSXCAD/CMakeLists.txt | 1 + + openEMS/CMakeLists.txt | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/AppCSXCAD/CMakeLists.txt b/AppCSXCAD/CMakeLists.txt +index d5a72c9..2d4b11b 100644 +--- a/AppCSXCAD/CMakeLists.txt ++++ b/AppCSXCAD/CMakeLists.txt +@@ -157,6 +157,7 @@ TARGET_LINK_LIBRARIES( AppCSXCAD + ${HDF5_HL_LIBRARIES} + ${QT_LIBRARIES} + ${vtk_LIBS} ++ hdf5_serial_hl + ) + + # +diff --git a/openEMS/CMakeLists.txt b/openEMS/CMakeLists.txt +index 5504590..794a498 100644 +--- a/openEMS/CMakeLists.txt ++++ b/openEMS/CMakeLists.txt +@@ -184,6 +184,7 @@ TARGET_LINK_LIBRARIES( openEMS + ${Boost_LIBRARIES} + ${vtk_LIBS} + ${MPI_LIBRARIES} ++ hdf5_serial_hl + ) + + # main program diff --git a/patches/0005-Deletede-CVS-dir-lintian.patch b/patches/0005-Deletede-CVS-dir-lintian.patch new file mode 100644 index 0000000..78a91e4 --- /dev/null +++ b/patches/0005-Deletede-CVS-dir-lintian.patch @@ -0,0 +1,73 @@ +From: Ruben Undheim +Date: Mon, 21 Nov 2016 00:08:20 +0100 +Subject: Deletede CVS dir (lintian) + +--- + QCSXCAD/images/CVS/Entries | 40 ---------------------------------------- + QCSXCAD/images/CVS/Repository | 1 - + QCSXCAD/images/CVS/Root | 1 - + 3 files changed, 42 deletions(-) + delete mode 100644 QCSXCAD/images/CVS/Entries + delete mode 100644 QCSXCAD/images/CVS/Repository + delete mode 100644 QCSXCAD/images/CVS/Root + +diff --git a/QCSXCAD/images/CVS/Entries b/QCSXCAD/images/CVS/Entries +deleted file mode 100644 +index 3593808..0000000 +--- a/QCSXCAD/images/CVS/Entries ++++ /dev/null +@@ -1,40 +0,0 @@ +-/GeoEdit.png/1.1/Mon Oct 20 07:11:47 2003/-kb/ +-/ParaSetup.png/1.1/Mon Oct 20 07:11:13 2003/-kb/ +-/Thumbs.db/1.2/Tue Jun 27 14:51:16 2006/-kb/ +-/accept.png/1.1/Mon Aug 29 14:17:00 2005/-kb/ +-/bulb.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/bulb_off.png/1.1/Wed Oct 11 20:48:27 2006/-kb/ +-/cancel.png/1.1/Mon Oct 20 07:16:21 2003/-kb/ +-/close.png/1.1/Mon Oct 20 07:16:25 2003/-kb/ +-/configure.png/1.1/Mon Oct 10 19:03:03 2005/-kb/ +-/down.png/1.1/Mon Oct 10 19:03:03 2005/-kb/ +-/edit.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/edit_add.png/1.1/Mon Oct 20 07:16:24 2003/-kb/ +-/edit_remove.png/1.1/Mon Oct 20 07:16:25 2003/-kb/ +-/editcopy.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/exit.png/1.1/Mon Oct 20 07:16:26 2003/-kb/ +-/failed.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/filenew.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/fileopen.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/filesave.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/filesaveas.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/folder.png/1.1/Fri Apr 4 12:47:44 2003/-kb/ +-/funct.png/1.1/Mon Oct 20 07:16:30 2003/-kb/ +-/hourglass.png/1.1/Wed Sep 28 17:56:00 2005/-kb/ +-/icon.gif/1.1/Sun Aug 28 21:13:00 2005/-kb/ +-/launch.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/qt-logo.png/1.1/Wed Dec 14 17:02:26 2005/-kb/ +-/reload.png/1.1/Mon Dec 16 23:41:14 2002/-kb/ +-/result_small.png/1.1/Mon Oct 20 07:16:29 2003/-kb/ +-/results.png/1.1/Mon Oct 20 07:11:58 2003/-kb/ +-/setup.png/1.1/Sun Aug 14 17:45:15 2005/-kb/ +-/simulation.png/1.1/Fri Jan 6 12:43:58 2006/-kb/ +-/simulation_icon.png/1.1/Fri Jan 6 14:24:45 2006/-kb/ +-/simulation_small.png/1.1/Thu Jun 29 20:43:26 2006/-kb/ +-/simulation_tr.png/1.1/Fri Jan 6 14:23:52 2006/-kb/ +-/up.png/1.1/Mon Oct 10 19:03:03 2005/-kb/ +-/viewmag+.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/viewmag-.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/viewmagfit.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +-/window_icon2.png/1.1/Mon Aug 29 14:17:00 2005/-kb/ +-/work.png/1.1/Mon Oct 20 07:14:09 2003/-kb/ +diff --git a/QCSXCAD/images/CVS/Repository b/QCSXCAD/images/CVS/Repository +deleted file mode 100644 +index d336c21..0000000 +--- a/QCSXCAD/images/CVS/Repository ++++ /dev/null +@@ -1 +0,0 @@ +-StaticSimulator/images +diff --git a/QCSXCAD/images/CVS/Root b/QCSXCAD/images/CVS/Root +deleted file mode 100644 +index 800d2fc..0000000 +--- a/QCSXCAD/images/CVS/Root ++++ /dev/null +@@ -1 +0,0 @@ +-:extssh:coft@atex.ate.uni-duisburg.de:/srv/CVS diff --git a/patches/0006-Don-t-exit-from-library.patch b/patches/0006-Don-t-exit-from-library.patch new file mode 100644 index 0000000..7c95eb5 --- /dev/null +++ b/patches/0006-Don-t-exit-from-library.patch @@ -0,0 +1,57 @@ +From: Ruben Undheim +Date: Mon, 21 Nov 2016 00:45:35 +0100 +Subject: Don't exit from library + +--- + openEMS/tools/array_ops.cpp | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/openEMS/tools/array_ops.cpp b/openEMS/tools/array_ops.cpp +index 8710b3c..7100f9a 100644 +--- a/openEMS/tools/array_ops.cpp ++++ b/openEMS/tools/array_ops.cpp +@@ -73,7 +73,7 @@ f4vector* Create1DArray_v4sf(const unsigned int numLines) + if (MEMALIGN( (void**)&array, 16, sizeof(typeof(f4vector))*numLines )) + { + cerr << "cannot allocate aligned memory" << endl; +- exit(3); ++ return 0; + } + for (unsigned int pos=0; pos Date: Sun, 2 Sep 2018 01:07:06 +0200 Subject: Import openems_0.0.35+dfsg.1.orig.tar.bz2 [dgit import orig openems_0.0.35+dfsg.1.orig.tar.bz2] --- AppCSXCAD/AppCSXCAD.bat | 12 + AppCSXCAD/AppCSXCAD.cpp | 147 + AppCSXCAD/AppCSXCAD.h | 49 + AppCSXCAD/AppCSXCAD.sh | 15 + AppCSXCAD/CMakeLists.txt | 178 + AppCSXCAD/COPYING | 674 ++++ AppCSXCAD/INSTALL | 19 + AppCSXCAD/README | 7 + AppCSXCAD/linux/AppCSXCAD.dsc | 9 + AppCSXCAD/linux/AppCSXCAD.spec | 82 + AppCSXCAD/linux/debian.changelog | 9 + AppCSXCAD/linux/debian.control | 11 + AppCSXCAD/linux/debian.rules | 7 + AppCSXCAD/linux/debian.series | 1 + AppCSXCAD/linux/start_script.patch | 10 + AppCSXCAD/main.cpp | 32 + CMakeLists.txt | 65 + CSXCAD/CMakeLists.txt | 146 + CSXCAD/COPYING | 165 + CSXCAD/INSTALL | 25 + CSXCAD/NEWS | 12 + CSXCAD/README | 18 + CSXCAD/cmake/Modules/FindTinyXML.cmake | 74 + CSXCAD/doxydoc | 1541 ++++++++ CSXCAD/linux/CSXCAD.dsc | 9 + CSXCAD/linux/CSXCAD.spec | 131 + CSXCAD/linux/CSXGeomPlot.m.patch | 25 + CSXCAD/linux/README.patch | 15 + CSXCAD/linux/debian.changelog | 27 + CSXCAD/linux/debian.control | 18 + CSXCAD/linux/debian.csxcad-dev.install | 2 + CSXCAD/linux/debian.csxcad.docs | 2 + CSXCAD/linux/debian.csxcad.install | 2 + CSXCAD/linux/debian.rules | 8 + CSXCAD/linux/debian.series | 2 + CSXCAD/matlab/AddBox.m | 42 + CSXCAD/matlab/AddConductingSheet.m | 47 + CSXCAD/matlab/AddCurve.m | 44 + CSXCAD/matlab/AddCylinder.m | 35 + CSXCAD/matlab/AddCylindricalShell.m | 41 + CSXCAD/matlab/AddDebyeMaterial.m | 29 + CSXCAD/matlab/AddDiscMaterial.m | 47 + CSXCAD/matlab/AddDump.m | 87 + CSXCAD/matlab/AddExcitation.m | 32 + CSXCAD/matlab/AddLinPoly.m | 41 + CSXCAD/matlab/AddLorentzMaterial.m | 60 + CSXCAD/matlab/AddLumpedElement.m | 29 + CSXCAD/matlab/AddMaterial.m | 26 + CSXCAD/matlab/AddMetal.m | 26 + CSXCAD/matlab/AddPlaneWaveExcite.m | 38 + CSXCAD/matlab/AddPoint.m | 14 + CSXCAD/matlab/AddPolygon.m | 41 + CSXCAD/matlab/AddPolyhedron.m | 51 + CSXCAD/matlab/AddProbe.m | 79 + CSXCAD/matlab/AddPropAttribute.m | 24 + CSXCAD/matlab/AddRotPoly.m | 48 + CSXCAD/matlab/AddSphere.m | 30 + CSXCAD/matlab/AddSphericalShell.m | 36 + CSXCAD/matlab/AddWire.m | 46 + CSXCAD/matlab/AnalyseMesh.m | 42 + CSXCAD/matlab/AutoSmoothMeshLines.m | 159 + CSXCAD/matlab/CSXGeomPlot.m | 43 + CSXCAD/matlab/CalcDebyeMaterial.m | 29 + CSXCAD/matlab/CalcDrudeMaterial.m | 37 + CSXCAD/matlab/CalcLorentzMaterial.m | 61 + CSXCAD/matlab/CheckMesh.m | 65 + CSXCAD/matlab/Convert_VF_DiscMaterial.m | 255 ++ CSXCAD/matlab/CreateDiscMaterial.m | 83 + CSXCAD/matlab/DefineRectGrid.m | 50 + CSXCAD/matlab/DetectEdges.m | 278 ++ CSXCAD/matlab/DirChar2Int.m | 31 + CSXCAD/matlab/ImportPLY.m | 23 + CSXCAD/matlab/ImportSTL.m | 23 + CSXCAD/matlab/InitCSX.m | 31 + CSXCAD/matlab/RecursiveSmoothMesh.m | 176 + CSXCAD/matlab/SetBackgroundMaterial.m | 23 + CSXCAD/matlab/SetExcitationWeight.m | 53 + CSXCAD/matlab/SetMaterialProperty.m | 29 + CSXCAD/matlab/SetMaterialWeight.m | 31 + CSXCAD/matlab/SmoothMesh.m | 73 + CSXCAD/matlab/SmoothMeshLines.m | 122 + CSXCAD/matlab/SmoothMeshLines2.m | 318 ++ CSXCAD/matlab/export_empire.m | 305 ++ CSXCAD/matlab/export_excellon.m | 144 + CSXCAD/matlab/export_gerber.m | 198 ++ CSXCAD/matlab/export_povray.m | 237 ++ CSXCAD/matlab/isOctave.m | 46 + CSXCAD/matlab/private/Add2Property.m | 26 + CSXCAD/matlab/private/AddPrimitiveArgs.m | 28 + CSXCAD/matlab/private/AddProperty.m | 29 + CSXCAD/matlab/private/CheckSymmtricLines.m | 34 + CSXCAD/matlab/private/FindProperty.m | 17 + CSXCAD/matlab/private/GetPropertyPosition.m | 41 + CSXCAD/matlab/private/GetPropertyType.m | 30 + CSXCAD/matlab/private/SetPropertyArgs.m | 16 + CSXCAD/matlab/private/SmoothRange.m | 58 + CSXCAD/matlab/private/octave_struct2xml_2.m | 57 + CSXCAD/matlab/private/struct_2_xmlNode.m | 48 + CSXCAD/matlab/private/vector2str.m | 35 + CSXCAD/matlab/searchBinary.m | 47 + CSXCAD/matlab/struct_2_xml.m | 23 + CSXCAD/src/CMakeLists.txt | 105 + CSXCAD/src/CSBackgroundMaterial.cpp | 115 + CSXCAD/src/CSBackgroundMaterial.h | 63 + CSXCAD/src/CSFunctionParser.cpp | 76 + CSXCAD/src/CSFunctionParser.h | 34 + CSXCAD/src/CSPrimBox.cpp | 149 + CSXCAD/src/CSPrimBox.h | 59 + CSXCAD/src/CSPrimCurve.cpp | 188 + CSXCAD/src/CSPrimCurve.h | 56 + CSXCAD/src/CSPrimCylinder.cpp | 210 ++ CSXCAD/src/CSPrimCylinder.h | 65 + CSXCAD/src/CSPrimCylindricalShell.cpp | 177 + CSXCAD/src/CSPrimCylindricalShell.h | 56 + CSXCAD/src/CSPrimLinPoly.cpp | 131 + CSXCAD/src/CSPrimLinPoly.h | 53 + CSXCAD/src/CSPrimMultiBox.cpp | 279 ++ CSXCAD/src/CSPrimMultiBox.h | 64 + CSXCAD/src/CSPrimPoint.cpp | 126 + CSXCAD/src/CSPrimPoint.h | 59 + CSXCAD/src/CSPrimPolygon.cpp | 294 ++ CSXCAD/src/CSPrimPolygon.h | 77 + CSXCAD/src/CSPrimPolyhedron.cpp | 357 ++ CSXCAD/src/CSPrimPolyhedron.h | 83 + CSXCAD/src/CSPrimPolyhedronReader.cpp | 177 + CSXCAD/src/CSPrimPolyhedronReader.h | 55 + CSXCAD/src/CSPrimPolyhedron_p.h | 48 + CSXCAD/src/CSPrimRotPoly.cpp | 191 + CSXCAD/src/CSPrimRotPoly.h | 61 + CSXCAD/src/CSPrimSphere.cpp | 176 + CSXCAD/src/CSPrimSphere.h | 72 + CSXCAD/src/CSPrimSphericalShell.cpp | 134 + CSXCAD/src/CSPrimSphericalShell.h | 57 + CSXCAD/src/CSPrimUserDefined.cpp | 252 ++ CSXCAD/src/CSPrimUserDefined.h | 66 + CSXCAD/src/CSPrimWire.cpp | 149 + CSXCAD/src/CSPrimWire.h | 53 + CSXCAD/src/CSPrimitives.cpp | 227 ++ CSXCAD/src/CSPrimitives.h | 213 ++ CSXCAD/src/CSPropConductingSheet.cpp | 97 + CSXCAD/src/CSPropConductingSheet.h | 67 + CSXCAD/src/CSPropDebyeMaterial.cpp | 238 ++ CSXCAD/src/CSPropDebyeMaterial.h | 91 + CSXCAD/src/CSPropDiscMaterial.cpp | 619 ++++ CSXCAD/src/CSPropDiscMaterial.h | 88 + CSXCAD/src/CSPropDispersiveMaterial.cpp | 40 + CSXCAD/src/CSPropDispersiveMaterial.h | 49 + CSXCAD/src/CSPropDumpBox.cpp | 158 + CSXCAD/src/CSPropDumpBox.h | 98 + CSXCAD/src/CSPropExcitation.cpp | 278 ++ CSXCAD/src/CSPropExcitation.h | 114 + CSXCAD/src/CSPropLorentzMaterial.cpp | 416 +++ CSXCAD/src/CSPropLorentzMaterial.h | 167 + CSXCAD/src/CSPropLumpedElement.cpp | 128 + CSXCAD/src/CSPropLumpedElement.h | 71 + CSXCAD/src/CSPropMaterial.cpp | 304 ++ CSXCAD/src/CSPropMaterial.h | 111 + CSXCAD/src/CSPropMetal.cpp | 39 + CSXCAD/src/CSPropMetal.h | 39 + CSXCAD/src/CSPropProbeBox.cpp | 102 + CSXCAD/src/CSPropProbeBox.h | 86 + CSXCAD/src/CSPropResBox.cpp | 53 + CSXCAD/src/CSPropResBox.h | 45 + CSXCAD/src/CSPropUnknown.cpp | 52 + CSXCAD/src/CSPropUnknown.h | 45 + CSXCAD/src/CSProperties.cpp | 399 +++ CSXCAD/src/CSProperties.h | 222 ++ CSXCAD/src/CSRectGrid.cpp | 340 ++ CSXCAD/src/CSRectGrid.h | 120 + CSXCAD/src/CSTransform.cpp | 762 ++++ CSXCAD/src/CSTransform.h | 143 + CSXCAD/src/CSUseful.cpp | 178 + CSXCAD/src/CSUseful.h | 41 + CSXCAD/src/CSXCAD_Global.h | 46 + CSXCAD/src/ContinuousStructure.cpp | 660 ++++ CSXCAD/src/ContinuousStructure.h | 218 ++ CSXCAD/src/ParameterCoord.cpp | 261 ++ CSXCAD/src/ParameterCoord.h | 90 + CSXCAD/src/ParameterObjects.cpp | 713 ++++ CSXCAD/src/ParameterObjects.h | 251 ++ CTB/AddElement2Port.m | 83 + CTB/ApplyCurrent2Port.m | 69 + CTB/ApplyRFPower2Port.m | 43 + CTB/InitNetwork.m | 53 + CTB/Makefile | 14 + CTB/SetPortTermination.m | 45 + CTB/a2s.m | 31 + CTB/a_PI.m | 15 + CTB/a_T.m | 14 + CTB/a_mul.m | 28 + CTB/a_series.m | 22 + CTB/a_shunt.m | 22 + CTB/license.txt | 22 + CTB/read_touchstone.m | 150 + CTB/readme.txt | 29 + CTB/s2a.m | 31 + CTB/s2y.m | 43 + CTB/s2z.m | 43 + CTB/s_renorm.m | 19 + CTB/write_touchstone.m | 87 + CTB/y2s.m | 43 + CTB/y2z.m | 22 + CTB/z2s.m | 44 + CTB/z2y.m | 18 + QCSXCAD/CMakeLists.txt | 199 ++ QCSXCAD/COPYING | 165 + QCSXCAD/INSTALL | 21 + QCSXCAD/NEWS | 6 + QCSXCAD/QCSGridEditor.cpp | 640 ++++ QCSXCAD/QCSGridEditor.h | 87 + QCSXCAD/QCSPrimEditor.cpp | 746 ++++ QCSXCAD/QCSPrimEditor.h | 237 ++ QCSXCAD/QCSPropEditor.cpp | 623 ++++ QCSXCAD/QCSPropEditor.h | 248 ++ QCSXCAD/QCSTreeWidget.cpp | 242 ++ QCSXCAD/QCSTreeWidget.h | 92 + QCSXCAD/QCSXCAD.cpp | 999 ++++++ QCSXCAD/QCSXCAD.h | 180 + QCSXCAD/QCSXCAD_Global.cpp | 58 + QCSXCAD/QCSXCAD_Global.h | 58 + QCSXCAD/QParameterGui.cpp | 401 +++ QCSXCAD/QParameterGui.h | 107 + QCSXCAD/QVTKStructure.cpp | 873 +++++ QCSXCAD/QVTKStructure.h | 143 + QCSXCAD/README | 7 + QCSXCAD/VTKPrimitives.cpp | 1019 ++++++ QCSXCAD/VTKPrimitives.h | 143 + QCSXCAD/cmake/Modules/FindTinyXML.cmake | 74 + QCSXCAD/export_pov.cpp | 267 ++ QCSXCAD/export_pov.h | 49 + QCSXCAD/export_x3d.cpp | 201 ++ QCSXCAD/export_x3d.h | 42 + QCSXCAD/images/Arrows/Arrows.odg | Bin 0 -> 10791 bytes QCSXCAD/images/Arrows/ArrowsXY.png | Bin 0 -> 7245 bytes QCSXCAD/images/Arrows/ArrowsXZ.odg | Bin 0 -> 10515 bytes QCSXCAD/images/Arrows/ArrowsXZ.png | Bin 0 -> 7203 bytes QCSXCAD/images/Arrows/ArrowsYZ.odg | Bin 0 -> 10425 bytes QCSXCAD/images/Arrows/ArrowsYZ.png | Bin 0 -> 6371 bytes QCSXCAD/images/ArrowsXY.png | Bin 0 -> 7245 bytes QCSXCAD/images/ArrowsXZ.png | Bin 0 -> 7203 bytes QCSXCAD/images/ArrowsYZ.png | Bin 0 -> 6371 bytes QCSXCAD/images/CVS/Entries | 40 + QCSXCAD/images/CVS/Repository | 1 + QCSXCAD/images/CVS/Root | 1 + QCSXCAD/images/GeoEdit.png | Bin 0 -> 13320 bytes QCSXCAD/images/ParaSetup.png | Bin 0 -> 20660 bytes QCSXCAD/images/QCSXCAD_Icon.png | Bin 0 -> 14030 bytes QCSXCAD/images/accept.png | Bin 0 -> 917 bytes QCSXCAD/images/bulb.png | Bin 0 -> 829 bytes QCSXCAD/images/bulb_off.png | Bin 0 -> 672 bytes QCSXCAD/images/cancel.png | Bin 0 -> 1821 bytes QCSXCAD/images/close.png | Bin 0 -> 1560 bytes QCSXCAD/images/configure.png | Bin 0 -> 943 bytes QCSXCAD/images/down.png | Bin 0 -> 1991 bytes QCSXCAD/images/edit.png | Bin 0 -> 1627 bytes QCSXCAD/images/edit_add.png | Bin 0 -> 1438 bytes QCSXCAD/images/edit_remove.png | Bin 0 -> 783 bytes QCSXCAD/images/editcopy.png | Bin 0 -> 3781 bytes QCSXCAD/images/exit.png | Bin 0 -> 2017 bytes QCSXCAD/images/failed.png | Bin 0 -> 821 bytes QCSXCAD/images/filenew.png | Bin 0 -> 1177 bytes QCSXCAD/images/fileopen.png | Bin 0 -> 2232 bytes QCSXCAD/images/filesave.png | Bin 0 -> 1348 bytes QCSXCAD/images/filesaveas.png | Bin 0 -> 2069 bytes QCSXCAD/images/folder.png | Bin 0 -> 2355 bytes QCSXCAD/images/funct.png | Bin 0 -> 1792 bytes QCSXCAD/images/hourglass.png | Bin 0 -> 945 bytes QCSXCAD/images/icon.gif | Bin 0 -> 263 bytes QCSXCAD/images/launch.png | Bin 0 -> 2288 bytes QCSXCAD/images/launch2.png | Bin 0 -> 2297 bytes QCSXCAD/images/launch3.png | Bin 0 -> 2302 bytes QCSXCAD/images/opening.png | Bin 0 -> 186733 bytes QCSXCAD/images/qt-logo.png | Bin 0 -> 3696 bytes QCSXCAD/images/reload.png | Bin 0 -> 1996 bytes QCSXCAD/images/result_small.png | Bin 0 -> 1345 bytes QCSXCAD/images/results.png | Bin 0 -> 7776 bytes QCSXCAD/images/setup.png | Bin 0 -> 11471 bytes QCSXCAD/images/simulation.png | Bin 0 -> 114512 bytes QCSXCAD/images/simulation_icon.png | Bin 0 -> 1411 bytes QCSXCAD/images/simulation_small.png | Bin 0 -> 10267 bytes QCSXCAD/images/simulation_tr.png | Bin 0 -> 80895 bytes QCSXCAD/images/up.png | Bin 0 -> 1992 bytes QCSXCAD/images/viewmag+.png | Bin 0 -> 2025 bytes QCSXCAD/images/viewmag-.png | Bin 0 -> 1998 bytes QCSXCAD/images/viewmagfit.png | Bin 0 -> 2011 bytes QCSXCAD/images/vtk-logo.png | Bin 0 -> 1193 bytes QCSXCAD/images/window_icon2.png | Bin 0 -> 917 bytes QCSXCAD/images/work.png | Bin 0 -> 13178 bytes QCSXCAD/linux/QCSXCAD.dsc | 9 + QCSXCAD/linux/QCSXCAD.spec | 115 + QCSXCAD/linux/debian.changelog | 9 + QCSXCAD/linux/debian.control | 17 + QCSXCAD/linux/debian.rules | 7 + QCSXCAD/linux/fedora17.diff | 13 + QCSXCAD/resources.qrc | 49 + QCSXCAD/vtkInteractorStyleRubberBand2DPlane.cpp | 73 + QCSXCAD/vtkInteractorStyleRubberBand2DPlane.h | 35 + brew/README.md | 35 + brew/openEMS.rb | 26 + hyp2mat/.gitignore | 11 + hyp2mat/AUTHORS | 2 + hyp2mat/COPYING | 674 ++++ hyp2mat/ChangeLog | 0 hyp2mat/INSTALL | 55 + hyp2mat/Makefile.am | 34 + hyp2mat/NEWS | 22 + hyp2mat/README | 16 + hyp2mat/README.md | 16 + hyp2mat/THANKS | 7 + hyp2mat/bootstrap.sh | 3 + hyp2mat/configure.ac | 48 + hyp2mat/doc/.gitignore | 2 + hyp2mat/doc/Makefile.am | 44 + hyp2mat/doc/hyp2mat.h2m | 144 + hyp2mat/eagle/Makefile.am | 40 + hyp2mat/eagle/README_eagle.txt | 10 + hyp2mat/eagle/hairpinfilter/README.txt | 26 + hyp2mat/eagle/hairpinfilter/demo_hairpin.m | 109 + hyp2mat/eagle/hairpinfilter/hairpinfilter.brd | 339 ++ hyp2mat/eagle/hairpinfilter/hairpinfilter.pdf | Bin 0 -> 2242 bytes hyp2mat/eagle/hairpinfilter/hairpinfilter.sch | Bin 0 -> 12738 bytes .../eagle/hairpinfilter/hairpinfilter_board.png | Bin 0 -> 105613 bytes .../hairpinfilter/hairpinfilter_simulation.png | Bin 0 -> 47744 bytes hyp2mat/eagle/notchfilter/README.txt | 26 + hyp2mat/eagle/notchfilter/demo_notch.m | 109 + hyp2mat/eagle/notchfilter/notchfilter.brd | Bin 0 -> 4098 bytes hyp2mat/eagle/notchfilter/notchfilter.pdf | Bin 0 -> 1933 bytes hyp2mat/eagle/notchfilter/notchfilter.sch | Bin 0 -> 12184 bytes hyp2mat/eagle/notchfilter/notchfilter_board.png | Bin 0 -> 126779 bytes .../eagle/notchfilter/notchfilter_simulation.png | Bin 0 -> 57456 bytes hyp2mat/eagle/tutorial/GetEpsilon.m | 59 + hyp2mat/eagle/tutorial/GetUnits.m | 38 + hyp2mat/eagle/tutorial/README.txt | 10 + hyp2mat/eagle/tutorial/msl.brd | 329 ++ hyp2mat/eagle/tutorial/msl.lbr | 3070 ++++++++++++++++ hyp2mat/eagle/tutorial/msl.patch | 24 + hyp2mat/eagle/tutorial/msl.pdf | 138 + hyp2mat/eagle/tutorial/msl.sch | 3138 +++++++++++++++++ hyp2mat/eagle/tutorial/sparam.png | Bin 0 -> 44918 bytes hyp2mat/eagle/tutorial/tutorial_hyp2mat.m | 124 + hyp2mat/lib/.gitignore | 11 + hyp2mat/lib/Makefile.am | 69 + hyp2mat/lib/clipper.cpp | 3700 ++++++++++++++++++++ hyp2mat/lib/clipper.hpp | 351 ++ hyp2mat/lib/clipper.txt | 29 + hyp2mat/lib/copper.cc | 382 ++ hyp2mat/lib/crop.cc | 108 + hyp2mat/lib/crop.h | 36 + hyp2mat/lib/csxcad.cc | 376 ++ hyp2mat/lib/csxcad.h | 53 + hyp2mat/lib/draw.cc | 296 ++ hyp2mat/lib/exec_board.cc | 251 ++ hyp2mat/lib/exec_devices.cc | 89 + hyp2mat/lib/exec_end.cc | 53 + hyp2mat/lib/exec_net.cc | 502 +++ hyp2mat/lib/exec_netclass.cc | 76 + hyp2mat/lib/exec_padstack.cc | 269 ++ hyp2mat/lib/exec_polygon.cc | 275 ++ hyp2mat/lib/exec_stackup.cc | 446 +++ hyp2mat/lib/exec_supplies.cc | 57 + hyp2mat/lib/hyp2mat.h | 224 ++ hyp2mat/lib/hyp2mat.pc.in | 12 + hyp2mat/lib/hyperlynx.cc | 348 ++ hyp2mat/lib/hyperlynx.h | 79 + hyp2mat/lib/hypfile.cc | 378 ++ hyp2mat/lib/hypfile.h | 333 ++ hyp2mat/lib/misc.cc | 65 + hyp2mat/lib/palette.cc | 120 + hyp2mat/lib/palette.h | 55 + hyp2mat/lib/parse.yy | 826 +++++ hyp2mat/lib/parse_param.h | 172 + hyp2mat/lib/parser.h | 40 + hyp2mat/lib/pcb.cc | 333 ++ hyp2mat/lib/pdf.cc | 292 ++ hyp2mat/lib/pdf.h | 59 + hyp2mat/lib/polygon.cc | 335 ++ hyp2mat/lib/polygon.h | 74 + hyp2mat/lib/scan.ll | 371 ++ hyp2mat/makewin32 | 23 + hyp2mat/matlab/AddHyperLynxComponent.m | 99 + hyp2mat/matlab/AddHyperLynxDielectric.m | 44 + hyp2mat/matlab/AddHyperLynxMetal2D.m | 40 + hyp2mat/matlab/AddHyperLynxMetal3D.m | 43 + hyp2mat/matlab/Contents.m | 10 + hyp2mat/matlab/GetHyperLynxPort.m | 84 + hyp2mat/matlab/ImportHyperLynx.m | 196 ++ hyp2mat/matlab/Makefile.am | 2 + hyp2mat/src/.gitignore | 13 + hyp2mat/src/Makefile.am | 23 + hyp2mat/src/cmdline.ggo | 43 + hyp2mat/src/hyp2mat.cc | 160 + openEMS/Analyse/PlotVoltage.m | 70 + openEMS/CMakeLists.txt | 209 ++ openEMS/COPYING | 674 ++++ openEMS/Common/CMakeLists.txt | 23 + openEMS/Common/engine_interface_base.cpp | 39 + openEMS/Common/engine_interface_base.h | 88 + openEMS/Common/operator_base.cpp | 154 + openEMS/Common/operator_base.h | 179 + openEMS/Common/processcurrent.cpp | 168 + openEMS/Common/processcurrent.h | 41 + openEMS/Common/processfieldprobe.cpp | 92 + openEMS/Common/processfieldprobe.h | 43 + openEMS/Common/processfields.cpp | 341 ++ openEMS/Common/processfields.h | 104 + openEMS/Common/processfields_fd.cpp | 225 ++ openEMS/Common/processfields_fd.h | 43 + openEMS/Common/processfields_sar.cpp | 335 ++ openEMS/Common/processfields_sar.h | 61 + openEMS/Common/processfields_td.cpp | 91 + openEMS/Common/processfields_td.h | 42 + openEMS/Common/processing.cpp | 372 ++ openEMS/Common/processing.h | 204 ++ openEMS/Common/processintegral.cpp | 177 + openEMS/Common/processintegral.h | 71 + openEMS/Common/processmodematch.cpp | 267 ++ openEMS/Common/processmodematch.h | 68 + openEMS/Common/processvoltage.cpp | 40 + openEMS/Common/processvoltage.h | 39 + openEMS/Common/readme.txt | 6 + openEMS/Doxyfile | 1551 ++++++++ openEMS/FDTD/CMakeLists.txt | 30 + openEMS/FDTD/engine.cpp | 232 ++ openEMS/FDTD/engine.h | 104 + openEMS/FDTD/engine_cylinder.cpp | 38 + openEMS/FDTD/engine_cylinder.h | 36 + openEMS/FDTD/engine_cylindermultigrid.cpp | 226 ++ openEMS/FDTD/engine_cylindermultigrid.h | 85 + openEMS/FDTD/engine_interface_cylindrical_fdtd.cpp | 64 + openEMS/FDTD/engine_interface_cylindrical_fdtd.h | 39 + openEMS/FDTD/engine_interface_fdtd.cpp | 274 ++ openEMS/FDTD/engine_interface_fdtd.h | 65 + openEMS/FDTD/engine_interface_sse_fdtd.cpp | 69 + openEMS/FDTD/engine_interface_sse_fdtd.h | 38 + openEMS/FDTD/engine_mpi.cpp | 211 ++ openEMS/FDTD/engine_mpi.h | 57 + openEMS/FDTD/engine_multithread.cpp | 343 ++ openEMS/FDTD/engine_multithread.h | 127 + openEMS/FDTD/engine_sse.cpp | 176 + openEMS/FDTD/engine_sse.h | 60 + openEMS/FDTD/engine_sse_compressed.cpp | 163 + openEMS/FDTD/engine_sse_compressed.h | 38 + openEMS/FDTD/excitation.cpp | 299 ++ openEMS/FDTD/excitation.h | 115 + openEMS/FDTD/extensions/CMakeLists.txt | 32 + .../FDTD/extensions/OptimizeCondSheetParameter.m | 107 + openEMS/FDTD/extensions/cond_sheet_parameter.h | 14 + openEMS/FDTD/extensions/engine_ext_cylinder.cpp | 101 + openEMS/FDTD/extensions/engine_ext_cylinder.h | 49 + .../extensions/engine_ext_cylindermultigrid.cpp | 165 + .../FDTD/extensions/engine_ext_cylindermultigrid.h | 58 + openEMS/FDTD/extensions/engine_ext_dispersive.cpp | 162 + openEMS/FDTD/extensions/engine_ext_dispersive.h | 51 + openEMS/FDTD/extensions/engine_ext_excitation.cpp | 170 + openEMS/FDTD/extensions/engine_ext_excitation.h | 40 + .../FDTD/extensions/engine_ext_lorentzmaterial.cpp | 322 ++ .../FDTD/extensions/engine_ext_lorentzmaterial.h | 48 + openEMS/FDTD/extensions/engine_ext_mur_abc.cpp | 263 ++ openEMS/FDTD/extensions/engine_ext_mur_abc.h | 63 + openEMS/FDTD/extensions/engine_ext_steadystate.cpp | 112 + openEMS/FDTD/extensions/engine_ext_steadystate.h | 51 + openEMS/FDTD/extensions/engine_ext_tfsf.cpp | 215 ++ openEMS/FDTD/extensions/engine_ext_tfsf.h | 40 + openEMS/FDTD/extensions/engine_ext_upml.cpp | 493 +++ openEMS/FDTD/extensions/engine_ext_upml.h | 55 + openEMS/FDTD/extensions/engine_extension.cpp | 95 + openEMS/FDTD/extensions/engine_extension.h | 88 + .../extensions/operator_ext_conductingsheet.cpp | 261 ++ .../FDTD/extensions/operator_ext_conductingsheet.h | 51 + openEMS/FDTD/extensions/operator_ext_cylinder.cpp | 114 + openEMS/FDTD/extensions/operator_ext_cylinder.h | 60 + .../FDTD/extensions/operator_ext_dispersive.cpp | 78 + openEMS/FDTD/extensions/operator_ext_dispersive.h | 56 + .../FDTD/extensions/operator_ext_excitation.cpp | 372 ++ openEMS/FDTD/extensions/operator_ext_excitation.h | 84 + .../extensions/operator_ext_lorentzmaterial.cpp | 453 +++ .../FDTD/extensions/operator_ext_lorentzmaterial.h | 62 + openEMS/FDTD/extensions/operator_ext_mur_abc.cpp | 210 ++ openEMS/FDTD/extensions/operator_ext_mur_abc.h | 68 + .../FDTD/extensions/operator_ext_steadystate.cpp | 104 + openEMS/FDTD/extensions/operator_ext_steadystate.h | 61 + openEMS/FDTD/extensions/operator_ext_tfsf.cpp | 429 +++ openEMS/FDTD/extensions/operator_ext_tfsf.h | 82 + openEMS/FDTD/extensions/operator_ext_upml.cpp | 478 +++ openEMS/FDTD/extensions/operator_ext_upml.h | 106 + openEMS/FDTD/extensions/operator_extension.cpp | 54 + openEMS/FDTD/extensions/operator_extension.h | 87 + openEMS/FDTD/openems_fdtd_mpi.cpp | 546 +++ openEMS/FDTD/openems_fdtd_mpi.h | 72 + openEMS/FDTD/operator.cpp | 2131 +++++++++++ openEMS/FDTD/operator.h | 287 ++ openEMS/FDTD/operator_cylinder.cpp | 576 +++ openEMS/FDTD/operator_cylinder.h | 118 + openEMS/FDTD/operator_cylindermultigrid.cpp | 569 +++ openEMS/FDTD/operator_cylindermultigrid.h | 109 + openEMS/FDTD/operator_mpi.cpp | 209 ++ openEMS/FDTD/operator_mpi.h | 90 + openEMS/FDTD/operator_multithread.cpp | 203 ++ openEMS/FDTD/operator_multithread.h | 89 + openEMS/FDTD/operator_sse.cpp | 91 + openEMS/FDTD/operator_sse.h | 63 + openEMS/FDTD/operator_sse_compressed.cpp | 251 ++ openEMS/FDTD/operator_sse_compressed.h | 84 + openEMS/INSTALL | 27 + openEMS/NEWS | 40 + openEMS/README | 19 + openEMS/TESTSUITE/combinedtests/Coax.m | 158 + openEMS/TESTSUITE/combinedtests/README | 3 + openEMS/TESTSUITE/combinedtests/cavity.m | 229 ++ openEMS/TESTSUITE/enginetests/cavity.m | 190 + openEMS/TESTSUITE/helperscripts/check_frequency.m | 31 + openEMS/TESTSUITE/helperscripts/check_limits.m | 22 + openEMS/TESTSUITE/probes/fieldprobes.m | 324 ++ openEMS/TESTSUITE/run_testsuite.m | 58 + openEMS/TODO | 14 + openEMS/astyle.sh | 4 + openEMS/cmake/Modules/FindTinyXML.cmake | 74 + openEMS/known_bugs | 1 + openEMS/known_problems | 4 + openEMS/linux/CalcNF2FF.m.patch | 14 + openEMS/linux/README.patch | 15 + openEMS/linux/debian.changelog | 27 + openEMS/linux/debian.control | 12 + openEMS/linux/debian.docs | 2 + openEMS/linux/debian.rules | 90 + openEMS/linux/debian.series | 3 + openEMS/linux/fedora17.diff | 13 + openEMS/linux/invoke_openEMS.m.patch | 15 + openEMS/linux/openEMS.dsc | 9 + openEMS/linux/openEMS.spec | 113 + openEMS/main.cpp | 85 + openEMS/matlab/AR_estimate.m | 115 + openEMS/matlab/Add2Queue.m | 48 + openEMS/matlab/AddCPWPort.m | 285 ++ openEMS/matlab/AddCircWaveGuidePort.m | 109 + openEMS/matlab/AddCoaxialPort.m | 232 ++ openEMS/matlab/AddCurvePort.m | 182 + openEMS/matlab/AddLumpedPort.m | 129 + openEMS/matlab/AddMRStub.m | 73 + openEMS/matlab/AddMSLPort.m | 265 ++ openEMS/matlab/AddPML.m | 92 + openEMS/matlab/AddRectWaveGuidePort.m | 92 + openEMS/matlab/AddStripLinePort.m | 283 ++ openEMS/matlab/AddWaveGuidePort.m | 119 + openEMS/matlab/AnalyzeNF2FF.m | 231 ++ openEMS/matlab/CalcNF2FF.m | 161 + openEMS/matlab/CheckQueue.m | 60 + openEMS/matlab/ConvertHDF5_VTK.m | 100 + openEMS/matlab/CreateNF2FFBox.m | 94 + openEMS/matlab/DFT_time2freq.m | 47 + openEMS/matlab/DelayFidelity.m | 93 + openEMS/matlab/Dump2VTK.m | 179 + openEMS/matlab/DumpFF2VTK.m | 105 + openEMS/matlab/FFT_time2freq.m | 18 + openEMS/matlab/FindFreeSSH.m | 87 + openEMS/matlab/FinishQueue.m | 40 + openEMS/matlab/GetField_Interpolation.m | 147 + openEMS/matlab/GetField_Range.m | 71 + openEMS/matlab/GetField_SubSampling.m | 63 + openEMS/matlab/GetField_TD2FD.m | 48 + openEMS/matlab/InitCylindricalFDTD.m | 21 + openEMS/matlab/InitFDTD.m | 64 + openEMS/matlab/InitQueue.m | 90 + openEMS/matlab/PlotHDF5FieldData.m | 94 + openEMS/matlab/ReadHDF5Attribute.m | 33 + openEMS/matlab/ReadHDF5Dump.m | 92 + openEMS/matlab/ReadHDF5FieldData.m | 119 + openEMS/matlab/ReadHDF5Mesh.m | 80 + openEMS/matlab/ReadUI.m | 107 + openEMS/matlab/ResultsQueue.m | 24 + openEMS/matlab/RunOpenEMS.m | 186 + openEMS/matlab/RunOpenEMS_MPI.m | 125 + openEMS/matlab/RunOpenEMS_Parallel.m | 92 + openEMS/matlab/SetBoundaryCond.m | 68 + openEMS/matlab/SetCustomExcite.m | 21 + openEMS/matlab/SetDiracExcite.m | 3 + openEMS/matlab/SetGaussExcite.m | 18 + openEMS/matlab/SetSinusExcite.m | 14 + openEMS/matlab/SetStepExcite.m | 3 + openEMS/matlab/SetupMPI.m | 17 + openEMS/matlab/Tutorials/Bent_Patch_Antenna.m | 197 ++ openEMS/matlab/Tutorials/CRLH_Extraction.m | 155 + openEMS/matlab/Tutorials/CRLH_LeakyWaveAnt.m | 168 + openEMS/matlab/Tutorials/Circ_Waveguide.m | 105 + openEMS/matlab/Tutorials/Conical_Horn_Antenna.m | 180 + openEMS/matlab/Tutorials/CreateCRLH.m | 55 + openEMS/matlab/Tutorials/CylindricalWave_CC.m | 104 + openEMS/matlab/Tutorials/Dipole_SAR.m | 221 ++ openEMS/matlab/Tutorials/Helical_Antenna.m | 202 ++ openEMS/matlab/Tutorials/Horn_Antenna.m | 202 ++ openEMS/matlab/Tutorials/MRI_LP_Birdcage.m | 320 ++ openEMS/matlab/Tutorials/MRI_Loop_Coil.m | 334 ++ openEMS/matlab/Tutorials/MSL_NotchFilter.m | 92 + .../matlab/Tutorials/Parallel_Plate_Waveguide.m | 51 + openEMS/matlab/Tutorials/Patch_Antenna_Array.m | 170 + .../matlab/Tutorials/Patch_Antenna_Phased_Array.m | 166 + openEMS/matlab/Tutorials/RCS_Sphere.m | 138 + openEMS/matlab/Tutorials/RadarUWBTutorial.m | 236 ++ openEMS/matlab/Tutorials/Rect_Waveguide.m | 121 + openEMS/matlab/Tutorials/Simple_Patch_Antenna.m | 187 + openEMS/matlab/Tutorials/StripLine2MSL.m | 133 + openEMS/matlab/Tutorials/readme | 1 + openEMS/matlab/WriteHDF5.m | 73 + openEMS/matlab/WriteOpenEMS.m | 19 + openEMS/matlab/calcLumpedPort.m | 107 + openEMS/matlab/calcPort.m | 82 + openEMS/matlab/calcTLPort.m | 173 + openEMS/matlab/calcWGPort.m | 145 + openEMS/matlab/calc_ypar.m | 69 + openEMS/matlab/examples/__deprecated__/MSL2.m | 254 ++ openEMS/matlab/examples/antennas/Bi_Quad_Antenna.m | 139 + openEMS/matlab/examples/antennas/Patch_Antenna.m | 218 ++ .../matlab/examples/antennas/Patch_Antenna_Array.m | 256 ++ openEMS/matlab/examples/antennas/infDipol.m | 121 + openEMS/matlab/examples/antennas/inverted_f.m | 205 ++ openEMS/matlab/examples/optimizer/optimizer_asco.m | 36 + .../matlab/examples/optimizer/optimizer_simfun.m | 134 + openEMS/matlab/examples/other/Helix.m | 154 + openEMS/matlab/examples/other/LumpedElement.m | 158 + .../examples/other/Metamaterial_PlaneWave_Drude.m | 147 + .../examples/other/PML_reflection_analysis.m | 196 ++ openEMS/matlab/examples/other/PlaneWave.m | 69 + .../matlab/examples/other/gauss_excitation_test.m | 72 + openEMS/matlab/examples/other/resistance_sheet.m | 207 ++ .../matlab/examples/transmission_lines/CPW_Line.m | 125 + .../examples/transmission_lines/Finite_Stripline.m | 91 + openEMS/matlab/examples/transmission_lines/MSL.m | 185 + .../examples/transmission_lines/MSL_Losses.m | 102 + .../matlab/examples/transmission_lines/Stripline.m | 78 + .../transmission_lines/directional_coupler.m | 261 ++ openEMS/matlab/examples/waveguide/Circ_Waveguide.m | 207 ++ .../waveguide/Circ_Waveguide_CylinderCoords.m | 204 ++ openEMS/matlab/examples/waveguide/Coax.m | 120 + .../examples/waveguide/Coax_CylinderCoords.m | 190 + .../examples/waveguide/Coax_Cylindrical_MG.m | 155 + openEMS/matlab/examples/waveguide/Rect_Waveguide.m | 240 ++ openEMS/matlab/h5readatt_octave.cc | 120 + openEMS/matlab/harminv.m | 77 + openEMS/matlab/optimize.m | 203 ++ openEMS/matlab/optimizer_asco_sim.m | 88 + openEMS/matlab/physical_constants.m | 12 + openEMS/matlab/plotFF3D.m | 91 + openEMS/matlab/plotFFdB.m | 78 + openEMS/matlab/plotRefl.m | 145 + openEMS/matlab/polarFF.m | 172 + openEMS/matlab/private/ReadNF2FF.m | 82 + openEMS/matlab/private/invoke_openEMS.m | 47 + openEMS/matlab/queue_addProcess.m | 22 + openEMS/matlab/queue_checkProcess.m | 25 + openEMS/matlab/queue_delProcess.m | 40 + openEMS/matlab/setup.m | 40 + openEMS/nf2ff/CMakeLists.txt | 54 + openEMS/nf2ff/main.cpp | 44 + openEMS/nf2ff/nf2ff.cpp | 661 ++++ openEMS/nf2ff/nf2ff.h | 74 + openEMS/nf2ff/nf2ff_calc.cpp | 513 +++ openEMS/nf2ff/nf2ff_calc.h | 136 + openEMS/openEMS.sh | 11 + openEMS/openEMS_MPI.sh | 11 + openEMS/openems.cpp | 1232 +++++++ openEMS/openems.h | 167 + openEMS/tools/AdrOp.cpp | 554 +++ openEMS/tools/AdrOp.h | 149 + openEMS/tools/CMakeLists.txt | 28 + openEMS/tools/ErrorMsg.cpp | 98 + openEMS/tools/ErrorMsg.h | 50 + openEMS/tools/ExpenseLog.cpp | 145 + openEMS/tools/ExpenseLog.h | 92 + openEMS/tools/aligned_allocator.h | 173 + openEMS/tools/array_ops.cpp | 144 + openEMS/tools/array_ops.h | 196 ++ openEMS/tools/constants.h | 29 + openEMS/tools/global.cpp | 78 + openEMS/tools/global.h | 65 + openEMS/tools/hdf5_file_reader.cpp | 689 ++++ openEMS/tools/hdf5_file_reader.h | 78 + openEMS/tools/hdf5_file_writer.cpp | 515 +++ openEMS/tools/hdf5_file_writer.h | 68 + openEMS/tools/sar_calculation.cpp | 656 ++++ openEMS/tools/sar_calculation.h | 122 + openEMS/tools/useful.cpp | 185 + openEMS/tools/useful.h | 44 + openEMS/tools/vtk_file_writer.cpp | 340 ++ openEMS/tools/vtk_file_writer.h | 94 + other/openEMS.png | Bin 0 -> 8715 bytes other/openEMS.svg | 195 ++ readme.md | 79 + update_openEMS.sh | 160 + 688 files changed, 95575 insertions(+) create mode 100644 AppCSXCAD/AppCSXCAD.bat create mode 100644 AppCSXCAD/AppCSXCAD.cpp create mode 100644 AppCSXCAD/AppCSXCAD.h create mode 100755 AppCSXCAD/AppCSXCAD.sh create mode 100644 AppCSXCAD/CMakeLists.txt create mode 100644 AppCSXCAD/COPYING create mode 100644 AppCSXCAD/INSTALL create mode 100644 AppCSXCAD/README create mode 100644 AppCSXCAD/linux/AppCSXCAD.dsc create mode 100644 AppCSXCAD/linux/AppCSXCAD.spec create mode 100644 AppCSXCAD/linux/debian.changelog create mode 100644 AppCSXCAD/linux/debian.control create mode 100644 AppCSXCAD/linux/debian.rules create mode 100644 AppCSXCAD/linux/debian.series create mode 100644 AppCSXCAD/linux/start_script.patch create mode 100644 AppCSXCAD/main.cpp create mode 100644 CMakeLists.txt create mode 100644 CSXCAD/CMakeLists.txt create mode 100644 CSXCAD/COPYING create mode 100644 CSXCAD/INSTALL create mode 100644 CSXCAD/NEWS create mode 100644 CSXCAD/README create mode 100644 CSXCAD/cmake/Modules/FindTinyXML.cmake create mode 100644 CSXCAD/doxydoc create mode 100644 CSXCAD/linux/CSXCAD.dsc create mode 100644 CSXCAD/linux/CSXCAD.spec create mode 100644 CSXCAD/linux/CSXGeomPlot.m.patch create mode 100644 CSXCAD/linux/README.patch create mode 100644 CSXCAD/linux/debian.changelog create mode 100644 CSXCAD/linux/debian.control create mode 100644 CSXCAD/linux/debian.csxcad-dev.install create mode 100644 CSXCAD/linux/debian.csxcad.docs create mode 100644 CSXCAD/linux/debian.csxcad.install create mode 100644 CSXCAD/linux/debian.rules create mode 100644 CSXCAD/linux/debian.series create mode 100644 CSXCAD/matlab/AddBox.m create mode 100644 CSXCAD/matlab/AddConductingSheet.m create mode 100644 CSXCAD/matlab/AddCurve.m create mode 100644 CSXCAD/matlab/AddCylinder.m create mode 100644 CSXCAD/matlab/AddCylindricalShell.m create mode 100644 CSXCAD/matlab/AddDebyeMaterial.m create mode 100644 CSXCAD/matlab/AddDiscMaterial.m create mode 100644 CSXCAD/matlab/AddDump.m create mode 100644 CSXCAD/matlab/AddExcitation.m create mode 100644 CSXCAD/matlab/AddLinPoly.m create mode 100644 CSXCAD/matlab/AddLorentzMaterial.m create mode 100644 CSXCAD/matlab/AddLumpedElement.m create mode 100644 CSXCAD/matlab/AddMaterial.m create mode 100644 CSXCAD/matlab/AddMetal.m create mode 100644 CSXCAD/matlab/AddPlaneWaveExcite.m create mode 100644 CSXCAD/matlab/AddPoint.m create mode 100644 CSXCAD/matlab/AddPolygon.m create mode 100644 CSXCAD/matlab/AddPolyhedron.m create mode 100644 CSXCAD/matlab/AddProbe.m create mode 100644 CSXCAD/matlab/AddPropAttribute.m create mode 100644 CSXCAD/matlab/AddRotPoly.m create mode 100644 CSXCAD/matlab/AddSphere.m create mode 100644 CSXCAD/matlab/AddSphericalShell.m create mode 100644 CSXCAD/matlab/AddWire.m create mode 100644 CSXCAD/matlab/AnalyseMesh.m create mode 100644 CSXCAD/matlab/AutoSmoothMeshLines.m create mode 100644 CSXCAD/matlab/CSXGeomPlot.m create mode 100644 CSXCAD/matlab/CalcDebyeMaterial.m create mode 100644 CSXCAD/matlab/CalcDrudeMaterial.m create mode 100644 CSXCAD/matlab/CalcLorentzMaterial.m create mode 100644 CSXCAD/matlab/CheckMesh.m create mode 100644 CSXCAD/matlab/Convert_VF_DiscMaterial.m create mode 100644 CSXCAD/matlab/CreateDiscMaterial.m create mode 100644 CSXCAD/matlab/DefineRectGrid.m create mode 100644 CSXCAD/matlab/DetectEdges.m create mode 100644 CSXCAD/matlab/DirChar2Int.m create mode 100644 CSXCAD/matlab/ImportPLY.m create mode 100644 CSXCAD/matlab/ImportSTL.m create mode 100644 CSXCAD/matlab/InitCSX.m create mode 100644 CSXCAD/matlab/RecursiveSmoothMesh.m create mode 100644 CSXCAD/matlab/SetBackgroundMaterial.m create mode 100644 CSXCAD/matlab/SetExcitationWeight.m create mode 100644 CSXCAD/matlab/SetMaterialProperty.m create mode 100644 CSXCAD/matlab/SetMaterialWeight.m create mode 100644 CSXCAD/matlab/SmoothMesh.m create mode 100644 CSXCAD/matlab/SmoothMeshLines.m create mode 100644 CSXCAD/matlab/SmoothMeshLines2.m create mode 100644 CSXCAD/matlab/export_empire.m create mode 100644 CSXCAD/matlab/export_excellon.m create mode 100644 CSXCAD/matlab/export_gerber.m create mode 100644 CSXCAD/matlab/export_povray.m create mode 100644 CSXCAD/matlab/isOctave.m create mode 100644 CSXCAD/matlab/private/Add2Property.m create mode 100644 CSXCAD/matlab/private/AddPrimitiveArgs.m create mode 100644 CSXCAD/matlab/private/AddProperty.m create mode 100644 CSXCAD/matlab/private/CheckSymmtricLines.m create mode 100644 CSXCAD/matlab/private/FindProperty.m create mode 100644 CSXCAD/matlab/private/GetPropertyPosition.m create mode 100644 CSXCAD/matlab/private/GetPropertyType.m create mode 100644 CSXCAD/matlab/private/SetPropertyArgs.m create mode 100644 CSXCAD/matlab/private/SmoothRange.m create mode 100644 CSXCAD/matlab/private/octave_struct2xml_2.m create mode 100644 CSXCAD/matlab/private/struct_2_xmlNode.m create mode 100644 CSXCAD/matlab/private/vector2str.m create mode 100644 CSXCAD/matlab/searchBinary.m create mode 100644 CSXCAD/matlab/struct_2_xml.m create mode 100644 CSXCAD/src/CMakeLists.txt create mode 100644 CSXCAD/src/CSBackgroundMaterial.cpp create mode 100644 CSXCAD/src/CSBackgroundMaterial.h create mode 100644 CSXCAD/src/CSFunctionParser.cpp create mode 100644 CSXCAD/src/CSFunctionParser.h create mode 100644 CSXCAD/src/CSPrimBox.cpp create mode 100644 CSXCAD/src/CSPrimBox.h create mode 100644 CSXCAD/src/CSPrimCurve.cpp create mode 100644 CSXCAD/src/CSPrimCurve.h create mode 100644 CSXCAD/src/CSPrimCylinder.cpp create mode 100644 CSXCAD/src/CSPrimCylinder.h create mode 100644 CSXCAD/src/CSPrimCylindricalShell.cpp create mode 100644 CSXCAD/src/CSPrimCylindricalShell.h create mode 100644 CSXCAD/src/CSPrimLinPoly.cpp create mode 100644 CSXCAD/src/CSPrimLinPoly.h create mode 100644 CSXCAD/src/CSPrimMultiBox.cpp create mode 100644 CSXCAD/src/CSPrimMultiBox.h create mode 100644 CSXCAD/src/CSPrimPoint.cpp create mode 100644 CSXCAD/src/CSPrimPoint.h create mode 100644 CSXCAD/src/CSPrimPolygon.cpp create mode 100644 CSXCAD/src/CSPrimPolygon.h create mode 100644 CSXCAD/src/CSPrimPolyhedron.cpp create mode 100644 CSXCAD/src/CSPrimPolyhedron.h create mode 100644 CSXCAD/src/CSPrimPolyhedronReader.cpp create mode 100644 CSXCAD/src/CSPrimPolyhedronReader.h create mode 100644 CSXCAD/src/CSPrimPolyhedron_p.h create mode 100644 CSXCAD/src/CSPrimRotPoly.cpp create mode 100644 CSXCAD/src/CSPrimRotPoly.h create mode 100644 CSXCAD/src/CSPrimSphere.cpp create mode 100644 CSXCAD/src/CSPrimSphere.h create mode 100644 CSXCAD/src/CSPrimSphericalShell.cpp create mode 100644 CSXCAD/src/CSPrimSphericalShell.h create mode 100644 CSXCAD/src/CSPrimUserDefined.cpp create mode 100644 CSXCAD/src/CSPrimUserDefined.h create mode 100644 CSXCAD/src/CSPrimWire.cpp create mode 100644 CSXCAD/src/CSPrimWire.h create mode 100644 CSXCAD/src/CSPrimitives.cpp create mode 100644 CSXCAD/src/CSPrimitives.h create mode 100644 CSXCAD/src/CSPropConductingSheet.cpp create mode 100644 CSXCAD/src/CSPropConductingSheet.h create mode 100644 CSXCAD/src/CSPropDebyeMaterial.cpp create mode 100644 CSXCAD/src/CSPropDebyeMaterial.h create mode 100644 CSXCAD/src/CSPropDiscMaterial.cpp create mode 100644 CSXCAD/src/CSPropDiscMaterial.h create mode 100644 CSXCAD/src/CSPropDispersiveMaterial.cpp create mode 100644 CSXCAD/src/CSPropDispersiveMaterial.h create mode 100644 CSXCAD/src/CSPropDumpBox.cpp create mode 100644 CSXCAD/src/CSPropDumpBox.h create mode 100644 CSXCAD/src/CSPropExcitation.cpp create mode 100644 CSXCAD/src/CSPropExcitation.h create mode 100644 CSXCAD/src/CSPropLorentzMaterial.cpp create mode 100644 CSXCAD/src/CSPropLorentzMaterial.h create mode 100644 CSXCAD/src/CSPropLumpedElement.cpp create mode 100644 CSXCAD/src/CSPropLumpedElement.h create mode 100644 CSXCAD/src/CSPropMaterial.cpp create mode 100644 CSXCAD/src/CSPropMaterial.h create mode 100644 CSXCAD/src/CSPropMetal.cpp create mode 100644 CSXCAD/src/CSPropMetal.h create mode 100644 CSXCAD/src/CSPropProbeBox.cpp create mode 100644 CSXCAD/src/CSPropProbeBox.h create mode 100644 CSXCAD/src/CSPropResBox.cpp create mode 100644 CSXCAD/src/CSPropResBox.h create mode 100644 CSXCAD/src/CSPropUnknown.cpp create mode 100644 CSXCAD/src/CSPropUnknown.h create mode 100644 CSXCAD/src/CSProperties.cpp create mode 100644 CSXCAD/src/CSProperties.h create mode 100644 CSXCAD/src/CSRectGrid.cpp create mode 100644 CSXCAD/src/CSRectGrid.h create mode 100644 CSXCAD/src/CSTransform.cpp create mode 100644 CSXCAD/src/CSTransform.h create mode 100644 CSXCAD/src/CSUseful.cpp create mode 100644 CSXCAD/src/CSUseful.h create mode 100644 CSXCAD/src/CSXCAD_Global.h create mode 100644 CSXCAD/src/ContinuousStructure.cpp create mode 100644 CSXCAD/src/ContinuousStructure.h create mode 100644 CSXCAD/src/ParameterCoord.cpp create mode 100644 CSXCAD/src/ParameterCoord.h create mode 100644 CSXCAD/src/ParameterObjects.cpp create mode 100644 CSXCAD/src/ParameterObjects.h create mode 100644 CTB/AddElement2Port.m create mode 100644 CTB/ApplyCurrent2Port.m create mode 100644 CTB/ApplyRFPower2Port.m create mode 100644 CTB/InitNetwork.m create mode 100644 CTB/Makefile create mode 100644 CTB/SetPortTermination.m create mode 100644 CTB/a2s.m create mode 100644 CTB/a_PI.m create mode 100644 CTB/a_T.m create mode 100644 CTB/a_mul.m create mode 100644 CTB/a_series.m create mode 100644 CTB/a_shunt.m create mode 100644 CTB/license.txt create mode 100644 CTB/read_touchstone.m create mode 100644 CTB/readme.txt create mode 100644 CTB/s2a.m create mode 100644 CTB/s2y.m create mode 100644 CTB/s2z.m create mode 100644 CTB/s_renorm.m create mode 100644 CTB/write_touchstone.m create mode 100644 CTB/y2s.m create mode 100644 CTB/y2z.m create mode 100644 CTB/z2s.m create mode 100644 CTB/z2y.m create mode 100644 QCSXCAD/CMakeLists.txt create mode 100644 QCSXCAD/COPYING create mode 100644 QCSXCAD/INSTALL create mode 100644 QCSXCAD/NEWS create mode 100644 QCSXCAD/QCSGridEditor.cpp create mode 100644 QCSXCAD/QCSGridEditor.h create mode 100644 QCSXCAD/QCSPrimEditor.cpp create mode 100644 QCSXCAD/QCSPrimEditor.h create mode 100644 QCSXCAD/QCSPropEditor.cpp create mode 100644 QCSXCAD/QCSPropEditor.h create mode 100644 QCSXCAD/QCSTreeWidget.cpp create mode 100644 QCSXCAD/QCSTreeWidget.h create mode 100644 QCSXCAD/QCSXCAD.cpp create mode 100644 QCSXCAD/QCSXCAD.h create mode 100644 QCSXCAD/QCSXCAD_Global.cpp create mode 100644 QCSXCAD/QCSXCAD_Global.h create mode 100644 QCSXCAD/QParameterGui.cpp create mode 100644 QCSXCAD/QParameterGui.h create mode 100644 QCSXCAD/QVTKStructure.cpp create mode 100644 QCSXCAD/QVTKStructure.h create mode 100644 QCSXCAD/README create mode 100644 QCSXCAD/VTKPrimitives.cpp create mode 100644 QCSXCAD/VTKPrimitives.h create mode 100644 QCSXCAD/cmake/Modules/FindTinyXML.cmake create mode 100644 QCSXCAD/export_pov.cpp create mode 100644 QCSXCAD/export_pov.h create mode 100644 QCSXCAD/export_x3d.cpp create mode 100644 QCSXCAD/export_x3d.h create mode 100644 QCSXCAD/images/Arrows/Arrows.odg create mode 100644 QCSXCAD/images/Arrows/ArrowsXY.png create mode 100644 QCSXCAD/images/Arrows/ArrowsXZ.odg create mode 100644 QCSXCAD/images/Arrows/ArrowsXZ.png create mode 100644 QCSXCAD/images/Arrows/ArrowsYZ.odg create mode 100644 QCSXCAD/images/Arrows/ArrowsYZ.png create mode 100644 QCSXCAD/images/ArrowsXY.png create mode 100644 QCSXCAD/images/ArrowsXZ.png create mode 100644 QCSXCAD/images/ArrowsYZ.png create mode 100644 QCSXCAD/images/CVS/Entries create mode 100644 QCSXCAD/images/CVS/Repository create mode 100644 QCSXCAD/images/CVS/Root create mode 100644 QCSXCAD/images/GeoEdit.png create mode 100644 QCSXCAD/images/ParaSetup.png create mode 100644 QCSXCAD/images/QCSXCAD_Icon.png create mode 100644 QCSXCAD/images/accept.png create mode 100644 QCSXCAD/images/bulb.png create mode 100644 QCSXCAD/images/bulb_off.png create mode 100644 QCSXCAD/images/cancel.png create mode 100644 QCSXCAD/images/close.png create mode 100644 QCSXCAD/images/configure.png create mode 100644 QCSXCAD/images/down.png create mode 100644 QCSXCAD/images/edit.png create mode 100644 QCSXCAD/images/edit_add.png create mode 100644 QCSXCAD/images/edit_remove.png create mode 100644 QCSXCAD/images/editcopy.png create mode 100644 QCSXCAD/images/exit.png create mode 100644 QCSXCAD/images/failed.png create mode 100644 QCSXCAD/images/filenew.png create mode 100644 QCSXCAD/images/fileopen.png create mode 100644 QCSXCAD/images/filesave.png create mode 100644 QCSXCAD/images/filesaveas.png create mode 100644 QCSXCAD/images/folder.png create mode 100644 QCSXCAD/images/funct.png create mode 100644 QCSXCAD/images/hourglass.png create mode 100644 QCSXCAD/images/icon.gif create mode 100644 QCSXCAD/images/launch.png create mode 100644 QCSXCAD/images/launch2.png create mode 100644 QCSXCAD/images/launch3.png create mode 100644 QCSXCAD/images/opening.png create mode 100644 QCSXCAD/images/qt-logo.png create mode 100644 QCSXCAD/images/reload.png create mode 100644 QCSXCAD/images/result_small.png create mode 100644 QCSXCAD/images/results.png create mode 100644 QCSXCAD/images/setup.png create mode 100644 QCSXCAD/images/simulation.png create mode 100644 QCSXCAD/images/simulation_icon.png create mode 100644 QCSXCAD/images/simulation_small.png create mode 100644 QCSXCAD/images/simulation_tr.png create mode 100644 QCSXCAD/images/up.png create mode 100644 QCSXCAD/images/viewmag+.png create mode 100644 QCSXCAD/images/viewmag-.png create mode 100644 QCSXCAD/images/viewmagfit.png create mode 100644 QCSXCAD/images/vtk-logo.png create mode 100644 QCSXCAD/images/window_icon2.png create mode 100644 QCSXCAD/images/work.png create mode 100644 QCSXCAD/linux/QCSXCAD.dsc create mode 100644 QCSXCAD/linux/QCSXCAD.spec create mode 100644 QCSXCAD/linux/debian.changelog create mode 100644 QCSXCAD/linux/debian.control create mode 100644 QCSXCAD/linux/debian.rules create mode 100644 QCSXCAD/linux/fedora17.diff create mode 100644 QCSXCAD/resources.qrc create mode 100644 QCSXCAD/vtkInteractorStyleRubberBand2DPlane.cpp create mode 100644 QCSXCAD/vtkInteractorStyleRubberBand2DPlane.h create mode 100644 brew/README.md create mode 100644 brew/openEMS.rb create mode 100644 hyp2mat/.gitignore create mode 100644 hyp2mat/AUTHORS create mode 100644 hyp2mat/COPYING create mode 100644 hyp2mat/ChangeLog create mode 100644 hyp2mat/INSTALL create mode 100644 hyp2mat/Makefile.am create mode 100644 hyp2mat/NEWS create mode 100644 hyp2mat/README create mode 100644 hyp2mat/README.md create mode 100644 hyp2mat/THANKS create mode 100755 hyp2mat/bootstrap.sh create mode 100644 hyp2mat/configure.ac create mode 100644 hyp2mat/doc/.gitignore create mode 100644 hyp2mat/doc/Makefile.am create mode 100644 hyp2mat/doc/hyp2mat.h2m create mode 100644 hyp2mat/eagle/Makefile.am create mode 100644 hyp2mat/eagle/README_eagle.txt create mode 100644 hyp2mat/eagle/hairpinfilter/README.txt create mode 100644 hyp2mat/eagle/hairpinfilter/demo_hairpin.m create mode 100644 hyp2mat/eagle/hairpinfilter/hairpinfilter.brd create mode 100644 hyp2mat/eagle/hairpinfilter/hairpinfilter.pdf create mode 100644 hyp2mat/eagle/hairpinfilter/hairpinfilter.sch create mode 100644 hyp2mat/eagle/hairpinfilter/hairpinfilter_board.png create mode 100644 hyp2mat/eagle/hairpinfilter/hairpinfilter_simulation.png create mode 100644 hyp2mat/eagle/notchfilter/README.txt create mode 100644 hyp2mat/eagle/notchfilter/demo_notch.m create mode 100644 hyp2mat/eagle/notchfilter/notchfilter.brd create mode 100644 hyp2mat/eagle/notchfilter/notchfilter.pdf create mode 100644 hyp2mat/eagle/notchfilter/notchfilter.sch create mode 100644 hyp2mat/eagle/notchfilter/notchfilter_board.png create mode 100644 hyp2mat/eagle/notchfilter/notchfilter_simulation.png create mode 100644 hyp2mat/eagle/tutorial/GetEpsilon.m create mode 100644 hyp2mat/eagle/tutorial/GetUnits.m create mode 100644 hyp2mat/eagle/tutorial/README.txt create mode 100644 hyp2mat/eagle/tutorial/msl.brd create mode 100644 hyp2mat/eagle/tutorial/msl.lbr create mode 100644 hyp2mat/eagle/tutorial/msl.patch create mode 100644 hyp2mat/eagle/tutorial/msl.pdf create mode 100644 hyp2mat/eagle/tutorial/msl.sch create mode 100644 hyp2mat/eagle/tutorial/sparam.png create mode 100644 hyp2mat/eagle/tutorial/tutorial_hyp2mat.m create mode 100644 hyp2mat/lib/.gitignore create mode 100644 hyp2mat/lib/Makefile.am create mode 100644 hyp2mat/lib/clipper.cpp create mode 100644 hyp2mat/lib/clipper.hpp create mode 100644 hyp2mat/lib/clipper.txt create mode 100644 hyp2mat/lib/copper.cc create mode 100644 hyp2mat/lib/crop.cc create mode 100644 hyp2mat/lib/crop.h create mode 100644 hyp2mat/lib/csxcad.cc create mode 100644 hyp2mat/lib/csxcad.h create mode 100644 hyp2mat/lib/draw.cc create mode 100644 hyp2mat/lib/exec_board.cc create mode 100644 hyp2mat/lib/exec_devices.cc create mode 100644 hyp2mat/lib/exec_end.cc create mode 100644 hyp2mat/lib/exec_net.cc create mode 100644 hyp2mat/lib/exec_netclass.cc create mode 100644 hyp2mat/lib/exec_padstack.cc create mode 100644 hyp2mat/lib/exec_polygon.cc create mode 100644 hyp2mat/lib/exec_stackup.cc create mode 100644 hyp2mat/lib/exec_supplies.cc create mode 100644 hyp2mat/lib/hyp2mat.h create mode 100644 hyp2mat/lib/hyp2mat.pc.in create mode 100644 hyp2mat/lib/hyperlynx.cc create mode 100644 hyp2mat/lib/hyperlynx.h create mode 100644 hyp2mat/lib/hypfile.cc create mode 100644 hyp2mat/lib/hypfile.h create mode 100644 hyp2mat/lib/misc.cc create mode 100644 hyp2mat/lib/palette.cc create mode 100644 hyp2mat/lib/palette.h create mode 100644 hyp2mat/lib/parse.yy create mode 100644 hyp2mat/lib/parse_param.h create mode 100644 hyp2mat/lib/parser.h create mode 100644 hyp2mat/lib/pcb.cc create mode 100644 hyp2mat/lib/pdf.cc create mode 100644 hyp2mat/lib/pdf.h create mode 100644 hyp2mat/lib/polygon.cc create mode 100644 hyp2mat/lib/polygon.h create mode 100644 hyp2mat/lib/scan.ll create mode 100755 hyp2mat/makewin32 create mode 100644 hyp2mat/matlab/AddHyperLynxComponent.m create mode 100644 hyp2mat/matlab/AddHyperLynxDielectric.m create mode 100644 hyp2mat/matlab/AddHyperLynxMetal2D.m create mode 100644 hyp2mat/matlab/AddHyperLynxMetal3D.m create mode 100644 hyp2mat/matlab/Contents.m create mode 100644 hyp2mat/matlab/GetHyperLynxPort.m create mode 100644 hyp2mat/matlab/ImportHyperLynx.m create mode 100644 hyp2mat/matlab/Makefile.am create mode 100644 hyp2mat/src/.gitignore create mode 100644 hyp2mat/src/Makefile.am create mode 100644 hyp2mat/src/cmdline.ggo create mode 100644 hyp2mat/src/hyp2mat.cc create mode 100644 openEMS/Analyse/PlotVoltage.m create mode 100644 openEMS/CMakeLists.txt create mode 100644 openEMS/COPYING create mode 100644 openEMS/Common/CMakeLists.txt create mode 100644 openEMS/Common/engine_interface_base.cpp create mode 100644 openEMS/Common/engine_interface_base.h create mode 100644 openEMS/Common/operator_base.cpp create mode 100644 openEMS/Common/operator_base.h create mode 100644 openEMS/Common/processcurrent.cpp create mode 100644 openEMS/Common/processcurrent.h create mode 100644 openEMS/Common/processfieldprobe.cpp create mode 100644 openEMS/Common/processfieldprobe.h create mode 100644 openEMS/Common/processfields.cpp create mode 100644 openEMS/Common/processfields.h create mode 100644 openEMS/Common/processfields_fd.cpp create mode 100644 openEMS/Common/processfields_fd.h create mode 100644 openEMS/Common/processfields_sar.cpp create mode 100644 openEMS/Common/processfields_sar.h create mode 100644 openEMS/Common/processfields_td.cpp create mode 100644 openEMS/Common/processfields_td.h create mode 100644 openEMS/Common/processing.cpp create mode 100644 openEMS/Common/processing.h create mode 100644 openEMS/Common/processintegral.cpp create mode 100644 openEMS/Common/processintegral.h create mode 100644 openEMS/Common/processmodematch.cpp create mode 100644 openEMS/Common/processmodematch.h create mode 100644 openEMS/Common/processvoltage.cpp create mode 100644 openEMS/Common/processvoltage.h create mode 100644 openEMS/Common/readme.txt create mode 100644 openEMS/Doxyfile create mode 100644 openEMS/FDTD/CMakeLists.txt create mode 100644 openEMS/FDTD/engine.cpp create mode 100644 openEMS/FDTD/engine.h create mode 100644 openEMS/FDTD/engine_cylinder.cpp create mode 100644 openEMS/FDTD/engine_cylinder.h create mode 100644 openEMS/FDTD/engine_cylindermultigrid.cpp create mode 100644 openEMS/FDTD/engine_cylindermultigrid.h create mode 100644 openEMS/FDTD/engine_interface_cylindrical_fdtd.cpp create mode 100644 openEMS/FDTD/engine_interface_cylindrical_fdtd.h create mode 100644 openEMS/FDTD/engine_interface_fdtd.cpp create mode 100644 openEMS/FDTD/engine_interface_fdtd.h create mode 100644 openEMS/FDTD/engine_interface_sse_fdtd.cpp create mode 100644 openEMS/FDTD/engine_interface_sse_fdtd.h create mode 100644 openEMS/FDTD/engine_mpi.cpp create mode 100644 openEMS/FDTD/engine_mpi.h create mode 100644 openEMS/FDTD/engine_multithread.cpp create mode 100644 openEMS/FDTD/engine_multithread.h create mode 100644 openEMS/FDTD/engine_sse.cpp create mode 100644 openEMS/FDTD/engine_sse.h create mode 100644 openEMS/FDTD/engine_sse_compressed.cpp create mode 100644 openEMS/FDTD/engine_sse_compressed.h create mode 100644 openEMS/FDTD/excitation.cpp create mode 100644 openEMS/FDTD/excitation.h create mode 100644 openEMS/FDTD/extensions/CMakeLists.txt create mode 100644 openEMS/FDTD/extensions/OptimizeCondSheetParameter.m create mode 100644 openEMS/FDTD/extensions/cond_sheet_parameter.h create mode 100644 openEMS/FDTD/extensions/engine_ext_cylinder.cpp create mode 100644 openEMS/FDTD/extensions/engine_ext_cylinder.h create mode 100644 openEMS/FDTD/extensions/engine_ext_cylindermultigrid.cpp create mode 100644 openEMS/FDTD/extensions/engine_ext_cylindermultigrid.h create mode 100644 openEMS/FDTD/extensions/engine_ext_dispersive.cpp create mode 100644 openEMS/FDTD/extensions/engine_ext_dispersive.h create mode 100644 openEMS/FDTD/extensions/engine_ext_excitation.cpp create mode 100644 openEMS/FDTD/extensions/engine_ext_excitation.h create mode 100644 openEMS/FDTD/extensions/engine_ext_lorentzmaterial.cpp create mode 100644 openEMS/FDTD/extensions/engine_ext_lorentzmaterial.h create mode 100644 openEMS/FDTD/extensions/engine_ext_mur_abc.cpp create mode 100644 openEMS/FDTD/extensions/engine_ext_mur_abc.h create mode 100644 openEMS/FDTD/extensions/engine_ext_steadystate.cpp create mode 100644 openEMS/FDTD/extensions/engine_ext_steadystate.h create mode 100644 openEMS/FDTD/extensions/engine_ext_tfsf.cpp create mode 100644 openEMS/FDTD/extensions/engine_ext_tfsf.h create mode 100644 openEMS/FDTD/extensions/engine_ext_upml.cpp create mode 100644 openEMS/FDTD/extensions/engine_ext_upml.h create mode 100644 openEMS/FDTD/extensions/engine_extension.cpp create mode 100644 openEMS/FDTD/extensions/engine_extension.h create mode 100644 openEMS/FDTD/extensions/operator_ext_conductingsheet.cpp create mode 100644 openEMS/FDTD/extensions/operator_ext_conductingsheet.h create mode 100644 openEMS/FDTD/extensions/operator_ext_cylinder.cpp create mode 100644 openEMS/FDTD/extensions/operator_ext_cylinder.h create mode 100644 openEMS/FDTD/extensions/operator_ext_dispersive.cpp create mode 100644 openEMS/FDTD/extensions/operator_ext_dispersive.h create mode 100644 openEMS/FDTD/extensions/operator_ext_excitation.cpp create mode 100644 openEMS/FDTD/extensions/operator_ext_excitation.h create mode 100644 openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp create mode 100644 openEMS/FDTD/extensions/operator_ext_lorentzmaterial.h create mode 100644 openEMS/FDTD/extensions/operator_ext_mur_abc.cpp create mode 100644 openEMS/FDTD/extensions/operator_ext_mur_abc.h create mode 100644 openEMS/FDTD/extensions/operator_ext_steadystate.cpp create mode 100644 openEMS/FDTD/extensions/operator_ext_steadystate.h create mode 100644 openEMS/FDTD/extensions/operator_ext_tfsf.cpp create mode 100644 openEMS/FDTD/extensions/operator_ext_tfsf.h create mode 100644 openEMS/FDTD/extensions/operator_ext_upml.cpp create mode 100644 openEMS/FDTD/extensions/operator_ext_upml.h create mode 100644 openEMS/FDTD/extensions/operator_extension.cpp create mode 100644 openEMS/FDTD/extensions/operator_extension.h create mode 100644 openEMS/FDTD/openems_fdtd_mpi.cpp create mode 100644 openEMS/FDTD/openems_fdtd_mpi.h create mode 100644 openEMS/FDTD/operator.cpp create mode 100644 openEMS/FDTD/operator.h create mode 100644 openEMS/FDTD/operator_cylinder.cpp create mode 100644 openEMS/FDTD/operator_cylinder.h create mode 100644 openEMS/FDTD/operator_cylindermultigrid.cpp create mode 100644 openEMS/FDTD/operator_cylindermultigrid.h create mode 100644 openEMS/FDTD/operator_mpi.cpp create mode 100644 openEMS/FDTD/operator_mpi.h create mode 100644 openEMS/FDTD/operator_multithread.cpp create mode 100644 openEMS/FDTD/operator_multithread.h create mode 100644 openEMS/FDTD/operator_sse.cpp create mode 100644 openEMS/FDTD/operator_sse.h create mode 100644 openEMS/FDTD/operator_sse_compressed.cpp create mode 100644 openEMS/FDTD/operator_sse_compressed.h create mode 100644 openEMS/INSTALL create mode 100644 openEMS/NEWS create mode 100644 openEMS/README create mode 100644 openEMS/TESTSUITE/combinedtests/Coax.m create mode 100644 openEMS/TESTSUITE/combinedtests/README create mode 100644 openEMS/TESTSUITE/combinedtests/cavity.m create mode 100644 openEMS/TESTSUITE/enginetests/cavity.m create mode 100644 openEMS/TESTSUITE/helperscripts/check_frequency.m create mode 100644 openEMS/TESTSUITE/helperscripts/check_limits.m create mode 100644 openEMS/TESTSUITE/probes/fieldprobes.m create mode 100644 openEMS/TESTSUITE/run_testsuite.m create mode 100644 openEMS/TODO create mode 100755 openEMS/astyle.sh create mode 100644 openEMS/cmake/Modules/FindTinyXML.cmake create mode 100644 openEMS/known_bugs create mode 100644 openEMS/known_problems create mode 100644 openEMS/linux/CalcNF2FF.m.patch create mode 100644 openEMS/linux/README.patch create mode 100644 openEMS/linux/debian.changelog create mode 100644 openEMS/linux/debian.control create mode 100644 openEMS/linux/debian.docs create mode 100644 openEMS/linux/debian.rules create mode 100644 openEMS/linux/debian.series create mode 100644 openEMS/linux/fedora17.diff create mode 100644 openEMS/linux/invoke_openEMS.m.patch create mode 100644 openEMS/linux/openEMS.dsc create mode 100644 openEMS/linux/openEMS.spec create mode 100644 openEMS/main.cpp create mode 100644 openEMS/matlab/AR_estimate.m create mode 100644 openEMS/matlab/Add2Queue.m create mode 100644 openEMS/matlab/AddCPWPort.m create mode 100644 openEMS/matlab/AddCircWaveGuidePort.m create mode 100644 openEMS/matlab/AddCoaxialPort.m create mode 100644 openEMS/matlab/AddCurvePort.m create mode 100644 openEMS/matlab/AddLumpedPort.m create mode 100644 openEMS/matlab/AddMRStub.m create mode 100644 openEMS/matlab/AddMSLPort.m create mode 100644 openEMS/matlab/AddPML.m create mode 100644 openEMS/matlab/AddRectWaveGuidePort.m create mode 100644 openEMS/matlab/AddStripLinePort.m create mode 100644 openEMS/matlab/AddWaveGuidePort.m create mode 100644 openEMS/matlab/AnalyzeNF2FF.m create mode 100644 openEMS/matlab/CalcNF2FF.m create mode 100644 openEMS/matlab/CheckQueue.m create mode 100644 openEMS/matlab/ConvertHDF5_VTK.m create mode 100644 openEMS/matlab/CreateNF2FFBox.m create mode 100644 openEMS/matlab/DFT_time2freq.m create mode 100644 openEMS/matlab/DelayFidelity.m create mode 100644 openEMS/matlab/Dump2VTK.m create mode 100644 openEMS/matlab/DumpFF2VTK.m create mode 100644 openEMS/matlab/FFT_time2freq.m create mode 100644 openEMS/matlab/FindFreeSSH.m create mode 100644 openEMS/matlab/FinishQueue.m create mode 100644 openEMS/matlab/GetField_Interpolation.m create mode 100644 openEMS/matlab/GetField_Range.m create mode 100644 openEMS/matlab/GetField_SubSampling.m create mode 100644 openEMS/matlab/GetField_TD2FD.m create mode 100644 openEMS/matlab/InitCylindricalFDTD.m create mode 100644 openEMS/matlab/InitFDTD.m create mode 100644 openEMS/matlab/InitQueue.m create mode 100644 openEMS/matlab/PlotHDF5FieldData.m create mode 100644 openEMS/matlab/ReadHDF5Attribute.m create mode 100644 openEMS/matlab/ReadHDF5Dump.m create mode 100644 openEMS/matlab/ReadHDF5FieldData.m create mode 100644 openEMS/matlab/ReadHDF5Mesh.m create mode 100644 openEMS/matlab/ReadUI.m create mode 100644 openEMS/matlab/ResultsQueue.m create mode 100644 openEMS/matlab/RunOpenEMS.m create mode 100644 openEMS/matlab/RunOpenEMS_MPI.m create mode 100644 openEMS/matlab/RunOpenEMS_Parallel.m create mode 100644 openEMS/matlab/SetBoundaryCond.m create mode 100644 openEMS/matlab/SetCustomExcite.m create mode 100644 openEMS/matlab/SetDiracExcite.m create mode 100644 openEMS/matlab/SetGaussExcite.m create mode 100644 openEMS/matlab/SetSinusExcite.m create mode 100644 openEMS/matlab/SetStepExcite.m create mode 100644 openEMS/matlab/SetupMPI.m create mode 100644 openEMS/matlab/Tutorials/Bent_Patch_Antenna.m create mode 100644 openEMS/matlab/Tutorials/CRLH_Extraction.m create mode 100644 openEMS/matlab/Tutorials/CRLH_LeakyWaveAnt.m create mode 100644 openEMS/matlab/Tutorials/Circ_Waveguide.m create mode 100644 openEMS/matlab/Tutorials/Conical_Horn_Antenna.m create mode 100644 openEMS/matlab/Tutorials/CreateCRLH.m create mode 100644 openEMS/matlab/Tutorials/CylindricalWave_CC.m create mode 100644 openEMS/matlab/Tutorials/Dipole_SAR.m create mode 100644 openEMS/matlab/Tutorials/Helical_Antenna.m create mode 100644 openEMS/matlab/Tutorials/Horn_Antenna.m create mode 100644 openEMS/matlab/Tutorials/MRI_LP_Birdcage.m create mode 100644 openEMS/matlab/Tutorials/MRI_Loop_Coil.m create mode 100644 openEMS/matlab/Tutorials/MSL_NotchFilter.m create mode 100644 openEMS/matlab/Tutorials/Parallel_Plate_Waveguide.m create mode 100644 openEMS/matlab/Tutorials/Patch_Antenna_Array.m create mode 100644 openEMS/matlab/Tutorials/Patch_Antenna_Phased_Array.m create mode 100644 openEMS/matlab/Tutorials/RCS_Sphere.m create mode 100644 openEMS/matlab/Tutorials/RadarUWBTutorial.m create mode 100644 openEMS/matlab/Tutorials/Rect_Waveguide.m create mode 100644 openEMS/matlab/Tutorials/Simple_Patch_Antenna.m create mode 100644 openEMS/matlab/Tutorials/StripLine2MSL.m create mode 100644 openEMS/matlab/Tutorials/readme create mode 100644 openEMS/matlab/WriteHDF5.m create mode 100644 openEMS/matlab/WriteOpenEMS.m create mode 100644 openEMS/matlab/calcLumpedPort.m create mode 100644 openEMS/matlab/calcPort.m create mode 100644 openEMS/matlab/calcTLPort.m create mode 100644 openEMS/matlab/calcWGPort.m create mode 100644 openEMS/matlab/calc_ypar.m create mode 100644 openEMS/matlab/examples/__deprecated__/MSL2.m create mode 100644 openEMS/matlab/examples/antennas/Bi_Quad_Antenna.m create mode 100644 openEMS/matlab/examples/antennas/Patch_Antenna.m create mode 100644 openEMS/matlab/examples/antennas/Patch_Antenna_Array.m create mode 100644 openEMS/matlab/examples/antennas/infDipol.m create mode 100644 openEMS/matlab/examples/antennas/inverted_f.m create mode 100644 openEMS/matlab/examples/optimizer/optimizer_asco.m create mode 100644 openEMS/matlab/examples/optimizer/optimizer_simfun.m create mode 100644 openEMS/matlab/examples/other/Helix.m create mode 100644 openEMS/matlab/examples/other/LumpedElement.m create mode 100644 openEMS/matlab/examples/other/Metamaterial_PlaneWave_Drude.m create mode 100644 openEMS/matlab/examples/other/PML_reflection_analysis.m create mode 100644 openEMS/matlab/examples/other/PlaneWave.m create mode 100644 openEMS/matlab/examples/other/gauss_excitation_test.m create mode 100644 openEMS/matlab/examples/other/resistance_sheet.m create mode 100644 openEMS/matlab/examples/transmission_lines/CPW_Line.m create mode 100644 openEMS/matlab/examples/transmission_lines/Finite_Stripline.m create mode 100644 openEMS/matlab/examples/transmission_lines/MSL.m create mode 100644 openEMS/matlab/examples/transmission_lines/MSL_Losses.m create mode 100644 openEMS/matlab/examples/transmission_lines/Stripline.m create mode 100644 openEMS/matlab/examples/transmission_lines/directional_coupler.m create mode 100644 openEMS/matlab/examples/waveguide/Circ_Waveguide.m create mode 100644 openEMS/matlab/examples/waveguide/Circ_Waveguide_CylinderCoords.m create mode 100644 openEMS/matlab/examples/waveguide/Coax.m create mode 100644 openEMS/matlab/examples/waveguide/Coax_CylinderCoords.m create mode 100644 openEMS/matlab/examples/waveguide/Coax_Cylindrical_MG.m create mode 100644 openEMS/matlab/examples/waveguide/Rect_Waveguide.m create mode 100755 openEMS/matlab/h5readatt_octave.cc create mode 100644 openEMS/matlab/harminv.m create mode 100644 openEMS/matlab/optimize.m create mode 100644 openEMS/matlab/optimizer_asco_sim.m create mode 100644 openEMS/matlab/physical_constants.m create mode 100644 openEMS/matlab/plotFF3D.m create mode 100644 openEMS/matlab/plotFFdB.m create mode 100644 openEMS/matlab/plotRefl.m create mode 100644 openEMS/matlab/polarFF.m create mode 100644 openEMS/matlab/private/ReadNF2FF.m create mode 100644 openEMS/matlab/private/invoke_openEMS.m create mode 100644 openEMS/matlab/queue_addProcess.m create mode 100644 openEMS/matlab/queue_checkProcess.m create mode 100644 openEMS/matlab/queue_delProcess.m create mode 100644 openEMS/matlab/setup.m create mode 100644 openEMS/nf2ff/CMakeLists.txt create mode 100644 openEMS/nf2ff/main.cpp create mode 100644 openEMS/nf2ff/nf2ff.cpp create mode 100644 openEMS/nf2ff/nf2ff.h create mode 100644 openEMS/nf2ff/nf2ff_calc.cpp create mode 100644 openEMS/nf2ff/nf2ff_calc.h create mode 100755 openEMS/openEMS.sh create mode 100755 openEMS/openEMS_MPI.sh create mode 100644 openEMS/openems.cpp create mode 100644 openEMS/openems.h create mode 100644 openEMS/tools/AdrOp.cpp create mode 100644 openEMS/tools/AdrOp.h create mode 100644 openEMS/tools/CMakeLists.txt create mode 100644 openEMS/tools/ErrorMsg.cpp create mode 100644 openEMS/tools/ErrorMsg.h create mode 100644 openEMS/tools/ExpenseLog.cpp create mode 100644 openEMS/tools/ExpenseLog.h create mode 100644 openEMS/tools/aligned_allocator.h create mode 100644 openEMS/tools/array_ops.cpp create mode 100644 openEMS/tools/array_ops.h create mode 100644 openEMS/tools/constants.h create mode 100644 openEMS/tools/global.cpp create mode 100644 openEMS/tools/global.h create mode 100644 openEMS/tools/hdf5_file_reader.cpp create mode 100644 openEMS/tools/hdf5_file_reader.h create mode 100644 openEMS/tools/hdf5_file_writer.cpp create mode 100644 openEMS/tools/hdf5_file_writer.h create mode 100644 openEMS/tools/sar_calculation.cpp create mode 100644 openEMS/tools/sar_calculation.h create mode 100644 openEMS/tools/useful.cpp create mode 100644 openEMS/tools/useful.h create mode 100644 openEMS/tools/vtk_file_writer.cpp create mode 100644 openEMS/tools/vtk_file_writer.h create mode 100644 other/openEMS.png create mode 100644 other/openEMS.svg create mode 100644 readme.md create mode 100755 update_openEMS.sh diff --git a/AppCSXCAD/AppCSXCAD.bat b/AppCSXCAD/AppCSXCAD.bat new file mode 100644 index 0000000..3941cde --- /dev/null +++ b/AppCSXCAD/AppCSXCAD.bat @@ -0,0 +1,12 @@ +echo off +set PATH=D:\Programme\Qt\2009.01\qt\bin +set PATH=%PATH%;D:\Programme\Qt\2009.01\bin;D:\Programme\Qt\2009.01\mingw\bin +set PATH=%PATH%;%SystemRoot%\System32 +set PATH=%PATH%;D:\devel\CSXCAD\release;D:\devel\QCSXCAD\release +set PATH=%PATH%;D:\devel\tinyxml\release +set PATH=%PATH%;D:\devel\fparser\release +set PATH=%PATH%;D:\opt\VTK\bin +echo on +echo %PATH% + +.\release\AppCSXCAD.exe \ No newline at end of file diff --git a/AppCSXCAD/AppCSXCAD.cpp b/AppCSXCAD/AppCSXCAD.cpp new file mode 100644 index 0000000..a9d7c28 --- /dev/null +++ b/AppCSXCAD/AppCSXCAD.cpp @@ -0,0 +1,147 @@ +/* +* Copyright (C) 2012-2015 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 . +*/ + +#include +#include +#include + +#include "AppCSXCAD.h" + +#include "QVTKStructure.h" +#include "QCSXCAD_Global.h" + +AppCSXCAD::AppCSXCAD(QWidget *parent) : QCSXCAD(parent) +{ + QMenuBar* mb = menuBar(); + QMenu *FileMenu = mb->addMenu("&File"); + + if (QCSX_Settings.GetEdit()) + FileMenu->addAction(QIcon(":/images/filenew.png"),tr("New"),this,SLOT(New()),QKeySequence(tr("Ctrl+N"))); + FileMenu->addAction(QIcon(":/images/fileopen.png"),tr("Load"),this,SLOT(ImportGeometry()),QKeySequence(tr("Ctrl+L"))); + FileMenu->addSeparator(); + if (QCSX_Settings.GetEdit()) + { + FileMenu->addAction(QIcon(":/images/filesave.png"),tr("Save"),this,SLOT(Save()),QKeySequence(tr("Ctrl+S"))); + FileMenu->addAction(QIcon(":/images/filesave.png"),tr("Save As"),this,SLOT(ExportGeometry())); + } + //FileMenu->addAction(QIcon(":/images/filesaveas.png"),tr("Save As.."),this,SLOT(SaveAs())); + QMenu *FileExportMenu = FileMenu->addMenu(tr("E&xport")); + FileExportMenu->addAction(QIcon(":/images/filesave.png"),tr("CSXCAD XML"),this,SLOT(ExportGeometry())); + FileExportMenu->addAction(QIcon(":/images/filesave.png"),tr("Pov&ray"),this,SLOT(ExportGeometry_Povray()),QKeySequence(tr("Ctrl+R"))); + FileExportMenu->addAction(QIcon(":/images/filesave.png"),tr("Polydata-&VTK"),this,SLOT(ExportGeometry_PolyDataVTK())); + FileExportMenu->addAction(QIcon(":/images/filesave.png"),tr("STL"),this,SLOT(ExportGeometry_STL())); + FileExportMenu->addAction(QIcon(":/images/filesave.png"),tr("PLY"),this,SLOT(ExportGeometry_PLY())); + FileExportMenu->addAction(QIcon(":/images/filesave.png"),tr("3D view to &PNG"),this,SLOT(ExportView2Image()),QKeySequence(tr("Ctrl+P"))); + FileExportMenu->addAction(QIcon(":/images/filesave.png"),tr("&X3D"),this,SLOT(ExportGeometry_X3D()),QKeySequence(tr("Ctrl+3"))); + FileMenu->addSeparator(); + FileMenu->addAction(QIcon(":/images/exit.png"),tr("Exit"),qApp,SLOT(quit())); + + QMenu *InfoMenu = mb->addMenu("Info"); + InfoMenu->addAction(tr("About"),this,SLOT(aboutQCSXCAD())); + + QStringList argList=qApp->arguments(); + if (argList.size()>1) + { + QString file = argList.back(); + if (!file.startsWith("-")) + if (ReadFile(file)==false) + QMessageBox::information(this,"File Error!",tr("Can't open file: %1").arg(file)); + GUIUpdate(); + } + + QString title = tr("AppCSXCAD"); + if (QCSX_Settings.GetEdit()==false) + title += " - " + tr("View Mode"); + setWindowTitle(title); + View3D(); + LoadSettings(); + + parseCommandLineArguments(qApp->arguments()); +} + +AppCSXCAD::~AppCSXCAD() +{ + SaveSettings(); +} + +void AppCSXCAD::parseCommandLineArguments(const QStringList &argList) +{ + for (int n=0;n. +*/ + +#ifndef APPCSXCAD_H +#define APPCSXCAD_H + +#include +#include +#include +#include "QCSXCAD.h" + +#define __APPNAME__ "AppCSXCAD" + +class AppCSXCAD : public QCSXCAD +{ + Q_OBJECT + +public: + AppCSXCAD(QWidget *parent = 0); + virtual ~AppCSXCAD(); + + virtual bool ReadFile(QString filename); + +public slots: + void Save(); + virtual void clear(); + +protected: + void parseCommandLineArguments(const QStringList &argList); + void SaveSettings(); + void LoadSettings(); + QString m_filename; +}; + +#endif // APPCSXCAD_H diff --git a/AppCSXCAD/AppCSXCAD.sh b/AppCSXCAD/AppCSXCAD.sh new file mode 100755 index 0000000..07ede64 --- /dev/null +++ b/AppCSXCAD/AppCSXCAD.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +BIN_PATH=`dirname $0` + +# unset the library search path +# Matlab sets it to point to an old libc +export LD_LIBRARY_PATH= + +# Important! If you get a vtk error like this: +# ERROR: In /builddir/build/BUILD/VTK/Rendering/vtkXOpenGLRenderWindow.cxx, line 404 +# vtkXOpenGLRenderWindow (0xbe2980): Could not find a decent visual +# you need to uncomment the next line: +# export LIBGL_ALWAYS_INDIRECT=y + +$BIN_PATH/AppCSXCAD $@ diff --git a/AppCSXCAD/CMakeLists.txt b/AppCSXCAD/CMakeLists.txt new file mode 100644 index 0000000..d5a72c9 --- /dev/null +++ b/AppCSXCAD/CMakeLists.txt @@ -0,0 +1,178 @@ + +# define build type +IF( DEFINED CMAKE_BUILD_TYPE ) + SET( CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Set to either \"Release\" or \"Debug\"" ) +ELSE() + SET( CMAKE_BUILD_TYPE Release CACHE STRING "Set to either \"Release\" or \"Debug\"" ) +ENDIF() + +PROJECT( AppCSXCAD CXX C) + +cmake_minimum_required(VERSION 2.8) + +if(POLICY CMP0020) + cmake_policy(SET CMP0020 OLD) +endif() + +IF(EXISTS ${PROJECT_SOURCE_DIR}/localConfig.cmake) + include(${PROJECT_SOURCE_DIR}/localConfig.cmake) +ENDIF() + +# default +set(VERSION "v0.2.2") + +# add git revision +IF(EXISTS ${PROJECT_SOURCE_DIR}/.git ) + FIND_PACKAGE(Git) + # Get the latest abbreviated commit hash of the working branch + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE GITREV + ) + set(VERSION ${GITREV}) + string(STRIP ${VERSION} VERSION) + message(STATUS "Found Git repository, ${PROJECT_NAME} version tag: ${VERSION}") +ENDIF() + +ADD_DEFINITIONS(-DGIT_VERSION=\"${VERSION}\") + +# +# Set up RPATH for the project +# +option(ENABLE_RPATH "Enable rpath support on Linux and Mac" ON) +if(NOT CMAKE_INSTALL_RPATH) + set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") +endif() +if(APPLE AND NOT CMAKE_INSTALL_NAME_DIR) + set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") +endif() +if(UNIX AND ENABLE_RPATH) + set(CMAKE_SKIP_BUILD_RPATH FALSE) + set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +endif() + +# Set locations of extra CMake modules +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${openEMS_SOURCE_DIR}/cmake/Modules/") + +# CSXCAD +# $ cmake -DCSXCAD_ROOT_DIR=~/opt/openEMS . +# SET(CSXCAD_ROOT_DIR ~/opt/openEMS) +find_library(CSXCAD_LIBRARIES + NAMES CSXCAD + HINTS ${CSXCAD_ROOT_DIR}/lib${LIB_SUFFIX} + NO_CMAKE_FIND_ROOT_PATH +) +message(STATUS "CSXCAD_LIBRARIES: ${CSXCAD_LIBRARIES}" ) +#TODO test if CSXCADs was found +find_path(CSXCAD_INCLUDE_DIR + NAMES ContinuousStructure.h + HINTS ${CSXCAD_ROOT_DIR}/include + PATH_SUFFIXES "CSXCAD" ${CSXCAD_INCLUDE_DIR} + NO_CMAKE_FIND_ROOT_PATH +) +message(STATUS "CSXCAD_INCLUDE_DIR: ${CSXCAD_INCLUDE_DIR}" ) +INCLUDE_DIRECTORIES( ${CSXCAD_INCLUDE_DIR} ) + + +# QCSXCAD +# $ cmake -DQCSXCAD_ROOT_DIR=~/opt/openEMS . +# SET(QCSXCAD_ROOT_DIR ~/opt/openEMS) +find_library(QCSXCAD_LIBRARIES + NAMES QCSXCAD + HINTS ${QCSXCAD_ROOT_DIR}/lib${LIB_SUFFIX} + NO_CMAKE_FIND_ROOT_PATH +) +message(STATUS "QCSXCAD_LIBRARIES: ${QCSXCAD_LIBRARIES}" ) +#TODO test if QCSXCADs was found +find_path(QCSXCAD_INCLUDE_DIR + NAMES QCSXCAD.h + HINTS ${QCSXCAD_ROOT_DIR}/include + PATH_SUFFIXES "QCSXCAD" ${QCSXCAD_INCLUDE_DIR} + NO_CMAKE_FIND_ROOT_PATH +) +message(STATUS "QCSXCAD_INCLUDE_DIR: ${QCSXCAD_INCLUDE_DIR}" ) +INCLUDE_DIRECTORIES( ${QCSXCAD_INCLUDE_DIR} ) + +# hdf5 +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() + +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") + find_package(Qt5Widgets REQUIRED) + include_directories(${Qt5Widgets_INCLUDE_DIRS}) + find_package(Qt5Xml REQUIRED) + include_directories(${Qt5Xml_INCLUDE_DIRS}) + INCLUDE_DIRECTORIES(${Qt5_INCLUDE_DIRS}) + set(CMAKE_CXX_FLAGS "${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") +else() + FIND_PACKAGE(Qt4 REQUIRED QtCore QtGui QtXml) + INCLUDE( ${QT_USE_FILE} ) +endif() + +message(STATUS "Found package VTK. Using version " ${VTK_VERSION}) + +SET(SOURCES + main.cpp + AppCSXCAD.cpp +) + +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} +) + +# +# Install the application. +# On Mac the bundle is also installed into bin. +# +INSTALL(TARGETS AppCSXCAD + BUNDLE DESTINATION bin COMPONENT Runtime + RUNTIME DESTINATION bin COMPONENT Runtime +) + +if (UNIX) + INSTALL(FILES AppCSXCAD.sh + DESTINATION bin + PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE) +endif () + +# TODO tarball + diff --git a/AppCSXCAD/COPYING b/AppCSXCAD/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/AppCSXCAD/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/AppCSXCAD/INSTALL b/AppCSXCAD/INSTALL new file mode 100644 index 0000000..c08d291 --- /dev/null +++ b/AppCSXCAD/INSTALL @@ -0,0 +1,19 @@ +Install instructions for AppCSXCAD: +--------------------------------------------- + +1) Prerequirements: + AppCSXCAD relies on the QCSXCAD & CSXCAD libraries and its dependencies: + - CSXCAD, QCSXCAD (http://openEMS.de) + +2) Build: + - change directory to QCSXCAD + - build: + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX= -DCSXCAD_ROOT_DIR= -DQCSXCAD_ROOT_DIR= + make + make install (may require root) + + Note: + - all path informations may be stored in a localConfig.cmake + - the default "prefix" is /usr/local diff --git a/AppCSXCAD/README b/AppCSXCAD/README new file mode 100644 index 0000000..7f8d911 --- /dev/null +++ b/AppCSXCAD/README @@ -0,0 +1,7 @@ +* +* AppCSXCAD - Minimal Application using the QCSXCAD library +* + +AppCSXCAD is a minimal application using the QCSXCAD library. +AppCSXCAD is licensed under the terms of the GPLv3. + diff --git a/AppCSXCAD/linux/AppCSXCAD.dsc b/AppCSXCAD/linux/AppCSXCAD.dsc new file mode 100644 index 0000000..9afcd66 --- /dev/null +++ b/AppCSXCAD/linux/AppCSXCAD.dsc @@ -0,0 +1,9 @@ +Format: 1.0 +Source: appcsxcad +Version: 0.1.1-1 +Binary: appcsxcad +Maintainer: Thorsten Liebig , Sebastian Held +Homepage: http://www.openems.de +Architecture: any +Build-Depends: debhelper (>= 5.0.0), libqt4-dev, qt4-qmake, libfparser4, libtinyxml-dev, csxcad-dev, libvtk5-qt4-dev, qcsxcad-dev +DEBTRANSFORM-TAR: AppCSXCAD-0.1.1.tar.bz2 diff --git a/AppCSXCAD/linux/AppCSXCAD.spec b/AppCSXCAD/linux/AppCSXCAD.spec new file mode 100644 index 0000000..1d0b47a --- /dev/null +++ b/AppCSXCAD/linux/AppCSXCAD.spec @@ -0,0 +1,82 @@ +# +# spec file for package [spectemplate] +# +# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + +# norootforbuild + +Name: AppCSXCAD +Version: 0.1.1 +Release: 1 +Summary: View CSXCAD geometries +Group: Productivity/Scientific/Physics +License: GPLv3 +URL: http://www.openems.de +Source0: %{name}-%{version}.tar.bz2 +#Patch0: install.patch +Patch1: start_script.patch +BuildRoot: %_tmppath/%name-%version-build + +# libfparser4-devel contains a static library => no runtime requirement +BuildRequires: libqt4-devel gcc-c++ libfparser4-devel tinyxml-devel CSXCAD-devel vtk-devel vtk-qt QCSXCAD-devel + + +# determine qt4 qmake executable +%if 0%{?fedora} + %global qmake qmake-qt4 +%else + %global qmake qmake +%endif + + + +%description +View CSXCAD geometries. Based on QCSXCAD. + + +%prep +%setup -q +#%patch0 -p1 +%patch1 -p1 + +%build +%qmake QMAKE_CFLAGS="%optflags" QMAKE_CXXFLAGS="%optflags" LIB_SUFFIX="$(echo %_lib | cut -b4-)" AppCSXCAD.pro +make %{?_smp_mflags} + + +%install +make INSTALL_ROOT=%{buildroot} install +find %{buildroot} -name '*.la' -exec rm -f {} ';' + + +%clean +rm -rf %{buildroot} + + +%files +%defattr(-,root,root) +/usr/bin/AppCSXCAD* + + + +%changelog +* Sun Jun 17 2012 Sebastian Held - 0.1.1-1 +- New upstream version +* Mon Jan 09 2012 Sebastian Held - 0.1.0-3 +- Modified start script +* Wed Dec 28 2011 Sebastian Held - 0.1.0-2 +- Fedora 16 build support +* Mon Dec 5 2011 Sebastian Held - 0.1.0-1 +- initial version diff --git a/AppCSXCAD/linux/debian.changelog b/AppCSXCAD/linux/debian.changelog new file mode 100644 index 0000000..4aee49c --- /dev/null +++ b/AppCSXCAD/linux/debian.changelog @@ -0,0 +1,9 @@ +appcsxcad (0.1.1-1) stable; urgency=low + * New upstream version + -- Sebastian Held Sun, 17 Jun 2012 23:06:00 +0200 +appcsxcad (0.1.0-2) stable; urgency=low + * Modified start script + -- Sebastian Held Mon, 9 Jan 2012 22:34:00 +0100 +appcsxcad (0.1.0-1) stable; urgency=low + * Initial Release + -- Sebastian Held Mon, 5 Dec 2011 19:55:00 +0100 diff --git a/AppCSXCAD/linux/debian.control b/AppCSXCAD/linux/debian.control new file mode 100644 index 0000000..427e68d --- /dev/null +++ b/AppCSXCAD/linux/debian.control @@ -0,0 +1,11 @@ +Source: appcsxcad +Section: contrib/science +Priority: optional +Maintainer: Sebastian Held +Build-Depends: debhelper (>=7.0.50~), libqt4-dev, qt4-qmake, libfparser4, libtinyxml-dev, csxcad-dev, libvtk5-qt4-dev, qcsxcad-dev + +Package: appcsxcad +Architecture: any +Depends: ${shlibs:Depends} +Description: View CSXCAD geometries + Based on QCSXCAD. diff --git a/AppCSXCAD/linux/debian.rules b/AppCSXCAD/linux/debian.rules new file mode 100644 index 0000000..874a39c --- /dev/null +++ b/AppCSXCAD/linux/debian.rules @@ -0,0 +1,7 @@ +#!/usr/bin/make -f + +export DH_VERBOSE=1 +export DH_OPTIONS=-v + +%: + dh $@ diff --git a/AppCSXCAD/linux/debian.series b/AppCSXCAD/linux/debian.series new file mode 100644 index 0000000..2a7bbe3 --- /dev/null +++ b/AppCSXCAD/linux/debian.series @@ -0,0 +1 @@ +start_script.patch -p1 diff --git a/AppCSXCAD/linux/start_script.patch b/AppCSXCAD/linux/start_script.patch new file mode 100644 index 0000000..f128374 --- /dev/null +++ b/AppCSXCAD/linux/start_script.patch @@ -0,0 +1,10 @@ +diff --git a/AppCSXCAD.sh b/AppCSXCAD.sh +index ca45a9e..72a9365 100755 +--- a/AppCSXCAD.sh ++++ b/AppCSXCAD.sh +@@ -12,4 +12,4 @@ export LD_LIBRARY_PATH= + # you need to uncomment the next line: + # export LIBGL_ALWAYS_INDIRECT=y + +-$DEVEL_PATH/AppCSXCAD/AppCSXCAD $@ ++AppCSXCAD $@ diff --git a/AppCSXCAD/main.cpp b/AppCSXCAD/main.cpp new file mode 100644 index 0000000..6aa19af --- /dev/null +++ b/AppCSXCAD/main.cpp @@ -0,0 +1,32 @@ +/* +* Copyright (C) 2012-2015 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 . +*/ + +#include "AppCSXCAD.h" + +#include + +int main(int argc, char *argv[]) +{ +#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(); +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..2e0e699 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,65 @@ + +## usage: cmake -DCMAKE_INSTALL_PREFIX= . +## use -DBUILD_APPCSXCAD=NO to not build QCSXCAD and AppCSXCAD + +PROJECT(openEMS-Project CXX) + +cmake_minimum_required(VERSION 2.8) + +if (CMAKE_TOOLCHAIN_FILE) + message(STATUS "Using CMAKE_TOOLCHAIN_FILE: " ${CMAKE_TOOLCHAIN_FILE}) +endif() + +if (CMAKE_INSTALL_PREFIX) + message(STATUS "Using CMAKE_INSTALL_PREFIX: " ${CMAKE_INSTALL_PREFIX}) +endif() + +if (NOT DEFINED BUILD_APPCSXCAD) + set(BUILD_APPCSXCAD "YES") +endif() + +message(STATUS "Build AppCSXCAD: " ${BUILD_APPCSXCAD}) + +IF(EXISTS ${PROJECT_SOURCE_DIR}/localConfig.cmake) + message(STATUS "include local config" ) + include(${PROJECT_SOURCE_DIR}/localConfig.cmake) +ENDIF() + +include(ExternalProject) + +# build fparser +ExternalProject_Add( fparser + SOURCE_DIR ${PROJECT_SOURCE_DIR}/fparser + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} +) + +# build CSXCAD +ExternalProject_Add( CSXCAD + DEPENDS fparser + SOURCE_DIR ${PROJECT_SOURCE_DIR}/CSXCAD + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DFPARSER_ROOT_DIR=${CMAKE_INSTALL_PREFIX} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} +) + +message(STATUS "with MPI: ${WITH_MPI}" ) +# build openEMS +ExternalProject_Add( openEMS + DEPENDS fparser CSXCAD + SOURCE_DIR ${PROJECT_SOURCE_DIR}/openEMS + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DFPARSER_ROOT_DIR=${CMAKE_INSTALL_PREFIX} -DCSXCAD_ROOT_DIR=${CMAKE_INSTALL_PREFIX} -DWITH_MPI=${WITH_MPI} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} +) + +if (${BUILD_APPCSXCAD}) + # build QCSXCAD + ExternalProject_Add( QCSXCAD + DEPENDS CSXCAD + SOURCE_DIR ${PROJECT_SOURCE_DIR}/QCSXCAD + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DCSXCAD_ROOT_DIR=${CMAKE_INSTALL_PREFIX} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} + ) + + # build AppCSXCAD + ExternalProject_Add( AppCSXCAD + DEPENDS QCSXCAD + SOURCE_DIR ${PROJECT_SOURCE_DIR}/AppCSXCAD + CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DCSXCAD_ROOT_DIR=${CMAKE_INSTALL_PREFIX} -DQCSXCAD_ROOT_DIR=${CMAKE_INSTALL_PREFIX} -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} + ) +endif() diff --git a/CSXCAD/CMakeLists.txt b/CSXCAD/CMakeLists.txt new file mode 100644 index 0000000..9d516d5 --- /dev/null +++ b/CSXCAD/CMakeLists.txt @@ -0,0 +1,146 @@ + +# define build type +IF( DEFINED CMAKE_BUILD_TYPE ) + SET( CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Set to either \"Release\" or \"Debug\"" ) +ELSE() + SET( CMAKE_BUILD_TYPE Release CACHE STRING "Set to either \"Release\" or \"Debug\"" ) +ENDIF() + +PROJECT(CSXCAD CXX C) + +cmake_minimum_required(VERSION 2.8) + +# default +set(LIB_VERSION_MAJOR 0) +set(LIB_VERSION_MINOR 6) +set(LIB_VERSION_PATCH 2) +set(LIB_VERSION_STRING ${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}) + +set(VERSION "v${LIB_VERSION_STRING}") + +IF(EXISTS ${PROJECT_SOURCE_DIR}/localConfig.cmake) + include(${PROJECT_SOURCE_DIR}/localConfig.cmake) +ENDIF() + +# add git revision +IF(EXISTS ${PROJECT_SOURCE_DIR}/.git ) + FIND_PACKAGE(Git) + # Get the latest abbreviated commit hash of the working branch + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE GITREV + ) + set(VERSION ${GITREV}) + string(STRIP ${VERSION} VERSION) + message(STATUS "Found Git repository, ${PROJECT_NAME} version tag: ${VERSION}") +ENDIF() + +ADD_DEFINITIONS(-DGIT_VERSION=\"${VERSION}\") + +if (WIN32) + ADD_DEFINITIONS( -DBUILD_CSXCAD_LIB ) +endif (WIN32) + +# +# Set up RPATH for the project +# +option(ENABLE_RPATH "Enable rpath support on Linux and Mac" ON) +if(NOT CMAKE_INSTALL_RPATH) + # the RPATH to be used when installing, but only if it's not a system directory + LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" isSystemDir) + IF("${isSystemDir}" STREQUAL "-1") + SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") + ENDIF("${isSystemDir}" STREQUAL "-1") +endif() +if(APPLE AND NOT CMAKE_INSTALL_NAME_DIR) + set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") +endif() +if(UNIX AND ENABLE_RPATH) + set(CMAKE_SKIP_BUILD_RPATH FALSE) + set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +endif() + +# Set locations of CMake modules +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CSXCAD_SOURCE_DIR}/cmake/Modules/") + +# fparser +# $ cmake -D FPARSER_ROOT_DIR=~/opt/openEMS . +IF(NOT EXISTS ${FPARSER_ROOT_DIR}) + SET(FPARSER_ROOT_DIR /usr) +ENDIF() +message(STATUS "FPARSER_ROOT_DIR: ${FPARSER_ROOT_DIR}" ) +find_library(fparser_LIBRARIES + NAMES fparser + HINTS ${FPARSER_ROOT_DIR}/lib${LIB_SUFFIX} + NO_CMAKE_FIND_ROOT_PATH +) +message(STATUS "fparser_LIBRARIES: ${fparser_LIBRARIES}" ) +find_path(fparser_INCLUDE_DIR + NAMES fparser.hh + HINTS ${FPARSER_ROOT_DIR}/include ${FPARSER_ROOT_DIR}/include/fparser + NO_CMAKE_FIND_ROOT_PATH +) +message(STATUS "fparser_INCLUDE_DIR: ${fparser_INCLUDE_DIR}" ) +#TODO test if fparser was found +INCLUDE_DIRECTORIES( ${fparser_INCLUDE_DIR} ) + +# TinyXML module from https://github.com/ros/cmake_modules +find_package(TinyXML REQUIRED) +ADD_DEFINITIONS( -DTIXML_USE_STL ) + +find_package(HDF5 1.8 COMPONENTS C HL REQUIRED) +INCLUDE_DIRECTORIES (${HDF5_INCLUDE_DIRS}) +link_directories(${HDF5_LIBRARY_DIRS}) +# hdf5 compat +ADD_DEFINITIONS( -DH5_USE_16_API ) + +# message(status "hdf5 all libs: ${HDF5_LIBRARIES}") + + +find_package(CGAL REQUIRED) +INCLUDE_DIRECTORIES (${CGAL_INCLUDE_DIR}) + +# cgal needs, fail o Linux otherwise +if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -frounding-math" ) +endif() + +# TODO what are the needed libs? +find_package(Boost 1.46 COMPONENTS + thread + system + date_time + serialization + chrono +) + +# 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() + +message(STATUS "Found package VTK. Using version " ${VTK_VERSION}) +include(${VTK_USE_FILE}) +INCLUDE_DIRECTORIES (${VTK_INCLUDE_DIR}) +if("${VTK_MAJOR_VERSION}" GREATER 5) + set( vtk_LIBS ${VTK_LIBRARIES} ) +else() + set( vtk_LIBS + vtkCommon + ) +endif() +message(STATUS "vtk libraries " ${vtk_LIBS}) +# depend on fparser.hh +ADD_SUBDIRECTORY( src ) + +INSTALL(DIRECTORY matlab DESTINATION share/CSXCAD) + +#TODO tarball, debug, release, doxygen diff --git a/CSXCAD/COPYING b/CSXCAD/COPYING new file mode 100644 index 0000000..cca7fc2 --- /dev/null +++ b/CSXCAD/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/CSXCAD/INSTALL b/CSXCAD/INSTALL new file mode 100644 index 0000000..2c87401 --- /dev/null +++ b/CSXCAD/INSTALL @@ -0,0 +1,25 @@ +Install instructions for the CSXCAD library: +--------------------------------------------- + +1) Prerequirements: + CSXCAD relies on a number of third-party open-source libraries: + - fparser (http://warp.povusers.org/FunctionParser/) + - tinyxml (http://www.grinninglizard.com/tinyxml/) + - hdf5 (http://www.hdfgroup.org/HDF5/) + - vtk (http://www.vtk.org/) + - boost (http://www.boost.org/) + - cgal (http://www.cgal.org/) + +2) Build: + - change directory to CSXCAD + - build: + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX= -DFPARSER_ROOT_DIR= + make + make install (may require root) + + Note: + - all path informations may be stored in a localConfig.cmake + - the default "prefix" is /usr/local + diff --git a/CSXCAD/NEWS b/CSXCAD/NEWS new file mode 100644 index 0000000..af8ecca --- /dev/null +++ b/CSXCAD/NEWS @@ -0,0 +1,12 @@ +Changes in v0.5.1 +------------------------------- +- matlab interface: throw an error when re-adding an already existing property (fix) + +Changes in v0.5.0 +------------------------------- +- new file-format for discrete materials +- new create function for discrete materials +- fix for curve primitive in cylindrical coordinates +- full multi-pole Lorentz/Drude/Debye material models +- extensive code-cleanup +- bug fixes \ No newline at end of file diff --git a/CSXCAD/README b/CSXCAD/README new file mode 100644 index 0000000..9b5056e --- /dev/null +++ b/CSXCAD/README @@ -0,0 +1,18 @@ +* +* CSXCAD - Continuous Structure XML +* + +A C++ library to describe geometrical objects and their physical or non-physical properties. +CSXCAD is licensed under the terms of the LGPLv3. + + +Website: http://openems.de/index.php/CSXCAD +Forum: http://openems.de/forum/ +Tutorials: http://openems.de/index.php/Tutorials + + +To use CSXCAD from Matlab or Octave, you need to include the /matlab folder in the respective environment: +> addpath( '/matlab' ); + +To verify the correct installation follow the instructions at: +http://openems.de/index.php/Tutorial:_First_Steps diff --git a/CSXCAD/cmake/Modules/FindTinyXML.cmake b/CSXCAD/cmake/Modules/FindTinyXML.cmake new file mode 100644 index 0000000..aabb323 --- /dev/null +++ b/CSXCAD/cmake/Modules/FindTinyXML.cmake @@ -0,0 +1,74 @@ +################################################################################################## +# +# CMake script for finding TinyXML. +# +# Input variables: +# +# - TinyXML_ROOT_DIR (optional): When specified, header files and libraries will be searched for in +# ${TinyXML_ROOT_DIR}/include +# ${TinyXML_ROOT_DIR}/libs +# respectively, and the default CMake search order will be ignored. When unspecified, the default +# CMake search order is used. +# This variable can be specified either as a CMake or environment variable. If both are set, +# preference is given to the CMake variable. +# Use this variable for finding packages installed in a nonstandard location, or for enforcing +# that one of multiple package installations is picked up. +# +# +# Cache variables (not intended to be used in CMakeLists.txt files) +# +# - TinyXML_INCLUDE_DIR: Absolute path to package headers. +# - TinyXML_LIBRARY: Absolute path to library. +# +# +# Output variables: +# +# - TinyXML_FOUND: Boolean that indicates if the package was found +# - TinyXML_INCLUDE_DIRS: Paths to the necessary header files +# - TinyXML_LIBRARIES: Package libraries +# +# +# Example usage: +# +# find_package(TinyXML) +# if(NOT TinyXML_FOUND) +# # Error handling +# endif() +# ... +# include_directories(${TinyXML_INCLUDE_DIRS} ...) +# ... +# target_link_libraries(my_target ${TinyXML_LIBRARIES}) +# +################################################################################################## + +# Get package location hint from environment variable (if any) +if(NOT TinyXML_ROOT_DIR AND DEFINED ENV{TinyXML_ROOT_DIR}) + set(TinyXML_ROOT_DIR "$ENV{TinyXML_ROOT_DIR}" CACHE PATH + "TinyXML base directory location (optional, used for nonstandard installation paths)") +endif() + +# Search path for nonstandard package locations +if(TinyXML_ROOT_DIR) + set(TinyXML_INCLUDE_PATH PATHS "${TinyXML_ROOT_DIR}/include" NO_DEFAULT_PATH) + set(TinyXML_LIBRARY_PATH PATHS "${TinyXML_ROOT_DIR}/lib" NO_DEFAULT_PATH) +endif() + +# Find headers and libraries +find_path(TinyXML_INCLUDE_DIR NAMES tinyxml.h PATH_SUFFIXES "tinyxml" ${TinyXML_INCLUDE_PATH}) +find_library(TinyXML_LIBRARY NAMES tinyxml PATH_SUFFIXES "tinyxml" ${TinyXML_LIBRARY_PATH}) + +mark_as_advanced(TinyXML_INCLUDE_DIR + TinyXML_LIBRARY) + +# Output variables generation +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(TinyXML DEFAULT_MSG TinyXML_LIBRARY + TinyXML_INCLUDE_DIR) + +set(TinyXML_FOUND ${TINYXML_FOUND}) # Enforce case-correctness: Set appropriately cased variable... +unset(TINYXML_FOUND) # ...and unset uppercase variable generated by find_package_handle_standard_args + +if(TinyXML_FOUND) + set(TinyXML_INCLUDE_DIRS ${TinyXML_INCLUDE_DIR}) + set(TinyXML_LIBRARIES ${TinyXML_LIBRARY}) +endif() diff --git a/CSXCAD/doxydoc b/CSXCAD/doxydoc new file mode 100644 index 0000000..2b272ce --- /dev/null +++ b/CSXCAD/doxydoc @@ -0,0 +1,1541 @@ +# Doxyfile 1.5.8 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = CSXCAD + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = $(CSXCAD_VERSION) + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, +# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, +# Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, +# Spanish, Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = /Users/dimitri/doxygen/mail/1.5.7/doxywizard/ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = src/ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = YES + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = ../CSXCAD.qch + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = de.openems.CSXCAD.$(CSXCAD_VERSION) + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = qhelpgenerator + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to FRAME, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. Other possible values +# for this tag are: HIERARCHIES, which will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list; +# ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which +# disables this behavior completely. For backwards compatibility with previous +# releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE +# respectively. + +GENERATE_TREEVIEW = NONE + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Options related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/CSXCAD/linux/CSXCAD.dsc b/CSXCAD/linux/CSXCAD.dsc new file mode 100644 index 0000000..43849b5 --- /dev/null +++ b/CSXCAD/linux/CSXCAD.dsc @@ -0,0 +1,9 @@ +Format: 1.0 +Source: csxcad +Version: 0.3.0-3 +Binary: csxcad, csxcad-dev +Maintainer: Thorsten Liebig , Sebastian Held +Homepage: http://www.openems.de +Architecture: any +Build-Depends: debhelper (>=7.0.50~), qt4-qmake, libfparser4, libhdf5-serial-dev, libtinyxml-dev, libvtk5-qt4-dev +DEBTRANSFORM-TAR: CSXCAD-0.3.0.tar.bz2 diff --git a/CSXCAD/linux/CSXCAD.spec b/CSXCAD/linux/CSXCAD.spec new file mode 100644 index 0000000..38fd332 --- /dev/null +++ b/CSXCAD/linux/CSXCAD.spec @@ -0,0 +1,131 @@ +# +# spec file for package [spectemplate] +# +# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + +# norootforbuild + +Name: CSXCAD +Version: 0.3.0 +Release: 2 +Summary: Library for Geometric Primitives primarily used by openEMS +Group: Development/Languages/C and C++ +License: LGPLv3 +URL: http://www.openems.de +Source0: %{name}-%{version}.tar.bz2 +Patch0: CSXGeomPlot.m.patch +Patch1: README.patch +# BuildArch: noarch +BuildRoot: %_tmppath/%name-%version-build + +BuildRequires: libqt4-devel gcc-c++ libfparser4-devel hdf5-devel tinyxml-devel vtk-devel +#Requires: + + +# determine qt4 qmake executable +%if 0%{?fedora} + %global qmake qmake-qt4 +%else + %global qmake qmake +%endif + + + +%description +Library for Geometric Primitives primarily used by openEMS. + +%package -n lib%{name}0 +Summary: Shared Library for %{name} +Group: Development/Languages/C and C++ + +%description -n lib%{name}0 +The lib%{name}0 package contains the shared library. + +%package devel +Summary: Development files for %{name} +Group: Development/Languages/C and C++ +Requires: %{name} = %{version}-%{release} +Requires: lib%{name}0 = %{version}-%{release} + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + + +%prep +%setup -q +%patch0 -p1 +%patch1 -p1 + +%build +%{qmake} QMAKE_CFLAGS="%optflags" QMAKE_CXXFLAGS="%optflags" LIB_SUFFIX="$(echo %_lib | cut -b4-)" +make %{?_smp_mflags} + + +%install +make INSTALL_ROOT=%{buildroot} install +find %{buildroot} -name '*.la' -exec rm -f {} ';' + + +%clean +rm -rf %{buildroot} + + +%post -n lib%{name}0 -p /sbin/ldconfig + +%postun -n lib%{name}0 -p /sbin/ldconfig + + +%files +%defattr(-,root,root) +%doc COPYING README +/usr/share/%{name} +#/usr/share/%{name}/matlab +#/usr/share/%{name}/matlab/* + + +%files -n lib%{name}0 +%defattr(-,root,root) +%{_libdir}/*.so.* + + +%files devel +%defattr(-,root,root) +%{_includedir}/* +%{_libdir}/*.so + + +%changelog +* Sat Jun 23 2012 Sebastian Held - 0.3.0-2 +- fixed missing files and version information +* Sun Jun 17 2012 Sebastian Held - 0.3.0-1 +- new upstream version +* Wed Feb 29 2012 Sebastian Held - 0.2.4-7 +- new upstream fixes +* Sat Jan 21 2012 Sebastian Held - 0.2.4-6 +- new upstream fixes +* Thu Dec 29 2011 Sebastian Held - 0.2.4-5 +- added README +* Thu Dec 22 2011 Sebastian Held - 0.2.4-4 +- new upstream fix and support for Fedora 16 +* Mon Dec 05 2011 Sebastian Held - 0.2.4-3 +- includes now in /usr/include/CSXCAD +- fix for CSXGeomView.m +* Sun Dec 04 2011 Sebastian Held - 0.2.4-2 +- missing build dep vtk-devel +* Sun Dec 04 2011 Sebastian Held - 0.2.4-1 +- next release +* Tue Sep 29 2011 Sebastian Held - 0.0.24-1 +- initial version diff --git a/CSXCAD/linux/CSXGeomPlot.m.patch b/CSXCAD/linux/CSXGeomPlot.m.patch new file mode 100644 index 0000000..09dc664 --- /dev/null +++ b/CSXCAD/linux/CSXGeomPlot.m.patch @@ -0,0 +1,25 @@ +diff --git a/matlab/CSXGeomPlot.m b/matlab/CSXGeomPlot.m +index 21d3ef8..37427a1 100644 +--- a/matlab/CSXGeomPlot.m ++++ b/matlab/CSXGeomPlot.m +@@ -13,18 +13,10 @@ if nargin < 1 + error 'specify the xml file to open' + end + +-filename = mfilename('fullpath'); +-dir = fileparts( filename ); +-AppCSXCAD_Path = [dir filesep '../../AppCSXCAD' filesep]; +- +-if (~exist(AppCSXCAD_Path,'dir')) +- AppCSXCAD_Path = [dir filesep '..' filesep] +-end +- + if isunix +- AppCSXCAD_Path = [AppCSXCAD_Path 'AppCSXCAD.sh']; ++ AppCSXCAD_Path = 'AppCSXCAD.sh'; + else +- AppCSXCAD_Path = [AppCSXCAD_Path 'AppCSXCAD']; ++ AppCSXCAD_Path = 'AppCSXCAD'; + end + + command = [AppCSXCAD_Path ' --disableEdit ' CSX_filename]; diff --git a/CSXCAD/linux/README.patch b/CSXCAD/linux/README.patch new file mode 100644 index 0000000..ea947f6 --- /dev/null +++ b/CSXCAD/linux/README.patch @@ -0,0 +1,15 @@ +diff --git a/README b/README +index 9b5056e..fc3176c 100644 +--- a/README ++++ b/README +@@ -11,8 +11,8 @@ Forum: http://openems.de/forum/ + Tutorials: http://openems.de/index.php/Tutorials + + +-To use CSXCAD from Matlab or Octave, you need to include the /matlab folder in the respective environment: +-> addpath( '/matlab' ); ++To use CSXCAD from Matlab or Octave, you need to include the /usr/share/CSXCAD/matlab folder in the respective environment: ++> addpath( '/usr/share/CSXCAD/matlab' ); + + To verify the correct installation follow the instructions at: + http://openems.de/index.php/Tutorial:_First_Steps diff --git a/CSXCAD/linux/debian.changelog b/CSXCAD/linux/debian.changelog new file mode 100644 index 0000000..dfbccbb --- /dev/null +++ b/CSXCAD/linux/debian.changelog @@ -0,0 +1,27 @@ +csxcad (0.3.0-3) stable; urgency=low + * replaced recommended deps by suggested deps + -- Sebastian Held Sat, 30 Jun 2012 12:16:00 +0200 +csxcad (0.3.0-2) stable; urgency=low + * fixed missing files and version information + -- Sebastian Held Sat, 23 Jun 2012 11:58:00 +0200 +csxcad (0.3.0-1) stable; urgency=low + * New upstream version + -- Sebastian Held Sun, 17 Jun 2012 21:54:30 +0200 +csxcad (0.2.4-6) stable; urgency=low + * New upstream fix + -- Sebastian Held Wed, 29 Feb 2012 23:20:00 +0100 +csxcad (0.2.4-5) stable; urgency=low + * New upstream fix + -- Sebastian Held Sat, 21 Jan 2012 21:22:00 +0100 +csxcad (0.2.4-4) stable; urgency=low + * Added README + -- Sebastian Held Thu, 29 Dec 2011 21:06:00 +0100 +csxcad (0.2.4-3) stable; urgency=low + * New upstream fix + -- Sebastian Held Thu, 22 Dec 2011 22:45:00 +0100 +csxcad (0.2.4-2) stable; urgency=low + * New upstream release + -- Sebastian Held Sun, 4 Dec 2011 15:20:00 +0100 +csxcad (0.0.24-1) stable; urgency=low + * Initial Release + -- Sebastian Held Thu, 6 Oct 2011 17:58:38 +0200 diff --git a/CSXCAD/linux/debian.control b/CSXCAD/linux/debian.control new file mode 100644 index 0000000..54ac8ab --- /dev/null +++ b/CSXCAD/linux/debian.control @@ -0,0 +1,18 @@ +Source: csxcad +Section: contrib/libdevel +Priority: optional +Maintainer: Sebastian Held +Build-Depends: debhelper (>=7.0.50~), qt4-qmake, libfparser4, libhdf5-serial-dev, libtinyxml-dev, libvtk5-qt4-dev + +Package: csxcad +Architecture: any +Depends: ${shlibs:Depends} +Suggests: appcsxcad +Description: Library for Geometric Primitives primarily used by openEMS + Library for Geometric Primitives primarily used by openEMS. + +Package: csxcad-dev +Architecture: any +Depends: ${shlibs:Depends} csxcad (= ${binary:Version}) +Description: Development files for csxcad + The csxcad-dev package contains libraries and header files for developing applications that use csxcad. diff --git a/CSXCAD/linux/debian.csxcad-dev.install b/CSXCAD/linux/debian.csxcad-dev.install new file mode 100644 index 0000000..1537de1 --- /dev/null +++ b/CSXCAD/linux/debian.csxcad-dev.install @@ -0,0 +1,2 @@ +usr/include/* +usr/lib/*.so diff --git a/CSXCAD/linux/debian.csxcad.docs b/CSXCAD/linux/debian.csxcad.docs new file mode 100644 index 0000000..2e3abae --- /dev/null +++ b/CSXCAD/linux/debian.csxcad.docs @@ -0,0 +1,2 @@ +COPYING +README diff --git a/CSXCAD/linux/debian.csxcad.install b/CSXCAD/linux/debian.csxcad.install new file mode 100644 index 0000000..96f3c01 --- /dev/null +++ b/CSXCAD/linux/debian.csxcad.install @@ -0,0 +1,2 @@ +usr/lib/*.so.* +usr/share/CSXCAD/* diff --git a/CSXCAD/linux/debian.rules b/CSXCAD/linux/debian.rules new file mode 100644 index 0000000..a6ec285 --- /dev/null +++ b/CSXCAD/linux/debian.rules @@ -0,0 +1,8 @@ +#!/usr/bin/make -f + +export DH_VERBOSE=1 +export DH_OPTIONS=-v +export DH_COMPAT=7 + +%: + dh $@ diff --git a/CSXCAD/linux/debian.series b/CSXCAD/linux/debian.series new file mode 100644 index 0000000..a16dfed --- /dev/null +++ b/CSXCAD/linux/debian.series @@ -0,0 +1,2 @@ +CSXGeomPlot.m.patch -p1 +README.patch -p1 diff --git a/CSXCAD/matlab/AddBox.m b/CSXCAD/matlab/AddBox.m new file mode 100644 index 0000000..d07274c --- /dev/null +++ b/CSXCAD/matlab/AddBox.m @@ -0,0 +1,42 @@ +function CSX = AddBox(CSX, propName, prio, start, stop, varargin) +% function CSX = AddBox(CSX, propName, prio, start, stop, varargin) +% +% Add a box to CSX and assign to a property with name . +% +% start: box start coordinates +% stop : box stop coordinates +% prio : primitive priority +% +% optional: +% Transformation: perform a transformation on a primitive by adding +% e.g.: 'Transform', {'Scale','1,1,2','Rotate_X',pi/4,'Translate','0,0,100'} +% Note: This will only affect the 3D material/metal discretisation +% +% example: +% CSX = AddMetal(CSX,'metal'); %create PEC with propName 'metal' +% CSX = AddBox(CSX,'metal',10,[0 0 0],[100 100 200]); %assign box +% +% with transformation: +% CSX = AddBox(CSX,'metal',10,[0 0 0],[100 100 200], ... +% 'Transform', {Rotate_Z, pi/4}); +% +% See also AddCylinder, AddCylindricalShell, AddSphere, AddSphericalShell, +% AddCurve, AddWire, AddMetal +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +box.ATTRIBUTE.Priority = prio; + +box.P1.ATTRIBUTE.X=start(1); +box.P1.ATTRIBUTE.Y=start(2); +box.P1.ATTRIBUTE.Z=start(3); + +box.P2.ATTRIBUTE.X=stop(1); +box.P2.ATTRIBUTE.Y=stop(2); +box.P2.ATTRIBUTE.Z=stop(3); + +box = AddPrimitiveArgs(box,varargin{:}); + +CSX = Add2Property(CSX,propName, box, 'Box'); \ No newline at end of file diff --git a/CSXCAD/matlab/AddConductingSheet.m b/CSXCAD/matlab/AddConductingSheet.m new file mode 100644 index 0000000..f3e79b4 --- /dev/null +++ b/CSXCAD/matlab/AddConductingSheet.m @@ -0,0 +1,47 @@ +function CSX = AddConductingSheet(CSX, name, conductivity, thickness) +%function CSX = AddConductingSheet(CSX, name, conductivity, thickness) +% +% Add a conducting sheet property to CSX with the given name. +% Remember to add at least one or more 2D!! geometrical primitives to this +% property. +% +% Hint: +% Set the thickness to 0 to fall back to a perfect metal (AddMetal) +% +% example: +% % create the conducting material peroperty, e.g. 40um thick copper +% CSX = AddConductingSheet(CSX,'copper',56e6,40e-6); +% % assign box the 2D box --> 40um thick sheet +% CSX = AddBox(CSX,'copper',10,[0 -50 200],[1000 50 200]); +% +% See also AddMaterial, AddMetal, AddExcitation, AddBox +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig 2012 + + +% fall back to ideal pec for t==0 or c==0 +if ((thickness==0) || (conductivity==0)) + CSX = AddMetal(CSX,name); + return; +end + +if ((conductivity<0) || (thickness<0)) + error('CSXCAD:AddConductingSheet','a negative conductivity or thickness is invalid'); +end + +if (conductivity<1e6) + warning('CSXCAD:AddConductingSheet','a conductivity below 1MA/Vm is not recommended'); +end + +if (thickness>500e-6) + warning('CSXCAD:AddConductingSheet','a thickness greater than 500um is not recommended'); +end + + +if (thickness<1e-6) + warning('CSXCAD:AddConductingSheet','a thickness lower than 1um is not recommended'); +end + +CSX = AddProperty(CSX, 'ConductingSheet', name,'Conductivity',conductivity,'Thickness',thickness); diff --git a/CSXCAD/matlab/AddCurve.m b/CSXCAD/matlab/AddCurve.m new file mode 100644 index 0000000..2e4e5b2 --- /dev/null +++ b/CSXCAD/matlab/AddCurve.m @@ -0,0 +1,44 @@ +function CSX = AddCurve(CSX, propName, prio, points, varargin) +% function CSX = AddCurve(CSX, propName, prio, points, varargin) +% +% Add a curve to CSX and assign to a property with name . +% +% Warning: This is a 1D object, not all properties may be compatible with a +% 1D object, e.g. a material property. +% +% points: curve coordinates array +% prio : primitive priority +% +% example: +% %first point +% points(1,1) = 0; +% points(2,1) = 5; +% points(3,1) = 10; +% %second point +% points(1,2) = 0; +% points(2,2) = 10; +% points(3,2) = 10; +% %third point ... +% % create a thin metal wire... +% CSX = AddMetal(CSX,'metal'); %create PEC with propName 'metal' +% CSX = AddCurve(CSX,'metal',10, points); +% +% See also AddBox, AddCylindricalShell, AddCylinder, AddSphere, +% AddSphericalShell, AddWire, AddMetal +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +curve.ATTRIBUTE.Priority = prio; + +curve.Vertex={}; +for s=1:size(points,2) + curve.Vertex{end+1}.ATTRIBUTE.X = points(1,s); + curve.Vertex{end}.ATTRIBUTE.Y = points(2,s); + curve.Vertex{end}.ATTRIBUTE.Z = points(3,s); +end + +curve = AddPrimitiveArgs(curve,varargin{:}); + +CSX = Add2Property(CSX,propName, curve, 'Curve'); \ No newline at end of file diff --git a/CSXCAD/matlab/AddCylinder.m b/CSXCAD/matlab/AddCylinder.m new file mode 100644 index 0000000..1998325 --- /dev/null +++ b/CSXCAD/matlab/AddCylinder.m @@ -0,0 +1,35 @@ +function CSX = AddCylinder(CSX, propName, prio, start, stop, rad, varargin) +% function CSX = AddCylinder(CSX, propName, prio, start, stop, rad, varargin) +% +% Add a cylinder to CSX and assign to a property with name . +% +% start: cylinder axis start coordinates +% stop : cylinder axis box stop coordinates +% rad : cylinder radius +% prio : primitive priority +% +% example: +% CSX = AddMetal(CSX,'metal'); %create PEC with propName 'metal' +% CSX = AddCylinder(CSX,'metal',10,[0 0 0],[0 0 200],50); +% +% See also AddBox, AddCylindricalShell, AddSphere, AddSphericalShell, +% AddCurve, AddWire, AddMetal +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +cylinder.ATTRIBUTE.Priority = prio; +cylinder.ATTRIBUTE.Radius = rad; + +cylinder.P1.ATTRIBUTE.X=start(1); +cylinder.P1.ATTRIBUTE.Y=start(2); +cylinder.P1.ATTRIBUTE.Z=start(3); + +cylinder.P2.ATTRIBUTE.X=stop(1); +cylinder.P2.ATTRIBUTE.Y=stop(2); +cylinder.P2.ATTRIBUTE.Z=stop(3); + +cylinder = AddPrimitiveArgs(cylinder,varargin{:}); + +CSX = Add2Property(CSX,propName, cylinder, 'Cylinder'); \ No newline at end of file diff --git a/CSXCAD/matlab/AddCylindricalShell.m b/CSXCAD/matlab/AddCylindricalShell.m new file mode 100644 index 0000000..53ff5f4 --- /dev/null +++ b/CSXCAD/matlab/AddCylindricalShell.m @@ -0,0 +1,41 @@ +function CSX = AddCylindricalShell(CSX, propName, prio, start, stop, rad, shell_width, varargin) +%function CSX = AddCylindricalShell(CSX, propName, prio, start, stop, rad, shell_width, varargin) +% +% Add a cylinder shell to CSX and assign to a property with name . +% +% start: cylinder axis start coordinates +% stop : cylinder axis box stop coordinates +% rad : cylinder radius +% shell_width: cylinder shell width +% prio : primitive priority +% +% Note: +% the inner radius of this shell is rad-shell_width/2 +% the outer radius of this shell is rad+shell_width/2 +% +% example: +% CSX = AddMetal(CSX,'metal'); %create PEC with propName 'metal' +% CSX = AddCylindricalShell(CSX,'metal',10,[0 0 0],[0 0 200],50,10); +% +% See also AddBox, AddCylinder, AddSphere, AddSphericalShell, +% AddCurve, AddWire, AddMetal +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +cylinder.ATTRIBUTE.Priority = prio; +cylinder.ATTRIBUTE.Radius = rad; +cylinder.ATTRIBUTE.ShellWidth = shell_width; + +cylinder.P1.ATTRIBUTE.X=start(1); +cylinder.P1.ATTRIBUTE.Y=start(2); +cylinder.P1.ATTRIBUTE.Z=start(3); + +cylinder.P2.ATTRIBUTE.X=stop(1); +cylinder.P2.ATTRIBUTE.Y=stop(2); +cylinder.P2.ATTRIBUTE.Z=stop(3); + +cylinder = AddPrimitiveArgs(cylinder,varargin{:}); + +CSX = Add2Property(CSX,propName, cylinder, 'CylindricalShell'); diff --git a/CSXCAD/matlab/AddDebyeMaterial.m b/CSXCAD/matlab/AddDebyeMaterial.m new file mode 100644 index 0000000..941ffe9 --- /dev/null +++ b/CSXCAD/matlab/AddDebyeMaterial.m @@ -0,0 +1,29 @@ +function CSX = AddDebyeMaterial(CSX, name, varargin) +% function CSX = AddDebyeMaterial(CSX, name, varargin) +% +% Add a Debye type dispersive material model. +% +% The Debye type frequency dependent material: +% eps_r(w) = eps_r + sum_p ( eps_r_delta,p / (1+jw*t_relex,p) ) - j*kappa/w +% +% with +% eps_r_delta,p: the delta electric relative permitivity +% t_relex,p: the electric relaxation time +% +% Use SetMaterialProperty to define the material constants: +% 'EpsilonDelta_p': p-th eps_r_delta,p +% 'EpsilonRelaxTime_p': p-th t_relex,p +% +% example: +% CSX = AddDebyeMaterial(CSX,'debye'); +% CSX = SetMaterialProperty(CSX,'debye','Epsilon',5,'EpsilonDelta_1',0.1,'EpsilonRelaxTime_1',1e-9); +% [..] +% CSX = AddBox(CSX,'debye', 10 ,start,stop); +% +% See also AddBox, AddMaterial, SetMaterialProperty, AddLorentzMaterial +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (2013) + +CSX = AddProperty(CSX, 'DebyeMaterial', name, varargin{:}); diff --git a/CSXCAD/matlab/AddDiscMaterial.m b/CSXCAD/matlab/AddDiscMaterial.m new file mode 100644 index 0000000..86f5213 --- /dev/null +++ b/CSXCAD/matlab/AddDiscMaterial.m @@ -0,0 +1,47 @@ +function CSX = AddDiscMaterial(CSX, name, varargin) +% function CSX = AddDiscMaterial(CSX, name, varargin) +% +% Add a discretized material model property to CSX with the given name. +% Discretized model has to be stored in an hdf5 file. +% Use Transform option to perfom some transformation actions. +% +% variable arguments (key/value) +% 'File' (mandatory): define the filename of the discrete material +% 'Scale': scale the discrete material +% e.g. to your drawing units: 'Scale', 1/unit +% 'Transform': Apply a transformation, see AddBox for more infos +% 'UseDBBackground': set to 0, to use the properties background material +% instead of the database material with index 0 (default) +% +% examples: +% %add human body model +% CSX = AddDiscMaterial(CSX, 'Ella', 'Scale', 1/unit, ... +% 'Transform', {'Rotate_Z',pi/2,'Translate','300,300,500'}, ... +% 'File', 'model_file_name.h5' ); +% start = [mesh.x(1) mesh.y(1) mesh.z(1)]; +% stop = [mesh.x(end) mesh.y(end) mesh.z(end)]; +% CSX = AddBox(CSX,'Ella', 0 ,start,stop); +% +% See also AddBox, AddMetal, AddExcitation, AddProbe, AddDump +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +transform = []; + +for n=1:2:(nargin-2) + if (strcmp(varargin{n},'Transform')) + transform = varargin([n:n+1]); + varargin([n:n+1]) = []; + break + end +end + +CSX = AddProperty(CSX, 'DiscMaterial', name, varargin{:}); + +if ~isempty(transform) + for n=1:2:numel(transform{2}) + CSX.Properties.DiscMaterial{end}.Transformation.(transform{2}{n}).ATTRIBUTE.Argument=transform{2}{n+1}; + end +end diff --git a/CSXCAD/matlab/AddDump.m b/CSXCAD/matlab/AddDump.m new file mode 100644 index 0000000..f454992 --- /dev/null +++ b/CSXCAD/matlab/AddDump.m @@ -0,0 +1,87 @@ +function CSX = AddDump(CSX, name, varargin) +% function CSX = AddDump(CSX, name, varargin) +% +% Add a dump property to CSX with the given name. +% +% possible arguments for useage with openEMS: +% DumpType: 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) +% +% Frequency: specify a frequency vector (required for dump types >=10) +% +% DumpMode: 0 no-interpolation +% 1 node-interpolation (default, see warning below) +% 2 cell-interpolation (see warning below) +% +% FileType: 0 vtk-file dump (default) +% 1 hdf5-file dump +% +% SubSampling: field domain sub-sampling, e.g. '2,2,4' +% OptResolution: field domain dump resolution, e.g. '10' or '10,20,5' +% +% MultiGridLevel: Request to dump from a multigrid level (default is 0) +% Note: This only takes effect if the method supports and +% uses multiple grids! +% +% StartTime/StopTime: Define a start and/or stop time (in seconds) +% for this dump to be active. +% +% Warning: +% 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 +% +% e.g. AddDump(CSX,'Et'); +% CSX = AddBox(CSX,'Et',10,[0 0 0],[100 100 200]); %assign box +% +% or AddDump(CSX,'Ef',DumpType, 10, 'Frequency',[1e9 2e9]); +% CSX = AddBox(CSX,'Ef',10,[0 0 0],[100 100 200]); %assign box +% +% or AddDump(CSX,'Ht','SubSampling','2,2,4','DumpType',1); +% CSX = AddBox(CSX,'Ht',10,[0 0 0],[100 100 200]); %assign box +% +% See also AddMaterial, AddExcitation, AddProbe, AddMetal, AddBox +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +[CSX pos] = AddProperty(CSX, 'DumpBox', name); + +% make Node-Interpolation the default +CSX.Properties.DumpBox{pos}.ATTRIBUTE.DumpMode = 1; + +for n=1:numel(varargin)/2 + if ~ischar(varargin{2*n-1}) + error(['CSXCAD::AddDump: not an attribute: ' varargin{2*n-1}]); + end + if strcmp(varargin{2*n-1},'Frequency') + CSX.Properties.DumpBox{pos}.FD_Samples=varargin{2*n}; + else + CSX.Properties.DumpBox{pos}.ATTRIBUTE.(varargin{2*n-1})=varargin{2*n}; + end +end diff --git a/CSXCAD/matlab/AddExcitation.m b/CSXCAD/matlab/AddExcitation.m new file mode 100644 index 0000000..45a1a2c --- /dev/null +++ b/CSXCAD/matlab/AddExcitation.m @@ -0,0 +1,32 @@ +function CSX = AddExcitation(CSX, name, type, excite, varargin) +% function CSX = AddExcitation(CSX, name, type, excite, varargin) +% +% Creates an E-field or H-field excitation. +% +% CSX: CSX-struct created by InitCSX +% name: property name for the excitation +% type: 0=E-field soft excitation 1=E-field hard excitation +% 2=H-field soft excitation 3=H-field hard excitation +% 10=plane wave excitation +% +% excite: e.g. [2 0 0] for excitation of 2 V/m in x-direction +% +% additional options for openEMS: +% 'Delay' : setup an excitation time delay in seconds +% 'PropDir': direction of plane wave propagation (plane wave excite only) +% +% example: +% CSX = AddExcitation( CSX, 'infDipole', 1, [1 0 0] ); +% start = [-dipole_length/2, 0, 0]; +% stop = [+dipole_length/2, 0, 0]; +% CSX = AddBox( CSX, 'infDipole', 1, start, stop ); +% +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also SetExcitationWeight, AddMetal, AddExcitation, AddProbe, +% AddDump, AddBox + +CSX = AddProperty(CSX, 'Excitation', name, 'Type', type, 'Excite', excite, varargin{:}); diff --git a/CSXCAD/matlab/AddLinPoly.m b/CSXCAD/matlab/AddLinPoly.m new file mode 100644 index 0000000..b93a4ac --- /dev/null +++ b/CSXCAD/matlab/AddLinPoly.m @@ -0,0 +1,41 @@ +function CSX = AddLinPoly( CSX, materialname, prio, normDir, elevation, points, Length, varargin) +% CSX = AddLinPoly( CSX, materialname, prio, normDir, elevation, points, Length, varargin) +% +% CSX: CSX-object created by InitCSX() +% materialname: created by AddMetal() or AddMaterial() +% prio: priority +% normDir: normal direction of the polygon, +% e.g. 'x', 'y' or 'z', or numeric 0..2 +% elevation: position of the polygon plane +% points: two-dimensional coordinates +% length: linear extrution in normal direction, starting at elevation +% +% Warning: Polygon has to be defined using Cartesian Coords +% for use with cylindrical mesh, set 'CoordSystem',0 +% +% example: +% p(1,1) = 0; % x-coord point 1 +% p(2,1) = 0; % y-coord point 1 +% p(1,2) = 10; % x-coord point 2 +% p(2,2) = 20; % y-coord point 2 +% % normal direction: z (2) +% CSX = AddLinPoly( CSX, 'PEC', 1, 2, 254, p , 10, 'CoordSystem',0) +% +% 2011, Thorsten Liebig +% +% See also InitCSX AddMetal AddMaterial AddPolygon AddRotPoly + +polygon.ATTRIBUTE.Priority = prio; +polygon.ATTRIBUTE.Elevation = elevation; +polygon.ATTRIBUTE.Length = Length; +polygon.ATTRIBUTE.NormDir = DirChar2Int(normDir); + +polygon.Vertex = {}; +for s=1:size(points,2) + polygon.Vertex{end+1}.ATTRIBUTE.X1 = points(1,s); + polygon.Vertex{end}.ATTRIBUTE.X2 = points(2,s); +end + +polygon = AddPrimitiveArgs(polygon,varargin{:}); + +CSX = Add2Property( CSX, materialname, polygon, 'LinPoly'); diff --git a/CSXCAD/matlab/AddLorentzMaterial.m b/CSXCAD/matlab/AddLorentzMaterial.m new file mode 100644 index 0000000..b0e9629 --- /dev/null +++ b/CSXCAD/matlab/AddLorentzMaterial.m @@ -0,0 +1,60 @@ +function CSX = AddLorentzMaterial(CSX, name, varargin) +% function CSX = AddLorentzMaterial(CSX, name, varargin) +% +% Add a Drude/Lorentz type dispersive material model. +% Note: openEMS currently only supports a drude material type. +% +% The drude type frequency dependent material: +% eps_r(f) = eps_r* ( 1 - f_eps_plasma^2/(f*(f-j/t_eps_r)) ) +% mue_r(f) = mue_r* ( 1 - f_mue_plasma^2/(f*(f-j/t_mue_r)) ) +% with +% f_eps_plasma: the respective electric angular plasma frequency +% f_mue_plasma: the respective magnetic angular plasma frequency +% t_eps_r: the respective electric relaxation time +% t_mue_r: the respective magnetic relaxation time +% +% Use SetMaterialProperty to define the material constants: +% 'EpsilonPlasmaFrequency': electric plasma frequency (f_eps_plasma) +% 'MuePlasmaFrequency': magnetic plasma frequency (f_mue_plasma) +% 'EpsilonRelaxTime': electric plasma relaxation time (losses) +% 'MueRelaxTime': magnetic plasma relaxation time (losses) +% +% Note: all properties must be positive values +% +% Higher order Drude type: +% 'EpsilonPlasmaFrequency_': n-th order electric plasma frequency (f_eps_plasma) +% 'MuePlasmaFrequency_': n-th order magnetic plasma frequency (f_mue_plasma) +% 'EpsilonRelaxTime_': n-th order electric plasma relaxation time (losses) +% 'MueRelaxTime_': n-th order magnetic plasma relaxation time (losses) +% +% The Lorentz type frequency dependent material: +% eps_r(f) = eps_r* ( 1 - f_eps_plasma^2/(f^2-f_eps_Lor_Pole^2-jf^2*/t_eps_r)) ) +% mue_r(f) = mue_r* ( 1 - f_mue_plasma^2/(f^2-f_mue_Lor_Pole^2-jf^2*/t_mue_r)) ) +% with the additional parameter (see above) +% f_eps_Lor_Pole: the respective electric angular lorentz pole frequency +% f_mue_Lor_Pole: the respective magnetic angular lorentz pole frequency +% +% Use SetMaterialProperty to define the material constants: +% 'EpsilonLorPoleFrequency': electric lorentz pole frequency (f_eps_Lor_Pole) +% 'MueLorPoleFrequency': magnetic lorentz pole frequency (f_mue_Lor_Pole) +% +% Note: all properties must be positive values +% +% Higher order Drude type: +% 'EpsilonLorPoleFrequency_': n-th order electric lorentz pole frequency (f_eps_plasma) +% 'MueLorPoleFrequency_': n-th order magnetic lorentz pole frequency (f_mue_plasma) +% +% example: +% CSX = AddLorentzMaterial(CSX,'drude'); +% CSX = SetMaterialProperty(CSX,'drude','Epsilon',5,'EpsilonPlasmaFrequency',5e9,'EpsilonRelaxTime',1e-9); +% CSX = SetMaterialProperty(CSX,'drude','Mue',5,'MuePlasmaFrequency',5e9,'MueRelaxTime',1e-9); +% [..] +% CSX = AddBox(CSX,'drude', 10 ,start,stop); +% +% See also AddBox, AddMaterial, SetMaterialProperty +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +CSX = AddProperty(CSX, 'LorentzMaterial', name, varargin{:}); diff --git a/CSXCAD/matlab/AddLumpedElement.m b/CSXCAD/matlab/AddLumpedElement.m new file mode 100644 index 0000000..cefa4c7 --- /dev/null +++ b/CSXCAD/matlab/AddLumpedElement.m @@ -0,0 +1,29 @@ +function CSX = AddLumpedElement(CSX, name, direction, varargin) +% function CSX = AddLumpedElement(CSX, name, direction, varargin) +% +% Add a lumped element property to CSX with the given name. +% Remember to add at least one or more box primitive to any +% property. +% +% arguments: +% direction: 0,1,2 or 'x','y','z' for the orientation of the lumped element +% +% optional arguments: +% 'R', 'C', 'L': definition of the lumped element properties +% 'Caps': 0 or 1 to (de)activate lumped element caps (1=default) +% If Caps are enable, a small PEC plate is added to each +% end of the lumped element to ensure contact to e.g +% a microstrip line +% +% examples: +% lumped element capacitor in y-direction with 1pF +% CSX = AddLumpedElement( CSX, 'Capacitor', 1, 'Caps', 1, 'C', 1e-12 ); +% CSX = AddBox( CSX, 'Capacitor', 0, [0 0 0], [10 10 10] ); +% +% See also AddMaterial, AddMetal, AddExcitation, AddProbe, AddDump, AddBox +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +CSX = AddProperty(CSX, 'LumpedElement', name, 'Direction', DirChar2Int(direction), varargin{:}); diff --git a/CSXCAD/matlab/AddMaterial.m b/CSXCAD/matlab/AddMaterial.m new file mode 100644 index 0000000..d21a8c9 --- /dev/null +++ b/CSXCAD/matlab/AddMaterial.m @@ -0,0 +1,26 @@ +function CSX = AddMaterial(CSX, name, varargin) +% function CSX = AddMaterial(CSX, name, varargin) +% +% Add a material property to CSX with the given name. +% Remember to add at least one or more geometrical primitives to any +% property. +% +% Use SetMaterialProperty to define the material constants: +% 'Epsilon': relative electric permitivity +% 'Mue': relative magnetic permeability +% 'Kappa': electric conductivity +% 'Sigma': magnetc conductivity (non-physical property) +% +% examples: +% CSX = AddMaterial( CSX, 'RO3010' ); +% CSX = SetMaterialProperty( CSX, 'RO3010', 'Epsilon', 10.2, 'Mue', 1 ); +% CSX = AddBox( CSX, 'RO3010', 0, [0 0 0], [100 1000 1000] ); +% +% See also SetMaterialProperty, SetMaterialWeight, AddMetal, AddExcitation, +% AddProbe, AddDump, AddBox +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +CSX = AddProperty(CSX, 'Material', name, varargin{:}); diff --git a/CSXCAD/matlab/AddMetal.m b/CSXCAD/matlab/AddMetal.m new file mode 100644 index 0000000..98ce9d1 --- /dev/null +++ b/CSXCAD/matlab/AddMetal.m @@ -0,0 +1,26 @@ +function CSX = AddMetal(CSX, name) +%function CSX = AddMetal(CSX, name) +% +% Add a metal property (PEC) to CSX with the given name. +% Remember to add at least one or more geometrical primitives to any +% property. +% +% example: +% CSX = AddMetal(CSX,'metal'); %create PEC with propName 'metal' +% CSX = AddBox(CSX,'metal',10,[0 0 0],[100 100 200]); %assign box +% +% See also AddMaterial, AddExcitation, AddProbe, AddDump, AddBox +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +% check if this property already exists +[type_found pos] = FindProperty(CSX, name); + +% since it has no varargs, accept already existing metal with this name +if ((pos>0) && strcmp(type_found,'Metal')) + return +end + +CSX = AddProperty(CSX, 'Metal', name); diff --git a/CSXCAD/matlab/AddPlaneWaveExcite.m b/CSXCAD/matlab/AddPlaneWaveExcite.m new file mode 100644 index 0000000..aa59c02 --- /dev/null +++ b/CSXCAD/matlab/AddPlaneWaveExcite.m @@ -0,0 +1,38 @@ +function CSX = AddPlaneWaveExcite(CSX, name, k_dir, E_dir, f0, varargin) +% function CSX = AddPlaneWaveExcite(CSX, name, k_dir, E_dir, ) +% +% Creates a plane wave excitation in the sense of a total-field/scattered +% field approach. +% +% Note: A plane wave excitation must not intersect with any kind of +% material. This exctiation type can only be applies in air/vacuum and +% completely surrounding a structure!!! +% +% Note: Only a single Box can be applied to this property!! +% +% Arguments +% CSX: CSX-struct created by InitCSX +% name: property name for the excitation +% k_dir: unit vector of wave progation direction +% E_dir: electric field polarisation vector (must be orthogonal to k_dir) +% f0: frequency for numerical phase velocity compensation (optional) +% +% example: +% inc_angle = 0 /180*pi; %incident angle on the x-axis +% k_dir = [cos(inc_angle) sin(inc_angle) 0]; % plane wave direction +% E_dir = [0 0 1]; % plane wave polarization --> E_z +% f0 = 500e6; % frequency for numerical phase velocity compensation +% +% CSX = AddPlaneWaveExcite(CSX, 'plane_wave', k_dir, E_dir, f0); +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also AddExcitation, AddBox + +if (nargin<5) + f0 = 0; +end + +CSX = AddExcitation(CSX, name, 10, E_dir, 'PropDir', k_dir, 'Frequency', f0, varargin{:}); diff --git a/CSXCAD/matlab/AddPoint.m b/CSXCAD/matlab/AddPoint.m new file mode 100644 index 0000000..15af7d4 --- /dev/null +++ b/CSXCAD/matlab/AddPoint.m @@ -0,0 +1,14 @@ +function CSX = AddPoint(CSX, propName, prio, pos, varargin) +% CSX = AddPoint(CSX, propName, prio, pos, varargin) +% +% CSXCAD matlab interface + +point.ATTRIBUTE.Priority = prio; + +point.ATTRIBUTE.X=pos(1); +point.ATTRIBUTE.Y=pos(2); +point.ATTRIBUTE.Z=pos(3); + +point = AddPrimitiveArgs(point,varargin{:}); + +CSX = Add2Property(CSX,propName, point, 'Point'); diff --git a/CSXCAD/matlab/AddPolygon.m b/CSXCAD/matlab/AddPolygon.m new file mode 100644 index 0000000..4590248 --- /dev/null +++ b/CSXCAD/matlab/AddPolygon.m @@ -0,0 +1,41 @@ +function CSX = AddPolygon( CSX, materialname, prio, normDir, elevation, points, varargin) +% CSX = AddPolygon( CSX, materialname, prio, normDir, elevation, points, varargin) +% +% CSX: CSX-object created by InitCSX() +% materialname: created by AddMetal() or AddMaterial() +% prio: priority +% normDir: normal direction of the polygon, +% e.g. 'x', 'y' or 'z', or numeric 0..2 +% elevation: position of the polygon plane +% points: two-dimensional coordinates +% +% Warning: Polygon has to be defined using Cartesian Coords +% for use with cylindrical mesh, set 'CoordSystem',0 +% +% example: +% p(1,1) = 0; % x-coord point 1 +% p(2,1) = 0; % y-coord point 1 +% p(1,2) = 10; % x-coord point 2 +% p(2,2) = 20; % y-coord point 2 +% % normal direction: z (2) +% CSX = AddPolygon( CSX, 'PEC', 1, 'z', 254, p, 'CoordSystem',0) +% +% +% (c) 2011 Thorsten Liebig +% (c) 2010 Sebastian Held +% +% See also InitCSX AddMetal AddMaterial AddLinPoly AddRotPoly + +polygon.ATTRIBUTE.Priority = prio; +polygon.ATTRIBUTE.Elevation = elevation; +polygon.ATTRIBUTE.NormDir = DirChar2Int(normDir); + +polygon.Vertex = {}; +for s=1:size(points,2) + polygon.Vertex{end+1}.ATTRIBUTE.X1 = points(1,s); + polygon.Vertex{end}.ATTRIBUTE.X2 = points(2,s); +end + +polygon = AddPrimitiveArgs(polygon,varargin{:}); + +CSX = Add2Property( CSX, materialname, polygon, 'Polygon'); diff --git a/CSXCAD/matlab/AddPolyhedron.m b/CSXCAD/matlab/AddPolyhedron.m new file mode 100644 index 0000000..7da8a86 --- /dev/null +++ b/CSXCAD/matlab/AddPolyhedron.m @@ -0,0 +1,51 @@ +function CSX = AddPolyhedron(CSX, propName, prio, vertices, faces, varargin) +% CSX = AddPolyhedron(CSX, propName, prio, vertices, faces, varargin) +% +% Add a polyhedron to CSX and assign to a property with name . +% +% prio: primitive priority +% vertices: cell array of all vertices +% faces: cell array of all faces +% +% Note: - The polyhedron must be a closed surface for 3D discretisation +% - All faces must contain the vertices in a right-handed order with +% the normal direction for each face pointing out of the solid +% +% optional: +% Transformation: perform a transformation on a primitive by adding +% e.g.: 'Transform', {'Scale','1,1,2','Rotate_X',pi/4,'Translate','0,0,100'} +% Note: This will only affect the 3D material/metal discretisation +% +% example: +% % example tetrahedron +% vertices{1}=[0 0 0]; +% vertices{2}=[1 0 0]; +% vertices{3}=[0 1 0]; +% vertices{4}=[0 0 1]; +% faces{1}=[0 2 1]; +% faces{2}=[0 1 3]; +% faces{3}=[0 3 2]; +% faces{4}=[1 2 3]; +% CSX = AddMetal( CSX, 'metal' ); +% CSX = AddPolyhedron(CSX, 'metal', 0, vertices, faces); +% +% +% See also AddBox, AddCylinder, AddCylindricalShell, AddSphere, AddSphericalShell, +% AddCurve, AddWire, AddMetal +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +polyhedron.ATTRIBUTE.Priority = prio; + +for n=1:numel(vertices) + polyhedron.Vertex{n}=vector2str(vertices{n}); +end +for n=1:numel(faces) + polyhedron.Face{n}=vector2str(faces{n}); +end + +polyhedron = AddPrimitiveArgs(polyhedron,varargin{:}); + +CSX = Add2Property(CSX,propName, polyhedron, 'Polyhedron'); diff --git a/CSXCAD/matlab/AddProbe.m b/CSXCAD/matlab/AddProbe.m new file mode 100644 index 0000000..2a6692e --- /dev/null +++ b/CSXCAD/matlab/AddProbe.m @@ -0,0 +1,79 @@ +function CSX = AddProbe(CSX, name, type, varargin) +% function CSX = AddProbe(CSX, name, type, varargin) +% +% Add a probe property to CSX with the given name. +% Remember to add a geometrical primitive to any property. +% +% name: name of the property and probe file +% +% type: 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 +% +% all following parameter are optional key/value parameter: +% +% weight: weighting factor (default is 1) +% frequency: dump in the frequency domain at the given samples (in Hz) +% ModeFunction: A mode function (used only with type 3/4) +% NormDir: necessary for current probing box with dimension~=2 +% StartTime/StopTime: Define a start and/or stop time (in seconds) +% for this probe to be active. + +% examples: +% CSX = AddProbe(CSX,'ut1',0); %voltate probe +% CSX = AddProbe(CSX,'it1',1); %current probe +% +% See also ReadUI in the openEMS matlab interface, AddDump, +% AddExcitation, AddMaterial, AddExcitation, AddProbe, AddBox +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +FD_samples = []; +ModeFunction = {}; + +if ~ischar(name) + error('CSXCAD::AddProbe: name must be a string'); +end + +prop_args = {'Type', type}; + +for n=1:2:numel(varargin) + if (strcmpi(varargin{n},'weight')==1); + prop_args{end+1} = 'Weight'; + prop_args{end+1} = varargin{n+1}; + elseif (strcmpi(varargin{n},'Frequency')==1); + FD_samples = varargin{n+1}; + elseif (strcmpi(varargin{n},'ModeFunction')==1); + ModeFunction = varargin{n+1}; + elseif (strcmpi(varargin{n},'NormDir')==1); + prop_args{end+1} = 'NormDir'; + prop_args{end+1} = varargin{n+1}; + elseif (strcmpi(varargin{n},'StartTime')==1); + prop_args{end+1} = 'StartTime'; + prop_args{end+1} = varargin{n+1}; + elseif (strcmpi(varargin{n},'StopTime')==1); + prop_args{end+1} = 'StopTime'; + prop_args{end+1} = varargin{n+1}; + else + warning('CSXCAD:AddProbe',['variable argument key: "' varargin{n+1} '" unknown']); + end +end + +[CSX pos] = AddProperty(CSX, 'ProbeBox', name, prop_args{:}); + +if (numel(FD_samples)>0) + CSX.Properties.ProbeBox{pos}.FD_Samples=FD_samples; +end + +if (numel(ModeFunction)>0) + CSX.Properties.ProbeBox{pos}.Attributes.ATTRIBUTE.ModeFunctionX = ModeFunction{1}; + CSX.Properties.ProbeBox{pos}.Attributes.ATTRIBUTE.ModeFunctionY = ModeFunction{2}; + CSX.Properties.ProbeBox{pos}.Attributes.ATTRIBUTE.ModeFunctionZ = ModeFunction{3}; +end + diff --git a/CSXCAD/matlab/AddPropAttribute.m b/CSXCAD/matlab/AddPropAttribute.m new file mode 100644 index 0000000..05408f9 --- /dev/null +++ b/CSXCAD/matlab/AddPropAttribute.m @@ -0,0 +1,24 @@ +function CSX = AddPropAttribute(CSX, name, att_name, att_value) +% CSX = AddPropAttribute(CSX, name, att_name, att_value) +% +% Add a given attribute (name and value) to the given property +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (c) 2013 + +type = GetPropertyType(CSX, name); + +pos=0; +for n=1:numel(CSX.Properties.(type)) + if strcmp(CSX.Properties.(type){n}.ATTRIBUTE.Name, name) + pos=n; + end +end + +if (pos==0) + error('CSXCAD::AddPropAttribute: property not found'); + return; +end + +CSX.Properties.(type){pos}.Attributes.ATTRIBUTE.(att_name) = att_value; diff --git a/CSXCAD/matlab/AddRotPoly.m b/CSXCAD/matlab/AddRotPoly.m new file mode 100644 index 0000000..e694e98 --- /dev/null +++ b/CSXCAD/matlab/AddRotPoly.m @@ -0,0 +1,48 @@ +function CSX = AddRotPoly( CSX, materialname, prio, normDir, points, RotAxisDir, angle, varargin) +% function CSX = AddRotPoly( CSX, materialname, prio, normDir, points, RotAxisDir, angle, varargin) +% +% CSX: CSX-object created by InitCSX() +% materialname: created by AddMetal() or AddMaterial() +% prio: priority +% normDir: normal direction of the polygon, +% e.g. 'x', 'y' or 'z', or numeric 0..2 +% points: two-dimensional coordinates +% RotAxisDir: direction of the rotational axis +% e.g. 'x', 'y' or 'z', or numeric 0..2 +% angle (optional): rotational start/stop angle, default is [0 2pi] +% +% Warning: Polygon has to be defined using Cartesian Coords +% for use with cylindrical mesh, set 'CoordSystem',0 +% +% example: +% p(1,1) = 0; % x-coord point 1 +% p(2,1) = 0; % y-coord point 1 +% p(1,2) = 10; % x-coord point 2 +% p(2,2) = 20; % y-coord point 2 +% % normal direction: z +% CSX = AddRotPoly( CSX, 'PEC', 1, 'z', p , 'y'); +% +% 2011, Thorsten Liebig +% +% See also InitCSX AddMetal AddMaterial AddPolygon + +if (nargin<7) + angle = [0 2*pi]; +end + +polygon.ATTRIBUTE.Priority = prio; +polygon.ATTRIBUTE.NormDir = DirChar2Int(normDir); +polygon.ATTRIBUTE.RotAxisDir = DirChar2Int(RotAxisDir); + +polygon.Angles.ATTRIBUTE.Start = angle(1); +polygon.Angles.ATTRIBUTE.Stop = angle(2); + +polygon.Vertex = {}; +for s=1:size(points,2) + polygon.Vertex{end+1}.ATTRIBUTE.X1 = points(1,s); + polygon.Vertex{end}.ATTRIBUTE.X2 = points(2,s); +end + +polygon = AddPrimitiveArgs(polygon,varargin{:}); + +CSX = Add2Property( CSX, materialname, polygon, 'RotPoly'); diff --git a/CSXCAD/matlab/AddSphere.m b/CSXCAD/matlab/AddSphere.m new file mode 100644 index 0000000..457142f --- /dev/null +++ b/CSXCAD/matlab/AddSphere.m @@ -0,0 +1,30 @@ +function CSX = AddSphere(CSX, propName, prio, center, rad, varargin) +% function CSX = AddSphere(CSX, propName, prio, center, rad, varargin) +% +% Add a sphere to CSX and assign to a property with name . +% +% center: sphere center coordinates +% rad : sphere radius +% prio : primitive priority +% +% example: +% CSX = AddMetal(CSX,'metal'); %create PEC with propName 'metal' +% CSX = AddSphere(CSX,'metal',10,[0 0 0],50); +% +% See also AddBox, AddCylindricalShell, AddCylinder, AddSphericalShell, +% AddCurve, AddWire, AddMetal +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +sphere.ATTRIBUTE.Priority = prio; +sphere.ATTRIBUTE.Radius = rad; + +sphere.Center.ATTRIBUTE.X=center(1); +sphere.Center.ATTRIBUTE.Y=center(2); +sphere.Center.ATTRIBUTE.Z=center(3); + +sphere = AddPrimitiveArgs(sphere,varargin{:}); + +CSX = Add2Property(CSX,propName, sphere, 'Sphere'); \ No newline at end of file diff --git a/CSXCAD/matlab/AddSphericalShell.m b/CSXCAD/matlab/AddSphericalShell.m new file mode 100644 index 0000000..3e76cef --- /dev/null +++ b/CSXCAD/matlab/AddSphericalShell.m @@ -0,0 +1,36 @@ +function CSX = AddSphericalShell(CSX, propName, prio, center, rad, shell_width, varargin) +% function CSX = AddSphericalShell(CSX, propName, prio, center, rad, shell_width, varargin) +% +% Add a sphere shell to CSX and assign to a property with name . +% +% center: sphere center coordinates +% rad : sphere radius +% shell_width: sphere shell width +% prio : primitive priority +% +% Note: +% the inner radius of this shell is rad-shell_width/2 +% the outer radius of this shell is rad+shell_width/2 +% +% example: +% CSX = AddMetal(CSX,'metal'); %create PEC with propName 'metal' +% CSX = AddSphericalShell(CSX,'metal',10,[0 0 0],50,10); +% +% See also AddBox, AddCylindricalShell, AddCylinder, AddSphere, +% AddCurve, AddWire, AddMetal +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +sphere.ATTRIBUTE.Priority = prio; +sphere.ATTRIBUTE.Radius = rad; +sphere.ATTRIBUTE.ShellWidth = shell_width; + +sphere.Center.ATTRIBUTE.X=center(1); +sphere.Center.ATTRIBUTE.Y=center(2); +sphere.Center.ATTRIBUTE.Z=center(3); + +sphere = AddPrimitiveArgs(sphere,varargin{:}); + +CSX = Add2Property(CSX,propName, sphere, 'SphericalShell'); \ No newline at end of file diff --git a/CSXCAD/matlab/AddWire.m b/CSXCAD/matlab/AddWire.m new file mode 100644 index 0000000..f90843c --- /dev/null +++ b/CSXCAD/matlab/AddWire.m @@ -0,0 +1,46 @@ +function CSX = AddWire(CSX, propName, prio, points, wire_rad, varargin) +% function CSX = AddWire(CSX, propName, prio, points, wire_rad, varargin) +% +% Add a wire to CSX and assign to a property with name . +% +% Warning: This is a 1D object, not all properties may be compatible with a +% 1D object, e.g. a material property. +% +% points: curve coordinates array +% prio : primitive priority +% wire_rad: wire radius +% +% example: +% %first point +% points(1,1) = 0; +% points(2,1) = 5; +% points(3,1) = 10; +% %second point +% points(1,2) = 0; +% points(2,2) = 10; +% points(3,2) = 10; +% %third point ... +% % create a metal wire with finite radius... +% CSX = AddMetal(CSX,'metal'); %create PEC with propName 'metal' +% CSX = AddCurve(CSX,'metal',10, points, 2); +% +% See also AddBox, AddCylindricalShell, AddCylinder, AddSphere, +% AddSphericalShell, AddCurve, AddMetal +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +wire.ATTRIBUTE.Priority = prio; +wire.ATTRIBUTE.WireRadius = wire_rad; + +wire.Vertex={}; +for s=1:size(points,2) + wire.Vertex{end+1}.ATTRIBUTE.X = points(1,s); + wire.Vertex{end}.ATTRIBUTE.Y = points(2,s); + wire.Vertex{end}.ATTRIBUTE.Z = points(3,s); +end + +wire = AddPrimitiveArgs(wire,varargin{:}); + +CSX = Add2Property(CSX,propName, wire, 'Wire'); \ No newline at end of file diff --git a/CSXCAD/matlab/AnalyseMesh.m b/CSXCAD/matlab/AnalyseMesh.m new file mode 100644 index 0000000..93295c3 --- /dev/null +++ b/CSXCAD/matlab/AnalyseMesh.m @@ -0,0 +1,42 @@ +function results = AnalyseMesh(lines) +% function results = AnalyseMesh(lines) +% +% Analyse a given mesh line vector +% +% output structure: +% results.numLines: number of lines +% results.max_res: max. resolution found +% results.min_res: min. resolution found +% results.max_ratio: max. grading ratio found +% results.homogeneous: true/false for homogeneous mesh +% results.symmetric: true/false for symmetric mesh +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (C) 2012 + +results = []; + +lines = sort(unique(lines)); + +if (numel(lines)<=1) + warning('CSXCAD:AnalyseMesh', 'more than one line needed to analyse mesh'); +end + +diff_lines = diff(lines); + +results.numLines = numel(lines); + +results.max_res = max(diff_lines); +results.min_res = min(diff_lines); +if (results.max_res==results.min_res) + results.homogeneous = 1; +else + results.homogeneous = 0; +end + +results.symmetric = CheckSymmtricLines(lines); + +ratio_lines = diff_lines(1:end-1)./diff_lines(2:end); + +results.max_ratio = max([ratio_lines 1./ratio_lines]); diff --git a/CSXCAD/matlab/AutoSmoothMeshLines.m b/CSXCAD/matlab/AutoSmoothMeshLines.m new file mode 100644 index 0000000..e41e261 --- /dev/null +++ b/CSXCAD/matlab/AutoSmoothMeshLines.m @@ -0,0 +1,159 @@ +function [lines quality] = AutoSmoothMeshLines( lines, max_res, ratio, varargin) +% function [lines quality] = AutoSmoothMeshLines( lines, max_res, ratio, varargin) +% +% Generate smooth mesh lines by choosing an appropriate algorithm. +% +% Currently supported algorithm: +% SmoothMeshLines, SmoothMeshLines2 and RecursiveSmoothMesh +% +% arguments: +% lines: given fixed lines to create a smooth mesh in between +% max_res: desired max. resolution +% ratio: grading ratio: desired neighboring line-delta ratio +% - default is 1.5 +% - see also 'allowed_max_ratio' argument +% +% variable arguments ('keyword',value): +% algorithm: define subset of tried algorihm, e.g. [1 3] +% symmetric: 0/1 force symmetric mesh (default is input symmetry) +% homogeneous: 0/1 force homogeneous mesh +% allowed_min_res: allow a given min resolution only +% allowed_max_ratio: allow only a given max. grading ratio +% (default --> ratio*1.25) +% debug: 0/1 off/on +% +% example: +% lines = AutoSmoothMeshLines([-100 -10 10 100], 20, 1.5, 'algorihm', ... +% 1:3); +% +% See also InitCSX, DefineRectGrid +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (C) 2012 + +if (nargin<2) + error('CSXCAD:AutoSmoothMeshLines','lines and max_res are a required parameter'); +end + +if (nargin<3) + ratio = 1.5; +end + +lines = sort(unique(lines)); + +range = lines(end)-lines(1); +if (~isempty(find(diff(lines)0) + disp(['AutoSmoothMeshLines: trying method: ' func2str(methods{m})]); + tic + end + out_lines{m} = methods{m}(lines, max_res, ratio, 'CheckMesh', false); + if (debug>0) + toc + end + quality(m) = eval_mesh(out_lines{m}, max_res, max_ratio, requires_homogen, requires_symmetric, allowed_min_res, 1); + if (quality(m)==100) % uncomment to release! + lines = out_lines{m}; + if (debug>0) + disp(['AutoSmoothMeshLines: The winner with 100% is ' func2str(methods{m})]); % remove to release + end + return + end +end +winner = find(quality==max(quality),1); +lines = out_lines{winner}; +if (debug>0) + disp(['New_SmoothMeshLines: The winner with ' num2str(quality(winner)) '% is ' func2str(methods{winner})]); % remove to release +end + +% show mesh problems +eval_mesh(lines, max_res, ratio, requires_homogen, requires_symmetric, allowed_min_res, 0); +return + +error('CSXCAD:AutoSmoothMeshLines',['unknown algorithm requested: ' algorithm ]); + +end + +function quality = eval_mesh(lines, max_res, ratio, requires_homogen, requires_symmetric, allowed_min_res, silent) + +quality = 100; + +results = AnalyseMesh(lines); +if ((requires_homogen==1) && (results.homogeneous~=1)) + if (silent==0) + warning('CSXCAD:AutoSmoothMeshLines','method failed to create homogenous mesh'); + end + quality = -1; + return +end +if ((requires_symmetric==1) && (results.symmetric~=1)) + if (silent==0) + warning('CSXCAD:AutoSmoothMeshLines','method failed to create symmetric mesh'); + end + quality = -1; + return +end + +if ((allowed_min_res>0) && (results.min_resmax_res*1.01) + if (silent==0) + warning('CSXCAD:AutoSmoothMeshLines',['method failed to fulfill max. res: ' num2str(results.max_res) ' > ' num2str(max_res)]); + end + quality = quality*(max_res/results.max_res); +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)]'); + end + quality = quality*(ratio/results.max_ratio); +end +end \ No newline at end of file diff --git a/CSXCAD/matlab/CSXGeomPlot.m b/CSXCAD/matlab/CSXGeomPlot.m new file mode 100644 index 0000000..df33c94 --- /dev/null +++ b/CSXCAD/matlab/CSXGeomPlot.m @@ -0,0 +1,43 @@ +function CSXGeomPlot(CSX_filename, args_string) +% function CSXGeomPlot(CSX_filename<, args_string>) +% +% Show the geometry stored in the CSX file using AppCSXCAD +% +% Optional AppCSXCAD arguments (args_string): +% '--RenderDiscMaterial', enable material rendering +% +% exports: +% '--export-polydata-vtk=' +% '--export-STL=' +% +% See also InitCSX, DefineRectGrid +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +if nargin < 1 + error 'specify the xml file to open' +end + +if nargin < 2 + args_string = ''; +end + +filename = mfilename('fullpath'); +dir = fileparts( filename ); + +if isunix + AppCSXCAD_bin = searchBinary('AppCSXCAD.sh', ... + {[dir filesep '..' filesep '..' filesep 'AppCSXCAD' filesep], ... + [dir filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}); +else % assume windows + AppCSXCAD_bin = searchBinary('AppCSXCAD.exe',[dir filesep '..' filesep]); +end + +command = [AppCSXCAD_bin ' --disableEdit ' args_string ' ' CSX_filename]; +disp( ['invoking AppCSXCAD, exit to continue script...'] ); +if isOctave() + fflush(stdout); +end +system(command); diff --git a/CSXCAD/matlab/CalcDebyeMaterial.m b/CSXCAD/matlab/CalcDebyeMaterial.m new file mode 100644 index 0000000..a4a3a5e --- /dev/null +++ b/CSXCAD/matlab/CalcDebyeMaterial.m @@ -0,0 +1,29 @@ +function eps_debye = CalcDebyeMaterial(f, eps_r, kappa, eps_Delta, t_relax) +% eps_debye = CalcDebyeMaterial(f, eps_r, kappa, eps_Delta, t_relax) +% +% Calculate the Debye type dispersive material constant +% +% arguments: +% f: frequeny range of interest +% eps_r: eps_r infinity +% kappa: conductivity (losses) +% eps_Delta: (vector) delta of relative permitivity +% t_relax: (vector) relaxation time (losses) +% +% return: +% eps_debye: the complex relative permitivity +% +% See also: CalcLorentzMaterial +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (2013) + +EPS0 = 8.85418781762e-12; +eps_debye = ones(size(f))*eps_r - 1j*kappa./(2*pi*f)/EPS0; + +for n=1:numel(eps_Delta) + eps_debye = eps_debye + eps_Delta(n)./(1+2j*pi*f*t_relax(n)); +end + +end diff --git a/CSXCAD/matlab/CalcDrudeMaterial.m b/CSXCAD/matlab/CalcDrudeMaterial.m new file mode 100644 index 0000000..9901566 --- /dev/null +++ b/CSXCAD/matlab/CalcDrudeMaterial.m @@ -0,0 +1,37 @@ +function eps_drude = CalcDrudeMaterial(f, eps_r, kappa, plasmaFreq, t_relax) +% eps_drude = CalcDrudeMaterial(f, eps_r, kappa, plasmaFreq, t_relax) +% +% Calculate the Drude type dispersive material constant +% +% arguments: +% f: frequeny range of interest +% eps_r: eps_r infinity +% kappa: conductivity (losses) +% plasmaFreq: (vector) plasma frequencies +% t_relax: (vector) relaxation time (losses) +% +% return: +% eps_drude: the complex relative permitivity +% +% Example: +% % silver (AG) at optical frequencies (Drude model) [1, p. 201] +% f = linspace(300e12, 1100e12, 201); +% eps_model = CalcDrudeMaterial(f, 3.942, 7.97e3, 7e15/2/pi, 0, 1/2.3e13); +% +% figure +% plot(f,real(eps_model)) +% hold on; +% grid on; +% plot(f,imag(eps_model),'r--') +% +% See also: CalcDebyeMaterial, CalcLorentzMaterial +% +% [1] Rennings, Andre: "Elektromagnetische Zeitbereichssimulationen +% innovativer Antennen auf Basis von Metamaterialien." +% PhD Thesis, University of Duisburg-Essen, September 2008 +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (2013) + +eps_drude = CalcLorentzMaterial(f, eps_r, kappa, plasmaFreq, plasmaFreq*0, t_relax); diff --git a/CSXCAD/matlab/CalcLorentzMaterial.m b/CSXCAD/matlab/CalcLorentzMaterial.m new file mode 100644 index 0000000..2785747 --- /dev/null +++ b/CSXCAD/matlab/CalcLorentzMaterial.m @@ -0,0 +1,61 @@ +function eps_lorentz = CalcLorentzMaterial(f, eps_r, kappa, plasmaFreq, LorPoleFreq, t_relax) +% eps_lorentz = CalcLorentzMaterial(f, eps_r, kappa, plasmaFreq, LorPoleFreq, t_relax) +% +% Calculate the Lorentz type dispersive material constant +% +% arguments: +% f: frequeny range of interest +% eps_r: eps_r infinity +% kappa: conductivity (losses) +% plasmaFreq: (vector) plasma frequencies (Drude model) +% LorPoleFreq: (vector) Lorentz pole frequencies (zero for pure Drude model) +% t_relax: (vector) relaxation time (losses) +% +% return: +% eps_lorentz: the complex relative permitivity +% +% Example: +% % silver (AG) at optical frequencies (Drude model) [1, p. 201] +% f = linspace(300e12, 1100e12, 201); +% eps_model = CalcLorentzMaterial(f, 3.942, 7.97e3, 7e15/2/pi, 0, 1/2.3e13); +% +% figure +% plot(f,real(eps_model)) +% hold on; +% grid on; +% plot(f,imag(eps_model),'r--') +% +% % silver (AG) at optical frequencies (Drude+Lorentz model) [1, p. 201] +% f = linspace(300e12, 1100e12, 201); +% eps_model = CalcLorentzMaterial(f, 1.138, 4.04e3, [13e15 9.61e15]/2/pi, [0 7.5e15]/2/pi,[1/2.59e13 1/3e14]); +% +% figure +% plot(f,real(eps_model)) +% hold on; +% grid on; +% plot(f,imag(eps_model),'r--') +% +% See also: CalcDebyeMaterial +% +% [1] Rennings, Andre: "Elektromagnetische Zeitbereichssimulationen +% innovativer Antennen auf Basis von Metamaterialien." +% PhD Thesis, University of Duisburg-Essen, September 2008 +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (2013) + +EPS0 = 8.85418781762e-12; +eps_lorentz = ones(size(f))*eps_r - 1j*kappa./(2*pi*f)/EPS0; + +w = 2*pi*f; +for n=1:numel(plasmaFreq) + if (t_relax(n)>0) + w_r = 1/t_relax(n); + else + w_r = 0; + end + eps_lorentz = eps_lorentz - eps_r*(2*pi*plasmaFreq(n))^2./(w.^2 - (2*pi*LorPoleFreq(n))^2 - 2j*pi*f*w_r); +end + +end diff --git a/CSXCAD/matlab/CheckMesh.m b/CSXCAD/matlab/CheckMesh.m new file mode 100644 index 0000000..68cac0b --- /dev/null +++ b/CSXCAD/matlab/CheckMesh.m @@ -0,0 +1,65 @@ +function [EC pos E_type] = CheckMesh(lines, min_res, max_res, ratio, be_quiet) +% function [EC pos E_type] = CheckMesh(lines, min_res, max_res, ratio, be_quiet) +% +% Check if mesh lines are valid +% +% parameter: +% min_res: minimal allowed mesh-diff +% max_res: maximal allowed mesh-diff +% ratio: maximal allowed mesh-diff ratio +% be_quiet: disable warnings +% +% return: +% EC: error code (number of found errors) +% pos: line positions with error +% E_type: error type +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +if (nargin<5) + be_quiet = 0; +end + +diff_lines = diff(lines); +EC = 0; +E_type = []; + +pos = []; +max_err = find(diff_lines>max_res); +if (~isempty(max_err) && ~be_quiet) + warning('CSXCAD:CheckMesh','found resolution larger than max_res'); + pos = [pos max_err]; + EC = EC + numel(max_err); + E_type = [E_type 1]; +end + +min_err = find(diff_lines ratio*1.01) + str = ['lines: ' num2str(n) '@' num2str(lines(n)) ' ' num2str(n+1) '@' num2str(lines(n+1)) ' ' num2str(n+2) '@' num2str(lines(n+2))]; + if (~be_quiet) + warning('CSXCAD:CheckMesh', [str '\nfound resolution increase larger than ratio: ' num2str(diff_lines(n+1)/diff_lines(n)) ' > ' num2str(ratio) ]); + end + pos = [pos n+1]; + EC = EC + 1; + E_type = [E_type 3]; + end + if (diff_lines(n+1)/diff_lines(n) < 1/ratio/1.01) + str = ['lines: ' num2str(n) '@' num2str(lines(n)) ' ' num2str(n+1) '@' num2str(lines(n+1)) ' ' num2str(n+2) '@' num2str(lines(n+2))]; + if (~be_quiet) + warning('CSXCAD:SmoothRange', [str '\nfound resolution decrease smaller than ratio: ' num2str(diff_lines(n+1)/diff_lines(n)) ' < 1/' num2str(ratio) '=' num2str(1/ratio) ]); + end + pos = [pos n]; + EC = EC + 1; + E_type = [E_type 4]; + end +end diff --git a/CSXCAD/matlab/Convert_VF_DiscMaterial.m b/CSXCAD/matlab/Convert_VF_DiscMaterial.m new file mode 100644 index 0000000..5d78451 --- /dev/null +++ b/CSXCAD/matlab/Convert_VF_DiscMaterial.m @@ -0,0 +1,255 @@ +function Convert_VF_DiscMaterial(raw_filesuffix, mat_db_file, out_filename, varargin) +% function Convert_VF_DiscMaterial(raw_filesuffix, mat_db_file, out_filename, varargin) +% +% function to convert the virtual family raw voxel data to a disc material +% property required by CSXCAD/openEMS +% +% Note: The conversion is (currently) done, converting the broad-band data +% into a relative permittivity and conductivity for a given frequency of +% interest. Thus the converted model is only valid within a small frequency +% range around the used conversion frequency. +% +% required arguments: +% raw_filesuffix: suffix for the virtual family body model files +% the files: +% .txt and .raw +% must be found! +% example: '/tmp/Ella_26y_V2_1mm' +% mat_db_file: tissue database file (incl. full path if necessary) +% example: '/tmp/DB_h5_20120711_SEMCADv14.8.h5' +% out_filename: outfile name, e.g. 'Ella_298MHz.h5' +% +% variable arguments (key/value): +% 'Frequency': specifiy the frequency of interest (required!) +% 'Center': 0/1 make the model centered around (0,0,0) +% (default is off) +% +% Requirements: +% - Matlab, Octave is currently not supported due to missing hdf5 write +% functions +% - ~6GB of RAM to convert the largest voxel model +% - Virtual Family voxel models +% e.g. Duke_34y_V5_1mm.raw and .txt +% See http://www.itis.ethz.ch/itis-for-health/virtual-population/overview/ +% - Virtual Family tissue database +% e.g. DB_h5_20120711_SEMCADv14.8.h5 +% Download from: http://www.itis.ethz.ch/assets/Downloads/TissueDb/DBh5_20120711_SEMCADv14.8.zip +% +% example: +% Convert_VF_DiscMaterial('/tmp/Ella_26y_V2_1mm', ... +% '/tmp/DB_h5_20120711_SEMCADv14.8.h5', ... +% 'Ella_centered_298MHz.h5', ... +% 'Frequency', 2.4e9); +% +% (c) 2013 Thorsten Liebig + +if exist(out_filename,'file') + disp(['requested model file: "' out_filename '" already exists, skipping']); + return +end + +%% default settings +center_Model = 0; % make the model centered around (0,0,0) +freq = nan; % frequency of interest +range = {[],[],[]}; + +% internal +range_used = 0; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'Frequency')) + freq = varargin{n+1}; + elseif (strcmp(varargin{n},'Center')) + center_Model = varargin{n+1}; + elseif (strcmp(varargin{n},'Range')) + range = varargin{n+1}; + range_used = 1; + else + warning('CSXCAD:Convert_VF_DiscMaterial',['unknown argument: ' varagin{n}]); + end +end + +if (isnan(freq)) + error('CSXCAD:Convert_VF_DiscMaterial','a frequency of interest must be specified'); +end + +%% end of settings (do not edit below) +physical_constants +w = 2*pi*freq; + +%% +disp(['reading raw body specs: ' raw_filesuffix '.txt']); +fid = fopen([raw_filesuffix '.txt']); +material_list = textscan(fid,'%d %f %f %f %s'); + +frewind(fid) +feof(fid); +while ~feof(fid) + line = fgetl(fid); + if strcmp(line,'Grid extent (number of cells)') + n_cells = textscan(fid,'n%c %f'); + end + if strcmp(line,'Spatial steps [m]') + d_cells = textscan(fid,'d%c %f'); + end +end + +fclose(fid); + +nx = n_cells{2}(1); +ny = n_cells{2}(2); +nz = n_cells{2}(3); + +disp(['body model contains ' num2str(nx*ny*nz) ' voxels']); + +dx = d_cells{2}(1); +dy = d_cells{2}(2); +dz = d_cells{2}(3); + +% +x = (0:nx)*dx; +y = (0:ny)*dy; +z = (0:nz)*dz; + +if (center_Model>0) + disp('centering model...'); + x = x - x(1) - (max(x)-min(x))/2; + y = y - y(1) - (max(y)-min(y))/2; + z = z - z(1) - (max(z)-min(z))/2; +end + +disp('Body model mesh range (original):'); +disp(['x: ' num2str(x(1)) ' --> ' num2str(x(end)) ', width: ' num2str(max(x)-min(x))]); +disp(['y: ' num2str(y(1)) ' --> ' num2str(y(end)) ', width: ' num2str(max(y)-min(y))]); +disp(['z: ' num2str(z(1)) ' --> ' num2str(z(end)) ', width: ' num2str(max(z)-min(z))]); + +%% map to range +if (isempty(range{1})) + x_idx = 1:nx; +else + x_idx = find(x>=range{1}(1) & x<=range{1}(2)); +end + +if (isempty(range{2})) + y_idx = 1:ny; +else + y_idx = find(y>=range{2}(1) & y<=range{2}(2)); +end + +if (isempty(range{3})) + z_idx = 1:nz; +else + z_idx = find(z>=range{3}(1) & z<=range{3}(2)); +end + +tic +disp(['reading raw body data: ' raw_filesuffix '.raw']); +fid = fopen([raw_filesuffix '.raw']); + +skip=(z(z_idx(1))-z(1))/dz*nx*ny; +fseek(fid,skip,'bof'); + +% read in line by line to save memory +for n=1:length(z_idx) + data_plane = reshape(fread(fid,nx*ny),nx,ny); + mat(1:numel(x_idx),1:numel(y_idx),n) = uint8(data_plane(x_idx,y_idx)); +end +fclose(fid); + +% resize to range +x = x(x_idx);x=[x x(end)+dx]; +y = y(y_idx);y=[y y(end)+dx]; +z = z(z_idx);z=[z z(end)+dx]; + +if (range_used) + disp('Body model mesh range (new):'); + disp(['x: ' num2str(x(1)) ' --> ' num2str(x(end)) ', width: ' num2str(max(x)-min(x))]); + disp(['y: ' num2str(y(1)) ' --> ' num2str(y(end)) ', width: ' num2str(max(y)-min(y))]); + disp(['z: ' num2str(z(1)) ' --> ' num2str(z(end)) ', width: ' num2str(max(z)-min(z))]); +end + +nx = numel(x_idx); +ny = numel(y_idx); +nz = numel(z_idx); + +mesh.x=x; +mesh.y=y; +mesh.z=z; + +toc + +%% +disp(['reading/analysing material database: ' mat_db_file]); + +mat_db_info = h5info(mat_db_file); + +%% +% there is no material in the list for number 0 +mat_db.epsR(1) = 1; +mat_db.kappa(1) = 0; +mat_db.density(1) = 0; +mat_db.Name{1} = 'Background'; + +for n=1:numel(material_list{end}) + mat_para = GetColeData(mat_db_info, material_list{end}{n}); + eps_colo_cole = mat_para.ef + mat_para.sig/(1j*w*EPS0); + if (mat_para.del1>0) + eps_colo_cole = eps_colo_cole + mat_para.del1/(1 + (1j*w*mat_para.tau1*1e-12)^(1-mat_para.alf1)); + end + if (mat_para.del2>0) + eps_colo_cole = eps_colo_cole + mat_para.del2/(1 + (1j*w*mat_para.tau2*1e-9)^(1-mat_para.alf2)); + end + if (mat_para.del3>0) + eps_colo_cole = eps_colo_cole + mat_para.del3/(1 + (1j*w*mat_para.tau3*1e-6)^(1-mat_para.alf3)); + end + if (mat_para.del4>0) + eps_colo_cole = eps_colo_cole + mat_para.del4/(1 + (1j*w*mat_para.tau4*1e-3)^(1-mat_para.alf4)); + end + mat_db.epsR(n+1) = real(eps_colo_cole); + mat_db.kappa(n+1) = -1*imag(eps_colo_cole)*w*EPS0; + mat_db.density(n+1) = mat_para.Dens; + mat_db.Name{n+1} = mat_para.Name; +end +toc +%% + +disp(['Creating DiscMaterial file: ' out_filename]); +CreateDiscMaterial(out_filename, mat, mat_db, mesh) +toc + +disp('done..'); + +end + +function [mat_para] = GetColeData(mat_db, mat_name) + +% search for mat_name in all "AlternNames" + +N_grp = numel(mat_db.Groups(1).Groups); + +mat_name = regexp(mat_name, '/','split'); +mat_name = mat_name{end}; + +for n=1:N_grp + found = false; + name = regexp(mat_db.Groups(1).Groups(n).Name, '/','split'); + alt_names = [name(end) regexp(mat_db.Groups(1).Groups(n).Attributes(end).Value, '/','split')]; + + alt_names = regexprep(alt_names,' ','_'); + + if (sum(strcmpi(alt_names, mat_name))>0) + % we found it, break + found = true; + break; + end +end + +if (found==false) + error(['property "' mat_name '" not found']); +end + +for a = 1:numel(mat_db.Groups(1).Groups(n).Attributes) + mat_para.(mat_db.Groups(1).Groups(n).Attributes(a).Name) = mat_db.Groups(1).Groups(n).Attributes(a).Value; +end + +end diff --git a/CSXCAD/matlab/CreateDiscMaterial.m b/CSXCAD/matlab/CreateDiscMaterial.m new file mode 100644 index 0000000..f874230 --- /dev/null +++ b/CSXCAD/matlab/CreateDiscMaterial.m @@ -0,0 +1,83 @@ +function CreateDiscMaterial(filename, data, mat_db, mesh) +% function CreateDiscMaterial(filename, data, mat_db, mesh) +% +% Create the discrete material hdf5 file (version 2) usable by AddDiscMaterial +% +% Note: This function currently requires Matlab. Octave is missing the +% necessary hdf5 write functions. +% +% arguments: +% filename: hdf5 file to create (must not exist) +% data: voxel based index data, index as used in mat_db-1 +% mat_db: material database +% mesh: used voxel mesh. Note size is size(data)+[1 1 1] +% +% example: +% mat_db.epsR = [1 3 4]; %relative permittivity +% mat_db.kappa = [0 0.2 0.4]; %electric conductivity (S/m) +% mat_db.density = [0 1000 1010]; %material density (kg/m³) +% mat_db.Name = {'Background','mat2','mat3'}; +% +% data = [0 1 0; 2 1 2; 0 1 0]; % 3x3x3 data +% mesh.x = [0 0.1 0.2 0.3]; % 4 mesh lines in x-dir (3 cells) +% mesh.y = [-0.1 0 0.1 0.2]; % 4 mesh lines in y-dir (3 cells) +% mesh.z = [0 0.4 0.8 1.2]; % 4 mesh lines in z-dir (3 cells) +% +% CreateDiscMaterial('test_mat.h5', data, mat_db, mesh); +% +% See also AddDiscMaterial +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (2013) + +if isOctave + error('CreateDiscMaterial currently does not support Octave, due to missing hdf5 functions!'); +end + +if (exist('h5create')==0) + error('CSXCAD:CreateDiscMaterial','Your matlab seems to be too old, h5create cannot be found!'); +end + +data_size = size(data); +mesh_size = [numel(mesh.x) numel(mesh.y) numel(mesh.z)]; + +if ((mesh_size-1)~=data_size) + error('data size and mesh size mismatch'); +end + +if (exist(filename,'file')) + error(['file "' filename '" already exist. Delete/rename first!']); +end + +h5create(filename, '/DiscData',data_size, 'Datatype', 'uint8', 'ChunkSize',data_size, 'Deflate',9); +h5write(filename, '/DiscData', data); + +clear data; + +h5writeatt(filename, '/DiscData', 'DB_Size', int32(numel(mat_db.epsR))); + +h5writeatt(filename, '/DiscData', 'epsR', mat_db.epsR); +h5writeatt(filename, '/DiscData', 'kappa', mat_db.kappa); +h5writeatt(filename, '/DiscData', 'density', mat_db.density); +h5writeatt(filename, '/DiscData', 'Name', strjoin(mat_db.Name,',')); + +h5create(filename, '/mesh/x', mesh_size(1)); +h5write(filename, '/mesh/x', mesh.x); + +h5create(filename, '/mesh/y', mesh_size(2)); +h5write(filename, '/mesh/y', mesh.y); + +h5create(filename, '/mesh/z', mesh_size(3)); +h5write(filename, '/mesh/z', mesh.z); + +h5writeatt(filename, '/', 'Version', 2); + + + +function out = strjoin(names, delimitier) + +out = names{1}; +for n=2:numel(names) + out = [out delimitier names{n}]; +end diff --git a/CSXCAD/matlab/DefineRectGrid.m b/CSXCAD/matlab/DefineRectGrid.m new file mode 100644 index 0000000..efc8a41 --- /dev/null +++ b/CSXCAD/matlab/DefineRectGrid.m @@ -0,0 +1,50 @@ +function CSX = DefineRectGrid(CSX, deltaUnit, mesh) +% function CSX = DefineRectGrid(CSX, deltaUnit, mesh); +% +% Create a rectiliniear grid. +% +% example Cartesian mesh: +% CSX = InitCSX(); +% mesh.x = AutoSmoothMeshLines([0 a], 10); +% mesh.y = AutoSmoothMeshLines([0 b], 10); +% mesh.z = AutoSmoothMeshLines([0 length], 15); +% CSX = DefineRectGrid(CSX, unit,mesh); +% +% example Cylindrical mesh: +% CSX = InitCSX('CoordSystem',1); +% mesh.r = AutoSmoothMeshLines([0 a], 10); +% mesh.a = AutoSmoothMeshLines([0 2*pi], pi/30); +% mesh.z = AutoSmoothMeshLines([-length 0 length], 15); +% CSX = DefineRectGrid(CSX, unit,mesh); +% +% See also InitCSX, SmoothMesh, AutoSmoothMeshLines, DetectEdges +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit = deltaUnit; + +if (isfield(CSX,'ATTRIBUTE')) + if (isfield(CSX.ATTRIBUTE,'CoordSystem')) + CSX.RectilinearGrid.ATTRIBUTE.CoordSystem = CSX.ATTRIBUTE.CoordSystem; + end +end + +if (isfield(mesh,'x')) + CSX.RectilinearGrid.XLines = mesh.x; +elseif ( (isfield(mesh,'r')) && (CSX.ATTRIBUTE.CoordSystem==1)) + CSX.RectilinearGrid.XLines = mesh.r; +else + error 'x/(r) direction not found' +end + +if (isfield(mesh,'y')) + CSX.RectilinearGrid.YLines = mesh.y; +elseif ((isfield(mesh,'a')) && (CSX.ATTRIBUTE.CoordSystem==1)) + CSX.RectilinearGrid.YLines = mesh.a; +else + error 'y/(a) direction not found' +end + +CSX.RectilinearGrid.ZLines = mesh.z; diff --git a/CSXCAD/matlab/DetectEdges.m b/CSXCAD/matlab/DetectEdges.m new file mode 100644 index 0000000..ea01909 --- /dev/null +++ b/CSXCAD/matlab/DetectEdges.m @@ -0,0 +1,278 @@ +function mesh = DetectEdges(CSX, mesh, varargin) +% mesh = DetectEdges(CSX <, mesh, varargin>) +% +% Returns a mesh with the edges added of certain (see below) primitives +% found in the CSX structure. +% +% optional arguments: +% mesh: add edges to an existing (predefined) mesh +% +% optional: 'keyword', value +% 'Debug' enable debug mode (default is 1) +% 'AddPropertyType' add a list of additional property types to detect +% e.g. 'DumpBox' or {'DumpBox','ProbeBox'} +% 'SetPropertyType' set the list of property types to detect (override default) +% e.g. 'Metal' or {'Metal','ConductingSheet'} +% 'ExcludeProperty' give a list of property names to exclude from +% detection +% 'SetProperty' give a list of property names to handly exlusively for detection +% +% advanced options: 'keyword', value +% '2D_Metal_Edge_Res' define a one-third/two-third metal edge resolution +% +% example: +% CSX = InitCSX(); +% % define all properties and primitives to detect +% % ... +% % ... +% mesh = DetectEdges(CSX); +% mesh = SmoothMesh(mesh, lambda/20/unit); +% CSX = DefineRectGrid(CSX, unit, mesh); +% +% Note: +% - Only primitives contained in Metal, Material, Excitation, LumpedElement +% or ConductingSheet properties are processed +% - Currently this function handles only Box, Polygons, LinPoly and Cylinder. +% +% CSXCAD matlab interface +% ----------------------- +% author: Koen De Vleeschauwer (c) 2012 +% modified by: Thorsten Liebig (c) 2012, 2013 +% +% See also InitCSX, SmoothMesh, DefineRectGrid + +supported_properties = {}; +supported_properties{end+1}='Metal'; +supported_properties{end+1}='Material'; +supported_properties{end+1}='Excitation'; +supported_properties{end+1}='LumpedElement'; +supported_properties{end+1}='ConductingSheet'; + +exclude_list = {}; +prop_list_only = {}; + +debug = 1; +mesh_2D_metal_edges = 0; + +for n=1:2:numel(varargin) + if (strcmpi(varargin{n},'debug')==1); + debug = varargin{n+1}; + elseif (strcmpi(varargin{n},'AddPropertyType')==1); + if iscell(varargin{n+1}) + supported_properties(end+1) = varargin{n+1}; + elseif ischar(varargin{n+1}) + supported_properties{end+1} = varargin{n+1}; + else + error('CSXCAD:DetectEdges','unknown property definition'); + end + elseif (strcmpi(varargin{n},'SetPropertyType')==1); + if iscell(varargin{n+1}) + supported_properties = varargin{n+1}; + elseif ischar(varargin{n+1}) + supported_properties = {varargin{n+1}}; + else + error('CSXCAD:DetectEdges','unknown property definition'); + end + elseif (strcmpi(varargin{n},'ExcludeProperty')==1); + exclude_list = varargin{n+1}; + elseif (strcmpi(varargin{n},'SetProperty')==1); + prop_list_only = varargin{n+1}; + elseif (strcmpi(varargin{n},'2D_Metal_Edge_Res')==1); + mesh_2D_metal_edges = varargin{n+1}*[-1 2]/3; + else + warning('CSXCAD:DetectEdges',['unknown argument: ' varargin{n}]); + end +end + +if (nargin<2) + mesh = []; +end + +if isempty(mesh) + if (CSX.ATTRIBUTE.CoordSystem==0) + mesh.x = []; + mesh.y = []; + mesh.z = []; + elseif (CSX.ATTRIBUTE.CoordSystem==1) + mesh.r = []; + mesh.a = []; + mesh.z = []; + else + error('CSXCAD:DetectEdges','unknown coordinate system used'); + end +end + +edges = {}; +edges.x = [ ]; +edges.y = [ ]; +edges.z = [ ]; + +if (~isstruct(CSX)) + error('expected a CSX structure'); +end + +CoordSystem = CSX.ATTRIBUTE.CoordSystem; + +if (isfield(CSX, 'Properties')) + prop_fn = fieldnames(CSX.Properties); + for p = 1:numel(prop_fn) + if (sum(strcmpi(prop_fn{p}, supported_properties))==0) + continue; + end + isMetal = sum(strcmpi(prop_fn{p},{'Metal','ConductingSheet'})); + property_group = CSX.Properties.(prop_fn{p}); + for m = 1:numel(property_group) + property=property_group{m}; + if ~isfield(property, 'Primitives') + continue; + end + if (sum(strcmpi(property.ATTRIBUTE.Name,exclude_list))) + continue; + end + if (~isempty(prop_list_only) && (sum(strcmpi(property.ATTRIBUTE.Name,prop_list_only))==0)) + continue; + end + primitives = property.Primitives; + prim_fn = fieldnames(primitives); + for n_prim = 1:numel(prim_fn) + if (strcmp(prim_fn{n_prim}, 'Box')) + for b = 1:length(primitives.Box) + box = primitives.Box{b}; + x1 = box.P1.ATTRIBUTE.X; + y1 = box.P1.ATTRIBUTE.Y; + z1 = box.P1.ATTRIBUTE.Z; + x2 = box.P2.ATTRIBUTE.X; + y2 = box.P2.ATTRIBUTE.Y; + z2 = box.P2.ATTRIBUTE.Z; + % check dimension + dim = (x1~=x2) + (y1~=y2) + (z1~=z2); + if ((dim==2) && isMetal) + % add to global list of edges, with a given 2D + % edge resolution + edges = AddEdge (edges, box, x1+sign(x1-x2)*mesh_2D_metal_edges, y1+sign(y1-y2)*mesh_2D_metal_edges, ... + z1+sign(z1-z2)*mesh_2D_metal_edges, CoordSystem, debug); + edges = AddEdge (edges, box, x2+sign(x2-x1)*mesh_2D_metal_edges, y2+sign(y2-y1)*mesh_2D_metal_edges, ... + z2+sign(z2-z1)*mesh_2D_metal_edges, CoordSystem, debug); + else + % add to global list of edges + edges = AddEdge (edges, box, x1, y1, z1, CoordSystem, debug); + edges = AddEdge (edges, box, x2, y2, z2, CoordSystem, debug); + end + end + elseif (strcmp(prim_fn{n_prim}, 'LinPoly') || strcmp(prim_fn{n_prim}, 'Polygon')) + for l = 1:length(primitives.(prim_fn{n_prim})) + poly = primitives.(prim_fn{n_prim}){l}; + dir = poly.ATTRIBUTE.NormDir + 1; + dirP = mod(poly.ATTRIBUTE.NormDir+1,3) + 1; + dirPP = mod(poly.ATTRIBUTE.NormDir+2,3) + 1; + lin_length = 0; + if (strcmp(prim_fn{n_prim}, 'LinPoly')) + lin_length = poly.ATTRIBUTE.Length; + end + if (isfield(poly, 'Vertex')) + for v = 1:length(poly.Vertex) + vertex = poly.Vertex{v}; + edge(dir) = poly.ATTRIBUTE.Elevation; + edge(dirP) = vertex.ATTRIBUTE.X1; + edge(dirPP) = vertex.ATTRIBUTE.X2; + edges = AddEdge (edges, poly, edge(1), edge(2), edge(3), CoordSystem, debug); + if (lin_length~=0) + edge(dir) = edge(dir) + lin_length; + edges = AddEdge (edges, poly, edge(1), edge(2), edge(3), CoordSystem, debug); + end + end + end + end + elseif (strcmp(prim_fn{n_prim}, 'Cylinder')) + for c = 1:length(primitives.Cylinder) + cylinder = primitives.Cylinder{c}; + r = cylinder.ATTRIBUTE.Radius; + x1 = cylinder.P1.ATTRIBUTE.X; + y1 = cylinder.P1.ATTRIBUTE.Y; + z1 = cylinder.P1.ATTRIBUTE.Z; + x2 = cylinder.P2.ATTRIBUTE.X; + y2 = cylinder.P2.ATTRIBUTE.Y; + z2 = cylinder.P2.ATTRIBUTE.Z; + if ((x1 == x2) && (y1 == y2) && (z1 ~= z2)) + % cylinder parallel with z axis + edges = AddEdge (edges, cylinder, x1 - r, y1 - r, z1, CoordSystem, debug); + edges = AddEdge (edges, cylinder, x2 + r, y2 + r, z2, CoordSystem, debug); + elseif ((x1 == x2) && (y1 ~= y2) && (z1 == z2)) + % cylinder parallel with y axis + edges = AddEdge (edges, cylinder, x1 - r, y1, z1 - r, CoordSystem, debug); + edges = AddEdge (edges, cylinder, x2 + r, y2, z2 + r, CoordSystem, debug); + elseif ((x1 ~= x2) && (y1 == y2) && (z1 == z2)) + % cylinder parallel with x axis + edges = AddEdge (edges, cylinder, x1, y1 - r, z1 - r, CoordSystem, debug); + edges = AddEdge (edges, cylinder, x2, y2 + r, z2 + r, CoordSystem, debug); + elseif (debug > 0) + warning('CSXCAD:DetectEdges',['unsupported primitive of type: "' prim_fn{n_prim} '" found, skipping edges']); + end + end + else + if (debug>0) + warning('CSXCAD:DetectEdges',['unsupported primitive of type: "' prim_fn{n_prim} '" found, skipping edges']); + end + end + end + end + end +end + +if (CSX.ATTRIBUTE.CoordSystem==0) + mesh.x = sort(unique([mesh.x edges.x])); + mesh.y = sort(unique([mesh.y edges.y])); + mesh.z = sort(unique([mesh.z edges.z])); +elseif (CSX.ATTRIBUTE.CoordSystem==1) + mesh.r = sort(unique([mesh.r edges.x])); + mesh.a = sort(unique([mesh.a edges.y])); + mesh.z = sort(unique([mesh.z edges.z])); +else + error('CSXCAD:DetectEdges','unknown coordinate system used'); +end + +end + + +function edges = AddEdge(edges, csx_prim, x, y, z, CoordSystem, debug) +% Add edges of CSX primitives including some transformations + +xt = unique(x); +yt = unique(y); +zt = unique(z); + +if isfield(csx_prim.ATTRIBUTE,'CoordSystem') + if (csx_prim.ATTRIBUTE.CoordSystem~=CoordSystem) + if (debug>2) + warning('CSXCAD:DetectEdges','different coordinate systems not supported, skipping edges'); + end + return + end +end + +if (isfield(csx_prim, 'Transformation')) + + transformation = csx_prim.Transformation; + trans_fn = fieldnames(transformation); + + for t=1:numel(trans_fn) + if (strcmp(trans_fn{t}, 'Translate')) + xt = xt + transformation.Translate.ATTRIBUTE.Argument(1); + yt = yt + transformation.Translate.ATTRIBUTE.Argument(2); + zt = zt + transformation.Translate.ATTRIBUTE.Argument(3); + else + if (debug>0) + warning('CSXCAD:DetectEdges','unsupported transformation found in primitive, skipping edges'); + end + return + end + end + +end + +% add to global list of edges +edges.x = [edges.x xt]; +edges.y = [edges.y yt]; +edges.z = [edges.z zt]; +end + diff --git a/CSXCAD/matlab/DirChar2Int.m b/CSXCAD/matlab/DirChar2Int.m new file mode 100644 index 0000000..0454448 --- /dev/null +++ b/CSXCAD/matlab/DirChar2Int.m @@ -0,0 +1,31 @@ +function n = DirChar2Int(dir_char) +% function n = DirChar2Int(dir_char) +% +% internal function to convert a character like 'x','y','z' into a numeric +% direction: 0..2! +% If input already is a numeric value from 0..2, it will just be copied! +% Everything else will raise an error! +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (c) 2013 + +if (numel(dir_char)>1) + error('CSXCAD:DirChar2Int','invalid normal direction') +end + +if (ischar(dir_char)) + if (strcmp(dir_char,'x') || strcmp(dir_char,'r')) + n = 0; return; + elseif (strcmp(dir_char,'y') || strcmp(dir_char,'a')) + n = 1; return; + elseif strcmp(dir_char,'z') + n = 2; return; + else + error('CSXCAD:DirChar2Int','invalid normal direction') + end +elseif (isnumeric(dir_char) && ((dir_char==0) || (dir_char==1) || (dir_char==2))) + n = dir_char; +else + error('CSXCAD:DirChar2Int','invalid normal direction') +end diff --git a/CSXCAD/matlab/ImportPLY.m b/CSXCAD/matlab/ImportPLY.m new file mode 100644 index 0000000..a221b38 --- /dev/null +++ b/CSXCAD/matlab/ImportPLY.m @@ -0,0 +1,23 @@ +function CSX = ImportPLY(CSX, propName, prio, filename, varargin) +% function CSX = ImportPLY(CSX, propName, prio, filename, varargin) +% +% example: +% CSX = AddMetal( CSX, 'cad_model' ); % create a perfect electric conductor (PEC) +% CSX = ImportPLY(CSX, 'cad_model',10, 'sphere.ply','Transform',{'Scale',1/unit}); +% +% Note: make sure the file 'sphere.ply' is in the working directory +% +% See also AddBox, AddCylinder, AddCylindricalShell, AddSphere, AddSphericalShell, +% AddCurve, AddWire, AddMetal, ImportSTL +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +plyfile.ATTRIBUTE.Priority = prio; +plyfile.ATTRIBUTE.FileName = filename; +plyfile.ATTRIBUTE.FileType = 'PLY'; + +plyfile = AddPrimitiveArgs(plyfile,varargin{:}); + +CSX = Add2Property(CSX,propName, plyfile, 'PolyhedronReader'); diff --git a/CSXCAD/matlab/ImportSTL.m b/CSXCAD/matlab/ImportSTL.m new file mode 100644 index 0000000..a3641f1 --- /dev/null +++ b/CSXCAD/matlab/ImportSTL.m @@ -0,0 +1,23 @@ +function CSX = ImportSTL(CSX, propName, prio, filename, varargin) +% function CSX = ImportSTL(CSX, propName, prio, filename, varargin) +% +% example: +% CSX = AddMetal( CSX, 'cad_model' ); % create a perfect electric conductor (PEC) +% CSX = ImportSTL(CSX, 'cad_model',10, 'sphere.stl','Transform',{'Scale',1/unit}); +% +% Note: make sure the file 'sphere.stl' is in the working directory +% +% See also AddBox, AddCylinder, AddCylindricalShell, AddSphere, AddSphericalShell, +% AddCurve, AddWire, AddMetal, ImportPLY +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +stlfile.ATTRIBUTE.Priority = prio; +stlfile.ATTRIBUTE.FileName = filename; +stlfile.ATTRIBUTE.FileType = 'STL'; + +stlfile = AddPrimitiveArgs(stlfile,varargin{:}); + +CSX = Add2Property(CSX,propName, stlfile, 'PolyhedronReader'); diff --git a/CSXCAD/matlab/InitCSX.m b/CSXCAD/matlab/InitCSX.m new file mode 100644 index 0000000..2411d85 --- /dev/null +++ b/CSXCAD/matlab/InitCSX.m @@ -0,0 +1,31 @@ +function CSX = InitCSX(varargin) +% function CSX = InitCSX() +% +% Inititalize the CSX data-structure. +% +% variable arguments: +% 'CoordSystem' : define the default coordinate system +% 0 -> Cartesian +% 1 -> Cylindircal +% 2 -> Sphercial (not yet implemented) +% +% example: +% CSX = InitCSX(); %for a default cartesian mesh +% or +% CSX = InitCSX('CoordSystem','1'); % for a cylindrical mesh definition +% +% See also DefineRectGrid, SmoothMeshLines, SmoothMeshLines2, +% SetBackgroundMaterial +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +CSX.Properties = []; + +%Cartesian mesh as default coordinate system +CSX.ATTRIBUTE.CoordSystem = 0; + +for n=1:2:numel(varargin) + CSX.ATTRIBUTE.(varargin{n}) = (varargin{n+1}); +end diff --git a/CSXCAD/matlab/RecursiveSmoothMesh.m b/CSXCAD/matlab/RecursiveSmoothMesh.m new file mode 100644 index 0000000..0ce791c --- /dev/null +++ b/CSXCAD/matlab/RecursiveSmoothMesh.m @@ -0,0 +1,176 @@ +function resultMeshPoints = RecursiveSmoothMesh(fixedMeshPoints, max_res, ratio, varargin) +% function resultMeshPoints = RecursiveSmoothMesh(fixedMeshPoints, max_res, ratio, varargin) +% +% RecursiveSmoothMesh: This function tries to generate an optimal mesh +% between the given fixedMeshPoints. The space between the fixed points is +% filled with the largest possible mesh step size considdering mesh max +% resolution and mesh increase/decrease ratio. +% +% Algorithm: Mesh creation is done via a simple try and error approach: +% The next mesh point could be between lastDistance*ratio and +% lastDistance/ratio away from the last mesh point. If a fixed mesh point +% exist in this distance, this point is used. If there is a fixed mesh +% point below this distance, the last (determined) mesh point is wrong, go +% back and try with a mesh point a few mm below. (If that is not possible +% because the distance to the mesh point behind the last point is to low, +% also update this mesh point). +% The algorithm seems to work very well, except if the ratio is to low. +% At a value of 1.2, the calculation takes a very long time. +% +% +% Parameter: fixedMeshPoints: List containing points at which a mesh +% line should appear +% max_res: Maximum distance between two mesh lines +% ratio: Maximum grading ratio between two +% neighbour mesh lines +% +% optional variable arguments ('key', value): +% CheckMesh: Do a final mesh check (default is true) +% allowed_max_ratio: allow only a given max. grading ratio +% (default --> ratio*1.25) +% +% Returns: resultMeshPoints: List containing the positions of all +% mesh lines. If a empty list is +% returned, no resolution could be +% found. +% +% CSXCAD matlab interface +% ----------------------- +% Author: Florian Pfanner +% Date: 28.09.2012 + + +if (nargin < 3) + ratio = 1.4; +end + +if (ratio < 1.2) + warning('ratio must be > 1.2, set it to 1.2'); + ratio = 1.2; +end + +check_mesh = true; +max_ratio = ratio*1.25; + +for vn=1:2:numel(varargin) + if (strcmpi(varargin{vn},'CheckMesh')) + check_mesh = varargin{vn+1}; + end + if (strcmpi(varargin{vn},'allowed_max_ratio')) + max_ratio = varargin{vn+1}; + end +end + +fixedMeshPoints = sort(unique(fixedMeshPoints(:)')); +if (length(fixedMeshPoints) < 2) + error('Not enoughts points to create mesh!'); +end + + +% special behaviour to generate a symetric mesh (If the fixedMeshPoints are +% given in a symetric way.) +symMesh = CheckSymmtricLines(fixedMeshPoints); +if (symMesh) + nPoints = length(fixedMeshPoints); + + symMeshEven = mod(nPoints,2)==0; + + if (symMeshEven) + center = mean(fixedMeshPoints); + if (center-fixedMeshPoints(nPoints/2) > 0.5*max_res) + fixedMeshPoints = [fixedMeshPoints(1:nPoints/2) center]; + else + % this is not working!!! + % fixedMeshPoints = fixedMeshPoints(1:nPoints/2+1); + fixedMeshPoints = [fixedMeshPoints(1:nPoints/2) center]; + end + else + % For symetric mesh, only the first half of the fixed mesh points is + % needed. But add center of the symetric mesh to the fixed mesh points + % to ensure the center is included. + fixedMeshPoints = fixedMeshPoints(1:(nPoints+1)/2); + end +end + + +minDistance = min(fixedMeshPoints(2:end)-fixedMeshPoints(1:end-1)); + +% two cases: +% * minDistance is smaller than max_res +% -> try spaces for the first mesh between max_res and minDistance/2 +% * max_res is smaller than minDistance +% -> try spaces for the first mesh between max_res and max_res/10 +if (minDistance < max_res) + trySpaces = linspace(max_res, minDistance/2, 10); +else + trySpaces = linspace(max_res, max_res/10, 10); +end +for k=1:length(trySpaces) + [resultMeshPoints, success] = recursiveMeshSearch(fixedMeshPoints(1), ... + trySpaces(k), fixedMeshPoints(2:end), max_res, ratio); + if (success) + resultMeshPoints = [fixedMeshPoints(1) resultMeshPoints]; + break; + end +end + + +if (symMesh) + resultMeshPoints = [resultMeshPoints(1:end-1) max(resultMeshPoints)*2-resultMeshPoints(end:-1:1)]; +end + +% check result +if (check_mesh) + CheckMesh(resultMeshPoints,0,max_res,ratio,0); +end + +end % main function + +function [meshPoints, success] = recursiveMeshSearch(lastMeshPoint, ... + lastSpace, fixedMeshPoints, max_res, ratio) + +nextMeshPointMax = lastMeshPoint + min(lastSpace*ratio, max_res); +nextMeshPointMin = lastMeshPoint + lastSpace/ratio; + +% check if below ratio is a fixed mesh point -> abbort +if (fixedMeshPoints(1) < nextMeshPointMin) + meshPoints = []; + success = false; + return; +end + +% check if in range of ratio is a fixed mesh point: +if (fixedMeshPoints(1) >= nextMeshPointMin && fixedMeshPoints(1) <= nextMeshPointMax) + % yes, use this fixed mesh point + nextMeshPoint = fixedMeshPoints(1); + if (length(fixedMeshPoints) > 1) + [meshPointsCall, success] = recursiveMeshSearch(nextMeshPoint, ... + nextMeshPoint-lastMeshPoint, fixedMeshPoints(2:end), ... + max_res, ratio); + if (success) % backtracking was successful, return result + meshPoints = [nextMeshPoint meshPointsCall]; + else % no possible resulution found, last step has to be repeated! + meshPoints = []; + end + else % this was the last mesh point, finish! + meshPoints = nextMeshPoint; + success = true; + end + return; +end + +% try to set next mesh point, begin with highest width +trySpace = linspace(nextMeshPointMax, nextMeshPointMin, 10); +for i=1:length(trySpace) + [meshPointsCall, success] = recursiveMeshSearch(trySpace(i), ... + trySpace(i)-lastMeshPoint, fixedMeshPoints, max_res, ... + ratio); + if (success) % backtracking was successful, return + meshPoints = [trySpace(i) meshPointsCall]; + return; + end +end +% no sucessful points found, return false +meshPoints = []; +success = false; +end diff --git a/CSXCAD/matlab/SetBackgroundMaterial.m b/CSXCAD/matlab/SetBackgroundMaterial.m new file mode 100644 index 0000000..5aaa6df --- /dev/null +++ b/CSXCAD/matlab/SetBackgroundMaterial.m @@ -0,0 +1,23 @@ +function CSX = SetBackgroundMaterial(CSX, varargin) +% function CSX = SetBackgroundMaterial(CSX, varargin)) +% +% Set the background material properties +% +% variable arguments: +% 'Epsilon' : background rel. electric permittivity (default 1) +% 'Kappa' : background electric conductivity (default 0) +% 'Mue' : background rel. magnetic permeability (default 1) +% +% example: +% CSX = InitCSX(); +% CSX = SetBackgroundMaterial(CSX, 'Epsilon', 4) +% +% See also InitCSX +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (c) 2013 + +for n=1:2:numel(varargin) + CSX.BackgroundMaterial.ATTRIBUTE.(varargin{n}) = (varargin{n+1}); +end diff --git a/CSXCAD/matlab/SetExcitationWeight.m b/CSXCAD/matlab/SetExcitationWeight.m new file mode 100644 index 0000000..67a50ee --- /dev/null +++ b/CSXCAD/matlab/SetExcitationWeight.m @@ -0,0 +1,53 @@ +function CSX = SetExcitationWeight(CSX, name, weight) +% function CSX = SetExcitationWeight(CSX, name, weight) +% +% Define weighting functions for x-, y- and z-direction of excitation +% +% 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 (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 +% +% example: +% start=[0 0 0]; +% stop=[width height 0]; +% CSX = AddExcitation(CSX,'excite',0,[1 1 0]); +% weight{1} = '2*cos(0.0031416*x)*sin(0.0062832*y)'; +% weight{2} = '1*sin(0.0031416*x)*cos(0.0062832*y)'; +% weight{3} = 0; +% CSX = SetExcitationWeight(CSX,'excite',weight); +% CSX = AddBox(CSX,'excite',0 ,start,stop); +% +% See also AddExcitation, InitCSX, DefineRectGrid +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +if ~isfield(CSX,'Properties') + error('CSXCAD::SetExcitationWeight: no properties not found'); +end +if ~isfield(CSX.Properties,'Excitation') + error('CSXCAD::SetExcitationWeight: no excitation properties found'); +end + +pos=0; +for n=1:numel(CSX.Properties.Excitation) + if strcmp(CSX.Properties.Excitation{n}.ATTRIBUTE.Name, name) + pos=n; + end +end + +if (pos==0) + error('CSXCAD::SetExcitationWeight: property not found'); + return; +end + +CSX.Properties.Excitation{pos}.Weight.ATTRIBUTE.X = weight{1}; +CSX.Properties.Excitation{pos}.Weight.ATTRIBUTE.Y = weight{2}; +CSX.Properties.Excitation{pos}.Weight.ATTRIBUTE.Z = weight{3}; diff --git a/CSXCAD/matlab/SetMaterialProperty.m b/CSXCAD/matlab/SetMaterialProperty.m new file mode 100644 index 0000000..463d22e --- /dev/null +++ b/CSXCAD/matlab/SetMaterialProperty.m @@ -0,0 +1,29 @@ +function CSX = SetMaterialProperty(CSX, name, varargin) +% function CSX = SetMaterialProperty(CSX, name, varargin) +% +% Use this function to define the material constants: +% 'Epsilon': relative electric permittivity: [Epsilon] = 1 +% 'Mue': relative magnetic permeability: [Mue} = 1 +% 'Kappa': electric conductivity: [Kappa] = S/m +% 'Sigma': magnetic conductivity (non-physical property): [Sigma] = Ohm/m +% 'Density': material mass density: [Density] = kg/m^3, e.g. water: 1000 +% necessary for SAR calculations +% +% examples: +% CSX = AddMaterial( CSX, 'RO3010' ); +% CSX = SetMaterialProperty( CSX, 'RO3010', 'Epsilon', 10.2, 'Mue', 1 ); +% CSX = AddBox( CSX, 'RO3010', 0, [0 0 0], [100 1000 1000] ); +% +% % anisotropic material +% CSX = AddMaterial( CSX, 'sheet','Isotropy',0); +% CSX = SetMaterialProperty(CSX, 'sheet', 'Kappa', [0 0 kappa]); +% CSX = AddBox( CSX, 'sheet', 0, [0 0 0], [10 1000 1000] ); +% +% See also AddMaterial, SetMaterialWeight +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +CSX = SetPropertyArgs(CSX, GetPropertyType(CSX,name), name, 'Property', varargin{:}); + diff --git a/CSXCAD/matlab/SetMaterialWeight.m b/CSXCAD/matlab/SetMaterialWeight.m new file mode 100644 index 0000000..825892e --- /dev/null +++ b/CSXCAD/matlab/SetMaterialWeight.m @@ -0,0 +1,31 @@ +function CSX = SetMaterialWeight(CSX, name, varargin) +% function CSX = SetMaterialWeight(CSX, name, varargin) +% +% Define 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 (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 +% +% example: +% %material distribution as a rect-function with 4 periods +% start=[-500 -100 -500]; +% stop =[ 500 100 500]; +% CSX = AddMaterial(CSX, 'material'); +% CSX = SetMaterialProperty(CSX, 'material', 'Epsilon', 1); +% CSX = SetMaterialWeight(CSX, 'material', 'Epsilon', ['(sin(4*z / 1000 *2*pi)>0)+1']); +% CSX = AddBox(CSX, 'material' ,10 , start, stop); +% +% See also AddMaterial, SetMaterialProperty, InitCSX, DefineRectGrid +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +CSX = SetPropertyArgs(CSX, GetPropertyType(CSX,name), name, 'Weight', varargin{:}); diff --git a/CSXCAD/matlab/SmoothMesh.m b/CSXCAD/matlab/SmoothMesh.m new file mode 100644 index 0000000..7ba37bc --- /dev/null +++ b/CSXCAD/matlab/SmoothMesh.m @@ -0,0 +1,73 @@ +function [mesh] = SmoothMesh( mesh, max_res, ratio, varargin) +% function [mesh] = SmoothMesh( mesh, max_res, ) +% +% Convienent function to create a smooth mesh in all directions. +% Generate smooth mesh by choosing an appropriate algorithm in each direction. +% +% Currently supported smoothing algorithm: +% SmoothMeshLines, SmoothMeshLines2 and RecursiveSmoothMesh +% +% arguments: +% lines: given fixed lines to create a smooth mesh in between +% max_res: scalar or vector of desired max. allowed resolution +% ratio: grading ratio: scalar or vector of desired neighboring +% line-delta ratio (optional, default is 1.5) +% - see also 'allowed_max_ratio' argument +% +% variable arguments ('keyword',value): +% algorithm: define subset of tried algorihm, e.g. [1 3] +% symmetric: 0/1 force symmetric mesh (default is input symmetry) +% homogeneous: 0/1 force homogeneous mesh +% allowed_min_res: allow a given min resolution only +% allowed_max_ratio: allow only a given max. grading ratio +% (default --> ratio*1.25) +% debug: 0/1 off/on +% +% example: +% mesh.x = [-BoundBox 0 BoundBox]; +% mesh.y = [-BoundBox 0 BoundBox]; +% mesh.z = [0 BoundBox]; +% mesh = SmoothMesh(mesh, lambda/20/unit); +% CSX = DefineRectGrid(CSX, unit, mesh); +% +% See also AutoSmoothMeshLines, InitCSX, DefineRectGrid, DetectEdges +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (C) 2012 + +if (nargin<3) + ratio = 1.5; +end + +if (numel(max_res)==1) + max_res = [max_res max_res max_res]; +end +if (numel(ratio)==1) + ratio = [ratio ratio ratio]; +end +if (numel(max_res)~=1) + max_res = [max_res max_res max_res]; +end + +if isfield(mesh,'x') + mesh.x = AutoSmoothMeshLines(mesh.x, max_res(1), ratio(1), varargin{:}); +elseif isfield(mesh,'r') + mesh.r = AutoSmoothMeshLines(mesh.r, max_res(1), ratio(1), varargin{:}); +else + error 'x/(r) direction not found' +end + +if isfield(mesh,'y') + mesh.y = AutoSmoothMeshLines(mesh.y, max_res(2), ratio(2), varargin{:}); +elseif isfield(mesh,'a') + mesh.a = AutoSmoothMeshLines(mesh.a, max_res(2), ratio(2), varargin{:}); +else + error 'y/(a) direction not found' +end + +if isfield(mesh,'z') + mesh.z = AutoSmoothMeshLines(mesh.z, max_res(3), ratio(3), varargin{:}); +else + error 'z direction not found' +end diff --git a/CSXCAD/matlab/SmoothMeshLines.m b/CSXCAD/matlab/SmoothMeshLines.m new file mode 100644 index 0000000..bc1160f --- /dev/null +++ b/CSXCAD/matlab/SmoothMeshLines.m @@ -0,0 +1,122 @@ +function lines = SmoothMeshLines( lines, max_res, ratio, varargin) +%function lines = SmoothMeshLines( lines, max_res, ratio, varargin) +% +% create smooth mesh lines +% +% Warning: This function may not always produce a desired output. +% +% lines: given fixed lines to create a smooth mesh in between +% max_res: desired max. resolution +% ratio: max. neighboring line-delta ratio, (optional, default is 1.3) +% +% optional variable arguments ('key', value) +% recursive: SmoothMeshLines a couple of times recursivly (default is 0) +% CheckMesh: Do a final mesh check (default is true) +% allowed_max_ratio: allow only a given max. grading ratio +% (default --> ratio*1.25) +% +% example: +% % create a x-mesh with lines at 0, 50 and 200 an a desired mesh +% resolution of 5 +% mesh.x = SmoothMeshLines([0 50 200],5,1.3); +% +% See also InitCSX, DefineRectGrid +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +if (numel(lines)<2) + return +end + +if (nargin<3) + ratio = 1.3; +end + +recursive = 0; +check_mesh = true; +max_ratio = ratio*1.25; + +for vn=1:2:numel(varargin) + if (strcmpi(varargin{vn},'recursive')) + recursive = varargin{vn+1}; + end + if (strcmpi(varargin{vn},'CheckMesh')) + check_mesh = varargin{vn+1}; + end + if (strcmpi(varargin{vn},'allowed_max_ratio')) + max_ratio = varargin{vn+1}; + end +end + +lines = unique(sort(lines)); + +diff_Lines = diff(lines); + +index = find(diff_Lines>(1.001*max_res)); + +% for n=1:numel(diff_Lines)-1 +% if ( (diff_Lines(n+1)/diff_Lines(n) > ratio) ) +% index = [index n+1]; +% end +% end + +index = unique(index); + +addLines = []; + +for n=1:numel(index) + if (index(n)==1) + start_res = max_res; + else + start_res = lines(index(n)) - lines(index(n)-1); + end + + if ((index(n)+1)==numel(lines)) + stop_res = max_res; + else + stop_res = lines(index(n)+2) - lines(index(n)+1); + end + + addLines = [addLines SmoothRange(lines(index(n)),lines(index(n)+1),start_res,stop_res,max_res,ratio)]; +end + + +lines = unique(sort([lines addLines])); + +addLines = []; +% relax ratio for test +ratio_relax = ratio + (ratio-1) * 1; + +[EC pos E_type] = CheckMesh(lines,0,max_res,ratio_relax,1); +diff_Lines = diff(lines); + +for n=1:EC + if pos(n)>1 + start_res = diff_Lines(pos(n)-1); + else + start_res = diff_Lines(pos(n)); + end + if pos(n) >= numel(diff_Lines) + stop_res = diff_Lines(end); + else + stop_res = diff_Lines(pos(n)+1); + end + max_res_R = max([start_res stop_res])/2/ratio; + addLines = [addLines SmoothRange(lines(pos(n)),lines(pos(n)+1),start_res,stop_res,max_res_R,ratio)]; +end + +lines = unique(sort([lines addLines])); + +for n=1:recursive + old_numL = numel(lines); + lines = SmoothMeshLines( lines, max_res, ratio, 0); + if numel(lines) == old_numL + return + end +end + +if (check_mesh) + CheckMesh(lines,0,max_res,max_ratio,0); +end diff --git a/CSXCAD/matlab/SmoothMeshLines2.m b/CSXCAD/matlab/SmoothMeshLines2.m new file mode 100644 index 0000000..5d347c0 --- /dev/null +++ b/CSXCAD/matlab/SmoothMeshLines2.m @@ -0,0 +1,318 @@ +function lines = SmoothMeshLines2(lines, max_res, ratio, varargin) +%lines = SmoothMeshLines2( lines, max_res [, ratio, varargin] ) +% +% Create smooth mesh lines. +% +% input: +% lines: 1xn vector of (fixed) mesh lines +% max_res: maximum distance between any two lines (e.g. lambda/10) +% ratio: (optional) default: 1.3 +% +% optional variable arguments ('key', value) +% CheckMesh: Do a final mesh check (default is true) +% allowed_max_ratio: allow only a given max. grading ratio +% (default --> ratio*1.25) +% output: +% lines: 1xn vector of (smoothed) mesh lines +% +% example: +% mesh.x = [0 100 2300 2400]; +% mesh.x = SmoothMeshLines2( mesh.x, 43 ); +% +% todo: +% - if gaps cannot be completely filled because of the ratio restriction, +% the spacing is not optimal. SmoothRange() needs to be optimized. +% - SmoothRange() has special handling if stop_taper is to long; can this +% also happen for start_taper? +% +% CSXCAD matlab interface +% ----------------------- +% (C) 2010 Sebastian Held +% See also SmoothMeshLines + +if (numel(lines)<2) + return +end + +if (nargin<3) + ratio = 1.3; +end + +check_mesh = true; +max_ratio = ratio*1.25; + +for vn=1:2:numel(varargin) + if (strcmpi(varargin{vn},'CheckMesh')) + check_mesh = varargin{vn+1}; + end + if (strcmpi(varargin{vn},'allowed_max_ratio')) + max_ratio = varargin{vn+1}; + end +end + +% +% | | | | +% | gap(1) | gap(2) | ... | +% | | | | +% +% lines(1) lines(2) ... lines(end) + +lines = unique(sort(lines)); + +for n=1:(numel(lines)-1) + old_gap(n).start_res = -1; + old_gap(n).stop_res = -1; + old_gap(n).lines = []; +end + +if numel(lines) == 2 + % special case + addLines = SmoothRange( lines(1), lines(2), [], [], max_res, ratio ); + lines = sort(unique([lines addLines])); + [EC pos] = CheckMesh(lines,0,max_res,ratio); + return +end + +while 1 + gap = calc_gaps(lines,old_gap,max_res); + + % determine gap to process + index = find( [old_gap(2:end).start_res] ~= [gap(2:end).start_res], 1, 'first' ) + 1; + if isempty(index) + index = find( [old_gap(1:end-1).stop_res] ~= [gap(1:end-1).stop_res], 1, 'first' ); + end + if isempty(index) + break; % done + end + + start_res = min( max_res, calc_start_res(index,lines,old_gap) ); + stop_res = min( max_res, calc_stop_res(index,lines,old_gap) ); + + % create new lines + old_gap(index).lines = SmoothRange( lines(index), lines(index+1), start_res, stop_res, max_res, ratio ); + + % remember gap setting + old_gap(index).start_res = start_res; + old_gap(index).stop_res = stop_res; + + % debug +% plot_lines +end + +% merge lines +for n=1:numel(old_gap) + lines = [lines old_gap(n).lines]; +end +lines = sort(unique(lines)); + +if (check_mesh) + CheckMesh(lines,0,max_res,max_ratio,0); +end + +end % SmoothMeshLines2() + +%% ------------------------------------------------------------------------ +function gap = calc_gaps(lines,old_gap,max_res) + temp_lines = lines; + for n=1:numel(old_gap) + temp_lines = [temp_lines old_gap(n).lines]; + end + temp_lines = sort(unique(temp_lines)); + + if numel(temp_lines) == 2 + gap(1).start_res = inf; % resolution not fixed + gap(1).stop_res = max_res; + return + end + + gap(1).start_res = inf; % resolution not fixed + idx = interp1( temp_lines, 1:numel(temp_lines), lines(2), 'nearest' ); + gap(1).stop_res = min( max_res, temp_lines(idx+1) - temp_lines(idx) ); + for n=2:numel(lines)-2 + idx = interp1( temp_lines, 1:numel(temp_lines), lines(n), 'nearest' ); + gap(n).start_res = min( max_res, temp_lines(idx) - temp_lines(idx-1) ); + idx = interp1( temp_lines, 1:numel(temp_lines), lines(n+1), 'nearest' ); + gap(n).stop_res = min( max_res, temp_lines(idx+1) - temp_lines(idx) ); + gap(n).lines = old_gap(n).lines; + end + idx = interp1( temp_lines, 1:numel(temp_lines), lines(end-1), 'nearest' ); + gap(numel(lines)-1).start_res = min( max_res, temp_lines(idx) - temp_lines(idx-1) ); + gap(numel(lines)-1).stop_res = inf; % resolution not fixed +end % calc_gaps() + + +%% ------------------------------------------------------------------------ +function plot_lines + temp_lines = lines; + for n=1:numel(old_gap) + temp_lines = [temp_lines old_gap(n).lines]; + end + temp_lines = sort(unique(temp_lines)); + + plot( temp_lines, ones(size(temp_lines)), 'r+' ); + hold on + plot( lines, ones(size(lines)), 'bo' ); + hold off +end % plot_lines + + +%% ------------------------------------------------------------------------ +function res = calc_start_res(pos,lines,old_gap) + if (pos < 2) || (pos > numel(lines)) + res = []; + return + end + temp_lines = lines; + for n=1:numel(old_gap) + temp_lines = [temp_lines old_gap(n).lines]; + end + temp_lines = sort(unique(temp_lines)); + + idx = interp1( temp_lines, 1:numel(temp_lines), lines(pos), 'nearest' ); + res = temp_lines(idx) - temp_lines(idx-1); +end % calc_res() + + +%% ------------------------------------------------------------------------ +function res = calc_stop_res(pos,lines,old_gap) + if (pos < 1) || (pos >= numel(lines)-1) + res = []; + return + end + temp_lines = lines; + for n=1:numel(old_gap) + temp_lines = [temp_lines old_gap(n).lines]; + end + temp_lines = sort(unique(temp_lines)); + + idx = interp1( temp_lines, 1:numel(temp_lines), lines(pos+1), 'nearest' ); + res = temp_lines(idx+1) - temp_lines(idx); +end % calc_res() + + +%% ------------------------------------------------------------------------ +function lines = SmoothRange(start, stop, start_res, stop_res, max_res, ratio) + +if (nargin<6) + ratio = 1.3; +end + +if isempty(start_res) && isempty(stop_res) + % special case: fill entire range with max_res + n1 = ceil( (stop-start) / max_res ) + 1; + lines = linspace( start, stop, n1 ); + return +end + +if isempty(start_res) + % special case: taper from stop_res at stop to max_res at start (if + % possible) + taper = stop_res*ratio; + stop_taper = stop; + while (taper*ratio < max_res) && (stop_taper(1)-taper > start) + stop_taper = [stop_taper(1)-taper stop_taper]; + taper = taper*ratio; + end + if (stop_taper(1) - start) >= max_res + % fill with equidistant lines + n1 = ceil( (stop_taper(1)-start) / max_res ) + 1; + stop_taper = [linspace(start,stop_taper(1),n1) stop_taper]; + else + % not enough space for entire taper + stop_taper(1) = []; % likely too near to start + if numel(stop_taper) > 0 + stop_taper = [(start+stop_taper(1))/2 stop_taper]; % create a centered line + end + end + lines = sort(unique(stop_taper(stop_taper>=start))); + return +end + +if isempty(stop_res) + % special case: taper from stop_res at stop to max_res at start (if + % possible) + taper = start_res*ratio; + start_taper = start; + while (taper*ratio < max_res) && (start_taper(end)+taper < stop) + start_taper = [start_taper start_taper(end)+taper]; + taper = taper*ratio; + end + if (stop - start_taper(end)) >= max_res + % fill with equidistant lines + n1 = ceil( (stop-start_taper(end)) / max_res ) + 1; + start_taper = [start_taper linspace(start_taper(end),stop,n1)]; + else + % not enough space for entire taper + start_taper(end) = []; % likely too near to stop + if numel(start_taper) > 0 + start_taper = [start_taper (stop+start_taper(end))/2]; % create a centered line + end + end + lines = sort(unique(start_taper(start_taper<=stop))); + return +end + +taper = start_res*ratio; +start_taper = start; +while (taper*ratio 1) && (start_taper(end) - start_taper(end-1) > stop - start_taper(end)) + % not enough space for entire taper + start_taper(end) = []; % likely too near to stop + start_taper = [start_taper (stop+start_taper(end))/2]; % create a centered line +end + +taper = stop_res*ratio; +stop_taper = stop; +while (taper*ratio start) + stop_taper = [stop_taper(1)-taper stop_taper]; + taper = taper*ratio; +end +if (numel(stop_taper) > 1) && (stop_taper(2) - stop_taper(1) > start - stop_taper(1)) + % not enough space for entire taper + stop_taper(1) = []; % likely too near to start + stop_taper = [(start+stop_taper(1))/2 stop_taper]; % create a centered line +end + +while ~isempty(start_taper) && ~isempty(stop_taper) && (stop_taper(1) < start_taper(end)) + + diff_start = diff(start_taper); + if isempty(diff_start) + diff_start = start_res; + end + diff_stop = diff(stop_taper); + if isempty(diff_stop) + diff_stop = stop_res; + end + + if (diff_start(end)>diff_stop(1)) + start_taper(end) = []; + else + stop_taper(1) = []; + end +end + +% it may happen, that the space between start_taper(end) and stop_taper(1) +% is very small; correct it: +if numel(start_taper)>=2 && numel(stop_taper)>=2 + d = diff( [start_taper(end-1) start_taper(end) stop_taper(1) stop_taper(2) ]); + if (d(1)/d(2) > ratio) || (d(3)/d(2) > ratio) + addLines = linspace( start_taper(end-1), stop_taper(2), 4 ); + lines = unique( [start_taper(1:end-1) addLines stop_taper(2:end)] ); + return + end +end + +if isempty(start_taper) + start_taper = start; +end +if isempty(stop_taper) + stop_taper = stop; +end + +% fill remaining space with equidistant lines +numL = ceil((stop_taper(1) - start_taper(end))/max_res)+1; +lines = unique([start_taper linspace(start_taper(end),stop_taper(1),numL) stop_taper]); +end % SmoothRange() diff --git a/CSXCAD/matlab/export_empire.m b/CSXCAD/matlab/export_empire.m new file mode 100644 index 0000000..104a0bf --- /dev/null +++ b/CSXCAD/matlab/export_empire.m @@ -0,0 +1,305 @@ +function export_empire( CSX, FDTD, filename, options ) +% export_empire( CSX, FDTD, filename, options ) +% +% Exports the geometry defined in CSX to filename as an Empire python file. +% +% CSX: CSX-object created by InitCSX() +% FDTD: FDTD-object created by InitFDTD() +% filename: export filename (e.g. '/tmp/export.py') +% options (optional): struct +% options.ignore : cell array with property names to ignore +% +% CSXCAD matlab interface +% ----------------------- +% author: Sebastian Held +% 17. Jun 2010: initial version +% 28. Sep 2010: rewritten using Empire python scripting +% See also InitCSX InitFDTD + +if nargin < 3 + options = []; +end + +fid = fopen( filename, 'w' ); + +% write header +fprintf( fid, ['# Empire python script\n\n' ... + '# start Empire and select File/"Run Script" and select this file\n\n'] ); +fprintf( fid, 'from scripting import *\n\n' ); +export_empire_meshlines( fid, CSX ); +export_empire_settings( fid, CSX, FDTD ); + +if isfield(CSX.Properties,'Material') + % process material + Material = CSX.Properties.Material; + options.Property = 'Material'; + process_primitives( fid, Material, options ); +end +if isfield(CSX.Properties,'Metal') + % process PEC + Metal = CSX.Properties.Metal; + options.Property = 'Metal'; + process_primitives( fid, Metal, options ); +end + +fclose( fid ); + +% ----------------------------------------------------------------------------- +function str = gym_vect( start,stop ) +str = ['[' num2str(start(1)) ',' num2str(stop(1)) ',' num2str(start(2)) ',' num2str(stop(2)) ',' num2str(start(3)) ',' num2str(stop(3)) ']']; +function str = gym_vector( v ) +str = ['[' num2str(v(1))]; +for a=2:numel(v), str = [str ', ' num2str(v(a))]; end +str = [str ']']; + +% ----------------------------------------------------------------------------- +function primitive_box( fid, CSX_box, layertype ) +%primitive_box( fid, CSX_box, layertype ) +% layertype may be: 'dielectric Dielectric' or 'conductor Conductor' +global current_layer_prio +properties = ''; +if current_layer_prio ~= CSX_box.ATTRIBUTE.Priority + properties = [properties ' prio ' num2str(CSX_box.ATTRIBUTE.Priority)]; +end +if ~isempty(properties) + fprintf( fid, 'g.objecttext("%s")\n', [layertype properties] ); +end +start = [CSX_box.P1.ATTRIBUTE.X CSX_box.P1.ATTRIBUTE.Y CSX_box.P1.ATTRIBUTE.Z]; +stop = [CSX_box.P2.ATTRIBUTE.X CSX_box.P2.ATTRIBUTE.Y CSX_box.P2.ATTRIBUTE.Z]; +fprintf( fid, 'g.layerextrude("z",%g,%g)\n', start(3), stop(3) ); +fprintf( fid, 'g.box(%g,%g,%g,%g)\n', start(1), start(2), stop(1), stop(2) ); + +% ----------------------------------------------------------------------------- +function primitive_cylinder( fid, CSX_cylinder, layertype ) +%primitive_cylinder( fid, CSX_cylinder, layertype ) +% layertype may be: 'dielectric Dielectric' or 'conductor Conductor' +global current_layer_prio +properties = ''; +if current_layer_prio ~= CSX_cylinder.ATTRIBUTE.Priority + properties = [properties ' prio ' num2str(CSX_cylinder.ATTRIBUTE.Priority)]; +end +if ~isempty(properties) + fprintf( fid, 'g.objecttext("%s")\n', [layertype properties] ); +end + +start = [CSX_cylinder.P1.ATTRIBUTE.X CSX_cylinder.P1.ATTRIBUTE.Y CSX_cylinder.P1.ATTRIBUTE.Z]; +stop = [CSX_cylinder.P2.ATTRIBUTE.X CSX_cylinder.P2.ATTRIBUTE.Y CSX_cylinder.P2.ATTRIBUTE.Z]; + +radius = CSX_cylinder.ATTRIBUTE.Radius; +if start([1 2]) == stop([1 2]) + fprintf( fid, 'g.layerextrude("z",%g,%g)\n', start(3), stop(3) ); + fprintf( fid, 'g.circle(%g,%g,%g)\n', start(1), start(2), radius ); +elseif start([1 3]) == stop([1 3]) + fprintf( fid, 'g.layerextrude("y",%g,%g)\n', start(2), stop(2) ); + fprintf( fid, 'g.circle(%g,%g,%g)\n', start(3), start(1), radius ); +elseif start([2 3]) == stop([2 3]) + fprintf( fid, 'g.layerextrude("x",%g,%g)\n', start(1), stop(1) ); + fprintf( fid, 'g.circle(%g,%g,%g)\n', start(2), start(3), radius ); +else + disp( ['cylinder coordinates: (' num2str(start) ') -> (' num2str(stop) ')'] ); + error 'cylinder orientation not supported' +end + +% ----------------------------------------------------------------------------- +function str = primitive_wire( CSX_wire, options ) +radius = CSX_wire.ATTRIBUTE.WireRadius; +str = ['sphere_sweep { linear_spline, ' num2str(numel(CSX_wire.Vertex))]; +for a=1:numel(CSX_wire.Vertex) + % iterate over all vertices + v = [CSX_wire.Vertex{a}.ATTRIBUTE.X CSX_wire.Vertex{a}.ATTRIBUTE.Y CSX_wire.Vertex{a}.ATTRIBUTE.Z]; + str = [str ', ' pov_vect(v) ', ' num2str(radius)]; +end +str = [str ' ' options '}']; + +% ----------------------------------------------------------------------------- +function primitive_polygon( fid, CSX_polygon, layertype ) +%primitive_polygon( fid, CSX_polygon, layertype ) +% layertype may be: 'dielectric Dielectric' or 'conductor Conductor' +global current_layer_prio +properties = ''; +if current_layer_prio ~= CSX_polygon.ATTRIBUTE.Priority + properties = [properties ' prio ' num2str(CSX_polygon.ATTRIBUTE.Priority)]; +end +if ~isempty(properties) + fprintf( fid, 'g.objecttext("%s")\n', [layertype properties] ); +end +Elevation = CSX_polygon.ATTRIBUTE.Elevation; +if (CSX_polygon.NormDir.ATTRIBUTE.X ~= 0) + NormDir = 'x'; +elseif (CSX_polygon.NormDir.ATTRIBUTE.Y ~= 0) + NormDir = 'y'; +elseif (CSX_polygon.NormDir.ATTRIBUTE.Z ~= 0) + NormDir = 'z'; +end +coords = []; +for a=1:numel(CSX_polygon.Vertex) + % iterate over all vertices + coords = [coords CSX_polygon.Vertex{a}.ATTRIBUTE.X1 CSX_polygon.Vertex{a}.ATTRIBUTE.X2]; +end +fprintf( fid, 'g.layerextrude("%s",%g,%g)\n', NormDir, Elevation, Elevation+1 ); +fprintf( fid, 'g.poly(' ); +for n=1:numel(coords) + if n > 1 + fprintf( fid, ', %g', coords(n) ); + else + fprintf( fid, '%g', coords(n) ); + end +end +fprintf( fid, ')\n' ); + + + + +% ----------------------------------------------------------------------------- +function process_primitives( fid, prop, options ) +global current_layer_prio +ignore = {}; +if isfield(options,'ignore'), ignore = options.ignore; end + +% iterate over all properties and extract the priority +prio = []; +for num=1:numel(prop) + if isfield(prop{num}.Primitives,'Box') + for a=1:numel(prop{num}.Primitives.Box) + % iterate over all boxes + prio(end+1) = prop{num}.Primitives.Box{a}.ATTRIBUTE.Priority; + end + end + if isfield(prop{num}.Primitives,'Cylinder') + for a=1:numel(prop{num}.Primitives.Cylinder) + % iterate over all cylinders + prio(end+1) = prop{num}.Primitives.Cylinder{a}.ATTRIBUTE.Priority; + end + end + if isfield(prop{num}.Primitives,'Polygon') + for a=1:numel(prop{num}.Primitives.Polygon) + % iterate over all polygons + prio(end+1) = prop{num}.Primitives.Polygon{a}.ATTRIBUTE.Priority; + end + end +end +% Now prio is a vector full of priorities. Extract the priority, which is +% most often used. +u_prios = unique(prio); +count = histc(prio,u_prios); +[~,idx] = max(count); +current_layer_prio = u_prios(idx); + +% now export all properties/primitives +for num=1:numel(prop) + Name = prop{num}.ATTRIBUTE.Name; + if any( strcmp(Name,ignore) ) + disp( ['omitting ' Name '...'] ); + continue + end + + disp( ['processing ' prop{num}.ATTRIBUTE.Name '...'] ); + + if strcmp(options.Property,'Metal') + layertype = 'conductor'; + properties = [layertype ' sigma infinite sides auto rough 0 prio ' num2str(current_layer_prio) ' automodel auto']; + else + layertype = 'dielectric'; + epsr = 1; + sigma = 0; + if isfield(prop{num},'PropertyX') + if isfield(prop{num}.PropertyX.ATTRIBUTE,'Epsilon'), epsr = prop{num}.PropertyX.ATTRIBUTE.Epsilon; end + if isfield(prop{num}.PropertyX.ATTRIBUTE,'Kappa'), sigma = prop{num}.PropertyX.ATTRIBUTE.Kappa; end + end + properties = [layertype ' epsr ' num2str(epsr) ' sigma ' num2str(sigma) ' prio ' num2str(current_layer_prio) ' tand 0 density 0']; + end + + export_empire_layer( fid, Name, properties ) + + if isfield(prop{num}.Primitives,'Box') + for a=1:numel(prop{num}.Primitives.Box) + % iterate over all boxes + Box = prop{num}.Primitives.Box{a}; + primitive_box( fid, Box, layertype ); + end + end + if isfield(prop{num}.Primitives,'Cylinder') + for a=1:numel(prop{num}.Primitives.Cylinder) + % iterate over all cylinders + Cylinder = prop{num}.Primitives.Cylinder{a}; + primitive_cylinder( fid, Cylinder, layertype ); + end + end + if isfield(prop{num}.Primitives,'Wire') + for a=1:numel(prop{num}.Primitives.Wire) + % iterate over all wires + Wire = prop{num}.Primitives.Wire{a}; +% str = primitive_wire( Wire, obj_modifier ); +% fprintf( fid, '%s\n', str ); + end + warning( 'CSXCAD:export_empire', 'primitive wire currently unsupported' ); + end + if isfield(prop{num}.Primitives,'Polygon') + for a=1:numel(prop{num}.Primitives.Polygon) + % iterate over all polygons + Polygon = prop{num}.Primitives.Polygon{a}; + primitive_polygon( fid, Polygon, layertype ); + end + end + + fprintf( fid, 'g.load()\n\n' ); +end + + + + +function export_empire_layer( fid, name, layertext ) +fprintf( fid, '# create a new layer\n' ); +fprintf( fid, 'g = gmf()\n' ); +fprintf( fid, 'g.layer("%s")\n', name ); +fprintf( fid, 'g.layerextrude("z",0,0)\n' ); +fprintf( fid, 'g.layertext("%s")\n', layertext ); + +function export_empire_meshlines(fid,CSX) +fprintf( fid, '# create the mesh\n' ); +fprintf( fid, 'empty_disc()\n' ); +fprintf( fid, 'g = gmf()\n' ); +fprintf( fid, 'g.raw_write("DISC X %g")\n', CSX.RectilinearGrid.XLines ); +fprintf( fid, 'g.raw_write("DISC Y %g")\n', CSX.RectilinearGrid.YLines ); +fprintf( fid, 'g.raw_write("DISC Z %g")\n', CSX.RectilinearGrid.ZLines ); +fprintf( fid, 'g.load()\n\n' ); + +function empire_BC = convert_BC( openEMS_BC ) +if ischar(openEMS_BC) + if strcmp(openEMS_BC,'PEC') + empire_BC = 'electric'; + elseif strcmp(openEMS_BC,'PMC') + empire_BC = 'magnetic'; + elseif strncmp(openEMS_BC,'MUR',3) || strncmp(openEMS_BC,'PML',3) + empire_BC = 'pml 6'; + else + empire_BC = 'UNKNOWN'; + end +else + if openEMS_BC == 0 + empire_BC = 'electric'; + elseif openEMS_BC == 1 + empire_BC = 'magnetic'; + elseif openEMS_BC == 2 || openEMS_BC == 3 + empire_BC = 'pml 6'; + else + empire_BC = 'UNKNOWN'; + end +end + +function export_empire_settings(fid,CSX,FDTD) +fprintf( fid, '# settings\n' ); +fprintf( fid, 'set_fs_parameter( ''dx'', %g )\n', CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit ); +fprintf( fid, 'set_fs_parameter( ''xmin'', ''%s'' )\n', convert_BC(FDTD.BoundaryCond.ATTRIBUTE.xmin) ); +fprintf( fid, 'set_fs_parameter( ''xmax'', ''%s'' )\n', convert_BC(FDTD.BoundaryCond.ATTRIBUTE.xmax) ); +fprintf( fid, 'set_fs_parameter( ''ymin'', ''%s'' )\n', convert_BC(FDTD.BoundaryCond.ATTRIBUTE.ymin) ); +fprintf( fid, 'set_fs_parameter( ''ymax'', ''%s'' )\n', convert_BC(FDTD.BoundaryCond.ATTRIBUTE.ymax) ); +fprintf( fid, 'set_fs_parameter( ''zmin'', ''%s'' )\n', convert_BC(FDTD.BoundaryCond.ATTRIBUTE.zmin) ); +fprintf( fid, 'set_fs_parameter( ''zmax'', ''%s'' )\n', convert_BC(FDTD.BoundaryCond.ATTRIBUTE.zmax) ); +fprintf( fid, 'set_fs_parameter( ''f_0'', %g )\n', FDTD.Excitation.ATTRIBUTE.f0 ); +fprintf( fid, 'set_fs_parameter( ''f_c'', %g )\n', FDTD.Excitation.ATTRIBUTE.fc ); +f_start = max(0,FDTD.Excitation.ATTRIBUTE.f0 - FDTD.Excitation.ATTRIBUTE.fc); +f_end = max(0,FDTD.Excitation.ATTRIBUTE.f0 + FDTD.Excitation.ATTRIBUTE.fc); +fprintf( fid, 'set_fs_parameter( ''F_START'', %g )\n', f_start ); +fprintf( fid, 'set_fs_parameter( ''F_END'', %g )\n', f_end ); +fprintf( fid, 'set_fs_parameter( ''F_MID'', %g )\n', (f_start+f_end)/2 ); diff --git a/CSXCAD/matlab/export_excellon.m b/CSXCAD/matlab/export_excellon.m new file mode 100644 index 0000000..8877fcd --- /dev/null +++ b/CSXCAD/matlab/export_excellon.m @@ -0,0 +1,144 @@ +function export_excellon( CSX, filename, options ) +% export_excellon( CSX, filename, options ) +% +% Exports the geometry defined in CSX to filename as an excellon drill file. +% Only cylinders will be considered for export. +% The xy-plane is exported. +% +% CSX: CSX-object created by InitCSX() +% filename: export filename (e.g. '/tmp/export.gbr') +% options (optional): struct +% .header: (string) add this to the header of the file +% comment line must have ';' as the very first character +% .exclude: (cell array) ignore these CSX-properties +% .include: (cell array) include only these CSX-properties +% if neither .exclude or .include is specified, process all properties +% +% See also InitCSX +% CSXCAD matlab interface +% ----------------------- +% author: Sebastian Held +% 26. Aug 2010: initial version + + +if nargin < 3 + options = []; +end + +fid = fopen( filename, 'w' ); + +% create header +header = []; +header = [header 'M48\n']; +header = [header '; EXCELLON file written by CSXCAD\n' ]; +header = [header '; ' datestr(now) '\n' ]; +header = [header 'METRIC,LZ\n']; +header = [header 'VER,1\n']; +header = [header 'FMAT,1\n']; + +if isfield(options,'header') + header = [header options.header]; +end + +% determine the drawing unit +options.drawingunit = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit; + +if isfield(CSX.Properties,'Material') + % process material + Material = CSX.Properties.Material; + options.Property = 'Material'; + [tools,drill] = process_primitives( Material, options ); +end +if isfield(CSX.Properties,'Metal') + % process PEC + Metal = CSX.Properties.Metal; + options.Property = 'Metal'; + [tools_,drill_] = process_primitives( Metal, options ); + tools = unique( [tools tools_] ); + drill = [drill drill_]; +end + +% check the generated tools +[~,m] = unique( cellfun( @(x) x(1:3), tools, 'UniformOutput', 0 ) ); +if length(m) ~= numel(tools) + disp( 'the tool list is not unique:' ); + disp( tools ); + error( 'the tool list is not unique!' ); +end +a = unique( cellfun( @(x) x(4), tools, 'UniformOutput', 0 ) ); +if (length(a) > 1) || (a ~= 'C') + disp( 'the tool list has errors:' ); + disp( tools ); + error( 'the tool list has errors!' ); +end + +% convert cell array of strings to string +tools = char(cellfun( @(x)[x '\n'], tools )); +drill = char(cellfun( @(x)[x '\n'], drill )); + +% save the file +fprintf( fid, header ); +fprintf( fid, tools ); +fprintf( fid, '%s\n', 'M95' ); % end of program header +fprintf( fid, drill ); +fprintf( fid, '%s\n', 'M00' ); % end +fclose( fid ); + + +% ----------------------------------------------------------------------------- +function str = coord(v) +% str = coord(v) +% 2D-vector v takes coordinates in unit m +x = sprintf( '%.3f', v(1)*1e3 ); % mm +y = sprintf( '%.3f', v(2)*1e3 ); % mm +str = ['X' x 'Y' y]; + +% ----------------------------------------------------------------------------- +function [tool,drill] = primitive_cylinder( CSX_cylinder, drawingunit ) +start = [CSX_cylinder.P1.ATTRIBUTE.X CSX_cylinder.P1.ATTRIBUTE.Y] * drawingunit; +stop = [CSX_cylinder.P2.ATTRIBUTE.X CSX_cylinder.P2.ATTRIBUTE.Y] * drawingunit; +radius = CSX_cylinder.ATTRIBUTE.Radius * drawingunit; +if start(1:2) == stop(1:2) + % via in z-plane + dia_mm = radius * 2 * 1e3; % mm + tool = sprintf( 'T%02iC1.3f', round(dia_mm*10), dia_mm ); + drill = sprintf( 'T%02i\n%s', round(dia_mm*10), coord(start(1:2)) ); +else + disp( 'omitting primitive cylinder, because the projection onto the z-plane is not a circle' ); +end + + +% ----------------------------------------------------------------------------- +function [tools,drill] = process_primitives( prop, options ) +exclude = {}; +if isfield(options,'exclude'), exclude = options.exclude; end +for num=1:numel(prop) + Name = prop{num}.ATTRIBUTE.Name; + if any( strcmp(Name,exclude) ) + disp( ['omitting ' Name '...'] ); + continue + end + if isfield(options,'include') + include = options.include; + if ~any( strcmp(Name,include) ) + disp( ['omitting ' Name '...'] ); + continue + end + end + + tools = {}; + drill = {}; + + disp( ['processing ' prop{num}.ATTRIBUTE.Name '...'] ); + fprintf( fid, '%s\n', ['%LN' Name '*%'] ); + if isfield(prop{num}.Primitives,'Cylinder') + for a=1:numel(prop{num}.Primitives.Cylinder) + % iterate over all cylinders + Cylinder = prop{num}.Primitives.Cylinder{a}; + [tool,drill_] = primitive_cylinder( fid, Cylinder ); + tools = [tools tool]; + drill = [drill drill_]; + end + end +end + diff --git a/CSXCAD/matlab/export_gerber.m b/CSXCAD/matlab/export_gerber.m new file mode 100644 index 0000000..8a50f6f --- /dev/null +++ b/CSXCAD/matlab/export_gerber.m @@ -0,0 +1,198 @@ +function export_gerber( CSX, filename, options ) +% export_gerber( CSX, filename, options ) +% +% Exports the geometry defined in CSX to filename as a gerber RS-274X file. +% The xy-plane is exported. +% +% CSX: CSX-object created by InitCSX() +% filename: export filename (e.g. '/tmp/export.gbr') +% options (optional): struct +% .header: (string) add this to the header of the file +% .ignore: (cell array) ignore these CSX-properties +% +% See also InitCSX +% CSXCAD matlab interface +% ----------------------- +% author: Sebastian Held +% 13. Jun 2010: initial version + +%TODO: +% .include: (cell array) include only these CSX-properties +% if neither .ignore or .include is specified, process all properties + +if nargin < 3 + options = []; +end + +fid = fopen( filename, 'w' ); + +% write header +fprintf( fid, '%s\n', 'G04 gerber RS274X-file exported by openEMS*' ); +fprintf( fid, '%s\n', '%FSLAX66Y66*%' ); % leading zeros omitted; absolute coordinate values; 123456.123456 +fprintf( fid, '%s\n', '%MOMM*%' ); % set units to mm +fprintf( fid, '%s\n', '%INopenEMS export*%' ); % image name +fprintf( fid, '%s\n', '%ADD10C,0.00100*%' ); % aperture description +if isfield(options,'header') + fprintf( fid, '%s\n', header ); +end + +global drawingunit +drawingunit = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit; +global CoordSystem +CoordSystem = CSX.ATTRIBUTE.CoordSystem; + +if isfield(CSX.Properties,'Material') + % process material + Material = CSX.Properties.Material; + options.Property = 'Material'; + process_primitives( fid, Material, options ); +end +if isfield(CSX.Properties,'Metal') + % process PEC + Metal = CSX.Properties.Metal; + options.Property = 'Metal'; + process_primitives( fid, Metal, options ); +end + +fprintf( fid, '%s\n', 'M02*' ); % end of program +fclose( fid ); + + +% ----------------------------------------------------------------------------- +function str = gerber_coord(v, CoordSystem) +global drawingunit + +if (CoordSystem==1) + r = v(1); + a = v(2); + v(1) = r*cos(a) * drawingunit; + v(2) = r*sin(a) * drawingunit; +else + v(1) = v(1) * drawingunit; + v(2) = v(2) * drawingunit; +end +x = sprintf( '%+013i', round(v(1)*1e9) ); % mm +y = sprintf( '%+013i', round(v(2)*1e9) ); % mm +if (numel(x) ~= 13) || (numel(y) ~= 13) + error( ['gerber_coord(): coordinate transformation failed: x=' x ' y=' y] ); +end +str = ['X' x 'Y' y]; + +% ----------------------------------------------------------------------------- +function primitive_box( fid, CSX_box, CoordSystem ) +start = [CSX_box.P1.ATTRIBUTE.X CSX_box.P1.ATTRIBUTE.Y]; +stop = [CSX_box.P2.ATTRIBUTE.X CSX_box.P2.ATTRIBUTE.Y]; + +if (CoordSystem==0) + fprintf( fid, '%s\n', 'G36*' ); + fprintf( fid, '%s\n', [gerber_coord(start, CoordSystem) 'D02*'] ); + fprintf( fid, '%s\n', [gerber_coord([stop(1) start(2)], CoordSystem) 'D01*'] ); + fprintf( fid, '%s\n', [gerber_coord([stop], CoordSystem) 'D01*'] ); + fprintf( fid, '%s\n', [gerber_coord([start(1) stop(2)], CoordSystem) 'D01*'] ); + fprintf( fid, '%s\n', [gerber_coord(start, CoordSystem) 'D01*'] ); + fprintf( fid, '%s\n', 'G37*' ); +elseif (CoordSystem==1) + r = sort([start(1) stop(1)]); + a = sort([start(2) stop(2)]); + max_arc = 0.5*pi/180; + a = linspace(a(1),a(2),ceil((a(2)-a(1))/max_arc)); + + fprintf( fid, '%s\n', 'G36*' ); + fprintf( fid, '%s\n', [gerber_coord([r(1) a(1)], CoordSystem) 'D02*'] ); + + for ang = a(2:end) + fprintf( fid, '%s\n', [gerber_coord([r(1) ang], CoordSystem) 'D01*'] ); + end + + for ang = fliplr(a) + fprintf( fid, '%s\n', [gerber_coord([r(2) ang], CoordSystem) 'D01*'] ); + end + + fprintf( fid, '%s\n', [gerber_coord([r(1) a(1)], CoordSystem) 'D01*'] ); + fprintf( fid, '%s\n', 'G37*' ); +else + error 'unknown coordinate system' +end + +% ----------------------------------------------------------------------------- +function primitive_cylinder( fid, CSX_cylinder, CoordSystem ) +global drawingunit +start = [CSX_cylinder.P1.ATTRIBUTE.X CSX_cylinder.P1.ATTRIBUTE.Y]; +stop = [CSX_cylinder.P2.ATTRIBUTE.X CSX_cylinder.P2.ATTRIBUTE.Y]; +radius = CSX_cylinder.ATTRIBUTE.Radius * drawingunit; +if start(1:2) == stop(1:2) + % via => draw circle + fprintf( fid, '%%ADD10C,%f*%%\n', radius*2*1e3 ); % aperture definition (mm) + fprintf( fid, '%s\n', 'G54D10*' ); % select aperture D10 + fprintf( fid, '%s\n', [gerber_coord(start, CoordSystem) 'D03*'] ); % flash +else + disp( ['omitting primitive cylinder, because the projection onto the z-plane is not a circle'] ); +end + + +% ----------------------------------------------------------------------------- +function primitive_polygon( fid, CSX_polygon, CoordSystem ) +if CSX_polygon.ATTRIBUTE.NormDir ~= 2 + disp( ['omitting primitive polygon, because the normal direction is not 2'] ); +end +fprintf( fid, '%s\n', 'G36*' ); +v = [CSX_polygon.Vertex{1}.ATTRIBUTE.X1 CSX_polygon.Vertex{1}.ATTRIBUTE.X2]; +fprintf( fid, '%s\n', [gerber_coord(v, CoordSystem) 'D02*'] ); +for a=2:numel(CSX_polygon.Vertex) + % iterate over all vertices + v = [CSX_polygon.Vertex{a}.ATTRIBUTE.X1 CSX_polygon.Vertex{a}.ATTRIBUTE.X2]; + fprintf( fid, '%s\n', [gerber_coord(v, CoordSystem) 'D01*'] ); +end +fprintf( fid, '%s\n', 'G37*' ); + +% ----------------------------------------------------------------------------- +function primCoordSystem = GetCoordSystem(prim) +global CoordSystem +primCoordSystem = CoordSystem; +if (isfield(prim.ATTRIBUTE,'CoordSystem')) + primCoordSystem = prim.ATTRIBUTE.CoordSystem; +end + +% ----------------------------------------------------------------------------- +function process_primitives( fid, prop, options ) +ignore = {}; +if isfield(options,'ignore'), ignore = options.ignore; end +for num=1:numel(prop) + Name = prop{num}.ATTRIBUTE.Name; + if any( strcmp(Name,ignore) ) + disp( ['omitting ' Name '...'] ); + continue + end + if strcmp(options.Property,'Material') && ~isfield(prop{num}.Property.ATTRIBUTE,'Kappa') + disp( ['omitting ' Name ' (no Kappa-value)...'] ); + continue + end + + disp( ['processing ' prop{num}.ATTRIBUTE.Name '...'] ); + fprintf( fid, '%s\n', ['%LN' Name '*%'] ); + if ~isfield(prop{num},'Primitives') + continue + end + if isfield(prop{num}.Primitives,'Box') + for a=1:numel(prop{num}.Primitives.Box) + % iterate over all boxes + Box = prop{num}.Primitives.Box{a}; + primitive_box( fid, Box, GetCoordSystem(Box) ); + end + end + if isfield(prop{num}.Primitives,'Cylinder') + for a=1:numel(prop{num}.Primitives.Cylinder) + % iterate over all cylinders + Cylinder = prop{num}.Primitives.Cylinder{a}; + primitive_cylinder( fid, Cylinder, GetCoordSystem(Cylinder) ); + end + end + if isfield(prop{num}.Primitives,'Polygon') + for a=1:numel(prop{num}.Primitives.Polygon) + % iterate over all polygons + Polygon = prop{num}.Primitives.Polygon{a}; + primitive_polygon( fid, Polygon, GetCoordSystem(Polygon) ); + end + end +end + diff --git a/CSXCAD/matlab/export_povray.m b/CSXCAD/matlab/export_povray.m new file mode 100644 index 0000000..a53cb13 --- /dev/null +++ b/CSXCAD/matlab/export_povray.m @@ -0,0 +1,237 @@ +function export_povray( CSX, filename, options ) +% export_povray( CSX, filename, options ) +% +% Exports the geometry defined in CSX to filename as a povray file. +% +% CSX: CSX-object created by InitCSX() +% filename: export filename (e.g. '/tmp/export.pov') +% options (optional): struct +% .camera: (string) use this as the camera definition line +% 1 camera on positive x-axis +% 2 camera on positive y-axis +% 3 camera on positive z-axis +% .light: (string) use this as the light definition line +% 1 point light at camera position +% .header: (string) add this to the header of the file +% .ignore: (cell array) ignore these CSX-properties +% .obj_modifier: struct +% .: (string) povray object modifier for corresponding primitives +% example: options.obj_modifier.copper = 'pigment { color rgbt <0.8,0.5,0,0> }'; +% +% See also InitCSX +% CSXCAD matlab interface +% ----------------------- +% author: Sebastian Held +% 12. Jun 2010: initial version + +if nargin < 3 + options = []; +end + +fid = fopen( filename, 'w' ); + +% write header +fprintf( fid, '%s\n', '// povray-file exported by openEMS' ); +fprintf( fid, '%s\n', '#include "colors.inc"' ); +fprintf( fid, '%s\n', '#include "metals.inc"' ); +fprintf( fid, '%s\n', '#include "textures.inc"' ); +fprintf( fid, '%s\n', '#include "transforms.inc"' ); +fprintf( fid, '%s\n', 'background { color rgb<1.000000,1.000000,1.000000> }' ); +if isfield(options,'header') + fprintf( fid, '%s\n', header ); +end + +if isfield(CSX.Properties,'Material') + % process material + Material = CSX.Properties.Material; + process_primitives( fid, Material, 'pigment { color rgbt <0.000, 0.533, 0.800,0.0> } finish { diffuse 0.6 }', options ); +end +if isfield(CSX.Properties,'Metal') + % process PEC + Metal = CSX.Properties.Metal; + process_primitives( fid, Metal, 'texture { Copper_Metal }', options ); +end + +% create coordinate system vectors (for debugging) +debug_coords = 0; +if debug_coords + fprintf( fid, [... + '#macro Axis_( AxisLen, RedTexture,WhiteTexture) \n' ... + 'union{\n' ... + ' cylinder {<0,-AxisLen,0>,<0,AxisLen,0>,0.5\n' ... + ' texture{checker texture{RedTexture} \n' ... + ' texture{WhiteTexture}\n' ... + ' translate<0.1,0,0.1>}}\n' ... + ' cone{<0,AxisLen,0>,2,<0,AxisLen+0.7,0>,0\n' ... + ' texture{RedTexture}}\n' ... + ' } // end of union \n' ... + '#end // of macro "Axis( )"\n' ... + '\n' ... + '#macro AxisXYZ( AxisLenX, AxisLenY, AxisLenZ, TexRed, TexWhite)\n' ... + 'union{\n' ... + ' object{Axis_(AxisLenX, TexRed, TexWhite) rotate< 0,0,-90>} // x axis\n' ... + ' object{Axis_(AxisLenY, TexRed, TexWhite) rotate< 0,0, 0>} // y axis \n' ... + ' object{Axis_(AxisLenZ, TexRed, TexWhite) rotate<90,0, 0>} // z axis\n' ... + ' text{ ttf"timrom.ttf", "x", 0.15, 0 texture{TexRed} \n' ... + ' scale 10 translate }\n' ... + ' text{ ttf"timrom.ttf", "y", 0.15, 0 texture{TexRed} \n' ... + ' scale 10 translate <-0.75,AxisLenY+0.50,-0.00>}\n' ... + ' text{ ttf"timrom.ttf", "z", 0.15, 0 texture{TexRed} \n' ... + ' scale 10 translate <-0.75,0.2,AxisLenZ+0.50>}\n' ... + ' scale <1000,1000,1000>\n' ... + '} // end of union\n' ... + '#end// of macro\n' ... + '\n' ... + 'object{AxisXYZ( 10, 10, 10, texture{ pigment{rgb<1,0,0>} finish{ phong 1}}, texture{ pigment{rgb<1,1,1>} finish{ phong 1}} )}\n' ... + ''] ); +end + +% create camera and light +xmin = min(CSX.RectilinearGrid.XLines); +xmax = max(CSX.RectilinearGrid.XLines); +ymin = min(CSX.RectilinearGrid.YLines); +ymax = max(CSX.RectilinearGrid.YLines); +zmin = min(CSX.RectilinearGrid.ZLines); +zmax = max(CSX.RectilinearGrid.ZLines); +center = [(xmin+xmax)/2 (ymin+ymax)/2 (zmin+zmax)/2]; +% default camera +camera_pos = [center(1), ymin, zmax+sqrt((xmax-xmin)^2+(ymax-ymin)^2)]; +camera = ['camera {location ' pov_vect(camera_pos) ' right <-1.33,0,0> look_at ' pov_vect(center) ' angle 40}']; % right-handed coordinate system +if isfield(options,'camera') + if ischar(options.camera) + camera = options.camera; + elseif options.camera == 1 + % looking from positive x-axis + camera_pos = [xmax+sqrt((ymax-ymin)^2+(zmax-zmin)^2), 0, 0]; + camera = ['camera {location ' pov_vect(camera_pos) ' right <-1.33,0,0> look_at ' pov_vect(center) ' angle 40}']; + elseif options.camera == 2 + % looking from positive y-axis + camera_pos = [0, ymax+sqrt((xmax-xmin)^2+(zmax-zmin)^2), 0]; + camera = ['camera {location ' pov_vect(camera_pos) ' right <-1.33,0,0> look_at ' pov_vect(center) ' angle 40}']; + elseif options.camera == 3 + % looking from positive z-axis + camera_pos = [0, 0, zmax+sqrt((xmax-xmin)^2+(ymax-ymin)^2)]; + camera = ['camera {location ' pov_vect(camera_pos) ' right <-1.33,0,0> look_at ' pov_vect(center) ' angle 40}']; + end +end +fprintf( fid, '%s\n', camera ); +% default light +light = 'light_source { <3500,-3500,10000> White area_light <10000, 0, 0>, <0, 10000, 0>, 2, 2 adaptive 1 }'; +if isfield(options,'light') + if ischar(options.light) + light = options.light; + elseif options.light == 1 + % point light at position of camera + light = ['light_source { ' pov_vect(camera_pos) ', rgb <1,1,1> }']; + end +end +fprintf( fid, '%s\n', light ); + +fclose( fid ); + +% ----------------------------------------------------------------------------- +function str = pov_vect( vec ) +if numel(vec) == 3 + str = ['<' num2str(vec(1)) ',' num2str(vec(2)) ',' num2str(vec(3)) '>']; +else + str = ['<' num2str(vec(1)) ',' num2str(vec(2)) '>']; +end + +% ----------------------------------------------------------------------------- +function str = primitive_box( CSX_box, options ) +start = [CSX_box.P1.ATTRIBUTE.X CSX_box.P1.ATTRIBUTE.Y CSX_box.P1.ATTRIBUTE.Z]; +stop = [CSX_box.P2.ATTRIBUTE.X CSX_box.P2.ATTRIBUTE.Y CSX_box.P2.ATTRIBUTE.Z]; +if any( start == stop ) + % 2D box + % povray supports 2D polygons, but has no priority concept, therefore use the box primitive + epsilon = 1; % FIXME this should be small compared to any other linear dimension of any object in the scene + epsilon = (start == stop) * epsilon; % select identical components + start = start - epsilon; + stop = stop + epsilon; +end +str = ['box { ' pov_vect(start) ', ' pov_vect(stop) ' ' options '}']; + +% ----------------------------------------------------------------------------- +function str = primitive_cylinder( CSX_cylinder, options ) +start = [CSX_cylinder.P1.ATTRIBUTE.X CSX_cylinder.P0.ATTRIBUTE.Y CSX_cylinder.P1.ATTRIBUTE.Z]; +stop = [CSX_cylinder.P2.ATTRIBUTE.X CSX_cylinder.P1.ATTRIBUTE.Y CSX_cylinder.P2.ATTRIBUTE.Z]; +radius = CSX_cylinder.ATTRIBUTE.Radius; +str = ['cylinder { ' pov_vect(start) ', ' pov_vect(stop) ', ' num2str(radius) ' ' options '}']; + +% ----------------------------------------------------------------------------- +function str = primitive_wire( CSX_wire, options ) +radius = CSX_wire.ATTRIBUTE.WireRadius; +str = ['sphere_sweep { linear_spline, ' num2str(numel(CSX_wire.Vertex))]; +for a=1:numel(CSX_wire.Vertex) + % iterate over all vertices + v = [CSX_wire.Vertex{a}.ATTRIBUTE.X CSX_wire.Vertex{a}.ATTRIBUTE.Y CSX_wire.Vertex{a}.ATTRIBUTE.Z]; + str = [str ', ' pov_vect(v) ', ' num2str(radius)]; +end +str = [str ' ' options '}']; + +% ----------------------------------------------------------------------------- +function str = primitive_polygon( CSX_polygon, options ) +Elevation = -CSX_polygon.ATTRIBUTE.Elevation; +% NormDir = CSX_polygon.ATTRIBUTE.NormDir; +epsilon = 1; % FIXME this should be small compared to any other linear dimension of any object in the scene +str = ['prism { linear_spline linear_sweep ' num2str(Elevation - epsilon) ', ' num2str(Elevation + epsilon) ', ' num2str(numel(CSX_polygon.Vertex)+1)]; +for a=1:numel(CSX_polygon.Vertex) + % iterate over all vertices + v = [CSX_polygon.Vertex{a}.ATTRIBUTE.X1 CSX_polygon.Vertex{a}.ATTRIBUTE.X2]; + str = [str ', ' pov_vect(v)]; +end +v = [CSX_polygon.Vertex{1}.ATTRIBUTE.X1 CSX_polygon.Vertex{1}.ATTRIBUTE.X2]; % close prism +str = [str ', ' pov_vect(v)]; +% str = [str ' ' options ' Point_At_Trans(' pov_vect(NormDir) ')}']; % needs transforms.inc +str = [str ' ' options ' rotate<-90,0,0> }']; + +% ----------------------------------------------------------------------------- +function process_primitives( fid, prop, default_obj_modifier, options ) +ignore = {}; +if isfield(options,'ignore'), ignore = options.ignore; end +for num=1:numel(prop) + Name = prop{num}.ATTRIBUTE.Name; + if any( strcmp(Name,ignore) ) + disp( ['omitting ' Name '...'] ); + continue + end + obj_modifier = default_obj_modifier; + if isfield(options,'obj_modifier') && isfield(options.obj_modifier,Name) + obj_modifier = options.obj_modifier.(Name); + end + disp( ['processing ' prop{num}.ATTRIBUTE.Name '...'] ); + fprintf( fid, '%s\n', ['// ' Name] ); + if isfield(prop{num}.Primitives,'Box') + for a=1:numel(prop{num}.Primitives.Box) + % iterate over all boxes + Box = prop{num}.Primitives.Box{a}; + str = primitive_box( Box, obj_modifier ); + fprintf( fid, '%s\n', str ); + end + end + if isfield(prop{num}.Primitives,'Cylinder') + for a=1:numel(prop{num}.Primitives.Cylinder) + % iterate over all cylinders + Cylinder = prop{num}.Primitives.Cylinder{a}; + str = primitive_cylinder( Cylinder, obj_modifier ); + fprintf( fid, '%s\n', str ); + end + end + if isfield(prop{num}.Primitives,'Wire') + for a=1:numel(prop{num}.Primitives.Wire) + % iterate over all wires + Wire = prop{num}.Primitives.Wire{a}; + str = primitive_wire( Wire, obj_modifier ); + fprintf( fid, '%s\n', str ); + end + end + if isfield(prop{num}.Primitives,'Polygon') + for a=1:numel(prop{num}.Primitives.Polygon) + % iterate over all polygons + Polygon = prop{num}.Primitives.Polygon{a}; + str = primitive_polygon( Polygon, obj_modifier ); + fprintf( fid, '%s\n', str ); + end + end +end + diff --git a/CSXCAD/matlab/isOctave.m b/CSXCAD/matlab/isOctave.m new file mode 100644 index 0000000..b536e48 --- /dev/null +++ b/CSXCAD/matlab/isOctave.m @@ -0,0 +1,46 @@ +function [isOct,ver] = isOctave() +% [isOct,version] = isOctave() +% +% Function to test if matlab or octave is used. +% +% Output: +% isOct: bool; true, if interpreter is Octave +% version: struct +% .major: number; major version +% .minor: number; minor version +% .release: number; release version +% +% example (Octave 3.6.1): +% isOct = true +% version.major = 3 +% version.minor = 6 +% version.release = 1 +% +% example (Matlab 7.8.0.347 (R2009a)): +% isOct = false +% version.major = 7 +% version.minor = 8 +% version.release = 0 +% +% openEMS matlab/octave interface +% ----------------------- +% (C) 2011 Thorsten Liebig +% (C) 2012 Sebastian Held + +isOct = exist('OCTAVE_VERSION','builtin') ~= 0; + +if (isOct) + ver_cell = strsplit( OCTAVE_VERSION, '.' ); +else + remain = version(); + ver_cell = {}; + while ~isempty(remain) + [str, remain] = strtok(remain, '.'); + ver_cell{end+1} = str; + end +end + +ver = []; +ver.major = str2double(ver_cell{1}); +ver.minor = str2double(ver_cell{2}); +ver.release = str2double(ver_cell{3}); diff --git a/CSXCAD/matlab/private/Add2Property.m b/CSXCAD/matlab/private/Add2Property.m new file mode 100644 index 0000000..e38ddc9 --- /dev/null +++ b/CSXCAD/matlab/private/Add2Property.m @@ -0,0 +1,26 @@ +function CSX = Add2Property(CSX, propName, newPrim, primName) +% function CSX = Add2Property(CSX, propName, newPrim, primName) +% +% meant for internal use!! +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +type = GetPropertyType(CSX, propName); +if isempty(type) + error('CSXCAD:Add2Property',['the type for the property "' propName '" cannot be found']); +end + +pos = GetPropertyPosition(CSX, type, propName); +if (pos==0) + error('CSXCAD:Add2Property',['property "' propName '" of type "' type '" not found!']); +end + +if ~isfield(CSX.Properties.(type){pos}, 'Primitives') + CSX.Properties.(type){pos}.Primitives.(primName){1}=newPrim; +elseif ~isfield(CSX.Properties.(type){pos}.Primitives, primName) + CSX.Properties.(type){pos}.Primitives.(primName){1}=newPrim; +else + CSX.Properties.(type){pos}.Primitives.(primName){end+1}=newPrim; +end diff --git a/CSXCAD/matlab/private/AddPrimitiveArgs.m b/CSXCAD/matlab/private/AddPrimitiveArgs.m new file mode 100644 index 0000000..df3cf28 --- /dev/null +++ b/CSXCAD/matlab/private/AddPrimitiveArgs.m @@ -0,0 +1,28 @@ +function primitive = AddPrimitiveArgs(primitive, varargin) +% prim = AddPrimitiveArgs(primitive, varargin) +% +% meant for internal use only +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +transform = []; + +for n=1:2:(nargin-2) + if (strcmp(varargin{n},'Transform')) + transform = varargin([n:n+1]); + varargin([n:n+1]) = []; + break + end +end + +for n=1:2:numel(varargin) + primitive.ATTRIBUTE.(varargin{n}) = varargin{n+1}; +end + +if ~isempty(transform) + for n=1:2:numel(transform{2}) + primitive.Transformation.(transform{2}{n}).ATTRIBUTE.Argument=transform{2}{n+1}; + end +end diff --git a/CSXCAD/matlab/private/AddProperty.m b/CSXCAD/matlab/private/AddProperty.m new file mode 100644 index 0000000..ec4c2ed --- /dev/null +++ b/CSXCAD/matlab/private/AddProperty.m @@ -0,0 +1,29 @@ +function [CSX pos] = AddProperty(CSX, type, name, varargin) +% function [CSX pos] = AddProperty(CSX, type, name, varargin) +% +% internal function to add a property to CSX.Properties +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +% check if this property already exists +[type_found pos] = FindProperty(CSX, name); +if (pos>0) + error('CSXCAD:AddProperty',['property with name "' name '" with type "' type_found '" already exists! Choose a different name!']); +end + +if isfield(CSX.Properties,type) + pos = numel(CSX.Properties.(type))+1; +else + CSX.Properties.(type) = {}; % create cell array + pos = 1; +end + +CSX.Properties.(type){pos}.ATTRIBUTE.Name=name; +for n=1:numel(varargin)/2 + if ~ischar(varargin{2*n-1}) + error(['CSXCAD::AddProperty: not an attribute: ' varargin{2*n-1}]); + end + CSX.Properties.(type){pos}.ATTRIBUTE.(varargin{2*n-1})=varargin{2*n}; +end diff --git a/CSXCAD/matlab/private/CheckSymmtricLines.m b/CSXCAD/matlab/private/CheckSymmtricLines.m new file mode 100644 index 0000000..6106d63 --- /dev/null +++ b/CSXCAD/matlab/private/CheckSymmtricLines.m @@ -0,0 +1,34 @@ +function result = CheckSymmtricLines(lines) +% function result = CheckSymmtricLines(lines) +% +% check mesh lines for symmetry +% +% Note: make sure lines are sorted and unique +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (C) 2012 + +result = false; + +tolerance = 1e-10; +NP = numel(lines); +range = lines(end)-lines(1); +center = 0.5*(lines(end)+lines(1)); + +% check all lines for symmetry +for n=1:NP/2 + if (abs((center-lines(n))-(lines(end-n+1)-center)) > range*tolerance/NP) + return; + end +end + +% check central point to be symmetry-center +if (mod(NP,2)) + if (abs(lines((NP+1)/2)-center) > range*tolerance/NP) + return; + end +end + +% if all checks pass, return true +result = true; diff --git a/CSXCAD/matlab/private/FindProperty.m b/CSXCAD/matlab/private/FindProperty.m new file mode 100644 index 0000000..1df5ef6 --- /dev/null +++ b/CSXCAD/matlab/private/FindProperty.m @@ -0,0 +1,17 @@ +function [type pos] = FindProperty(CSX, name) +% function [type pos] = FindProperty(CSX, name) +% +% internal function to find a given property +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (c) 2013 + +pos = 0; +type = GetPropertyType(CSX, name); + +if isempty(type) + return; +end + +pos = GetPropertyPosition(CSX, type, name); diff --git a/CSXCAD/matlab/private/GetPropertyPosition.m b/CSXCAD/matlab/private/GetPropertyPosition.m new file mode 100644 index 0000000..8305876 --- /dev/null +++ b/CSXCAD/matlab/private/GetPropertyPosition.m @@ -0,0 +1,41 @@ +function pos = GetPropertyPosition(CSX, type, name) +% function pos = GetPropertyPosition(CSX, type, name) +% +% - internal function to get the position of property with name: +% inside a given type +% - function will perform a series of validitiy tests +% - will return 0 if not found +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (c) 2013 + +pos = 0; + +if ~ischar(name) + error('CSXCAD::GetPropertyPosition: name must be a string'); +end + +if ~ischar(type) + error('CSXCAD::GetPropertyPosition: type name must be a string'); +end + +if ~isfield(CSX,'Properties') + error('CSXCAD:GetPropertyPosition','CSX.Properties is not defined'); +end + +if isempty(type) + error('CSXCAD:GetPropertyPosition','type is empty, maybe the property you requested is undefined'); +end + +% type not (yet) defined, thus not found +if ~isfield(CSX.Properties,type) + return +end + +for n=1:numel(CSX.Properties.(type)) + if strcmp(CSX.Properties.(type){n}.ATTRIBUTE.Name, name) + pos=n; + return + end +end diff --git a/CSXCAD/matlab/private/GetPropertyType.m b/CSXCAD/matlab/private/GetPropertyType.m new file mode 100644 index 0000000..5a63dff --- /dev/null +++ b/CSXCAD/matlab/private/GetPropertyType.m @@ -0,0 +1,30 @@ +function type_name = GetPropertyType(CSX, name) +% function type_name = GetPropertyType(CSX, name) +% +% internal function to get the type of a given property +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig (c) 2010-2013 + +if ~ischar(name) + error('CSXCAD::GetPropertyType: name must be a string'); +end +if ~isfield(CSX,'Properties') + error('CSXCAD:GetPropertyPosition','CSX.Properties is not defined'); +end + +type_name = ''; +if isempty(CSX.Properties) + return +end + +prop_types = fieldnames(CSX.Properties); +for n=1:numel(prop_types) + for p = 1:numel(CSX.Properties.(prop_types{n})) + if (strcmp(CSX.Properties.(prop_types{n}){p}.ATTRIBUTE.Name,name)) + type_name = prop_types{n}; + return; + end + end +end diff --git a/CSXCAD/matlab/private/SetPropertyArgs.m b/CSXCAD/matlab/private/SetPropertyArgs.m new file mode 100644 index 0000000..893a642 --- /dev/null +++ b/CSXCAD/matlab/private/SetPropertyArgs.m @@ -0,0 +1,16 @@ +function CSX = SetPropertyArgs(CSX, type, name, property, varargin) +% CSX = SetPropertyArgs(CSX, type, name, property, varargin) +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +pos = GetPropertyPosition(CSX, type, name); + +if (pos==0) + error('CSXCAD:SetPropertyArgs',['property "' name '" of type "' type '" not found!']); +end + +for n=1:numel(varargin)/2 + CSX.Properties.(type){pos}.(property).ATTRIBUTE.(varargin{2*n-1}) = varargin{2*n}; +end diff --git a/CSXCAD/matlab/private/SmoothRange.m b/CSXCAD/matlab/private/SmoothRange.m new file mode 100644 index 0000000..d36db70 --- /dev/null +++ b/CSXCAD/matlab/private/SmoothRange.m @@ -0,0 +1,58 @@ +function [ lines ] = SmoothRange(start, stop, start_res, stop_res, max_res, ratio) +%function [ lines ] = SmoothRange(start, stop, start_res, stop_res, max_res, ratio) +% +% internal function only, use SmoothMeshLines instead +% +% See also SmoothMeshLines +% +% CSXCAD matlab interface +% ----------------------- +% author: Thorsten Liebig + +if (nargin<6) + ratio = 1.3; +end + +taper = start_res*ratio; +start_taper = start; +while (taperdiff_stop(1)) + start_taper = start_taper(1:end-1); + else + stop_taper = stop_taper(2:end); + end + + if (numel(stop_taper)==0) || (numel(start_taper)==0) + break + end +end + +if (numel(stop_taper)==0) || (numel(start_taper)==0) + lines = unique([start_taper stop_taper]); +else + numL = ceil((stop_taper(1) - start_taper(end))/max_res)+1; + lines = unique([start_taper linspace(start_taper(end),stop_taper(1),numL) stop_taper]); +end \ No newline at end of file diff --git a/CSXCAD/matlab/private/octave_struct2xml_2.m b/CSXCAD/matlab/private/octave_struct2xml_2.m new file mode 100644 index 0000000..3ebc549 --- /dev/null +++ b/CSXCAD/matlab/private/octave_struct2xml_2.m @@ -0,0 +1,57 @@ +function out = octave_struct2xml_2( in, rootName, indent ) + +out = [indent '<' rootName]; + +float_accuracy = 15; + +% process attributes +if isstruct( in ) + fnames = fieldnames( in ); + for n=1:numel(fnames) + current_field = fnames{n}; + if strcmp( current_field, 'ATTRIBUTE' ) + attributes = fieldnames( in.ATTRIBUTE ); + for m=1:numel( attributes ) + temp = in.ATTRIBUTE.(attributes{m}); + if ~ischar( temp ) + temp = vector2str( temp, float_accuracy ); + end + out = [out ' ' attributes{m} '="' temp '"']; + end + break + end + end +end + +out = [out '>']; + + +% process content +if ~isstruct( in ) + if ~ischar( in ) + temp = vector2str(in, float_accuracy); + else + temp = in; + end + out = [out temp '\n']; + return +end + +out = [out '\n']; + +fnames = fieldnames( in ); +for n=1:numel(fnames) + current_field = fnames{n}; + if strcmp( current_field, 'ATTRIBUTE' ) + continue + end + if iscell( in.(current_field) ) + for m=1:numel( in.(current_field) ) + out = [out octave_struct2xml_2( in.(current_field){m}, current_field, [indent ' '] )]; + end + else + out = [out octave_struct2xml_2( in.(current_field), current_field, [indent ' '] )]; + end +end + +out = [out indent '\n']; diff --git a/CSXCAD/matlab/private/struct_2_xmlNode.m b/CSXCAD/matlab/private/struct_2_xmlNode.m new file mode 100644 index 0000000..207632f --- /dev/null +++ b/CSXCAD/matlab/private/struct_2_xmlNode.m @@ -0,0 +1,48 @@ +function docElem = struct_2_xmlNode(docNode, docElem, mat_struct) + +if (isfield(mat_struct,'ATTRIBUTE')) + names = fieldnames(mat_struct.ATTRIBUTE); + for n=1:numel(names) + if isnumeric(getfield(mat_struct.ATTRIBUTE,names{n})) || islogical(getfield(mat_struct.ATTRIBUTE,names{n})) + docElem.setAttribute(names{n},vector2str(getfield(mat_struct.ATTRIBUTE,names{n}),15)); + else + docElem.setAttribute(names{n},getfield(mat_struct.ATTRIBUTE,names{n})); + end + end + mat_struct = rmfield(mat_struct,'ATTRIBUTE'); +end + +names = fieldnames(mat_struct); + +for n=1:numel(names) + if isstruct(getfield(mat_struct,names{n})) + docNewElem = docNode.createElement(names{n}); + docNewElem = struct_2_xmlNode(docNode, docNewElem, getfield(mat_struct,names{n})); + docElem.appendChild(docNewElem); + elseif iscell(getfield(mat_struct,names{n})) + cellfield = getfield(mat_struct,names{n}); + for m=1:numel(cellfield) + if ischar(cellfield{m}) + docNewElem = docNode.createElement(names{n}); + docNewElem.appendChild(docNode.createTextNode(cellfield{m})); + docElem.appendChild(docNewElem); + else + docNewElem = docNode.createElement(names{n}); + docNewElem = struct_2_xmlNode(docNode, docNewElem, cellfield{m}); + docElem.appendChild(docNewElem); + end + end + elseif isempty(getfield(mat_struct,names{n})) + %do nothing... + elseif isnumeric(getfield(mat_struct,names{n})) + number = getfield(mat_struct,names{n}); + str = vector2str(number,15); + docNewElem = docNode.createElement(names{n}); + docNewElem.appendChild(docNode.createTextNode(str)); + docElem.appendChild(docNewElem); + elseif ischar(getfield(mat_struct,names{n})) + docNewElem = docNode.createElement(names{n}); + docNewElem.appendChild(docNode.createTextNode(getfield(mat_struct,names{n}))); + docElem.appendChild(docNewElem); + end +end diff --git a/CSXCAD/matlab/private/vector2str.m b/CSXCAD/matlab/private/vector2str.m new file mode 100644 index 0000000..5e3685b --- /dev/null +++ b/CSXCAD/matlab/private/vector2str.m @@ -0,0 +1,35 @@ +function str = vector2str(vec, acc) +% str = vector2str( vec [, acc] ) +% +% internal function for CSXCAD +% +% (c) 2012-2015 Thorsten Liebig +% (C) 2012 Sebastian Held + +str = ''; + +if (numel(vec)==0) + return +end + +if (nargin<2) + acc = 9; +end + +% Octave < 3.8.0 has a bug in num2str() (only 64bit versions) +% see bug report https://savannah.gnu.org/bugs/index.php?36121 +[isOct,version] = isOctave(); +if (isOct && version.major <= 3 && version.minor < 8) + % affected Octave versions + for n = 1:numel(vec) + str = [str sprintf('%.*g', acc, vec(n)) ',']; + end +else + % Matlab and non affected Octave + for n = 1:numel(vec) + str = [str num2str(vec(n),acc) ',']; + end +end + +% remove the last ',' +str = str(1:end-1); diff --git a/CSXCAD/matlab/searchBinary.m b/CSXCAD/matlab/searchBinary.m new file mode 100644 index 0000000..6310dde --- /dev/null +++ b/CSXCAD/matlab/searchBinary.m @@ -0,0 +1,47 @@ +function [binary_location] = searchBinary(name, searchpath, err_fail) +% [binary_location] = searchBinary(name, searchpath<, err_fail>) +% +% Function to search for executable. If the executable isn't found +% in searchpath, look in environment search path. +% +% parameter: +% name: name of the binary to search +% searchpath: (list of) search paths +% err_fail: 0/1, throw an error if binary is not found (default is 1) +% +% Output: +% binary_location: +% if found in searchpath: full path of binary +% if found in environment search path: name of binary +% if not found: empty string +% +% +% openEMS matlab/octave interface +% ----------------------- +% (C) 2013 Stefan Mahr + +if (nargin<3) + err_fail = 1; +end + +if ischar(searchpath) + searchpath = {searchpath}; +end + +% append PATH search paths +searchpath = [searchpath regexp(getenv('PATH'), pathsep, 'split')]; + +% try all search paths +for n=1:numel(searchpath) + binary_location = [searchpath{n} name]; + if exist(binary_location, 'file') + return + end +end + +% binary not found +binary_location = ''; + +if (err_fail) + error('CSXCAD:binary_location', [name ' binary not found!']); +end diff --git a/CSXCAD/matlab/struct_2_xml.m b/CSXCAD/matlab/struct_2_xml.m new file mode 100644 index 0000000..73c0a30 --- /dev/null +++ b/CSXCAD/matlab/struct_2_xml.m @@ -0,0 +1,23 @@ +function struct_2_xml(filename, xml_struct, rootName); + +if ~isOctave() + docNode = com.mathworks.xml.XMLUtils.createDocument(rootName); + docElem = docNode.getDocumentElement; + + docElem = struct_2_xmlNode(docNode, docElem, xml_struct); + + % Save the sample XML document. + xmlFileName = [filename]; + xmlwrite(xmlFileName,docNode); +else +% % for octave you need the octave_xmltoolbox (C) 2007 Thomas Geiger +% % http://wiki.octave.org/wiki.pl?XMLToolboxPort +% xml_struct = octave_struct2xml( xml_struct, rootName ); +% xml_save( filename, xml_struct, 'any' ); + +% xml_toolbox is buggy (sequence of elements is not preserved) + fid = fopen( filename, 'w' ); + fprintf( fid, '\n' ); + fprintf( fid, octave_struct2xml_2(xml_struct,rootName,'') ); + fclose( fid ); +end diff --git a/CSXCAD/src/CMakeLists.txt b/CSXCAD/src/CMakeLists.txt new file mode 100644 index 0000000..8903a60 --- /dev/null +++ b/CSXCAD/src/CMakeLists.txt @@ -0,0 +1,105 @@ + +set( PUB_HEADERS + ContinuousStructure.h + CSPrimitives.h + CSProperties.h + CSRectGrid.h + CSXCAD_Global.h + ParameterObjects.h + CSFunctionParser.h + CSUseful.h + ParameterCoord.h + CSTransform.h + CSBackgroundMaterial.h + CSPrimPoint.h + CSPrimBox.h + CSPrimMultiBox.h + CSPrimSphere.h + CSPrimSphericalShell.h + CSPrimCylinder.h + CSPrimCylindricalShell.h + CSPrimPolygon.h + CSPrimLinPoly.h + CSPrimRotPoly.h + CSPrimPolyhedron.h + CSPrimPolyhedronReader.h + CSPrimCurve.h + CSPrimWire.h + CSPrimUserDefined.h + CSPropUnknown.h + CSPropMaterial.h + CSPropDispersiveMaterial.h + CSPropLorentzMaterial.h + CSPropDebyeMaterial.h + CSPropDiscMaterial.h + CSPropLumpedElement.h + CSPropMetal.h + CSPropConductingSheet.h + CSPropExcitation.h + CSPropProbeBox.h + CSPropDumpBox.h + CSPropResBox.h +) + +set(SOURCES + ContinuousStructure.cpp + CSPrimitives.cpp + CSProperties.cpp + CSRectGrid.cpp + ParameterObjects.cpp + CSFunctionParser.cpp + CSUseful.cpp + ParameterCoord.cpp + CSTransform.cpp + CSPrimPoint.cpp + CSPrimBox.cpp + CSPrimMultiBox.cpp + CSPrimSphere.cpp + CSPrimSphericalShell.cpp + CSPrimCylinder.cpp + CSPrimCylindricalShell.cpp + CSPrimPolygon.cpp + CSPrimLinPoly.cpp + CSPrimRotPoly.cpp + CSPrimPolyhedron.cpp + CSPrimPolyhedronReader.cpp + CSPrimCurve.cpp + CSPrimWire.cpp + CSPrimUserDefined.cpp + CSPropUnknown.cpp + CSPropMaterial.cpp + CSPropDispersiveMaterial.cpp + CSPropLorentzMaterial.cpp + CSPropDebyeMaterial.cpp + CSPropDiscMaterial.cpp + CSPropLumpedElement.cpp + CSPropMetal.cpp + CSPropConductingSheet.cpp + CSPropExcitation.cpp + CSPropProbeBox.cpp + CSPropDumpBox.cpp + CSPropResBox.cpp + CSBackgroundMaterial.cpp +) + +# CSXCAD library +add_library( CSXCAD SHARED ${SOURCES} ) + +TARGET_LINK_LIBRARIES( CSXCAD + ${fparser_LIBRARIES} + ${TinyXML_LIBRARIES} + ${HDF5_LIBRARIES} + ${HDF5_HL_LIBRARIES} + CGAL + ${Boost_LIBRARIES} + ${vtk_LIBS} +) + +set_target_properties(CSXCAD PROPERTIES VERSION ${LIB_VERSION_STRING} + SOVERSION ${LIB_VERSION_MAJOR}) + +INSTALL(TARGETS CSXCAD DESTINATION lib${LIB_SUFFIX}) + +INSTALL(FILES ${PUB_HEADERS} DESTINATION include/CSXCAD) + + diff --git a/CSXCAD/src/CSBackgroundMaterial.cpp b/CSXCAD/src/CSBackgroundMaterial.cpp new file mode 100644 index 0000000..02067fe --- /dev/null +++ b/CSXCAD/src/CSBackgroundMaterial.cpp @@ -0,0 +1,115 @@ +/* +* Copyright (C) 2013 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 . +*/ + +#include "CSBackgroundMaterial.h" + +#include "tinyxml.h" +#include +#include +#include +#include + +CSBackgroundMaterial::CSBackgroundMaterial() +{ + // init material + Reset(); +} + +void CSBackgroundMaterial::Reset() +{ + SetEpsilon(1); + SetMue(1); + SetKappa(0); + SetSigma(0); +} + +void CSBackgroundMaterial::SetEpsilon(double val) +{ + if (val<1) + { + std::cerr << __func__ << ": Error, a relative electric permittivity smaller 1 is not allowed! Skipping. " << std::endl; + return; + } + m_epsR=val; +} + +void CSBackgroundMaterial::SetMue(double val) +{ + if (val<1) + { + std::cerr << __func__ << ": Error, a relative magnetic permeability smaller 1 is not allowed! Skipping. " << std::endl; + return; + } + m_mueR=val; +} + +void CSBackgroundMaterial::SetKappa(double val) +{ + if (val<0) + { + std::cerr << __func__ << ": Error, a negative electric conductivity is not allowed! Skipping. " << std::endl; + return; + } + m_kappa=val; +} + +void CSBackgroundMaterial::SetSigma(double val) +{ + if (val<0) + { + std::cerr << __func__ << ": Error, a negative (artificial) magnetic conductivity is not allowed! Skipping. " << std::endl; + return; + } + m_sigma=val; +} + +bool CSBackgroundMaterial::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + UNUSED(parameterised); + UNUSED(sparse); + TiXmlElement bg_elem("BackgroundMaterial"); + + bg_elem.SetDoubleAttribute("Epsilon", GetEpsilon()); + bg_elem.SetDoubleAttribute("Mue", GetMue()); + bg_elem.SetDoubleAttribute("Kappa", GetKappa()); + bg_elem.SetDoubleAttribute("Sigma", GetSigma()); + + root.InsertEndChild(bg_elem); + + return true; +} + +bool CSBackgroundMaterial::ReadFromXML(TiXmlNode &root) +{ + Reset(); + TiXmlElement* rootElem=root.ToElement(); + + if (rootElem==NULL) + return false; + + double val; + if (rootElem->QueryDoubleAttribute("Epsilon",&val) == TIXML_SUCCESS) + SetEpsilon(val); + if (rootElem->QueryDoubleAttribute("Mue",&val) == TIXML_SUCCESS) + SetMue(val); + if (rootElem->QueryDoubleAttribute("Kappa",&val) == TIXML_SUCCESS) + SetKappa(val); + if (rootElem->QueryDoubleAttribute("Sigma",&val) == TIXML_SUCCESS) + SetSigma(val); + + return true; +} diff --git a/CSXCAD/src/CSBackgroundMaterial.h b/CSXCAD/src/CSBackgroundMaterial.h new file mode 100644 index 0000000..8a54f54 --- /dev/null +++ b/CSXCAD/src/CSBackgroundMaterial.h @@ -0,0 +1,63 @@ +/* +* Copyright (C) 2013 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 . +*/ + +#ifndef CSBACKGROUNDMATERIAL_H +#define CSBACKGROUNDMATERIAL_H + +#include "CSXCAD_Global.h" + +class TiXmlNode; + +class CSBackgroundMaterial +{ +public: + CSBackgroundMaterial(); + + //! Get the rel. electric permittivity + double GetEpsilon() const {return m_epsR;} + //! Set the rel. electric permittivity + void SetEpsilon(double val); + + //! Get the rel. magnetic permeability + double GetMue() const {return m_mueR;} + //! Set the rel. magnetic permeability + void SetMue(double val); + + //! Get the electric conductivity + double GetKappa() const {return m_kappa;} + //! Set the electric conductivity + void SetKappa(double val); + + //! Get the (artificial) magnetic conductivity + double GetSigma() const {return m_sigma;} + //! Set the (artificial) magnetic conductivity + void SetSigma(double val); + + //! Reset all values to default + void Reset(); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + +protected: + double m_epsR; + double m_mueR; + double m_kappa; + double m_sigma; +}; + +#endif // CSBACKGROUNDMATERIAL_H diff --git a/CSXCAD/src/CSFunctionParser.cpp b/CSXCAD/src/CSFunctionParser.cpp new file mode 100644 index 0000000..c8741ff --- /dev/null +++ b/CSXCAD/src/CSFunctionParser.cpp @@ -0,0 +1,76 @@ +/* +* Copyright (C) 2010,2011 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 . +*/ + +#include "CSFunctionParser.h" +#include +#include + +double bessel_first_kind_0(const double* p) +{ + return j0(p[0]); +} +double bessel_first_kind_1(const double* p) +{ + return j1(p[0]); +} +double bessel_first_kind_n(const double* p) +{ + int n=p[0]; + if (n<0) + { + std::cerr << "CSFunctionParser::bessel_first_kind_n (jn): first argument must be integer larger than zero! found: " << p[0] << std::endl; + return 0; + } + return jn(n,p[1]); +} + +double bessel_second_kind_0(const double* p) +{ + return y0(p[0]); +} +double bessel_second_kind_1(const double* p) +{ + return y1(p[0]); +} +double bessel_second_kind_n(const double* p) +{ + int n=p[0]; + if (n<0) + { + std::cerr << "CSFunctionParser::bessel_second_kind_n (yn): first argument must be integer larger than zero! found: " << p[0] << std::endl; + return 0; + } + return yn(n,p[1]); +} + + +CSFunctionParser::CSFunctionParser() +{ + //some usefull constants + AddConstant("pi", 3.14159265358979323846); + AddConstant("e", 2.71828182845904523536); + + //some bessel functions of first kind + AddFunction("j0",bessel_first_kind_0,1); + AddFunction("j1",bessel_first_kind_1,1); + AddFunction("jn",bessel_first_kind_n,2); + + //some bessel functions of second kind + AddFunction("y0",bessel_second_kind_0,1); + AddFunction("y1",bessel_second_kind_1,1); + AddFunction("yn",bessel_second_kind_n,2); +} diff --git a/CSXCAD/src/CSFunctionParser.h b/CSXCAD/src/CSFunctionParser.h new file mode 100644 index 0000000..06304fc --- /dev/null +++ b/CSXCAD/src/CSFunctionParser.h @@ -0,0 +1,34 @@ +/* +* Copyright (C) 2010,2011 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 . +*/ + +#ifndef CSFUNCTIONPARSER_H +#define CSFUNCTIONPARSER_H + +#include "CSXCAD_Global.h" +#include "fparser.hh" + +//! Extended FunctionParser using some additional constants (pi,e) and functions +/*! + This is an extended FunctionParser with the additional constants, "pi" and "e", as well as severel bessel functions of first (j0, j1, jn) and second kind (y0, y1, yn). +*/ +class CSXCAD_EXPORT CSFunctionParser : public FunctionParser +{ +public: + CSFunctionParser(); +}; + +#endif // CSFUNCTIONPARSER_H diff --git a/CSXCAD/src/CSPrimBox.cpp b/CSXCAD/src/CSPrimBox.cpp new file mode 100644 index 0000000..e4acf77 --- /dev/null +++ b/CSXCAD/src/CSPrimBox.cpp @@ -0,0 +1,149 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimBox.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimBox::CSPrimBox(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(ID,paraSet,prop) +{ + Type=BOX; + m_Coords[0].SetParameterSet(paraSet); + m_Coords[1].SetParameterSet(paraSet); + PrimTypeName = std::string("Box"); +} + +CSPrimBox::CSPrimBox(CSPrimBox* primBox, CSProperties *prop) : CSPrimitives(primBox,prop) +{ + Type=BOX; + m_Coords[0].Copy(&primBox->m_Coords[0]); + m_Coords[1].Copy(&primBox->m_Coords[1]); + PrimTypeName = std::string("Box"); +} + +CSPrimBox::CSPrimBox(ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(paraSet,prop) +{ + Type=BOX; + m_Coords[0].SetParameterSet(paraSet); + m_Coords[1].SetParameterSet(paraSet); + PrimTypeName = std::string("Box"); +} + + +CSPrimBox::~CSPrimBox() +{ +} + +bool CSPrimBox::GetBoundBox(double dBoundBox[6], bool PreserveOrientation) +{ + const double* start = m_Coords[0].GetCoords(m_MeshType); + const double* stop = m_Coords[1].GetCoords(m_MeshType); + + m_BoundBox_CoordSys = m_MeshType; + m_Dimension=0; + for (int i=0;i<3;++i) + { + dBoundBox[2*i] = start[i]; + dBoundBox[2*i+1]= stop[i]; + + if (start[i]!=stop[i]) + ++m_Dimension; + } + if (PreserveOrientation) + return true; + for (int i=0;i<3;++i) + if (dBoundBox[2*i]>dBoundBox[2*i+1]) + { + double help=dBoundBox[2*i]; + dBoundBox[2*i]=dBoundBox[2*i+1]; + dBoundBox[2*i+1]=help; + } + if ( (m_MeshType!=m_PrimCoordSystem) && (m_PrimCoordSystem!=UNDEFINED_CS)) + // if the box is defined in a coordinate system other than the expected one, this BB is invalid + return false; + return true; +} + +bool CSPrimBox::IsInside(const double* Coord, double /*tol*/) +{ + if (Coord==NULL) return false; + + const double* start = m_Coords[0].GetCoords(m_PrimCoordSystem); + const double* stop = m_Coords[1].GetCoords(m_PrimCoordSystem); + double pos[3] = {Coord[0],Coord[1],Coord[2]}; + + TransformCoords(pos, true, m_MeshType); + //transform incoming coordinates into the coorindate system of the primitive + TransformCoordSystem(pos,pos,m_MeshType,m_PrimCoordSystem); + + if (m_PrimCoordSystem!=UNDEFINED_CS) + return CoordInRange(pos, start, stop, m_PrimCoordSystem); + else + return CoordInRange(pos, start, stop, m_MeshType); +} + + +bool CSPrimBox::Update(std::string *ErrStr) +{ + bool bOK=m_Coords[0].Evaluate(ErrStr) && m_Coords[1].Evaluate(ErrStr); + if (bOK==false) + { + std::stringstream stream; + stream << std::endl << "Error in Box (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + } + m_Coords[0].SetCoordinateSystem(m_PrimCoordSystem, m_MeshType); + m_Coords[1].SetCoordinateSystem(m_PrimCoordSystem, m_MeshType); + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + return bOK; +} + +bool CSPrimBox::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimitives::Write2XML(elem,parameterised); + + TiXmlElement P1("P1"); + m_Coords[0].Write2XML(&P1,parameterised); + elem.InsertEndChild(P1); + + TiXmlElement P2("P2"); + m_Coords[1].Write2XML(&P2,parameterised); + elem.InsertEndChild(P2); + return true; +} + +bool CSPrimBox::ReadFromXML(TiXmlNode &root) +{ + if (CSPrimitives::ReadFromXML(root)==false) return false; + if (m_Coords[0].ReadFromXML(root.FirstChildElement("P1")) == false) return false; + if (m_Coords[1].ReadFromXML(root.FirstChildElement("P2")) == false) return false; + return true; +} + +void CSPrimBox::ShowPrimitiveStatus(std::ostream& stream) +{ + CSPrimitives::ShowPrimitiveStatus(stream); + stream << " Start: " << m_Coords[0].GetValueString(0) << "," << m_Coords[0].GetValueString(1) << "," << m_Coords[0].GetValueString(2) << std::endl; + stream << " Stop : " << m_Coords[1].GetValueString(0) << "," << m_Coords[1].GetValueString(1) << "," << m_Coords[1].GetValueString(2) << std::endl; +} diff --git a/CSXCAD/src/CSPrimBox.h b/CSXCAD/src/CSPrimBox.h new file mode 100644 index 0000000..972602f --- /dev/null +++ b/CSXCAD/src/CSPrimBox.h @@ -0,0 +1,59 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" + +//! Box Primitive (Cube) +/*! + This is a cube primitive defined by its start-, end-coordinates. + */ +class CSXCAD_EXPORT CSPrimBox : public CSPrimitives +{ +public: + CSPrimBox(ParameterSet* paraSet, CSProperties* prop); + CSPrimBox(CSPrimBox* primBox, CSProperties *prop=NULL); + CSPrimBox(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimBox(); + + virtual CSPrimitives* GetCopy(CSProperties *prop=NULL) {return new CSPrimBox(this,prop);} + + void SetCoord(int index, double val) {if ((index>=0) && (index<6)) m_Coords[index%2].SetValue(index/2,val);} + void SetCoord(int index, const char* val) {if ((index>=0) && (index<6)) m_Coords[index%2].SetValue(index/2,val);} + void SetCoord(int index, std::string val) {if ((index>=0) && (index<6)) m_Coords[index%2].SetValue(index/2,val);} + + double GetCoord(int index) {if ((index>=0) && (index<6)) return m_Coords[index%2].GetValue(index/2); else return 0;} + ParameterScalar* GetCoordPS(int index) {if ((index>=0) && (index<6)) return m_Coords[index%2].GetCoordPS(index/2); else return NULL;} + + ParameterCoord* GetStartCoord() {return &m_Coords[0];} + ParameterCoord* GetStopCoord() {return &m_Coords[1];} + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPrimitiveStatus(std::ostream& stream); + +protected: + //start and stop coords defining the box + ParameterCoord m_Coords[2]; +}; + diff --git a/CSXCAD/src/CSPrimCurve.cpp b/CSXCAD/src/CSPrimCurve.cpp new file mode 100644 index 0000000..4a1d5ba --- /dev/null +++ b/CSXCAD/src/CSPrimCurve.cpp @@ -0,0 +1,188 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimCurve.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimCurve::CSPrimCurve(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(ID,paraSet,prop) +{ + Type=CURVE; + PrimTypeName = std::string("Curve"); +} + +CSPrimCurve::CSPrimCurve(CSPrimCurve* primCurve, CSProperties *prop) : CSPrimitives(primCurve,prop) +{ + Type=CURVE; + for (size_t i=0;ipoints.size();++i) + points.push_back(new ParameterCoord(primCurve->points.at(i))); + PrimTypeName = std::string("Curve"); +} + +CSPrimCurve::CSPrimCurve(ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(paraSet,prop) +{ + Type=CURVE; + PrimTypeName = std::string("Curve"); +} + + +CSPrimCurve::~CSPrimCurve() +{ + points.clear(); +} + +size_t CSPrimCurve::AddPoint(double coords[]) +{ + points.push_back(new ParameterCoord(clParaSet,coords)); + return points.size(); +} + +void CSPrimCurve::SetCoord(size_t point_index, int nu, double val) +{ + if (point_index>=GetNumberOfPoints()) return; + if ((nu<0) || (nu>2)) return; + points.at(point_index)->SetValue(nu,val); +} + +void CSPrimCurve::SetCoord(size_t point_index, int nu, std::string val) +{ + if (point_index>=GetNumberOfPoints()) return; + if ((nu<0) || (nu>2)) return; + points.at(point_index)->SetValue(nu,val); +} + +bool CSPrimCurve::GetPoint(size_t point_index, double point[3]) +{ + if (point_index>=GetNumberOfPoints()) return false; + point[0] = points.at(point_index)->GetValue(0); + point[1] = points.at(point_index)->GetValue(1); + point[2] = points.at(point_index)->GetValue(2); + return true; +} + +bool CSPrimCurve::GetPoint(size_t point_index, double* point, CoordinateSystem c_system, bool transform) +{ + if (point_index>=GetNumberOfPoints()) return false; + point[0] = points.at(point_index)->GetCoordValue(0,c_system); + point[1] = points.at(point_index)->GetCoordValue(1,c_system); + point[2] = points.at(point_index)->GetCoordValue(2,c_system); + if (transform) + TransformCoords(point, false, c_system); + return true; +} + +void CSPrimCurve::ClearPoints() +{ + points.clear(); +} + +bool CSPrimCurve::GetBoundBox(double dBoundBox[6], bool /*PreserveOrientation*/) +{ +// cerr << "CSPrimCurve::GetBoundBox: Warning: The bounding box for this object is not calculated properly... " << std::endl; + bool accurate=false; + m_BoundBox_CoordSys = CARTESIAN; + for (int n=0;n<6;++n) dBoundBox[n] = 0; + for (size_t i=0;iGetCoordValue(n,CARTESIAN); + dBoundBox[2*n+1]=dBoundBox[2*n]; + } + } + for (int n=0;n<3;++n) + { + if (points.at(i)->GetValue(n)GetCoordValue(n,CARTESIAN); + else if (points.at(i)->GetValue(n)>dBoundBox[2*n+1]) + dBoundBox[2*n+1]=points.at(i)->GetCoordValue(n,CARTESIAN); + } + } + if (points.size()<=1) + m_Dimension=0; + else + m_Dimension=1; + return accurate; +} + +bool CSPrimCurve::IsInside(const double* /*Coord*/, double /*tol*/) +{ + //this is a 1D-object, you can never be inside... + return false; +} + + +bool CSPrimCurve::Update(std::string *ErrStr) +{ + bool bOK=true; + for (size_t i=0;iEvaluate(ErrStr); + if (isOK==false) + { + std::stringstream stream; + stream << std::endl << "Error in " << PrimTypeName << " (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + } + points.at(i)->SetCoordinateSystem(m_PrimCoordSystem, m_MeshType); + bOK &= isOK; + } + + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + + return bOK; +} + +bool CSPrimCurve::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimitives::Write2XML(elem,parameterised); + + for (size_t i=0;iWrite2XML(&VT,parameterised); + elem.InsertEndChild(VT); + } + return true; +} + +bool CSPrimCurve::ReadFromXML(TiXmlNode &root) +{ + if (CSPrimitives::ReadFromXML(root)==false) return false; + + TiXmlElement *VT=root.FirstChildElement("Vertex"); + if (points.size()!=0) return false; + ParameterCoord *newPoint; + while (VT) + { + newPoint = new ParameterCoord(clParaSet); + if (newPoint->ReadFromXML(VT)) + points.push_back(newPoint); + VT=VT->NextSiblingElement("Vertex"); + }; + + return true; +} diff --git a/CSXCAD/src/CSPrimCurve.h b/CSXCAD/src/CSPrimCurve.h new file mode 100644 index 0000000..40caafb --- /dev/null +++ b/CSXCAD/src/CSPrimCurve.h @@ -0,0 +1,56 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" + +//! Curve Primitive (Polygonal chain) +/*! + This is a curve primitive defined by a number of 3D points + */ +class CSXCAD_EXPORT CSPrimCurve : public CSPrimitives +{ +public: + CSPrimCurve(ParameterSet* paraSet, CSProperties* prop); + CSPrimCurve(CSPrimCurve* primCurve, CSProperties *prop=NULL); + CSPrimCurve(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimCurve(); + + virtual CSPrimitives* GetCopy(CSProperties *prop=NULL) {return new CSPrimCurve(this,prop);} + + virtual size_t AddPoint(double coords[]); + virtual void SetCoord(size_t point_index, int nu, double val); + virtual void SetCoord(size_t point_index, int nu, std::string val); + + virtual size_t GetNumberOfPoints() {return points.size();} + virtual bool GetPoint(size_t point_index, double point[3]); + //! Get the point coordinates for the given index in the specified coordinate system + virtual bool GetPoint(size_t point_index, double* point, CoordinateSystem c_system, bool transform=true); + + virtual void ClearPoints(); + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + +protected: + std::vector points; +}; diff --git a/CSXCAD/src/CSPrimCylinder.cpp b/CSXCAD/src/CSPrimCylinder.cpp new file mode 100644 index 0000000..fb16262 --- /dev/null +++ b/CSXCAD/src/CSPrimCylinder.cpp @@ -0,0 +1,210 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimCylinder.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimCylinder::CSPrimCylinder(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(ID,paraSet,prop) +{ + Type=CYLINDER; + m_AxisCoords[0].SetParameterSet(paraSet); + m_AxisCoords[1].SetParameterSet(paraSet); + psRadius.SetParameterSet(paraSet); + PrimTypeName = std::string("Cylinder"); +} + +CSPrimCylinder::CSPrimCylinder(CSPrimCylinder* cylinder, CSProperties *prop) : CSPrimitives(cylinder,prop) +{ + Type=CYLINDER; + m_AxisCoords[0].Copy(&cylinder->m_AxisCoords[0]); + m_AxisCoords[1].Copy(&cylinder->m_AxisCoords[1]); + psRadius.Copy(&cylinder->psRadius); + PrimTypeName = std::string("Cylinder"); +} + +CSPrimCylinder::CSPrimCylinder(ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(paraSet,prop) +{ + Type=CYLINDER; + m_AxisCoords[0].SetParameterSet(paraSet); + m_AxisCoords[1].SetParameterSet(paraSet); + psRadius.SetParameterSet(paraSet); + PrimTypeName = std::string("Cylinder"); +} + + +CSPrimCylinder::~CSPrimCylinder() +{ +} + +bool CSPrimCylinder::GetBoundBox(double dBoundBox[6], bool PreserveOrientation) +{ +// cerr << "CSPrimCylinder::GetBoundBox: Warning: The bounding box for this object is not calculated properly... " << std::endl; + UNUSED(PreserveOrientation); //has no orientation or preserved anyways + bool accurate=false; + int Direction=0; + const double* start=m_AxisCoords[0].GetCartesianCoords(); + const double* stop =m_AxisCoords[1].GetCartesianCoords(); + m_BoundBox_CoordSys=CARTESIAN; + + double rad=psRadius.GetValue(); + for (unsigned int i=0;i<3;++i) + { + double min=start[i]; + double max=stop[i]; + if (min0) + m_Dimension=3; + else if (Direction==7) + m_Dimension=0; + else + m_Dimension=1; + return accurate; +} + +bool CSPrimCylinder::IsInside(const double* Coord, double /*tol*/) +{ + if (Coord==NULL) return false; + + const double* start=m_AxisCoords[0].GetCartesianCoords(); + const double* stop =m_AxisCoords[1].GetCartesianCoords(); + double pos[3]; + //transform incoming coordinates into cartesian coords + TransformCoordSystem(Coord,pos,m_MeshType,CARTESIAN); + if (m_Transform) + m_Transform->InvertTransform(pos,pos); + + for (int n=0;n<3;++n) + if (pos[n]m_BoundBox[2*n+1]) + return false; + + double foot,dist; + Point_Line_Distance(pos,start,stop,foot,dist); + + if ((foot<0) || (foot>1)) //the foot point is not on the axis + return false; + if (dist>psRadius.GetValue()) + return false; + + return true; +} + +bool CSPrimCylinder::Update(std::string *ErrStr) +{ + int EC=0; + bool bOK=m_AxisCoords[0].Evaluate(ErrStr) && m_AxisCoords[1].Evaluate(ErrStr); + if (bOK==false) + { + std::stringstream stream; + stream << std::endl << "Error in " << PrimTypeName << " Coord (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + } + m_AxisCoords[0].SetCoordinateSystem(m_PrimCoordSystem, m_MeshType); + m_AxisCoords[1].SetCoordinateSystem(m_PrimCoordSystem, m_MeshType); + + + EC=psRadius.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + bOK=false; + std::stringstream stream; + stream << std::endl << "Error in " << PrimTypeName << " Radius (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + + return bOK; +} + +bool CSPrimCylinder::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimitives::Write2XML(elem,parameterised); + + WriteTerm(psRadius,elem,"Radius",parameterised); + + TiXmlElement Start("P1"); + m_AxisCoords[0].Write2XML(&Start,parameterised); + elem.InsertEndChild(Start); + + TiXmlElement Stop("P2"); + m_AxisCoords[1].Write2XML(&Stop,parameterised); + elem.InsertEndChild(Stop); + + return true; +} + +bool CSPrimCylinder::ReadFromXML(TiXmlNode &root) +{ + if (CSPrimitives::ReadFromXML(root)==false) return false; + + TiXmlElement *elem = root.ToElement(); + if (elem==NULL) return false; + if (ReadTerm(psRadius,*elem,"Radius")==false) return false; + + if (m_AxisCoords[0].ReadFromXML(root.FirstChildElement("P1")) == false) return false; + if (m_AxisCoords[1].ReadFromXML(root.FirstChildElement("P2")) == false) return false; + + return true; +} + +void CSPrimCylinder::ShowPrimitiveStatus(std::ostream& stream) +{ + CSPrimitives::ShowPrimitiveStatus(stream); + stream << " Axis-Start: " << m_AxisCoords[0].GetValueString(0) << "," << m_AxisCoords[0].GetValueString(1) << "," << m_AxisCoords[0].GetValueString(2) << std::endl; + stream << " Axis-Stop : " << m_AxisCoords[1].GetValueString(0) << "," << m_AxisCoords[1].GetValueString(1) << "," << m_AxisCoords[1].GetValueString(2) << std::endl; + stream << " Radius: " << psRadius.GetValueString() << std::endl; +} + diff --git a/CSXCAD/src/CSPrimCylinder.h b/CSXCAD/src/CSPrimCylinder.h new file mode 100644 index 0000000..21e6c05 --- /dev/null +++ b/CSXCAD/src/CSPrimCylinder.h @@ -0,0 +1,65 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" + +//! Cylinder Primitive +/*! + This is a cylindrical primitive defined by its axis start-, end-coordinates and a radius. + */ +class CSXCAD_EXPORT CSPrimCylinder : public CSPrimitives +{ +public: + CSPrimCylinder(ParameterSet* paraSet, CSProperties* prop); + CSPrimCylinder(CSPrimCylinder* cylinder, CSProperties *prop=NULL); + CSPrimCylinder(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimCylinder(); + + virtual CSPrimitives* GetCopy(CSProperties *prop=NULL) {return new CSPrimCylinder(this,prop);} + + void SetCoord(int index, double val) {if ((index>=0) && (index<6)) m_AxisCoords[index%2].SetValue(index/2,val);} + void SetCoord(int index, const char* val) {if ((index>=0) && (index<6)) m_AxisCoords[index%2].SetValue(index/2,val);} + void SetCoord(int index, std::string val) {if ((index>=0) && (index<6)) m_AxisCoords[index%2].SetValue(index/2,val);} + + double GetCoord(int index) {if ((index>=0) && (index<6)) return m_AxisCoords[index%2].GetValue(index/2); else return 0;} + ParameterScalar* GetCoordPS(int index) {if ((index>=0) && (index<6)) return m_AxisCoords[index%2].GetCoordPS(index/2); else return NULL;} + + ParameterCoord* GetAxisStartCoord() {return &m_AxisCoords[0];} + ParameterCoord* GetAxisStopCoord() {return &m_AxisCoords[1];} + + void SetRadius(double val) {psRadius.SetValue(val);} + void SetRadius(const char* val) {psRadius.SetValue(val);} + + double GetRadius() {return psRadius.GetValue();} + ParameterScalar* GetRadiusPS() {return &psRadius;} + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPrimitiveStatus(std::ostream& stream); + +protected: + ParameterCoord m_AxisCoords[2]; + ParameterScalar psRadius; +}; + diff --git a/CSXCAD/src/CSPrimCylindricalShell.cpp b/CSXCAD/src/CSPrimCylindricalShell.cpp new file mode 100644 index 0000000..0ca1701 --- /dev/null +++ b/CSXCAD/src/CSPrimCylindricalShell.cpp @@ -0,0 +1,177 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimCylindricalShell.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimCylindricalShell::CSPrimCylindricalShell(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimCylinder(ID,paraSet,prop) +{ + Type=CYLINDRICALSHELL; + PrimTypeName = std::string("CylindricalShell"); + psShellWidth.SetParameterSet(paraSet); +} + +CSPrimCylindricalShell::CSPrimCylindricalShell(CSPrimCylindricalShell* cylinder, CSProperties *prop) : CSPrimCylinder(cylinder,prop) +{ + Type=CYLINDRICALSHELL; + PrimTypeName = std::string("CylindricalShell"); + psShellWidth.Copy(&cylinder->psShellWidth); +} + +CSPrimCylindricalShell::CSPrimCylindricalShell(ParameterSet* paraSet, CSProperties* prop) : CSPrimCylinder(paraSet,prop) +{ + Type=CYLINDRICALSHELL; + PrimTypeName = std::string("CylindricalShell"); + psShellWidth.SetParameterSet(paraSet); +} + +CSPrimCylindricalShell::~CSPrimCylindricalShell() +{ +} + +bool CSPrimCylindricalShell::GetBoundBox(double dBoundBox[6], bool PreserveOrientation) +{ +// cerr << "CSPrimCylindricalShell::GetBoundBox: Warning: The bounding box for this object is not calculated properly... " << std::endl; + UNUSED(PreserveOrientation); //has no orientation or preserved anyways + bool accurate=false; + int Direction=0; + const double* start=m_AxisCoords[0].GetCartesianCoords(); + const double* stop =m_AxisCoords[1].GetCartesianCoords(); + m_BoundBox_CoordSys=CARTESIAN; + double rad=psRadius.GetValue()+psShellWidth.GetValue()/2.0; + for (unsigned int i=0;i<3;++i) + { + double min=start[i]; + double max=stop[i]; + if (min0) + m_Dimension=3; + else if (Direction==7) + m_Dimension=0; + else + m_Dimension=1; + return accurate; +} + +bool CSPrimCylindricalShell::IsInside(const double* Coord, double /*tol*/) +{ + if (Coord==NULL) return false; + const double* start=m_AxisCoords[0].GetCartesianCoords(); + const double* stop =m_AxisCoords[1].GetCartesianCoords(); + double pos[3]; + //transform incoming coordinates into cartesian coords + TransformCoordSystem(Coord,pos,m_MeshType,CARTESIAN); + if (m_Transform) + m_Transform->InvertTransform(pos,pos); + + for (int n=0;n<3;++n) + if (pos[n]m_BoundBox[2*n+1]) + return false; + + double foot,dist; + Point_Line_Distance(pos,start,stop,foot,dist); + + if ((foot<0) || (foot>1)) //the foot point is not on the axis + return false; + if (fabs(dist-psRadius.GetValue())>psShellWidth.GetValue()/2.0) + return false; + + return true; +} + +bool CSPrimCylindricalShell::Update(std::string *ErrStr) +{ + int EC=0; + bool bOK=CSPrimCylinder::Update(ErrStr); + + EC=psShellWidth.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + bOK=false; + std::stringstream stream; + stream << std::endl << "Error in " << PrimTypeName << " shell-width (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + + return bOK; +} + +bool CSPrimCylindricalShell::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimCylinder::Write2XML(elem,parameterised); + + WriteTerm(psShellWidth,elem,"ShellWidth",parameterised); + return true; +} + +bool CSPrimCylindricalShell::ReadFromXML(TiXmlNode &root) +{ + if (CSPrimCylinder::ReadFromXML(root)==false) return false; + + TiXmlElement *elem = root.ToElement(); + if (elem==NULL) return false; + if (ReadTerm(psShellWidth,*elem,"ShellWidth")==false) return false; + return true; +} + +void CSPrimCylindricalShell::ShowPrimitiveStatus(std::ostream& stream) +{ + CSPrimCylinder::ShowPrimitiveStatus(stream); + stream << " Shell width: " << psShellWidth.GetValueString() << std::endl; +} diff --git a/CSXCAD/src/CSPrimCylindricalShell.h b/CSXCAD/src/CSPrimCylindricalShell.h new file mode 100644 index 0000000..ef76897 --- /dev/null +++ b/CSXCAD/src/CSPrimCylindricalShell.h @@ -0,0 +1,56 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" +#include "CSPrimCylinder.h" + +//! CylindicalShell Primitive +/*! + This is a cylindrical shell primitive derived from the cylinder primitive, adding a shell width which is centered around the cylinder radius. + \sa CSPrimCylinder + */ +class CSXCAD_EXPORT CSPrimCylindricalShell : public CSPrimCylinder +{ +public: + CSPrimCylindricalShell(ParameterSet* paraSet, CSProperties* prop); + CSPrimCylindricalShell(CSPrimCylindricalShell* cylinder, CSProperties *prop=NULL); + CSPrimCylindricalShell(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimCylindricalShell(); + + virtual CSPrimitives* GetCopy(CSProperties *prop=NULL) {return new CSPrimCylindricalShell(this,prop);} + + void SetShellWidth(double val) {psShellWidth.SetValue(val);} + void SetShellWidth(const char* val) {psShellWidth.SetValue(val);} + + double GetShellWidth() {return psShellWidth.GetValue();} + ParameterScalar* GetShellWidthPS() {return &psShellWidth;} + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPrimitiveStatus(std::ostream& stream); + +protected: + ParameterScalar psShellWidth; +}; + diff --git a/CSXCAD/src/CSPrimLinPoly.cpp b/CSXCAD/src/CSPrimLinPoly.cpp new file mode 100644 index 0000000..5ca3201 --- /dev/null +++ b/CSXCAD/src/CSPrimLinPoly.cpp @@ -0,0 +1,131 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimLinPoly.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimLinPoly::CSPrimLinPoly(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimPolygon(ID,paraSet,prop) +{ + Type=LINPOLY; + extrudeLength.SetParameterSet(paraSet); + PrimTypeName = std::string("LinPoly"); +} + +CSPrimLinPoly::CSPrimLinPoly(CSPrimLinPoly* primLinPoly, CSProperties *prop) : CSPrimPolygon(primLinPoly,prop) +{ + Type=LINPOLY; + extrudeLength.Copy(&primLinPoly->extrudeLength); + PrimTypeName = std::string("LinPoly"); +} + +CSPrimLinPoly::CSPrimLinPoly(ParameterSet* paraSet, CSProperties* prop) : CSPrimPolygon(paraSet,prop) +{ + Type=LINPOLY; + extrudeLength.SetParameterSet(paraSet); + PrimTypeName = std::string("LinPoly"); +} + + +CSPrimLinPoly::~CSPrimLinPoly() +{ +} + +bool CSPrimLinPoly::GetBoundBox(double dBoundBox[6], bool PreserveOrientation) +{ + UNUSED(PreserveOrientation); //has no orientation or preserved anyways + bool accurate; + accurate = CSPrimPolygon::GetBoundBox(dBoundBox); + + double len = extrudeLength.GetValue(); + + if (len>0) + { + dBoundBox[2*m_NormDir] = Elevation.GetValue(); + dBoundBox[2*m_NormDir+1] = dBoundBox[2*m_NormDir] + len; + } + else + { + dBoundBox[2*m_NormDir+1] = Elevation.GetValue(); + dBoundBox[2*m_NormDir] = dBoundBox[2*m_NormDir+1] + len; + } + m_Dimension=0; + for (int n=0;n<3;++n) + { + if (dBoundBox[2*n]!=dBoundBox[2*n+1]) + ++m_Dimension; + } + return accurate; +} + +bool CSPrimLinPoly::IsInside(const double* Coord, double tol) +{ + if (Coord==NULL) return false; + double coords[3]={Coord[0],Coord[1],Coord[2]}; + if (m_Transform && Type==LINPOLY) + TransformCoords(coords,true, m_MeshType); + return CSPrimPolygon::IsInside(coords, tol); +} + + +bool CSPrimLinPoly::Update(std::string *ErrStr) +{ + int EC=0; + + bool bOK = CSPrimPolygon::Update(ErrStr); + + EC=extrudeLength.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + bOK=false; + std::stringstream stream; + stream << std::endl << "Error in Polygon Elevation (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + + return bOK; +} + +bool CSPrimLinPoly::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimPolygon::Write2XML(elem,parameterised); + + WriteTerm(extrudeLength,elem,"Length",parameterised); + return true; +} + +bool CSPrimLinPoly::ReadFromXML(TiXmlNode &root) +{ + if (CSPrimPolygon::ReadFromXML(root)==false) return false; + + TiXmlElement *elem = root.ToElement(); + if (elem==NULL) return false; + if (ReadTerm(extrudeLength,*elem,"Length")==false) return false; + + return true; +} diff --git a/CSXCAD/src/CSPrimLinPoly.h b/CSXCAD/src/CSPrimLinPoly.h new file mode 100644 index 0000000..25dce21 --- /dev/null +++ b/CSXCAD/src/CSPrimLinPoly.h @@ -0,0 +1,53 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" +#include "CSPrimPolygon.h" + +//! Linear extruded polygon Primitive +/*! + This is a linear extruded area polygon primitive defined by a number of points in space and an extrude vector. + Warning: This primitive currently can only be defined in Cartesian coordinates. + */ +class CSXCAD_EXPORT CSPrimLinPoly : public CSPrimPolygon +{ +public: + CSPrimLinPoly(ParameterSet* paraSet, CSProperties* prop); + CSPrimLinPoly(CSPrimLinPoly* primPolygon, CSProperties *prop=NULL); + CSPrimLinPoly(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimLinPoly(); + + virtual CSPrimLinPoly* GetCopy(CSProperties *prop=NULL) {return new CSPrimLinPoly(this,prop);} + + void SetLength(double val) {extrudeLength.SetValue(val);} + void SetLength(const std::string val) {extrudeLength.SetValue(val);} + + double GetLength() {return extrudeLength.GetValue();} + ParameterScalar* GetLengthPS() {return &extrudeLength;} + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + +protected: + ParameterScalar extrudeLength; +}; diff --git a/CSXCAD/src/CSPrimMultiBox.cpp b/CSXCAD/src/CSPrimMultiBox.cpp new file mode 100644 index 0000000..e5547f0 --- /dev/null +++ b/CSXCAD/src/CSPrimMultiBox.cpp @@ -0,0 +1,279 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimMultiBox.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimMultiBox::CSPrimMultiBox(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(ID,paraSet,prop) +{ + Type=MULTIBOX; + PrimTypeName = std::string("Multi Box"); +} + +CSPrimMultiBox::CSPrimMultiBox(CSPrimMultiBox* multiBox, CSProperties *prop) : CSPrimitives(multiBox, prop) +{ + Type=MULTIBOX; + for (size_t i=0;ivCoords.size();++i) + vCoords.push_back(new ParameterScalar(multiBox->vCoords.at(i))); + PrimTypeName = std::string("Multi Box"); +} + +CSPrimMultiBox::CSPrimMultiBox(ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(paraSet,prop) +{ + Type=MULTIBOX; + PrimTypeName = std::string("Multi Box"); +} + +CSPrimMultiBox::~CSPrimMultiBox() +{ +} + +void CSPrimMultiBox::SetCoord(int index, double val) +{ + if ((index>=0) && (index<(int)vCoords.size())) + vCoords.at(index)->SetValue(val); +} + +void CSPrimMultiBox::SetCoord(int index, const char* val) +{ + if ((index>=0) && (index<(int)vCoords.size())) + vCoords.at(index)->SetValue(val); +} + +void CSPrimMultiBox::AddCoord(double val) +{ + vCoords.push_back(new ParameterScalar(clParaSet,val)); +} + +void CSPrimMultiBox::AddCoord(const char* val) +{ + vCoords.push_back(new ParameterScalar(clParaSet,val)); +} + +void CSPrimMultiBox::AddBox(int initBox) +{ + ClearOverlap(); + if ((initBox<0) || (((initBox+1)*6)>(int)vCoords.size())) + { + for (unsigned int i=0;i<6;++i) + AddCoord(0.0); + } + else for (unsigned int i=0;i<6;++i) + vCoords.push_back(new ParameterScalar(vCoords.at(6*initBox+i))); +} + +void CSPrimMultiBox::DeleteBox(size_t box) +{ + if ((box+1)*6>vCoords.size()) return; + std::vector::iterator start=vCoords.begin()+(box*6); + std::vector::iterator end=vCoords.begin()+(box*6+6); + + vCoords.erase(start,end); +} + + +double CSPrimMultiBox::GetCoord(int index) +{ + if ((index>=0) && (index<(int)vCoords.size())) + return vCoords.at(index)->GetValue(); + return 0; +} + +ParameterScalar* CSPrimMultiBox::GetCoordPS(int index) +{ + if ((index>=0) && (index<(int)vCoords.size())) + return vCoords.at(index); + return NULL; +} + +double* CSPrimMultiBox::GetAllCoords(size_t &Qty, double* array) +{ + Qty=vCoords.size(); + delete[] array; + array = new double[Qty]; + for (size_t i=0;iGetValue(); + return array; +} + +void CSPrimMultiBox::ClearOverlap() +{ + if (vCoords.size()%6==0) return; //no work to be done + + vCoords.resize(vCoords.size()-vCoords.size()%6); +} + +bool CSPrimMultiBox::GetBoundBox(double dBoundBox[6], bool PreserveOrientation) +{ + UNUSED(PreserveOrientation); //has no orientation or preserved anyways + for (int n=0;n<6;++n) dBoundBox[n] = 0; + //Update(); + for (unsigned int i=0;iGetValue()<=vCoords.at(6*i+2*n+1)->GetValue()) + { + if (i==0) + { + dBoundBox[2*n]=vCoords.at(6*i+2*n)->GetValue(); + dBoundBox[2*n+1]=vCoords.at(6*i+2*n+1)->GetValue(); + } + else + { + if (vCoords.at(6*i+2*n)->GetValue()GetValue(); + if (vCoords.at(6*i+2*n+1)->GetValue()>dBoundBox[2*n+1]) dBoundBox[2*n+1]=vCoords.at(6*i+2*n+1)->GetValue(); + } + + } + else + { + if (i==0) + { + dBoundBox[2*n]=vCoords.at(6*i+2*n+1)->GetValue(); + dBoundBox[2*n+1]=vCoords.at(6*i+2*n)->GetValue(); + } + else + { + if (vCoords.at(6*i+2*n+1)->GetValue()GetValue(); + if (vCoords.at(6*i+2*n)->GetValue()>dBoundBox[2*n+1]) dBoundBox[2*n+1]=vCoords.at(6*i+2*n)->GetValue(); + } + } + } + } + m_Dimension=0; + m_BoundBox_CoordSys = m_MeshType; + for (int n=0;n<3;++n) + { + if (dBoundBox[2*n]!=dBoundBox[2*n+1]) + ++m_Dimension; + } + return false; +} + +bool CSPrimMultiBox::IsInside(const double* Coord, double /*tol*/) +{ + if (Coord==NULL) return false; + bool in=false; + double UpVal,DownVal; + double coords[3]={Coord[0],Coord[1],Coord[2]}; + TransformCoords(coords, true, m_MeshType); + //fprintf(stderr,"here\n"); + for (unsigned int i=0;iGetValue(),vCoords.at(6*i+2*n+1)->GetValue()); + UpVal=vCoords.at(6*i+2*n+1)->GetValue(); + DownVal=vCoords.at(6*i+2*n)->GetValue(); + if (DownValcoords[n]) {in=false;break;} + if (UpValcoords[n]) {in=false;break;} + } + } + if (in==true) { return true;} + } + return false; +} + +bool CSPrimMultiBox::Update(std::string *ErrStr) +{ + int EC=0; + bool bOK=true; + for (size_t i=0;iEvaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=0) && (ErrStr!=NULL)) + { + bOK=false; + std::stringstream stream; + stream << std::endl << "Error in MultiBox (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + } + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + return bOK; +} + +bool CSPrimMultiBox::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimitives::Write2XML(elem,parameterised); + elem.SetAttribute("QtyBox",(int)vCoords.size()/6); + + for (size_t i=0;iAddCoord(0.0); + + if (ReadTerm(*vCoords.at(i*6),*SP,"X")==false) return false; + if (ReadTerm(*vCoords.at(i*6+2),*SP,"Y")==false) return false; + if (ReadTerm(*vCoords.at(i*6+4),*SP,"Z")==false) return false; + + if (ReadTerm(*vCoords.at(i*6+1),*EP,"X")==false) return false; + if (ReadTerm(*vCoords.at(i*6+3),*EP,"Y")==false) return false; + if (ReadTerm(*vCoords.at(i*6+5),*EP,"Z")==false) return false; + +// for (int n=0;n<6;++n) fprintf(stderr,"%e ",vCoords.at(i*6+n)->GetValue()); +// fprintf(stderr,"\n"); + + SP=SP->NextSiblingElement("StartP"); + EP=EP->NextSiblingElement("EndP"); + ++i; + }; + return true; +} diff --git a/CSXCAD/src/CSPrimMultiBox.h b/CSXCAD/src/CSPrimMultiBox.h new file mode 100644 index 0000000..d2d204a --- /dev/null +++ b/CSXCAD/src/CSPrimMultiBox.h @@ -0,0 +1,64 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" + +//! Multi-Box Primitive (Multi-Cube) +/*! + This is a primitive defined by multiple cubes. Mostly used for already discretized objects. + */ +class CSXCAD_EXPORT CSPrimMultiBox : public CSPrimitives +{ +public: + CSPrimMultiBox(ParameterSet* paraSet, CSProperties* prop); + CSPrimMultiBox(CSPrimMultiBox* multiBox,CSProperties *prop=NULL); + CSPrimMultiBox(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimMultiBox(); + + virtual CSPrimitives* GetCopy(CSProperties *prop=NULL) {return new CSPrimMultiBox(this,prop);} + + void SetCoord(int index, double val); + void SetCoord(int index, const char* val); + + void AddCoord(double val); + void AddCoord(const char* val); + + void AddBox(int initBox=-1); + void DeleteBox(size_t box); + + double GetCoord(int index); + ParameterScalar* GetCoordPS(int index); + + double* GetAllCoords(size_t &Qty, double* array); + + void ClearOverlap(); + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + unsigned int GetQtyBoxes() {return (unsigned int) vCoords.size()/6;} + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + +protected: + std::vector vCoords; +}; + diff --git a/CSXCAD/src/CSPrimPoint.cpp b/CSXCAD/src/CSPrimPoint.cpp new file mode 100644 index 0000000..8ed258d --- /dev/null +++ b/CSXCAD/src/CSPrimPoint.cpp @@ -0,0 +1,126 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimPoint.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimPoint::CSPrimPoint(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(ID,paraSet,prop) +{ + Type = POINT; + m_Coords.SetParameterSet(paraSet); + PrimTypeName = "Point"; +} + +CSPrimPoint::CSPrimPoint(CSPrimPoint* primPoint, CSProperties *prop) : CSPrimitives(primPoint,prop) +{ + Type = POINT; + m_Coords.Copy(&primPoint->m_Coords); + PrimTypeName = "Point"; +} + +CSPrimPoint::CSPrimPoint(ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(paraSet,prop) +{ + Type = POINT; + m_Coords.SetParameterSet(paraSet); + PrimTypeName = "Point"; +} + +CSPrimPoint::~CSPrimPoint() +{ +} + +void CSPrimPoint::SetCoord(int index, double val) +{ + m_Coords.SetValue(index,val); +} + +void CSPrimPoint::SetCoord(int index, const std::string val) +{ + m_Coords.SetValue(index,val); +} + +double CSPrimPoint::GetCoord(int index) +{ + return m_Coords.GetCoordValue(index,m_MeshType); +} + +ParameterScalar* CSPrimPoint::GetCoordPS(int index) +{ + return m_Coords.GetCoordPS(index); +} + +bool CSPrimPoint::GetBoundBox(double dBoundBox[6], bool PreserveOrientation) +{ + UNUSED(PreserveOrientation); //has no orientation or preserved anyways + const double *coord = m_Coords.GetCoords(m_MeshType); + for (int i=0; i<3; i++) + { + dBoundBox[2*i] = coord[i]; + dBoundBox[2*i+1] = coord[i]; + } + m_Dimension=0; + m_BoundBox_CoordSys = m_PrimCoordSystem; + return true; +} + +bool CSPrimPoint::IsInside(const double* /*Coord*/, double /*tol*/) +{ + // this is a 0D-object, you can never be inside... + return false; +} + + +bool CSPrimPoint::Update(std::string *ErrStr) +{ + bool bOK=m_Coords.Evaluate(ErrStr); + if (bOK==false) + { + std::stringstream stream; + stream << std::endl << "Error in Point (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + } + m_Coords.SetCoordinateSystem(m_PrimCoordSystem, m_MeshType); + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + return bOK; +} + +bool CSPrimPoint::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimitives::Write2XML(elem,parameterised); + return m_Coords.Write2XML(&elem,parameterised); +} + +bool CSPrimPoint::ReadFromXML(TiXmlNode &root) +{ + if (!CSPrimitives::ReadFromXML(root)) return false; + return m_Coords.ReadFromXML(dynamic_cast(&root)); +} + + +void CSPrimPoint::ShowPrimitiveStatus(std::ostream& stream) +{ + CSPrimitives::ShowPrimitiveStatus(stream); + stream << " Coordinate: " << m_Coords.GetValueString(0) << "," << m_Coords.GetValueString(1) << "," << m_Coords.GetValueString(2) << std::endl; +} diff --git a/CSXCAD/src/CSPrimPoint.h b/CSXCAD/src/CSPrimPoint.h new file mode 100644 index 0000000..890b45c --- /dev/null +++ b/CSXCAD/src/CSPrimPoint.h @@ -0,0 +1,59 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" + +//! Point Primitive +/*! + This is a point primitive (useful for field probes). + */ +class CSXCAD_EXPORT CSPrimPoint : public CSPrimitives +{ +public: + CSPrimPoint(ParameterSet* paraSet, CSProperties* prop); + CSPrimPoint(CSPrimPoint* primPoint, CSProperties *prop=NULL); + CSPrimPoint(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimPoint(); + + virtual CSPrimPoint* GetCopy(CSProperties *prop=NULL) {return new CSPrimPoint(this,prop);} + + void SetCoord(int index, double val); + void SetCoord(int index, const std::string val); + void SetCoords( double c1, double c2, double c3 ); + + //! Get the point coordinates according to the input mesh type + double GetCoord(int index); + ParameterScalar* GetCoordPS(int index); + + const ParameterCoord* GetCoords() const {return &m_Coords;} + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPrimitiveStatus(std::ostream& stream); + +protected: + //! Vector describing the point: x,y,z + ParameterCoord m_Coords; +}; + diff --git a/CSXCAD/src/CSPrimPolygon.cpp b/CSXCAD/src/CSPrimPolygon.cpp new file mode 100644 index 0000000..733fb0a --- /dev/null +++ b/CSXCAD/src/CSPrimPolygon.cpp @@ -0,0 +1,294 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimPolygon.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimPolygon::CSPrimPolygon(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(ID,paraSet,prop) +{ + Type=POLYGON; + m_NormDir = 0; + Elevation.SetParameterSet(paraSet); + PrimTypeName = std::string("Polygon"); +} + +CSPrimPolygon::CSPrimPolygon(CSPrimPolygon* primPolygon, CSProperties *prop) : CSPrimitives(primPolygon,prop) +{ + Type=POLYGON; + m_NormDir = primPolygon->m_NormDir; + Elevation.Copy(&primPolygon->Elevation); + PrimTypeName = std::string("Polygon"); +} + +CSPrimPolygon::CSPrimPolygon(ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(paraSet,prop) +{ + Type=POLYGON; + m_NormDir = 0; + Elevation.SetParameterSet(paraSet); + PrimTypeName = std::string("Polygon"); +} + +CSPrimPolygon::~CSPrimPolygon() +{ +} + +void CSPrimPolygon::SetCoord(int index, double val) +{ + if ((index>=0) && (index<(int)vCoords.size())) vCoords.at(index).SetValue(val); +} + +void CSPrimPolygon::SetCoord(int index, const std::string val) +{ + if ((index>=0) && (index<(int)vCoords.size())) vCoords.at(index).SetValue(val); +} + +void CSPrimPolygon::AddCoord(double val) +{ + vCoords.push_back(ParameterScalar(clParaSet,val)); +} + +void CSPrimPolygon::AddCoord(const std::string val) +{ + vCoords.push_back(ParameterScalar(clParaSet,val)); +} + +void CSPrimPolygon::RemoveCoords(int /*index*/) +{ + //not yet implemented +} + +double CSPrimPolygon::GetCoord(int index) +{ + if ((index>=0) && (index<(int)vCoords.size())) return vCoords.at(index).GetValue(); + return 0; +} + +ParameterScalar* CSPrimPolygon::GetCoordPS(int index) +{ + if ((index>=0) && (index<(int)vCoords.size())) return &vCoords.at(index); + return NULL; +} + +double* CSPrimPolygon::GetAllCoords(size_t &Qty, double* array) +{ + Qty=vCoords.size(); + delete[] array; + array = new double[Qty]; + for (size_t i=0;ixmax) xmax=x; + if (yymax) ymax=y; + } + int nP = (m_NormDir+1)%3; + int nPP = (m_NormDir+2)%3; + dBoundBox[2*m_NormDir] = dBoundBox[2*m_NormDir+1] = Elevation.GetValue(); + dBoundBox[2*nP] = xmin; + dBoundBox[2*nP+1] = xmax; + dBoundBox[2*nPP] = ymin; + dBoundBox[2*nPP+1] = ymax; + m_Dimension=0; + for (int n=0;n<3;++n) + { + if (dBoundBox[2*n]!=dBoundBox[2*n+1]) + ++m_Dimension; + } + return accurate; +} + +bool CSPrimPolygon::IsInside(const double* inCoord, double /*tol*/) +{ + if (inCoord==NULL) return false; + if (vCoords.size()<2) return false; + + double Coord[3]; + //transform incoming coordinates into cartesian coords + TransformCoordSystem(inCoord,Coord,m_MeshType,CARTESIAN); + if (m_Transform && Type==POLYGON) + TransformCoords(Coord,true, CARTESIAN); + + for (unsigned int n=0;n<3;++n) + if ((m_BoundBox[2*n]>Coord[n]) || (m_BoundBox[2*n+1]= y ? true : false; + bool endover; + + for (size_t i=0;iy2)) || ((y>y1) && (yx2)) || ((x>x1) && (x= y ? true : false; + if (startover != endover) + { + if ((y2 - y)*(x2 - x1) <= (y2 - y1)*(x2 - x)) + { + if (endover) wn ++; + } + else + { + if (!endover) wn --; + } + } + startover = endover; + y1 = y2; + x1 = x2; + } + // return true if polygon is inside the polygon + if (wn != 0) + return true; + + return false; +} + + +bool CSPrimPolygon::Update(std::string *ErrStr) +{ + int EC=0; + bool bOK=true; + if (! ((m_PrimCoordSystem==CARTESIAN) || (m_PrimCoordSystem==UNDEFINED_CS && m_MeshType==CARTESIAN))) + { + std::cerr << "CSPrimPolygon::Update: Warning: CSPrimPolygon can not be defined in non Cartesian coordinate systems! Result may be unexpected..." << std::endl; + ErrStr->append("Warning: CSPrimPolygon can not be defined in non Cartesian coordinate systems! Result may be unexpected...\n"); + } + for (size_t i=1;iappend(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + } + + EC=Elevation.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + bOK=false; + std::stringstream stream; + stream << std::endl << "Error in Polygon Elevation (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + //update local bounding box used to speedup IsInside() + m_BoundBoxValid = GetBoundBox(m_BoundBox); + + return bOK; +} + +bool CSPrimPolygon::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimitives::Write2XML(elem,parameterised); + + WriteTerm(Elevation,elem,"Elevation",parameterised); + + elem.SetAttribute("NormDir",m_NormDir); + + elem.SetAttribute("QtyVertices",(int)vCoords.size()/2); + + for (size_t i=0;iQueryIntAttribute("NormDir",&help)!=TIXML_SUCCESS) + return false; + m_NormDir=help; + + TiXmlElement *VT=root.FirstChildElement("Vertex"); + if (vCoords.size()!=0) return false; + int i=0; + while (VT) + { + for (int n=0;n<2;++n) this->AddCoord(0.0); + + if (ReadTerm(vCoords.at(i*2),*VT,"X1")==false) return false; + if (ReadTerm(vCoords.at(i*2+1),*VT,"X2")==false) return false; + + VT=VT->NextSiblingElement("Vertex"); + ++i; + }; + + return true; +} diff --git a/CSXCAD/src/CSPrimPolygon.h b/CSXCAD/src/CSPrimPolygon.h new file mode 100644 index 0000000..f7bb371 --- /dev/null +++ b/CSXCAD/src/CSPrimPolygon.h @@ -0,0 +1,77 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" + +//! 2D Polygon Primitive +/*! + This is an area polygon primitive defined by a number of points in space. + Warning: This primitive currently can only be defined in Cartesian coordinates. + */ +class CSXCAD_EXPORT CSPrimPolygon : public CSPrimitives +{ +public: + CSPrimPolygon(ParameterSet* paraSet, CSProperties* prop); + CSPrimPolygon(CSPrimPolygon* primPolygon, CSProperties *prop=NULL); + CSPrimPolygon(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimPolygon(); + + virtual CSPrimPolygon* GetCopy(CSProperties *prop=NULL) {return new CSPrimPolygon(this,prop);} + + void SetCoord(int index, double val); + void SetCoord(int index, const std::string val); + + void AddCoord(double val); + void AddCoord(const std::string val); + + void RemoveCoords(int index); + void ClearCoords() {vCoords.clear();} + + double GetCoord(int index); + ParameterScalar* GetCoordPS(int index); + + size_t GetQtyCoords() {return vCoords.size()/2;} + double* GetAllCoords(size_t &Qty, double* array); + + void SetNormDir(int dir) {if ((dir>=0) && (dir<3)) m_NormDir=dir;} + + int GetNormDir() {return m_NormDir;} + + void SetElevation(double val) {Elevation.SetValue(val);} + void SetElevation(const char* val) {Elevation.SetValue(val);} + + double GetElevation() {return Elevation.GetValue();} + ParameterScalar* GetElevationPS() {return &Elevation;} + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + +protected: + ///Vector describing the polygon, x1,y1,x2,y2 ... xn,yn + std::vector vCoords; + ///The polygon plane normal direction + int m_NormDir; + ///The polygon plane elevation in direction of the normal vector + ParameterScalar Elevation; +}; + diff --git a/CSXCAD/src/CSPrimPolyhedron.cpp b/CSXCAD/src/CSPrimPolyhedron.cpp new file mode 100644 index 0000000..7eac505 --- /dev/null +++ b/CSXCAD/src/CSPrimPolyhedron.cpp @@ -0,0 +1,357 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimPolyhedron.h" +#include "CSPrimPolyhedron_p.h" +#include "CSProperties.h" +#include "CSUseful.h" + +void Polyhedron_Builder::operator()(HalfedgeDS &hds) +{ + // Postcondition: `hds' is a valid polyhedral surface. + CGAL::Polyhedron_incremental_builder_3 B( hds, true); + B.begin_surface( m_polyhedron->m_Vertices.size(), m_polyhedron->m_Faces.size()); + typedef HalfedgeDS::Vertex Vertex; + typedef Vertex::Point Point; + for (size_t n=0;nm_Vertices.size();++n) + B.add_vertex( Point( m_polyhedron->m_Vertices.at(n).coord[0], m_polyhedron->m_Vertices.at(n).coord[1], m_polyhedron->m_Vertices.at(n).coord[2])); + + for (size_t f=0;fm_Faces.size();++f) + { + m_polyhedron->m_Faces.at(f).valid=false; + int *first = m_polyhedron->m_Faces.at(f).vertices, *beyond = first+m_polyhedron->m_Faces.at(f).numVertex; + if (B.test_facet(first, beyond)) + { + B.add_facet(first, beyond); + if (B.error()) + { + std::cerr << "Polyhedron_Builder::operator(): Error in polyhedron construction" << std::endl; + break; + } + m_polyhedron->m_Faces.at(f).valid=true; + } + else + { + std::cerr << "Polyhedron_Builder::operator(): Face " << f << ": Trying reverse order... "; + int help[m_polyhedron->m_Faces.at(f).numVertex]; + for (unsigned int n=0;nm_Faces.at(f).numVertex;++n) + help[n]=m_polyhedron->m_Faces.at(f).vertices[m_polyhedron->m_Faces.at(f).numVertex-1-n]; + first = help; + beyond = first+m_polyhedron->m_Faces.at(f).numVertex; + if (B.test_facet(first, beyond)) + { + B.add_facet(first, beyond); + if (B.error()) + { + std::cerr << "Polyhedron_Builder::operator(): Error in polyhedron construction" << std::endl; + break; + } + std::cerr << "success" << std::endl; + m_polyhedron->m_Faces.at(f).valid=true; + } + else + { + std::cerr << "failed" << std::endl; + ++m_polyhedron->m_InvalidFaces; + } + } + } + B.end_surface(); +} + +/*********************CSPrimPolyhedron********************************************************************/ +CSPrimPolyhedron::CSPrimPolyhedron(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(ID,paraSet,prop), d_ptr(new CSPrimPolyhedronPrivate) +{ + Type = POLYHEDRON; + PrimTypeName = "Polyhedron"; + d_ptr->m_PolyhedronTree = NULL; + m_InvalidFaces = 0; +} + +CSPrimPolyhedron::CSPrimPolyhedron(CSPrimPolyhedron* primPolyhedron, CSProperties *prop) : CSPrimitives(primPolyhedron,prop), d_ptr(new CSPrimPolyhedronPrivate) +{ + Type = POLYHEDRON; + PrimTypeName = "Polyhedron"; + d_ptr->m_PolyhedronTree = NULL; + m_InvalidFaces = 0; + + //copy all vertices + for (size_t n=0;nm_Vertices.size();++n) + AddVertex(primPolyhedron->m_Vertices.at(n).coord); + //copy all faces + for (size_t n=0;nm_Faces.size();++n) + AddFace(primPolyhedron->m_Faces.at(n).numVertex,primPolyhedron->m_Faces.at(n).vertices); +} + +CSPrimPolyhedron::CSPrimPolyhedron(ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(paraSet,prop), d_ptr(new CSPrimPolyhedronPrivate) +{ + Type = POLYHEDRON; + PrimTypeName = "Polyhedron"; + d_ptr->m_PolyhedronTree = NULL; + m_InvalidFaces = 0; +} + +CSPrimPolyhedron::~CSPrimPolyhedron() +{ + Reset(); + delete d_ptr; +} + +void CSPrimPolyhedron::Reset() +{ + m_Vertices.clear(); + for (size_t n=0;nm_Polyhedron.clear(); + d_ptr->m_PolyhedronTree = NULL; + m_InvalidFaces = 0; +} + +void CSPrimPolyhedron::AddVertex(float px, float py, float pz) +{ + vertex nv; + nv.coord[0]=px;nv.coord[1]=py;nv.coord[2]=pz; + m_Vertices.push_back(nv); +} + +float* CSPrimPolyhedron::GetVertex(unsigned int n) +{ + if (n vertices) +{ + face f; + f.numVertex=vertices.size(); + if (f.numVertex>3) + std::cerr << __func__ << ": Warning, faces other than triangles are currently not supported for discretization, expect false results!!!" << std::endl; + f.vertices=new int[f.numVertex]; + for (unsigned int n=0;nm_Polyhedron.delegate(builder); + + if (d_ptr->m_Polyhedron.is_closed()) + m_Dimension = 3; + else + { + m_Dimension = 2; + + //if structure is not closed due to invalud faces, mark it as 3D + if (m_InvalidFaces>0) + { + m_Dimension = 3; + std::cerr << "CSPrimPolyhedron::BuildTree: Warning, found polyhedron has invalud faces and is not a closed surface, setting to 3D solid anyway!" << std::endl; + } + } + + //build tree + delete d_ptr->m_PolyhedronTree; +#if CGAL_VERSION_NR >= CGAL_VERSION_NUMBER(4,6,0) + d_ptr->m_PolyhedronTree = new CGAL::AABB_tree< Traits >(faces(d_ptr->m_Polyhedron).first,faces(d_ptr->m_Polyhedron).second,d_ptr->m_Polyhedron); +#else + d_ptr->m_PolyhedronTree = new CGAL::AABB_tree< Traits >(d_ptr->m_Polyhedron.facets_begin(),d_ptr->m_Polyhedron.facets_end()); +#endif + + //update local bounding box + GetBoundBox(m_BoundBox); + double p[3] = {m_BoundBox[1]*(1.0+(double)rand()/RAND_MAX),m_BoundBox[3]*(1.0+(double)rand()/RAND_MAX),m_BoundBox[5]*(1.0+(double)rand()/RAND_MAX)}; + d_ptr->m_RandPt = Point(p[0],p[1],p[2]); + return true; +} + +int* CSPrimPolyhedron::GetFace(unsigned int n, unsigned int &numVertices) +{ + numVertices = 0; + if (nInvertTransform(pos,pos); + + for (unsigned int n=0;n<3;++n) + { + if ((m_BoundBox[2*n]>pos[n]) || (m_BoundBox[2*n+1]m_RandPt); + // return true for an odd number of intersections + if ((d_ptr->m_PolyhedronTree->number_of_intersected_primitives(segment_query)%2)==1) + return true; + return false; +} + + +bool CSPrimPolyhedron::Update(std::string *ErrStr) +{ + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + return CSPrimitives::Update(ErrStr); +} + +bool CSPrimPolyhedron::Write2XML(TiXmlElement &elem, bool parameterised) +{ + if (CSPrimitives::Write2XML(elem,parameterised)==false) + return false; + + for (size_t n=0;n coords; + TiXmlElement* vertex = root.FirstChildElement("Vertex"); + while (vertex) + { + coords.clear(); + FN = vertex->FirstChild(); + if (FN!=NULL) + { + Text = FN->ToText(); + if (Text!=NULL) + coords = SplitString2Double(std::string(Text->Value()), ','); + else + return false; + if (coords.size()!=3) + return false; + AddVertex(coords.at(0),coords.at(1),coords.at(2)); + } + else + return false; + vertex = vertex->NextSiblingElement("Vertex"); + } + + // read faces + std::vector vertices; + TiXmlElement* face = root.FirstChildElement("Face"); + while (face) + { + coords.clear(); + FN = face->FirstChild(); + if (FN!=NULL) + { + Text = FN->ToText(); + if (Text!=NULL) + vertices = SplitString2Int(std::string(Text->Value()), ','); + else + return false; + AddFace(vertices); + } + else + return false; + face = face->NextSiblingElement("Face"); + } + return BuildTree(); +} + + +void CSPrimPolyhedron::ShowPrimitiveStatus(std::ostream& stream) +{ + CSPrimitives::ShowPrimitiveStatus(stream); + stream << " Number of Vertices: " << m_Vertices.size() << std::endl; + stream << " Number of Faces: " << m_Faces.size() << std::endl; + stream << " Number of invalid Faces: " << m_InvalidFaces << std::endl; +} diff --git a/CSXCAD/src/CSPrimPolyhedron.h b/CSXCAD/src/CSPrimPolyhedron.h new file mode 100644 index 0000000..25c2add --- /dev/null +++ b/CSXCAD/src/CSPrimPolyhedron.h @@ -0,0 +1,83 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" + +struct CSPrimPolyhedronPrivate; + +//! Polyhedron Primitive +/*! + This is a polyhedron primitive. A 3D solid object, defined by vertices and faces + */ +class CSXCAD_EXPORT CSPrimPolyhedron : public CSPrimitives +{ + friend class Polyhedron_Builder; +public: + struct face + { + unsigned int numVertex; + int* vertices; + bool valid; + }; + struct vertex + { + float coord[3]; + }; + + CSPrimPolyhedron(ParameterSet* paraSet, CSProperties* prop); + CSPrimPolyhedron(CSPrimPolyhedron* primPolyhedron, CSProperties *prop=NULL); + CSPrimPolyhedron(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimPolyhedron(); + + virtual void Reset(); + + virtual void AddVertex(float p[3]) {AddVertex(p[0],p[1],p[2]);} + virtual void AddVertex(double p[3]) {AddVertex(p[0],p[1],p[2]);} + virtual void AddVertex(float px, float py, float pz); + + virtual unsigned int GetNumVertices() const {return m_Vertices.size();} + virtual float* GetVertex(unsigned int n); + + virtual void AddFace(face f); + virtual void AddFace(int numVertex, int* vertices); + virtual void AddFace(std::vector vertices); + + virtual bool BuildTree(); + + virtual unsigned int GetNumFaces() const {return m_Faces.size();} + virtual int* GetFace(unsigned int n, unsigned int &numVertices); + virtual bool GetFaceValid(unsigned int n) const {return m_Faces.at(n).valid;} + + virtual CSPrimPolyhedron* GetCopy(CSProperties *prop=NULL) {return new CSPrimPolyhedron(this,prop);} + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPrimitiveStatus(std::ostream& stream); + +protected: + unsigned int m_InvalidFaces; + std::vector m_Vertices; + std::vector m_Faces; + CSPrimPolyhedronPrivate *d_ptr; //!< pointer to private data structure, to hide the CGAL dependency from applications +}; diff --git a/CSXCAD/src/CSPrimPolyhedronReader.cpp b/CSXCAD/src/CSPrimPolyhedronReader.cpp new file mode 100644 index 0000000..ed224fd --- /dev/null +++ b/CSXCAD/src/CSPrimPolyhedronReader.cpp @@ -0,0 +1,177 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include +#include +#include +#include + +#include "CSPrimPolyhedronReader.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimPolyhedronReader::CSPrimPolyhedronReader(ParameterSet* paraSet, CSProperties* prop): CSPrimPolyhedron(paraSet,prop) +{ + Type = POLYHEDRONREADER; + PrimTypeName = "PolyhedronReader"; + m_filetype = UNKNOWN; + m_filename = std::string(); +} + +CSPrimPolyhedronReader::CSPrimPolyhedronReader(CSPrimPolyhedronReader* primPHReader, CSProperties *prop) : CSPrimPolyhedron(primPHReader, prop) +{ + Type = POLYHEDRONREADER; + PrimTypeName = "PolyhedronReader"; + + m_filename = primPHReader->m_filename; + m_filetype = primPHReader->m_filetype; +} + +CSPrimPolyhedronReader::CSPrimPolyhedronReader(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimPolyhedron(ID, paraSet, prop) +{ + Type = POLYHEDRONREADER; + PrimTypeName = "PolyhedronReader"; + m_filetype = UNKNOWN; + m_filename = std::string(); +} + +CSPrimPolyhedronReader::~CSPrimPolyhedronReader() +{ +} + +bool CSPrimPolyhedronReader::Update(std::string *ErrStr) +{ + return CSPrimPolyhedron::Update(ErrStr); +} + +bool CSPrimPolyhedronReader::Write2XML(TiXmlElement &elem, bool parameterised) +{ + elem.SetAttribute("Filename",m_filename); + + switch (m_filetype) + { + case STL_FILE: + elem.SetAttribute("FileType","STL"); + break; + case PLY_FILE: + elem.SetAttribute("FileType","PLY"); + break; + default: + elem.SetAttribute("FileType","Unkown"); + break; + } + return CSPrimitives::Write2XML(elem,parameterised); +} + +bool CSPrimPolyhedronReader::ReadFromXML(TiXmlNode &root) +{ + if (!CSPrimitives::ReadFromXML(root)) return false; + + TiXmlElement* elem=root.ToElement(); + if (elem==NULL) return false; + if (elem->QueryStringAttribute("FileName",&m_filename)!=TIXML_SUCCESS) + { + std::cerr << "CSPrimPolyhedronReader::ReadFromXML: Error, can't read filename!" << std::endl; + return false; + } + std::string type; + if (elem->QueryStringAttribute("FileType",&type)!=TIXML_SUCCESS) + { + std::cerr << "CSPrimPolyhedronReader::ReadFromXML: Error, can't read file type!" << std::endl; + return false; + } + if (type.compare("STL")==0) + m_filetype=STL_FILE; + else if (type.compare("PLY")==0) + m_filetype=PLY_FILE; + else + m_filetype=UNKNOWN; + + if (ReadFile()==false) + { + std::cerr << "CSPrimPolyhedronReader::ReadFromXML: Failed to read file." << std::endl; + return false; + } + + return BuildTree(); +} + +bool CSPrimPolyhedronReader::ReadFile() +{ + vtkPolyData *polydata = NULL; + switch (m_filetype) + { + case STL_FILE: + { + vtkSTLReader* reader = vtkSTLReader::New(); + reader->SetFileName(m_filename.c_str()); + reader->SetMerging(1); + polydata = reader->GetOutput(0); + reader->Update(); + break; + } + case PLY_FILE: + { + vtkPLYReader* reader = vtkPLYReader::New(); + reader->SetFileName(m_filename.c_str()); + polydata = reader->GetOutput(0); + reader->Update(); + break; + } + case UNKNOWN: + default: + { + std::cerr << "CSPrimPolyhedronReader::ReadFile: unknown filetype, skipping..." << std::endl; + return false; + break; + } + } + //polydata->Update(); // not availabe for vtk 6.x, now done only on reader? + if ((polydata->GetNumberOfPoints()==0) || (polydata->GetNumberOfCells()==0)) + { + std::cerr << "CSPrimPolyhedronReader::ReadFile: file invalid or empty, skipping ..." << std::endl; + return false; + } + vtkCellArray *verts = polydata->GetPolys(); + if (verts->GetNumberOfCells()==0) + { + std::cerr << "CSPrimPolyhedronReader::ReadFile: file invalid or empty, skipping ..." << std::endl; + return false; + } + + for (int n=0;nGetNumberOfPoints();++n) + AddVertex(polydata->GetPoint(n)); + + vtkIdType numP; + vtkIdType *vertices = new vtkIdType[10]; + while (verts->GetNextCell(numP, vertices)) + { + face f; + f.numVertex=numP; + f.vertices = new int[f.numVertex]; + for (unsigned int np=0;np. +*/ + +#pragma once + +#include "CSPrimitives.h" +#include "CSPrimPolyhedron.h" + +//! STL/PLY import primitive +class CSXCAD_EXPORT CSPrimPolyhedronReader : public CSPrimPolyhedron +{ +public: + //! Import file type + enum FileType + { + UNKNOWN, STL_FILE, PLY_FILE + }; + + CSPrimPolyhedronReader(ParameterSet* paraSet, CSProperties* prop); + CSPrimPolyhedronReader(CSPrimPolyhedronReader* primPHReader, CSProperties *prop=NULL); + CSPrimPolyhedronReader(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimPolyhedronReader(); + + virtual CSPrimPolyhedronReader* GetCopy(CSProperties *prop=NULL) {return new CSPrimPolyhedronReader(this,prop);} + + virtual void SetFilename(std::string name) {m_filename=name;} + virtual std::string GetFilename() const {return m_filename;} + + virtual void SetFileType(FileType ft) {m_filetype=ft;} + virtual FileType GetFileType() const {return m_filetype;} + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual bool ReadFile(); + +protected: + std::string m_filename; + FileType m_filetype; +}; diff --git a/CSXCAD/src/CSPrimPolyhedron_p.h b/CSXCAD/src/CSPrimPolyhedron_p.h new file mode 100644 index 0000000..e2877cc --- /dev/null +++ b/CSXCAD/src/CSPrimPolyhedron_p.h @@ -0,0 +1,48 @@ +#ifndef CSPRIMPOLYHEDRON_P_H +#define CSPRIMPOLYHEDRON_P_H + +#include +#include +#include +#include +#include +#if CGAL_VERSION_NR >= CGAL_VERSION_NUMBER(4,6,0) + #include +#else + #include + #include +#endif + +typedef CGAL::Simple_cartesian Kernel; +typedef CGAL::Polyhedron_3 Polyhedron; +typedef Polyhedron::HalfedgeDS HalfedgeDS; + +class Polyhedron_Builder : public CGAL::Modifier_base +{ +public: + Polyhedron_Builder(CSPrimPolyhedron* polyhedron) {m_polyhedron=polyhedron;} + void operator()(HalfedgeDS &hds); + +protected: + CSPrimPolyhedron* m_polyhedron; +}; + +typedef Kernel::Point_3 Point; +#if CGAL_VERSION_NR >= CGAL_VERSION_NUMBER(4,6,0) +typedef CGAL::AABB_face_graph_triangle_primitive Primitive; +#else +typedef CGAL::AABB_polyhedron_triangle_primitive Primitive; +#endif +typedef CGAL::AABB_traits Traits; +typedef CGAL::Simple_cartesian::Ray_3 Ray; +typedef Kernel::Segment_3 Segment; + +struct CSPrimPolyhedronPrivate +{ + Polyhedron m_Polyhedron; + Point m_RandPt; + CGAL::AABB_tree *m_PolyhedronTree; +}; + + +#endif // CSPRIMPOLYHEDRON_P_H diff --git a/CSXCAD/src/CSPrimRotPoly.cpp b/CSXCAD/src/CSPrimRotPoly.cpp new file mode 100644 index 0000000..705b08e --- /dev/null +++ b/CSXCAD/src/CSPrimRotPoly.cpp @@ -0,0 +1,191 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" +#include + +#include "CSPrimRotPoly.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimRotPoly::CSPrimRotPoly(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimPolygon(ID,paraSet,prop) +{ + Type=ROTPOLY; + m_RotAxisDir=0; + PrimTypeName = std::string("RotPoly"); +} + +CSPrimRotPoly::CSPrimRotPoly(CSPrimRotPoly* primRotPoly, CSProperties *prop) : CSPrimPolygon(primRotPoly,prop) +{ + Type=ROTPOLY; + m_RotAxisDir=primRotPoly->m_RotAxisDir; + PrimTypeName = std::string("RotPoly"); +} + +CSPrimRotPoly::CSPrimRotPoly(ParameterSet* paraSet, CSProperties* prop) : CSPrimPolygon(paraSet,prop) +{ + Type=ROTPOLY; + m_RotAxisDir=0; + PrimTypeName = std::string("RotPoly"); +} + +CSPrimRotPoly::~CSPrimRotPoly() +{ +} + +bool CSPrimRotPoly::IsInside(const double* inCoord, double /*tol*/) +{ + if (inCoord==NULL) return false; + + double Coord[3]; + //transform incoming coordinates into cartesian coords + TransformCoordSystem(inCoord,Coord,m_MeshType,CARTESIAN); + if (m_Transform && Type==ROTPOLY) + TransformCoords(Coord,true, CARTESIAN); + + double origin[3]={0,0,0}; + double dir[3]={0,0,0}; + dir[m_RotAxisDir] = 1; + double foot; + double dist; + Point_Line_Distance(Coord, origin, dir, foot, dist); + + int raP = (m_RotAxisDir+1)%3; + int raPP = (m_RotAxisDir+2)%3; + double alpha = atan2(Coord[raPP],Coord[raP]); + if (raP == m_NormDir) + alpha=alpha-M_PI/2; + if (alpha<0) + alpha+=2*M_PI; + + origin[0] = dist;origin[1] = dist;origin[2] = dist; + origin[m_NormDir] = 0; + origin[m_RotAxisDir] = foot; + + if (alpha2*M_PI) + alpha-=2*M_PI; + + if (alpham_StartStopAng[1]) + return false; + + origin[0] = dist;origin[1] = dist;origin[2] = dist; + origin[m_NormDir] = 0; + origin[m_RotAxisDir] = foot; + return CSPrimPolygon::IsInside(origin); +} + + +bool CSPrimRotPoly::Update(std::string *ErrStr) +{ + int EC=0; + bool bOK = CSPrimPolygon::Update(ErrStr); + + EC=StartStopAngle[0].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + bOK=false; + std::stringstream stream; + stream << std::endl << "Error in RotPoly Start Angle (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + EC=StartStopAngle[1].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + bOK=false; + std::stringstream stream; + stream << std::endl << "Error in RotPoly Stop Angle (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + // make angle range to 0..2*M_PI & stop > start! + m_StartStopAng[0]=StartStopAngle[0].GetValue(); + m_StartStopAng[1]=StartStopAngle[1].GetValue(); + if (m_StartStopAng[0]>m_StartStopAng[1]) + m_StartStopAng[1]+=2*M_PI; + if (m_StartStopAng[0]>2*M_PI) + { + m_StartStopAng[0]-=2*M_PI; + m_StartStopAng[1]-=2*M_PI; + } + if (m_StartStopAng[0]<0) + { + m_StartStopAng[0]+=2*M_PI; + m_StartStopAng[1]+=2*M_PI; + } + + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + + return bOK; +} + +bool CSPrimRotPoly::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimPolygon::Write2XML(elem,parameterised); + + elem.SetAttribute("RotAxisDir",m_RotAxisDir); + + TiXmlElement Ang("Angles"); + WriteTerm(StartStopAngle[0],Ang,"Start",parameterised); + WriteTerm(StartStopAngle[1],Ang,"Stop",parameterised); + elem.InsertEndChild(Ang); + return true; +} + +bool CSPrimRotPoly::ReadFromXML(TiXmlNode &root) +{ + if (CSPrimPolygon::ReadFromXML(root)==false) return false; + + if (Elevation.GetValue()!=0) + std::cerr << __func__ << ": Warning: An elevation for a rotational poly is not supported! Skipping!" << std::endl; + Elevation.SetValue(0); + + TiXmlElement *elem = root.ToElement(); + if (elem==NULL) return false; + + int help; + if (elem->QueryIntAttribute("RotAxisDir",&help)!=TIXML_SUCCESS) + return false; + m_RotAxisDir=help; + + TiXmlElement *NV=elem->FirstChildElement("Angles"); + if (NV==NULL) return false; + if (ReadTerm(StartStopAngle[0],*NV,"Start")==false) return false; + if (ReadTerm(StartStopAngle[1],*NV,"Stop")==false) return false; + + return true; +} diff --git a/CSXCAD/src/CSPrimRotPoly.h b/CSXCAD/src/CSPrimRotPoly.h new file mode 100644 index 0000000..174e887 --- /dev/null +++ b/CSXCAD/src/CSPrimRotPoly.h @@ -0,0 +1,61 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" +#include "CSPrimPolygon.h" + +//! Rotational extruded polygon Primitive +/*! + This is a rotation extruded area polygon primitive defined by a number of points in space, an extrude axis and start-, stop-angle. + Warning: This primitive currently can only be defined in Cartesian coordinates. + */ +class CSXCAD_EXPORT CSPrimRotPoly : public CSPrimPolygon +{ +public: + CSPrimRotPoly(ParameterSet* paraSet, CSProperties* prop); + CSPrimRotPoly(CSPrimRotPoly* primPolygon, CSProperties *prop=NULL); + CSPrimRotPoly(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimRotPoly(); + + virtual CSPrimRotPoly* GetCopy(CSProperties *prop=NULL) {return new CSPrimRotPoly(this,prop);} + + void SetRotAxisDir(int dir) {if ((dir>=0) && (dir<3)) m_RotAxisDir=dir;} + + int GetRotAxisDir() const {return m_RotAxisDir;} + + void SetAngle(int index, double val) {if ((index>=0) && (index<2)) StartStopAngle[index].SetValue(val);} + void SetAngle(int index, const std::string val) {if ((index>=0) && (index<2)) StartStopAngle[index].SetValue(val);} + + double GetAngle(int index) const {if ((index>=0) && (index<2)) return StartStopAngle[index].GetValue(); else return 0;} + ParameterScalar* GetAnglePS(int index) {if ((index>=0) && (index<2)) return &StartStopAngle[index]; else return NULL;} + + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + +protected: + //start-stop angle + ParameterScalar StartStopAngle[2]; + //sorted and pre evaluated angles + double m_StartStopAng[2]; + //rot axis direction + int m_RotAxisDir; +}; diff --git a/CSXCAD/src/CSPrimSphere.cpp b/CSXCAD/src/CSPrimSphere.cpp new file mode 100644 index 0000000..a372fe3 --- /dev/null +++ b/CSXCAD/src/CSPrimSphere.cpp @@ -0,0 +1,176 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimSphere.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimSphere::CSPrimSphere(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(ID,paraSet,prop) +{ + Type=SPHERE; + m_Center.SetParameterSet(paraSet); + psRadius.SetParameterSet(paraSet); + PrimTypeName = std::string("Sphere"); +} + +CSPrimSphere::CSPrimSphere(CSPrimSphere* sphere, CSProperties *prop) : CSPrimitives(sphere,prop) +{ + Type=SPHERE; + m_Center.Copy(&sphere->m_Center); + psRadius.Copy(&sphere->psRadius); + PrimTypeName = std::string("Sphere"); +} + +CSPrimSphere::CSPrimSphere(ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(paraSet,prop) +{ + Type=SPHERE; + m_Center.SetParameterSet(paraSet); + psRadius.SetParameterSet(paraSet); + PrimTypeName = std::string("Sphere"); +} + + +CSPrimSphere::~CSPrimSphere() +{ +} + +void CSPrimSphere::SetCenter(double x1, double x2, double x3) +{ + SetCoord(0,x1); + SetCoord(1,x2); + SetCoord(2,x3); +} + +void CSPrimSphere::SetCenter(double x[3]) +{ + for (int n=0;n<3;++n) + SetCoord(n, x[n]); +} + +void CSPrimSphere::SetCenter(std::string x1, std::string x2, std::string x3) +{ + SetCoord(0,x1); + SetCoord(1,x2); + SetCoord(2,x3); +} + +void CSPrimSphere::SetCenter(std::string x[3]) +{ + for (int n=0;n<3;++n) + SetCoord(n, x[n]); +} + + +bool CSPrimSphere::GetBoundBox(double dBoundBox[6], bool PreserveOrientation) +{ + UNUSED(PreserveOrientation); //has no orientation or preserved anyways + const double* center = m_Center.GetCartesianCoords(); + m_BoundBox_CoordSys=CARTESIAN; + double radius = psRadius.GetValue(); + for (unsigned int i=0;i<3;++i) + { + dBoundBox[2*i]=center[i]-radius; + dBoundBox[2*i+1]=center[i]+radius; + } + if (radius>0) + m_Dimension=3; + else + m_Dimension=0; + return true; +} + +bool CSPrimSphere::IsInside(const double* Coord, double /*tol*/) +{ + if (Coord==NULL) return false; + double out[3]; + const double* center = m_Center.GetCartesianCoords(); + TransformCoordSystem(Coord,out,m_MeshType,CARTESIAN); + if (m_Transform) + m_Transform->InvertTransform(out,out); + double dist=sqrt(pow(out[0]-center[0],2)+pow(out[1]-center[1],2)+pow(out[2]-center[2],2)); + if (distappend(stream.str()); + } + m_Center.SetCoordinateSystem(m_PrimCoordSystem, m_MeshType); + + EC=psRadius.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + bOK=false; + std::stringstream stream; + stream << std::endl << "Error in " << PrimTypeName << " Radius (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + + return bOK; +} + +bool CSPrimSphere::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimitives::Write2XML(elem,parameterised); + + WriteTerm(psRadius,elem,"Radius",parameterised); + + TiXmlElement Center("Center"); + m_Center.Write2XML(&Center,parameterised); + elem.InsertEndChild(Center); + return true; +} + +bool CSPrimSphere::ReadFromXML(TiXmlNode &root) +{ + if (CSPrimitives::ReadFromXML(root)==false) return false; + + TiXmlElement *elem = root.ToElement(); + if (elem==NULL) return false; + if (ReadTerm(psRadius,*elem,"Radius")==false) return false; + + TiXmlElement* Center=root.FirstChildElement("Center"); + if (m_Center.ReadFromXML(Center) == false) return false; + + return true; +} + +void CSPrimSphere::ShowPrimitiveStatus(std::ostream& stream) +{ + CSPrimitives::ShowPrimitiveStatus(stream); + stream << " Center: " << m_Center.GetValueString(0) << "," << m_Center.GetValueString(1) << "," << m_Center.GetValueString(2) << std::endl; + stream << " Radius: " << psRadius.GetValueString() << std::endl; +} diff --git a/CSXCAD/src/CSPrimSphere.h b/CSXCAD/src/CSPrimSphere.h new file mode 100644 index 0000000..d7fb071 --- /dev/null +++ b/CSXCAD/src/CSPrimSphere.h @@ -0,0 +1,72 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" + +//! Sphere Primitive +/*! + This is a spherical primitive defined by its center coordinates and a radius. + */ +class CSXCAD_EXPORT CSPrimSphere : public CSPrimitives +{ +public: + CSPrimSphere(ParameterSet* paraSet, CSProperties* prop); + CSPrimSphere(CSPrimSphere* sphere, CSProperties *prop=NULL); + CSPrimSphere(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimSphere(); + + virtual CSPrimitives* GetCopy(CSProperties *prop=NULL) {return new CSPrimSphere(this,prop);} + + //! Set the center point coordinate + void SetCoord(int index, double val) {m_Center.SetValue(index,val);} + //! Set the center point coordinate as paramater string + void SetCoord(int index, const char* val) {m_Center.SetValue(index,val);} + //! Set the center point coordinate as paramater string + void SetCoord(int index, std::string val) {m_Center.SetValue(index,val);} + + void SetCenter(double x1, double x2, double x3); + void SetCenter(double x[3]); + + void SetCenter(std::string x1, std::string x2, std::string x3); + void SetCenter(std::string x[3]); + + double GetCoord(int index) {return m_Center.GetValue(index);} + ParameterScalar* GetCoordPS(int index) {return m_Center.GetCoordPS(index);} + ParameterCoord* GetCenter() {return &m_Center;} + + void SetRadius(double val) {psRadius.SetValue(val);} + void SetRadius(const char* val) {psRadius.SetValue(val);} + + double GetRadius() {return psRadius.GetValue();} + ParameterScalar* GetRadiusPS() {return &psRadius;} + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPrimitiveStatus(std::ostream& stream); + +protected: + ParameterCoord m_Center; + ParameterScalar psRadius; +}; + diff --git a/CSXCAD/src/CSPrimSphericalShell.cpp b/CSXCAD/src/CSPrimSphericalShell.cpp new file mode 100644 index 0000000..73f2d82 --- /dev/null +++ b/CSXCAD/src/CSPrimSphericalShell.cpp @@ -0,0 +1,134 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimSphericalShell.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimSphericalShell::CSPrimSphericalShell(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimSphere(ID,paraSet,prop) +{ + Type=SPHERICALSHELL; + PrimTypeName = std::string("SphericalShell"); + psShellWidth.SetParameterSet(paraSet); +} + +CSPrimSphericalShell::CSPrimSphericalShell(CSPrimSphericalShell* sphere, CSProperties *prop) : CSPrimSphere(sphere,prop) +{ + Type=SPHERICALSHELL; + PrimTypeName = std::string("SphericalShell"); + psShellWidth.Copy(&sphere->psShellWidth); +} + +CSPrimSphericalShell::CSPrimSphericalShell(ParameterSet* paraSet, CSProperties* prop) : CSPrimSphere(paraSet,prop) +{ + Type=SPHERICALSHELL; + PrimTypeName = std::string("SphericalShell"); + psShellWidth.SetParameterSet(paraSet); +} + + +CSPrimSphericalShell::~CSPrimSphericalShell() +{ +} + +bool CSPrimSphericalShell::GetBoundBox(double dBoundBox[6], bool PreserveOrientation) +{ + UNUSED(PreserveOrientation); //has no orientation or preserved anyways + const double* center = m_Center.GetCartesianCoords(); + m_BoundBox_CoordSys=CARTESIAN; + double radius = psRadius.GetValue(); + double shellwidth = psShellWidth.GetValue(); + for (unsigned int i=0;i<3;++i) + { + dBoundBox[2*i]=center[i]-radius-shellwidth/2.0; + dBoundBox[2*i+1]=center[i]+radius+shellwidth/2.0; + } + if (shellwidth>0) + m_Dimension=3; + else if (radius>0) + m_Dimension=1; + else + m_Dimension=0; + return true; +} + +bool CSPrimSphericalShell::IsInside(const double* Coord, double /*tol*/) +{ + if (Coord==NULL) return false; + double out[3]; + const double* center = m_Center.GetCartesianCoords(); + TransformCoordSystem(Coord,out,m_MeshType,CARTESIAN); + if (m_Transform) + m_Transform->InvertTransform(out,out); + double dist=sqrt(pow(out[0]-center[0],2)+pow(out[1]-center[1],2)+pow(out[2]-center[2],2)); + if (fabs(dist-psRadius.GetValue())< psShellWidth.GetValue()/2.0) + return true; + return false; +} + +bool CSPrimSphericalShell::Update(std::string *ErrStr) +{ + int EC=0; + bool bOK=CSPrimSphere::Update(ErrStr); + + EC=psShellWidth.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + bOK=false; + std::stringstream stream; + stream << std::endl << "Error in " << PrimTypeName << " shell-width (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + + return bOK; +} + +bool CSPrimSphericalShell::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimSphere::Write2XML(elem,parameterised); + + WriteTerm(psShellWidth,elem,"ShellWidth",parameterised); + return true; +} + +bool CSPrimSphericalShell::ReadFromXML(TiXmlNode &root) +{ + if (CSPrimSphere::ReadFromXML(root)==false) return false; + + TiXmlElement *elem = root.ToElement(); + if (elem==NULL) return false; + if (ReadTerm(psShellWidth,*elem,"ShellWidth")==false) return false; + + return true; +} + +void CSPrimSphericalShell::ShowPrimitiveStatus(std::ostream& stream) +{ + CSPrimSphere::ShowPrimitiveStatus(stream); + stream << " Shell width: " << psShellWidth.GetValueString() << std::endl; +} diff --git a/CSXCAD/src/CSPrimSphericalShell.h b/CSXCAD/src/CSPrimSphericalShell.h new file mode 100644 index 0000000..f1f1e17 --- /dev/null +++ b/CSXCAD/src/CSPrimSphericalShell.h @@ -0,0 +1,57 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" +#include "CSPrimSphere.h" + +//! SphericalShell Primitive +/*! + This is a spherical shell primitive derived from the sphere primitive, adding a shell width which is centered around the sphere radius. + \sa CSPrimSphere + */ +class CSXCAD_EXPORT CSPrimSphericalShell : public CSPrimSphere +{ +public: + CSPrimSphericalShell(ParameterSet* paraSet, CSProperties* prop); + CSPrimSphericalShell(CSPrimSphericalShell* sphereshell, CSProperties *prop=NULL); + CSPrimSphericalShell(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimSphericalShell(); + + virtual CSPrimitives* GetCopy(CSProperties *prop=NULL) {return new CSPrimSphericalShell(this,prop);} + + void SetShellWidth(double val) {psShellWidth.SetValue(val);} + void SetShellWidth(const char* val) {psShellWidth.SetValue(val);} + + double GetShellWidth() {return psShellWidth.GetValue();} + ParameterScalar* GetShellWidthPS() {return &psShellWidth;} + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPrimitiveStatus(std::ostream& stream); + +protected: + ParameterScalar psShellWidth; +}; + + diff --git a/CSXCAD/src/CSPrimUserDefined.cpp b/CSXCAD/src/CSPrimUserDefined.cpp new file mode 100644 index 0000000..2cd5219 --- /dev/null +++ b/CSXCAD/src/CSPrimUserDefined.cpp @@ -0,0 +1,252 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimUserDefined.h" +#include "CSProperties.h" +#include "CSFunctionParser.h" +#include "CSUseful.h" + +CSPrimUserDefined::CSPrimUserDefined(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(ID,paraSet,prop) +{ + Type=USERDEFINED; + fParse = new CSFunctionParser(); + stFunction = std::string(); + CoordSystem=CARESIAN_SYSTEM; + for (int i=0;i<3;++i) {dPosShift[i].SetParameterSet(paraSet);} + PrimTypeName = std::string("User-Defined"); +} + +CSPrimUserDefined::CSPrimUserDefined(CSPrimUserDefined* primUDef, CSProperties *prop) : CSPrimitives(primUDef,prop) +{ + Type=USERDEFINED; + fParse = new CSFunctionParser(*primUDef->fParse); + stFunction = std::string(primUDef->stFunction); + CoordSystem = primUDef->CoordSystem; + for (int i=0;i<3;++i) + dPosShift[i].Copy(&primUDef->dPosShift[i]); + PrimTypeName = std::string("User-Defined"); +} + +CSPrimUserDefined::CSPrimUserDefined(ParameterSet* paraSet, CSProperties* prop) : CSPrimitives(paraSet,prop) +{ + Type=USERDEFINED; + fParse = new CSFunctionParser(); + stFunction = std::string(); + CoordSystem=CARESIAN_SYSTEM; + for (int i=0;i<3;++i) + dPosShift[i].SetParameterSet(paraSet); + PrimTypeName = std::string("User-Defined"); +} + + +CSPrimUserDefined::~CSPrimUserDefined() +{ + delete fParse;fParse=NULL; +} + +void CSPrimUserDefined::SetCoordSystem(UserDefinedCoordSystem newSystem) +{ + CoordSystem=newSystem; +} + +void CSPrimUserDefined::SetFunction(const char* func) +{ + if (func==NULL) return; + stFunction = std::string(func); +} + +bool CSPrimUserDefined::GetBoundBox(double dBoundBox[6], bool PreserveOrientation) +{ + UNUSED(PreserveOrientation); //has no orientation or preserved anyways + //this type has no simple bound box + double max=std::numeric_limits::max(); + dBoundBox[0]=dBoundBox[2]=dBoundBox[4]=-max; + dBoundBox[1]=dBoundBox[3]=dBoundBox[5]=max; + bool accurate=false; + return accurate; +} + +bool CSPrimUserDefined::IsInside(const double* Coord, double /*tol*/) +{ + if (Coord==NULL) return false; + + int NrPara=clParaSet->GetQtyParameter(); + if (NrPara!=iQtyParameter) return false; + double *vars = new double[NrPara+6]; + + vars=clParaSet->GetValueArray(vars); + + double inCoord[3] = {Coord[0],Coord[1],Coord[2]}; + //transform incoming coordinates into cartesian coords + TransformCoordSystem(Coord,inCoord,m_MeshType,CARTESIAN); + if (m_Transform) + m_Transform->InvertTransform(inCoord,inCoord); + + double x=inCoord[0]-dPosShift[0].GetValue(); + double y=inCoord[1]-dPosShift[1].GetValue(); + double z=inCoord[2]-dPosShift[2].GetValue(); + double rxy=sqrt(x*x+y*y); + vars[NrPara]=x; + vars[NrPara+1]=y; + vars[NrPara+2]=z; + + switch (CoordSystem) + { + case CARESIAN_SYSTEM: //uses x,y,z + vars[NrPara+3]=0; + vars[NrPara+4]=0; + vars[NrPara+5]=0; break; + case CYLINDER_SYSTEM: //uses x,y,z,r,a,0 + vars[NrPara+3]=rxy; + vars[NrPara+4]=atan2(y,x); + vars[NrPara+5]=0; + break; + case SPHERE_SYSTEM: //uses x,y,z,r,a,t + vars[NrPara+3]=sqrt(x*x+y*y+z*z); + vars[NrPara+4]=atan2(y,x); + vars[NrPara+5]=asin(1)-atan(z/rxy); + //cout << "x::" << x << "y::" << y << "z::" << z << "r::" << vars[NrPara] << "a::" << vars[NrPara+1] << "t::" << vars[NrPara+2] << std::endl; + break; + default: + //unknown System + return false; + break; + } + double dValue=0; + + if (fParse->GetParseErrorType()==FunctionParser::FP_NO_ERROR) dValue=fParse->Eval(vars); + else dValue=0; + delete[] vars;vars=NULL; + + if (dValue==1) + return true; + return false; +} + + +bool CSPrimUserDefined::Update(std::string *ErrStr) +{ + int EC=0; + bool bOK=true; + std::string vars; + switch (CoordSystem) + { + case CARESIAN_SYSTEM: + vars=std::string("x,y,z"); + break; + case CYLINDER_SYSTEM: + vars=std::string("x,y,z,r,a"); + break; + case SPHERE_SYSTEM: + vars=std::string("x,y,z,r,a,t"); + break; + default: + //unknown System + return false; + break; + } + iQtyParameter=clParaSet->GetQtyParameter(); + if (iQtyParameter>0) + { + fParameter=std::string(clParaSet->GetParameterString()); + vars = fParameter + "," + vars; + } + + fParse->Parse(stFunction,vars); + + EC=fParse->GetParseErrorType(); + //cout << fParse.ErrorMsg(); + + if (EC!=FunctionParser::FP_NO_ERROR) bOK=false; + + if ((EC!=FunctionParser::FP_NO_ERROR) && (ErrStr!=NULL)) + { + std::ostringstream oss; + oss << "\nError in User Defined Primitive Function (ID: " << uiID << "): " << fParse->ErrorMsg(); + ErrStr->append(oss.str()); + bOK=false; + } + + 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)) + { + bOK=false; + std::ostringstream oss; + oss << "\nError in User Defined Primitive Coord (ID: " << uiID << "): "; + ErrStr->append(oss.str()); + PSErrorCode2Msg(EC,ErrStr); + } + } + + //update local bounding box + m_BoundBoxValid = GetBoundBox(m_BoundBox); + + return bOK; +} + +bool CSPrimUserDefined::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimitives::Write2XML(elem,parameterised); + + elem.SetAttribute("CoordSystem",CoordSystem); + + TiXmlElement P1("CoordShift"); + WriteTerm(dPosShift[0],P1,"X",parameterised); + WriteTerm(dPosShift[1],P1,"Y",parameterised); + WriteTerm(dPosShift[2],P1,"Z",parameterised); + elem.InsertEndChild(P1); + + TiXmlElement FuncElem("Function"); + TiXmlText FuncText(GetFunction()); + FuncElem.InsertEndChild(FuncText); + + elem.InsertEndChild(FuncElem); + return true; +} + +bool CSPrimUserDefined::ReadFromXML(TiXmlNode &root) +{ + if (CSPrimitives::ReadFromXML(root)==false) return false; + + int value; + TiXmlElement* elem=root.ToElement(); + if (elem==NULL) return false; + if (elem->QueryIntAttribute("CoordSystem",&value)!=TIXML_SUCCESS) return false; + SetCoordSystem((UserDefinedCoordSystem)value); + + //P1 + TiXmlElement* P1=root.FirstChildElement("CoordShift"); + if (P1==NULL) return false; + if (ReadTerm(dPosShift[0],*P1,"X")==false) return false; + if (ReadTerm(dPosShift[1],*P1,"Y")==false) return false; + if (ReadTerm(dPosShift[2],*P1,"Z")==false) return false; + + TiXmlElement* FuncElem=root.FirstChildElement("Function"); + if (FuncElem==NULL) return false; + SetFunction(FuncElem->GetText()); + + return true; +} diff --git a/CSXCAD/src/CSPrimUserDefined.h b/CSXCAD/src/CSPrimUserDefined.h new file mode 100644 index 0000000..047ed66 --- /dev/null +++ b/CSXCAD/src/CSPrimUserDefined.h @@ -0,0 +1,66 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" + +//! User defined Primitive given by an analytic formula +/*! + This primitive is defined by a boolean result analytic formula. If a given coordinate results in a true result the primitive is assumed existing at these coordinate. + */ +class CSXCAD_EXPORT CSPrimUserDefined: public CSPrimitives +{ +public: + enum UserDefinedCoordSystem + { + CARESIAN_SYSTEM,CYLINDER_SYSTEM,SPHERE_SYSTEM + }; + CSPrimUserDefined(ParameterSet* paraSet, CSProperties* prop); + CSPrimUserDefined(CSPrimUserDefined* primUDef, CSProperties *prop=NULL); + CSPrimUserDefined(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimUserDefined(); + + virtual CSPrimUserDefined* GetCopy(CSProperties *prop=NULL) {return new CSPrimUserDefined(this,prop);} + + void SetCoordSystem(UserDefinedCoordSystem newSystem); + UserDefinedCoordSystem GetCoordSystem() {return CoordSystem;} + + void SetCoordShift(int index, double val) {if ((index>=0) && (index<3)) dPosShift[index].SetValue(val);} + void SetCoordShift(int index, const char* val) {if ((index>=0) && (index<3)) dPosShift[index].SetValue(val);} + + double GetCoordShift(int index) {if ((index>=0) && (index<3)) return dPosShift[index].GetValue(); else return 0;} + ParameterScalar* GetCoordShiftPS(int index) {if ((index>=0) && (index<3)) return &dPosShift[index]; else return NULL;} + + void SetFunction(const char* func); + const char* GetFunction() {return stFunction.c_str();} + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + +protected: + std::string stFunction; + UserDefinedCoordSystem CoordSystem; + CSFunctionParser* fParse; + std::string fParameter; + int iQtyParameter; + ParameterScalar dPosShift[3]; +}; diff --git a/CSXCAD/src/CSPrimWire.cpp b/CSXCAD/src/CSPrimWire.cpp new file mode 100644 index 0000000..a182400 --- /dev/null +++ b/CSXCAD/src/CSPrimWire.cpp @@ -0,0 +1,149 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimWire.h" +#include "CSProperties.h" +#include "CSUseful.h" + +CSPrimWire::CSPrimWire(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) : CSPrimCurve(ID,paraSet,prop) +{ + Type=WIRE; + PrimTypeName = std::string("Wire"); + wireRadius.SetParameterSet(paraSet); +} + +CSPrimWire::CSPrimWire(CSPrimWire* primCurve, CSProperties *prop) : CSPrimCurve(primCurve,prop) +{ + Type=WIRE; + PrimTypeName = std::string("Wire"); + wireRadius.Copy(&primCurve->wireRadius); +} + +CSPrimWire::CSPrimWire(ParameterSet* paraSet, CSProperties* prop) : CSPrimCurve(paraSet,prop) +{ + Type=WIRE; + PrimTypeName = std::string("Wire"); + wireRadius.SetParameterSet(paraSet); +} + + +CSPrimWire::~CSPrimWire() +{ +} + + +bool CSPrimWire::GetBoundBox(double dBoundBox[6], bool PreserveOrientation) +{ + bool accurate; + accurate = CSPrimCurve::GetBoundBox(dBoundBox,PreserveOrientation); + double rad = wireRadius.GetValue(); + for (int n=0;n<3;++n) + { + dBoundBox[2*n]-=rad; + dBoundBox[2*n+1]+=rad; + } + if (rad>0) + m_Dimension+=2; + return accurate; +} + +bool CSPrimWire::IsInside(const double* Coord, double /*tol*/) +{ + if (Coord==NULL) return false; + double rad = wireRadius.GetValue(); + const double* p0; + const double* p1; + double pos[3]; + //transform incoming coordinates into cartesian coords + TransformCoordSystem(Coord,pos,m_MeshType,CARTESIAN); + if (m_Transform) + m_Transform->InvertTransform(pos,pos); + + for (unsigned int n=0;n<3;++n) + { + if ((m_BoundBox[2*n]>pos[n]) || (m_BoundBox[2*n+1]GetCartesianCoords(); + + dist = sqrt(pow(pos[0]-p0[0],2)+pow(pos[1]-p0[1],2)+pow(pos[2]-p0[2],2)); + if (distGetCartesianCoords(); + distPP = sqrt(pow(p1[0]-p0[0],2)+pow(p1[1]-p0[1],2)+pow(p1[2]-p0[2],2))+rad; + if (dist0) && (foot<1) && (distappend(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + //update local bounding box used to speedup IsInside() + m_BoundBoxValid = GetBoundBox(m_BoundBox); + return bOK; +} + +bool CSPrimWire::Write2XML(TiXmlElement &elem, bool parameterised) +{ + CSPrimCurve::Write2XML(elem,parameterised); + + WriteTerm(wireRadius,elem,"WireRadius",parameterised); + return true; +} + +bool CSPrimWire::ReadFromXML(TiXmlNode &root) +{ + if (CSPrimCurve::ReadFromXML(root)==false) return false; + + TiXmlElement *elem = root.ToElement(); + if (elem==NULL) return false; + if (ReadTerm(wireRadius,*elem,"WireRadius")==false) return false; + return true; +} diff --git a/CSXCAD/src/CSPrimWire.h b/CSXCAD/src/CSPrimWire.h new file mode 100644 index 0000000..c5c6e76 --- /dev/null +++ b/CSXCAD/src/CSPrimWire.h @@ -0,0 +1,53 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPrimitives.h" +#include "CSPrimCurve.h" + +//! Wire Primitive (Polygonal chain with finite radius) +/*! + This is a wire primitive derived from a curve with an additional wire radius + \sa CSPrimCurve + */ +class CSXCAD_EXPORT CSPrimWire : public CSPrimCurve +{ +public: + CSPrimWire(ParameterSet* paraSet, CSProperties* prop); + CSPrimWire(CSPrimWire* primCurve, CSProperties *prop=NULL); + CSPrimWire(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + virtual ~CSPrimWire(); + + virtual CSPrimitives* GetCopy(CSProperties *prop=NULL) {return new CSPrimWire(this,prop);} + + void SetWireRadius(double val) {wireRadius.SetValue(val);} + void SetWireRadius(const char* val) {wireRadius.SetValue(val);} + + double GetWireRadius() {return wireRadius.GetValue();} + ParameterScalar* GetWireRadiusPS() {return &wireRadius;} + + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false); + virtual bool IsInside(const double* Coord, double tol=0); + + virtual bool Update(std::string *ErrStr=NULL); + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + virtual bool ReadFromXML(TiXmlNode &root); + +protected: + ParameterScalar wireRadius; +}; diff --git a/CSXCAD/src/CSPrimitives.cpp b/CSXCAD/src/CSPrimitives.cpp new file mode 100644 index 0000000..f852328 --- /dev/null +++ b/CSXCAD/src/CSPrimitives.cpp @@ -0,0 +1,227 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include +#include +#include +#include "tinyxml.h" +#include "stdint.h" + +#include "CSPrimitives.h" + +#include "CSProperties.h" +#include "CSFunctionParser.h" +#include "CSUseful.h" + +#include + +#define PI acos(-1) + +int g_PrimUniqueIDCounter=0; + +void Point_Line_Distance(const double P[], const double start[], const double stop[], double &foot, double &dist, CoordinateSystem c_system) +{ + double l_P[3],l_start[3],l_stop[3]; + TransformCoordSystem(P,l_P,c_system,CARTESIAN); + TransformCoordSystem(start,l_start,c_system,CARTESIAN); + TransformCoordSystem(stop,l_stop,c_system,CARTESIAN); + + double dir[] = {l_stop[0]-l_start[0],l_stop[1]-l_start[1],l_stop[2]-l_start[2]}; + + double LL = pow(dir[0],2)+pow(dir[1],2)+pow(dir[2],2); //Line length^2 + foot = (l_P[0]-l_start[0])*dir[0] + (l_P[1]-l_start[1])*dir[1] + (l_P[2]-l_start[2])*dir[2]; + foot /= LL; + + double footP[] = {l_start[0] + foot*dir[0], l_start[1] + foot*dir[1], l_start[2] + foot*dir[2]}; + + dist = sqrt(pow(l_P[0]-footP[0],2)+pow(l_P[1]-footP[1],2)+pow(l_P[2]-footP[2],2)); +} + +bool CSXCAD_EXPORT CoordInRange(const double* coord, const double* start, const double* stop, CoordinateSystem cs_in) +{ + double p[] = {coord[0],coord[1],coord[2]}; + switch (cs_in) + { + case CYLINDRICAL: + if (p[1]std::max(start[1],stop[1])) + while (p[1]>std::max(start[1],stop[1])) + p[1]-=2*PI; + case CARTESIAN: + default: + for (int n=0;n<3;++n) + if ((p[n]std::max(start[n],stop[n]))) + return false; + return true; + break; + } + return true; +} + +/*********************CSPrimitives********************************************************************/ +CSPrimitives::CSPrimitives(unsigned int ID, ParameterSet* paraSet, CSProperties* prop) +{ + this->Init(); + SetProperty(prop); + uiID=ID; + clParaSet=paraSet; +} + +CSPrimitives::CSPrimitives(CSPrimitives* prim, CSProperties *prop) +{ + this->Init(); + if (prop==NULL) + SetProperty(prim->clProperty); + else + SetProperty(prop); + clParaSet=prim->clParaSet; + m_Transform=CSTransform::New(prim->m_Transform); + iPriority=prim->iPriority; + m_MeshType = prim->m_MeshType; + m_PrimCoordSystem = prim->m_PrimCoordSystem; + m_Dimension = prim->m_Dimension; +} + +CSPrimitives::CSPrimitives(ParameterSet* paraSet, CSProperties* prop) +{ + this->Init(); + SetProperty(prop); + clParaSet=paraSet; +} + +void CSPrimitives::Init() +{ + clProperty=NULL; + clParaSet=NULL; + m_Transform=NULL; + uiID=g_PrimUniqueIDCounter++; + iPriority=0; + PrimTypeName = std::string("Base Type"); + m_Primtive_Used = false; + m_MeshType = CARTESIAN; + m_PrimCoordSystem = UNDEFINED_CS; + m_BoundBox_CoordSys = UNDEFINED_CS; + m_Dimension = 0; + for (int n=0;n<6;++n) + m_BoundBox[n]=0; + m_BoundBoxValid = false; +} + +CSTransform* CSPrimitives::GetTransform() +{ + if (m_Transform==NULL) + m_Transform = new CSTransform(clParaSet); + return m_Transform; +} + +void CSPrimitives::SetProperty(CSProperties *prop) +{ + if ((clProperty!=NULL) && (clProperty!=prop)) + clProperty->RemovePrimitive(this); + clProperty=prop; + if ((prop!=NULL) && (!prop->HasPrimitive(this))) + prop->AddPrimitive(this); +} + +CSPrimitives::~CSPrimitives() +{ + if (clProperty!=NULL) + clProperty->RemovePrimitive(this); + delete m_Transform; + m_Transform=NULL; +} + +int CSPrimitives::IsInsideBox(const double *boundbox) +{ + if (m_BoundBoxValid==false) + return 0; // unable to decide with an invalid bounding box + if ((this->GetBoundBoxCoordSystem()!=UNDEFINED_CS) && (this->GetBoundBoxCoordSystem()!=this->GetCoordInputType())) + return 0; // unable to decide if coordinate system do not match + if (m_Transform!=NULL) + if (m_Transform->HasTransform()) + return 0; // unable to decide if a transformation is used + + for (int i=0;i<3;++i) + { + int d_l = 2*i; + int d_u = d_l+1; + if ((boundbox[d_l]m_BoundBox[d_l]) && (boundbox[d_l]>m_BoundBox[d_u]) && (boundbox[d_u]>m_BoundBox[d_l]) && (boundbox[d_u]>m_BoundBox[d_u])) + return -1; + } + return 1; +} + +bool CSPrimitives::Write2XML(TiXmlElement &elem, bool /*parameterised*/) +{ + elem.SetAttribute("Priority",iPriority); + + if (m_PrimCoordSystem!=UNDEFINED_CS) + elem.SetAttribute("CoordSystem",(int)m_PrimCoordSystem); + + if (m_Transform) + m_Transform->Write2XML(&elem); + + return true; +} + +bool CSPrimitives::ReadFromXML(TiXmlNode &root) +{ + int help; + TiXmlElement* elem=root.ToElement(); + if (elem==NULL) return false; + if (elem->QueryIntAttribute("Priority",&iPriority)!=TIXML_SUCCESS) return false; + + if (elem->QueryIntAttribute("CoordSystem",&help)==TIXML_SUCCESS) + m_PrimCoordSystem = (CoordinateSystem)help; + + delete m_Transform; + m_Transform = CSTransform::New(elem, clParaSet); + + return true; +} + +void CSPrimitives::ShowPrimitiveStatus(std::ostream& stream) +{ + stream << " Primitive #" << GetID() << " Type: \"" << GetTypeName() << "\" Priority: " << GetPriority() << std::endl; + stream << " Primary Coord-System: " << m_PrimCoordSystem << " Mesh Coord-System: " << m_MeshType << " Bound-Box Coord-System: " << m_BoundBox_CoordSys << std::endl; + stream << " Bounding Box (Valid: " << m_BoundBoxValid << "): P1: (" << m_BoundBox[0] << "," << m_BoundBox[2] << "," << m_BoundBox[4] << ") P2: (" << m_BoundBox[1] << "," << m_BoundBox[3] << "," << m_BoundBox[5] << ")" << std::endl; + if (m_Transform) + { + stream << " Transform: " << std::endl; + m_Transform->PrintTransformations(stream, "\t* "); + } + else + stream << " Transform: None" << std::endl; +} + +void CSPrimitives::TransformCoords(double* Coord, bool invers, CoordinateSystem cs_in) const +{ + if (m_Transform==NULL) + return; + // transform to Cartesian for transformation + TransformCoordSystem(Coord,Coord,cs_in,CARTESIAN); + if (invers) + m_Transform->InvertTransform(Coord,Coord); + else + m_Transform->Transform(Coord,Coord); + // transform back from Cartesian to incoming coordinate system + TransformCoordSystem(Coord,Coord,CARTESIAN,cs_in); +} diff --git a/CSXCAD/src/CSPrimitives.h b/CSXCAD/src/CSPrimitives.h new file mode 100644 index 0000000..545c152 --- /dev/null +++ b/CSXCAD/src/CSPrimitives.h @@ -0,0 +1,213 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#pragma once +/* + * Author: Thorsten Liebig + * Date: 03-12-2008 + * Lib: CSXCAD + * Version: 0.1a + */ + +#include +#include +#include + +#include "ParameterObjects.h" +#include "ParameterCoord.h" +#include "CSXCAD_Global.h" + +class CSPrimPoint; +class CSPrimBox; +class CSPrimMultiBox; +class CSPrimSphere; + class CSPrimSphericalShell; +class CSPrimCylinder; + class CSPrimCylindricalShell; +class CSPrimPolygon; + class CSPrimLinPoly; + class CSPrimRotPoly; +class CSPrimPolyhedron; + class CSPrimPolyhedronReader; +class CSPrimCurve; + class CSPrimWire; +class CSPrimUserDefined; + +class CSProperties; //include VisualProperties + +class TiXmlNode; +class CSFunctionParser; +class CSTransform; + +/*! + Calculate the distance of a point to a line (defined by start/stop coordinates). + Foot will return the normalized foot-point on the line. A value between 0..1 means the foot-point is one the given line. + foot == 0 --> foot-point is on start, foot == 1 --> foot-point is on stop +*/ +void CSXCAD_EXPORT Point_Line_Distance(const double P[], const double start[], const double stop[], double &foot, double &dist, CoordinateSystem c_system=UNDEFINED_CS); + +bool CSXCAD_EXPORT CoordInRange(const double* p, const double* start, const double* stop, CoordinateSystem cs_in); + +//! Abstract base class for different geometrical primitives. +/*! + This is an abstract base class for different geometrical primitives like boxes, spheres, cylinders etc. + !!! Tolerances not yet obeyed !!! + */ +class CSXCAD_EXPORT CSPrimitives +{ +public: + virtual ~CSPrimitives(); + + virtual void Init(); + + //! Primitive type definitions. + enum PrimitiveType + { + POINT,BOX,MULTIBOX,SPHERE,SPHERICALSHELL,CYLINDER,CYLINDRICALSHELL,POLYGON,LINPOLY,ROTPOLY,POLYHEDRON,CURVE,WIRE,USERDEFINED, + POLYHEDRONREADER + }; + + //! Set or change the property for this primitive. + void SetProperty(CSProperties *prop); + //! Get the property for this primitive. + CSProperties* GetProperty() {return clProperty;} + + //! Getthe unique ID for this primitive. + unsigned int GetID() {return uiID;} + //! Change the unique ID for this primitive. This is not recommended! Be sure what you are doing! + void SetID(unsigned int ID) {uiID=ID;} + + //! Get the type of this primitive. \sa PrimitiveType + int GetType() {return Type;} + + std::string GetTypeName() {return PrimTypeName;} + + //! Create a copy of ths primitive with different property. + virtual CSPrimitives* GetCopy(CSProperties *prop=NULL) {return new CSPrimitives(this,prop);} + + //! Get the bounding box (for the given mesh type) for this special primitive. \sa GetBoundBoxCoordSystem + virtual bool GetBoundBox(double dBoundBox[6], bool PreserveOrientation=false) {UNUSED(PreserveOrientation);UNUSED(dBoundBox);return false;} + + virtual CoordinateSystem GetBoundBoxCoordSystem() const {return m_BoundBox_CoordSys;} + + //! Get the dimension of this primitive + virtual int GetDimension() {return m_Dimension;} + + //! Check if given Coordinate (in the given mesh type) is inside the Primitive. + virtual bool IsInside(const double* Coord, double tol=0) {UNUSED(Coord);UNUSED(tol);return false;} + + //! Check if the primitive is inside a given box (box must be specified in the bounding box coordinate system) + //! @return -1 if not, +1 if it is, 0 if unknown + virtual int IsInsideBox(const double* boundbox); + + //! Check whether this primitive was used. (--> IsInside() return true) \sa SetPrimitiveUsed + bool GetPrimitiveUsed() {return m_Primtive_Used;} + //! Set the primitve uses flag. \sa GetPrimitiveUsed + void SetPrimitiveUsed(bool val) {m_Primtive_Used=val;} + + //! Set or change the priotity for this primitive. + void SetPriority(int val) {iPriority=val;} + //! Get the priotity for this primitive. + int GetPriority() {return iPriority;} + + //! Update this primitive with respect to the parameters set. + virtual bool Update(std::string *ErrStr=NULL) {UNUSED(ErrStr);return true;} + //! Write this primitive to a XML-node. + virtual bool Write2XML(TiXmlElement &elem, bool parameterised=true); + //! Read this primitive from a XML-node. + virtual bool ReadFromXML(TiXmlNode &root); + + //! Get the corresponing Box-Primitive or NULL in case of different type. + CSPrimBox* ToBox() { return ( this && Type == BOX ) ? (CSPrimBox*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing MultiBox-Primitive or NULL in case of different type. + CSPrimMultiBox* ToMultiBox() { return ( this && Type == MULTIBOX ) ? (CSPrimMultiBox*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing Sphere-Primitive or NULL in case of different type. + CSPrimSphere* ToSphere() { return ( this && Type == SPHERE ) ? (CSPrimSphere*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing SphereicalShell-Primitive or NULL in case of different type. + CSPrimSphericalShell* ToSphericalShell() { return ( this && Type == SPHERICALSHELL ) ? (CSPrimSphericalShell*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing Cylinder-Primitive or NULL in case of different type. + CSPrimCylinder* ToCylinder() { return ( this && Type == CYLINDER ) ? (CSPrimCylinder*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing CylindricalShell-Primitive or NULL in case of different type. + CSPrimCylindricalShell* ToCylindricalShell() { return ( this && Type == CYLINDRICALSHELL ) ? (CSPrimCylindricalShell*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing Polygon-Primitive or NULL in case of different type. + CSPrimPolygon* ToPolygon() { return ( this && Type == POLYGON ) ? (CSPrimPolygon*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing LinPoly-Primitive or NULL in case of different type. + CSPrimLinPoly* ToLinPoly() { return ( this && Type == LINPOLY ) ? (CSPrimLinPoly*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing Cylinder-Primitive or NULL in case of different type. + CSPrimRotPoly* ToRotPoly() { return ( this && Type == ROTPOLY ) ? (CSPrimRotPoly*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing Polyhedron-Primitive or NULL in case of different type. + CSPrimPolyhedron* ToPolyhedron() { return ( this && Type == POLYHEDRON ) ? (CSPrimPolyhedron*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing Polyhedron-Import-Primitive or NULL in case of different type. + CSPrimPolyhedronReader* ToPolyhedronReader() { return ( this && Type == POLYHEDRONREADER ) ? (CSPrimPolyhedronReader*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing Curve-Primitive or NULL in case of different type. + CSPrimCurve* ToCurve() { return ( this && Type == CURVE ) ? (CSPrimCurve*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing Wire-Primitive or NULL in case of different type. + CSPrimWire* ToWire() { return ( this && Type == WIRE ) ? (CSPrimWire*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing UserDefined-Primitive or NULL in case of different type. + CSPrimUserDefined* ToUserDefined() { return ( this && Type == USERDEFINED ) ? (CSPrimUserDefined*) this : 0; } /// Cast Primitive to a more defined type. Will return null if not of the requested type. + //! Get the corresponing Point-Primitive or 0 in case of different type. + CSPrimPoint* ToPoint() { return ( this && Type == POINT ) ? (CSPrimPoint*) this : 0; } //!< Cast Primitive to a more defined type. Will return 0 if not of the requested type. + + bool operator<(CSPrimitives& vgl) { return iPriority(CSPrimitives& vgl) { return iPriority>vgl.GetPriority();} + bool operator==(CSPrimitives& vgl) { return iPriority==vgl.GetPriority();} + bool operator!=(CSPrimitives& vgl) { return iPriority!=vgl.GetPriority();} + + //! Define the input type for the weighting coordinate system 0=cartesian, 1=cylindrical, 2=spherical + void SetCoordInputType(CoordinateSystem type, bool doUpdate=true) {m_MeshType=type; if (doUpdate) Update();} + //! Get the input type for the weighting coordinate system 0=cartesian, 1=cylindrical, 2=spherical + CoordinateSystem GetCoordInputType() const {return m_MeshType;} + + //! Define the coordinate system this primitive is defined in (may be different to the input mesh type) \sa SetCoordInputType + void SetCoordinateSystem(CoordinateSystem cs) {m_PrimCoordSystem=cs;} + //! Read the coordinate system for this primitive (may be different to the input mesh type) \sa GetCoordInputType + CoordinateSystem GetCoordinateSystem() const {return m_PrimCoordSystem;} + + //! Get the CSTransform if it exists already or create a new one + CSTransform* GetTransform(); + + //! Show status of this primitve + virtual void ShowPrimitiveStatus(std::ostream& stream); + +protected: + CSPrimitives(ParameterSet* paraSet, CSProperties* prop); + CSPrimitives(CSPrimitives* prim, CSProperties *prop=NULL); + CSPrimitives(unsigned int ID, ParameterSet* paraSet, CSProperties* prop); + + //! Apply (invers) transformation to the given coordinate in the given coordinate system + void TransformCoords(double* Coord, bool invers, CoordinateSystem cs_in) const; + + unsigned int uiID; + int iPriority; + CoordinateSystem m_PrimCoordSystem; + CoordinateSystem m_MeshType; + PrimitiveType Type; + ParameterSet* clParaSet; + CSProperties* clProperty; + CSTransform* m_Transform; + std::string PrimTypeName; + bool m_Primtive_Used; + + //internal bounding box, updated by Update(), can be used to speedup IsInside + bool m_BoundBoxValid; + double m_BoundBox[6]; + CoordinateSystem m_BoundBox_CoordSys; + + int m_Dimension; +}; + + diff --git a/CSXCAD/src/CSPropConductingSheet.cpp b/CSXCAD/src/CSPropConductingSheet.cpp new file mode 100644 index 0000000..adce7fd --- /dev/null +++ b/CSXCAD/src/CSPropConductingSheet.cpp @@ -0,0 +1,97 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropConductingSheet.h" + +CSPropConductingSheet::CSPropConductingSheet(ParameterSet* paraSet) : CSPropMetal(paraSet) {Type=(CSProperties::PropertyType)(CONDUCTINGSHEET | METAL);Init();} +CSPropConductingSheet::CSPropConductingSheet(CSProperties* prop) : CSPropMetal(prop) {Type=(CSProperties::PropertyType)(CONDUCTINGSHEET | METAL);Init();} +CSPropConductingSheet::CSPropConductingSheet(unsigned int ID, ParameterSet* paraSet) : CSPropMetal(ID,paraSet) {Type=(CSProperties::PropertyType)(CONDUCTINGSHEET | METAL);Init();} + +CSPropConductingSheet::~CSPropConductingSheet() +{ +} + + +void CSPropConductingSheet::Init() +{ + Conductivity.SetValue(0); + Thickness.SetValue(0); +} + + +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)) + { + std::stringstream stream; + stream << std::endl << "Error in ConductingSheet-Property Conductivity-Value"; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + EC=Thickness.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in ConductingSheet-Property Thickness-Value"; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + return bOK & CSPropMetal::Update(ErrStr); +} + +bool CSPropConductingSheet::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSPropMetal::Write2XML(root,parameterised,sparse) == false) return false; + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + WriteTerm(Conductivity,*prop,"Conductivity",parameterised); + WriteTerm(Thickness,*prop,"Thickness",parameterised); + + return true; +} + +bool CSPropConductingSheet::ReadFromXML(TiXmlNode &root) +{ + if (CSProperties::ReadFromXML(root)==false) return false; + + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + if (ReadTerm(Conductivity,*prop,"Conductivity")==false) + std::cerr << "CSPropConductingSheet::ReadFromXML: Warning: Failed to read Conductivity. Set to 0." << std::endl; + if (ReadTerm(Thickness,*prop,"Thickness")==false) + std::cerr << "CSPropConductingSheet::ReadFromXML: Warning: Failed to read Thickness. Set to 0." << std::endl; + + return true; +} + +void CSPropConductingSheet::ShowPropertyStatus(std::ostream& stream) +{ + CSPropMetal::ShowPropertyStatus(stream); + stream << " --- Conducting Sheet Properties --- " << std::endl; + stream << " Conductivity: " << Conductivity.GetValueString() << std::endl; + stream << " Thickness: " << Thickness.GetValueString() << std::endl; +} diff --git a/CSXCAD/src/CSPropConductingSheet.h b/CSXCAD/src/CSPropConductingSheet.h new file mode 100644 index 0000000..6f3e96a --- /dev/null +++ b/CSXCAD/src/CSPropConductingSheet.h @@ -0,0 +1,67 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPropMetal.h" + +//! Continuous Structure Conductive Sheet Material Property +/*! + This is a condiction sheet dispersive model for an efficient wide band Analysis of planar waveguides and circuits. + */ +class CSXCAD_EXPORT CSPropConductingSheet : public CSPropMetal +{ +public: + CSPropConductingSheet(ParameterSet* paraSet); + CSPropConductingSheet(CSProperties* prop); + CSPropConductingSheet(unsigned int ID, ParameterSet* paraSet); + virtual ~CSPropConductingSheet(); + + virtual void Init(); + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("ConductingSheet");} + + //! Set the Conductivity + void SetConductivity(double val) {Conductivity.SetValue(val);} + //! Set the Conductivity + int SetConductivity(const std::string val) {return Conductivity.SetValue(val);} + //! Get the Conductivity + double GetConductivity() {return Conductivity.GetValue();} + //! Get the Conductivity as a string + const std::string GetConductivityTerm() {return Conductivity.GetString();} + + //! Set the Thickness + void SetThickness(double val) {Thickness.SetValue(val);} + //! Set the Thickness + int SetThickness(const std::string val) {return Thickness.SetValue(val);} + //! Get the Thickness + double GetThickness() {return Thickness.GetValue();} + //! Get the Thickness as a string + const std::string GetThicknessTerm() {return Thickness.GetString();} + + virtual bool Update(std::string *ErrStr=NULL); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPropertyStatus(std::ostream& stream); + +protected: + ParameterScalar Conductivity; + ParameterScalar Thickness; +}; diff --git a/CSXCAD/src/CSPropDebyeMaterial.cpp b/CSXCAD/src/CSPropDebyeMaterial.cpp new file mode 100644 index 0000000..f12c261 --- /dev/null +++ b/CSXCAD/src/CSPropDebyeMaterial.cpp @@ -0,0 +1,238 @@ +/* +* Copyright (C) 2013 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropDebyeMaterial.h" + +CSPropDebyeMaterial::CSPropDebyeMaterial(ParameterSet* paraSet) : CSPropDispersiveMaterial(paraSet) {Type=(CSProperties::PropertyType)(DEBYEMATERIAL | DISPERSIVEMATERIAL | MATERIAL);Init();} +CSPropDebyeMaterial::CSPropDebyeMaterial(CSProperties* prop) : CSPropDispersiveMaterial(prop) {Type=(CSProperties::PropertyType)(DEBYEMATERIAL | DISPERSIVEMATERIAL | MATERIAL);Init();} +CSPropDebyeMaterial::CSPropDebyeMaterial(unsigned int ID, ParameterSet* paraSet) : CSPropDispersiveMaterial(ID,paraSet) {Type=(CSProperties::PropertyType)(DEBYEMATERIAL | DISPERSIVEMATERIAL | MATERIAL);Init();} + +CSPropDebyeMaterial::~CSPropDebyeMaterial() +{ + DeleteValues(); + m_Order = 0; +} + +void CSPropDebyeMaterial::Init() +{ + m_Order = 0; + EpsDelta=NULL; + WeightEpsDelta=NULL; + EpsRelaxTime=NULL; + WeightEpsRelaxTime=NULL; + InitValues(); + CSPropDispersiveMaterial::Init(); +} + +void CSPropDebyeMaterial::DeleteValues() +{ + for (int o=0;oappend(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + EC=WeightEpsDelta[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Debye Material-Property epsilon Delta frequency weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + EC=EpsRelaxTime[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Debye Material-Property epsilon relaxation time value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + EC=WeightEpsRelaxTime[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Debye Material-Property epsilon relaxation time weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + } + } + return bOK & CSPropDispersiveMaterial::Update(ErrStr); +} + +bool CSPropDebyeMaterial::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSPropDispersiveMaterial::Write2XML(root,parameterised,sparse) == false) return false; + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + std::string suffix; + for (int o=0;oFirstChildElement("Property"); + if (value==NULL) + return false; + WriteVectorTerm(EpsDelta[o],*value,"EpsilonDelta_"+suffix,parameterised); + WriteVectorTerm(EpsRelaxTime[o],*value,"EpsilonRelaxTime_"+suffix,parameterised); + + TiXmlElement* weight=prop->FirstChildElement("Weight"); + if (weight==NULL) + return false; + WriteVectorTerm(WeightEpsDelta[o],*weight,"EpsilonDelta_"+suffix,parameterised); + WriteVectorTerm(WeightEpsRelaxTime[o],*weight,"EpsilonRelaxTime_"+suffix,parameterised); + } + return true; +} + +bool CSPropDebyeMaterial::ReadFromXML(TiXmlNode &root) +{ + if (CSPropDispersiveMaterial::ReadFromXML(root)==false) return false; + TiXmlElement* prop=root.ToElement(); + + if (prop==NULL) return false; + + // count m_Order + TiXmlElement* matProp=prop->FirstChildElement("Property"); + if (matProp!=NULL) + { + m_Order=1; + while (1) + { + if (matProp->Attribute("EpsilonDelta_"+ConvertInt(m_Order+1))) + ++m_Order; + else if (matProp->Attribute("MueDelta_"+ConvertInt(m_Order+1))) + ++m_Order; + else + break; + } + } + else + return false; + + InitValues(); + + if (ReadVectorTerm(EpsDelta[0],*matProp,"EpsilonDelta_1",0.0)==false) + ReadVectorTerm(EpsDelta[0],*matProp,"EpsilonDelta",0.0); + + if (ReadVectorTerm(EpsRelaxTime[0],*matProp,"EpsilonRelaxTime_1",0.0)==false) + ReadVectorTerm(EpsRelaxTime[0],*matProp,"EpsilonRelaxTime",0.0); + + TiXmlElement* weightProp=prop->FirstChildElement("Weight"); + if (weightProp) + { + if (ReadVectorTerm(WeightEpsDelta[0],*weightProp,"EpsilonDelta_1",1.0)==false) + ReadVectorTerm(WeightEpsDelta[0],*weightProp,"EpsilonDelta",1.0); + + if (ReadVectorTerm(WeightEpsRelaxTime[0],*weightProp,"EpsilonRelaxTime_1",1.0)==false) + ReadVectorTerm(WeightEpsRelaxTime[0],*weightProp,"EpsilonRelaxTime",1.0); + } + + for (int o=1;o. +*/ + +#pragma once + +#include "CSProperties.h" +#include "CSPropDispersiveMaterial.h" + +//! Continuous Structure Debye Dispersive Material Property +/*! + This Property can hold information about the special properties of Debye dispersive materials. + \todo Add all the other parameter needed by this model + */ +class CSXCAD_EXPORT CSPropDebyeMaterial : public CSPropDispersiveMaterial +{ +public: + CSPropDebyeMaterial(ParameterSet* paraSet); + CSPropDebyeMaterial(CSProperties* prop); + CSPropDebyeMaterial(unsigned int ID, ParameterSet* paraSet); + virtual ~CSPropDebyeMaterial(); + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("DebyeMaterial");} + + //! Set the epsilon plasma frequency + void SetEpsDelta(int order, double val, int ny=0) {SetValue(val,EpsDelta[order],ny);} + //! Set the epsilon plasma frequency + int SetEpsDelta(int order, const std::string val, int ny=0) {return SetValue(val,EpsDelta[order],ny);} + //! Get the epsilon plasma frequency + double GetEpsDelta(int order, int ny=0) {return GetValue(EpsDelta[order],ny);} + //! Get the epsilon plasma frequency as a string + const std::string GetEpsDeltaTerm(int order, int ny=0) {return GetTerm(EpsDelta[order],ny);} + + //! Set the epsilon plasma frequency weighting + int SetEpsDeltaWeightFunction(int order, const std::string val, int ny) {return SetValue(val,WeightEpsDelta[order],ny);} + //! Get the epsilon plasma frequency weighting string + const std::string GetEpsDeltaWeightFunction(int order, int ny) {return GetTerm(WeightEpsDelta[order],ny);} + //! Get the epsilon plasma frequency weighting + double GetEpsDeltaWeighted(int order, int ny, const double* coords) {return GetWeight(WeightEpsDelta[order],ny,coords)*GetEpsDelta(order,ny);} + + //! Set the epsilon relaxation time + void SetEpsRelaxTime(int order, double val, int ny=0) {SetValue(val,EpsRelaxTime[order],ny);} + //! Set the epsilon relaxation time + int SetEpsRelaxTime(int order, const std::string val, int ny=0) {return SetValue(val,EpsRelaxTime[order],ny);} + //! Get the epsilon relaxation time + double GetEpsRelaxTime(int order, int ny=0) {return GetValue(EpsRelaxTime[order],ny);} + //! Get the epsilon relaxation time as a string + const std::string GetEpsRelaxTimeTerm(int order, int ny=0) {return GetTerm(EpsRelaxTime[order],ny);} + + //! Set the epsilon relaxation time weighting + int SetEpsRelaxTimeWeightFunction(int order, const std::string val, int ny) {return SetValue(val,WeightEpsRelaxTime[order],ny);} + //! Get the epsilon relaxation time weighting string + const std::string GetEpsRelaxTimeWeightFunction(int order, int ny) {return GetTerm(WeightEpsRelaxTime[order],ny);} + //! Get the epsilon relaxation time weighting + double GetEpsRelaxTimeWeighted(int order, int ny, const double* coords) {return GetWeight(WeightEpsRelaxTime[order],ny,coords)*GetEpsRelaxTime(order,ny);} + + virtual void Init(); + virtual bool Update(std::string *ErrStr=NULL); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPropertyStatus(std::ostream& stream); + +protected: + virtual void InitValues(); + virtual void DeleteValues(); + //! Epsilon delta + ParameterScalar** EpsDelta; + //! Epsilon delta weighting functions + ParameterScalar** WeightEpsDelta; + + //! Relaxation times for epsilon + ParameterScalar** EpsRelaxTime; + //! Relaxation times for epsilon weighting functions + ParameterScalar** WeightEpsRelaxTime; +}; diff --git a/CSXCAD/src/CSPropDiscMaterial.cpp b/CSXCAD/src/CSPropDiscMaterial.cpp new file mode 100644 index 0000000..12f565a --- /dev/null +++ b/CSXCAD/src/CSPropDiscMaterial.cpp @@ -0,0 +1,619 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" +#include +#include + +#include "vtkPolyData.h" +#include "vtkCellArray.h" +#include "vtkPoints.h" + +#include "ParameterCoord.h" +#include "CSPropDiscMaterial.h" + +CSPropDiscMaterial::CSPropDiscMaterial(ParameterSet* paraSet) : CSPropMaterial(paraSet) +{ + Type=(CSProperties::PropertyType)(DISCRETE_MATERIAL | MATERIAL); + Init(); +} + +CSPropDiscMaterial::CSPropDiscMaterial(CSProperties* prop) : CSPropMaterial(prop) +{ + Type=(CSProperties::PropertyType)(DISCRETE_MATERIAL | MATERIAL); + Init(); +} + +CSPropDiscMaterial::CSPropDiscMaterial(unsigned int ID, ParameterSet* paraSet) : CSPropMaterial(ID, paraSet) +{ + Type=(CSProperties::PropertyType)(DISCRETE_MATERIAL | MATERIAL); + Init(); +} + +CSPropDiscMaterial::~CSPropDiscMaterial() +{ + for (int n=0;n<3;++n) + { + delete[] m_mesh[n]; + m_mesh[n]=NULL; + } + delete[] m_Disc_Ind; + m_Disc_Ind=NULL; + delete[] m_Disc_epsR; + m_Disc_epsR=NULL; + delete[] m_Disc_kappa; + m_Disc_kappa=NULL; + delete[] m_Disc_mueR; + m_Disc_mueR=NULL; + delete[] m_Disc_sigma; + m_Disc_sigma=NULL; + delete[] m_Disc_Density; + m_Disc_Density=NULL; + + delete m_Transform; + m_Transform=NULL; +} + +unsigned int CSPropDiscMaterial::GetWeightingPos(const double* inCoords) +{ + double coords[3]; + TransformCoordSystem(inCoords, coords, coordInputType, CARTESIAN); + if (m_Transform) + m_Transform->InvertTransform(coords,coords); + for (int n=0;n<3;++n) + coords[n]/=m_Scale; + unsigned int pos[3]; + if (!(m_mesh[0] && m_mesh[1] && m_mesh[2])) + return -1; + for (int n=0;n<3;++n) + { + if (coords[n]m_mesh[n][m_Size[n]-1]) + return -1; + pos[n]=0; + for (unsigned int i=1;i=(int)m_DB_size) + { + //sanity check, this should not happen!!! + std::cerr << __func__ << ": Error, false DB position!" << std::endl; + return -1; + } + return db_pos; +} + +double CSPropDiscMaterial::GetEpsilonWeighted(int ny, const double* inCoords) +{ + if (m_Disc_epsR==NULL) + return CSPropMaterial::GetEpsilonWeighted(ny,inCoords); + int pos = GetDBPos(inCoords); + if (pos<0) + return CSPropMaterial::GetEpsilonWeighted(ny,inCoords); + return m_Disc_epsR[pos]; +} + +double CSPropDiscMaterial::GetKappaWeighted(int ny, const double* inCoords) +{ + if (m_Disc_kappa==NULL) + return CSPropMaterial::GetKappaWeighted(ny,inCoords); + int pos = GetDBPos(inCoords); + if (pos<0) + return CSPropMaterial::GetKappaWeighted(ny,inCoords); + return m_Disc_kappa[pos]; +} + +double CSPropDiscMaterial::GetMueWeighted(int ny, const double* inCoords) +{ + if (m_Disc_mueR==NULL) + return CSPropMaterial::GetMueWeighted(ny,inCoords); + int pos = GetDBPos(inCoords); + if (pos<0) + return CSPropMaterial::GetMueWeighted(ny,inCoords); + return m_Disc_mueR[pos]; +} + +double CSPropDiscMaterial::GetSigmaWeighted(int ny, const double* inCoords) +{ + if (m_Disc_sigma==NULL) + return CSPropMaterial::GetSigmaWeighted(ny,inCoords); + int pos = GetDBPos(inCoords); + if (pos<0) + return CSPropMaterial::GetSigmaWeighted(ny,inCoords); + return m_Disc_sigma[pos]; +} + +double CSPropDiscMaterial::GetDensityWeighted(const double* inCoords) +{ + if (m_Disc_Density==NULL) + return CSPropMaterial::GetDensityWeighted(inCoords); + int pos = GetDBPos(inCoords); + if (pos<0) + return CSPropMaterial::GetDensityWeighted(inCoords); + return m_Disc_Density[pos]; +} + +void CSPropDiscMaterial::Init() +{ + m_Filename.clear(); + m_FileType=-1; + + m_DB_size = 0; + m_DB_Background = true; + + for (int n=0;n<3;++n) + m_mesh[n]=NULL; + m_Disc_Ind=NULL; + m_Disc_epsR=NULL; + m_Disc_kappa=NULL; + m_Disc_mueR=NULL; + m_Disc_sigma=NULL; + m_Disc_Density=NULL; + + m_Scale=1; + m_Transform=NULL; + + CSPropMaterial::Init(); +} + +bool CSPropDiscMaterial::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSPropMaterial::Write2XML(root,parameterised,sparse) == false) return false; + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + TiXmlElement filename("DiscFile"); + filename.SetAttribute("Type",m_FileType); + filename.SetAttribute("File",m_Filename.c_str()); + filename.SetAttribute("UseDBBackground",m_DB_Background); + filename.SetAttribute("Scale",m_Scale); + + if (m_Transform) + m_Transform->Write2XML(prop); + + prop->InsertEndChild(filename); + + return true; +} + +bool CSPropDiscMaterial::ReadFromXML(TiXmlNode &root) +{ + if (CSPropMaterial::ReadFromXML(root)==false) return false; + TiXmlElement* prop=root.ToElement(); + + if (prop==NULL) return false; + + m_FileType = 0; + prop->QueryIntAttribute("Type",&m_FileType); + const char* c_filename = prop->Attribute("File"); + + int help; + if (prop->QueryIntAttribute("UseDBBackground",&help)==TIXML_SUCCESS) + SetUseDataBaseForBackground(help!=0); + + delete m_Transform; + m_Transform = CSTransform::New(prop, clParaSet); + + if (prop->QueryDoubleAttribute("Scale",&m_Scale)!=TIXML_SUCCESS) + m_Scale=1; + + if (c_filename==NULL) + return true; + + if ((m_FileType==0) && (c_filename!=NULL)) + return ReadHDF5(c_filename); + else + std::cerr << "CSPropDiscMaterial::ReadFromXML: Unknown file type or no filename given." << std::endl; + + return true; +} + +void *CSPropDiscMaterial::ReadDataSet(std::string filename, std::string d_name, int type_id, int &rank, unsigned int &size, bool debug) +{ + herr_t status; + H5T_class_t class_id; + size_t type_size; + rank = -1; + + // open hdf5 file + hid_t file_id = H5Fopen( filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT ); + if (file_id < 0) + { + if (debug) + std::cerr << __func__ << ": Failed to open file, skipping..." << std::endl; + H5Fclose(file_id); + return NULL; + } + + if (H5Lexists(file_id, d_name.c_str(), H5P_DEFAULT)<=0) + { + if (debug) + std::cerr << __func__ << ": Warning, dataset: \"" << d_name << "\" not found... skipping" << std::endl; + H5Fclose(file_id); + return NULL; + } + + status = H5LTget_dataset_ndims(file_id, d_name.c_str(), &rank); + if (status < 0) + { + if (debug) + std::cerr << __func__ << ": Warning, failed to read dimension for dataset: \"" << d_name << "\" skipping..." << std::endl; + H5Fclose(file_id); + return NULL; + } + + hsize_t dims[rank]; + status = H5LTget_dataset_info( file_id, d_name.c_str(), dims, &class_id, &type_size); + if (status < 0) + { + if (debug) + std::cerr << __func__ << ": Warning, failed to read dataset info: \"" << d_name << "\" skipping..." << std::endl; + H5Fclose(file_id); + return NULL; + } + + size = 1; + for (int n=0;n0) + bd=true; + } + else if (pos[n]==m_Size[n]-2) + { + if (m_Disc_Ind[mat_idx]>0) + bu=true; + } + else + { + rpos[n] = pos[n]-1; // set relative pos + mat_idx_down = rpos[0] + rpos[1]*(m_Size[0]-1) + rpos[2]*(m_Size[0]-1)*(m_Size[1]-1); + rpos[n] = pos[n]; // reset relative pos + if ((m_Disc_Ind[mat_idx]>0) && (m_Disc_Ind[mat_idx_down]==0)) + bd=true; + else if (m_Disc_Ind[mat_idx]==0 && (m_Disc_Ind[mat_idx_down]>0)) + bu=true; + } + + rpos[0]=pos[0]; + rpos[1]=pos[1]; + rpos[2]=0; + + if (bu) // draw poly for surface up + { + nP = (n+1)%3; + nPP = (n+2)%3; + poly->InsertNextCell(4); + + mesh_idx = rpos[0] + rpos[1]*m_Size[0]; + if (pointIdx[rpos[2]][mesh_idx]<0) + pointIdx[rpos[2]][mesh_idx] = (int)points->InsertNextPoint(m_mesh[0][rpos[0]],m_mesh[1][rpos[1]],m_mesh[2][pos[2]+rpos[2]]); + poly->InsertCellPoint(pointIdx[rpos[2]][mesh_idx]); + + ++rpos[nP]; + mesh_idx = rpos[0] + rpos[1]*m_Size[0]; + if (pointIdx[rpos[2]][mesh_idx]<0) + pointIdx[rpos[2]][mesh_idx] = (int)points->InsertNextPoint(m_mesh[0][rpos[0]],m_mesh[1][rpos[1]],m_mesh[2][pos[2]+rpos[2]]); + poly->InsertCellPoint(pointIdx[rpos[2]][mesh_idx]); + + ++rpos[nPP]; + mesh_idx = rpos[0] + rpos[1]*m_Size[0]; + if (pointIdx[rpos[2]][mesh_idx]<0) + pointIdx[rpos[2]][mesh_idx] = (int)points->InsertNextPoint(m_mesh[0][rpos[0]],m_mesh[1][rpos[1]],m_mesh[2][pos[2]+rpos[2]]); + poly->InsertCellPoint(pointIdx[rpos[2]][mesh_idx]); + + --rpos[nP]; + mesh_idx = rpos[0] + rpos[1]*m_Size[0]; + if (pointIdx[rpos[2]][mesh_idx]<0) + pointIdx[rpos[2]][mesh_idx] = (int)points->InsertNextPoint(m_mesh[0][rpos[0]],m_mesh[1][rpos[1]],m_mesh[2][pos[2]+rpos[2]]); + poly->InsertCellPoint(pointIdx[rpos[2]][mesh_idx]); + } + else if (bd) // draw poly for surface down + { + nP = (n+1)%3; + nPP = (n+2)%3; + poly->InsertNextCell(4); + mesh_idx = rpos[0] + rpos[1]*m_Size[0]; + if (pointIdx[rpos[2]][mesh_idx]<0) + pointIdx[rpos[2]][mesh_idx] = (int)points->InsertNextPoint(m_mesh[0][rpos[0]],m_mesh[1][rpos[1]],m_mesh[2][pos[2]+rpos[2]]); + poly->InsertCellPoint(pointIdx[rpos[2]][mesh_idx]); + + ++rpos[nPP]; + mesh_idx = rpos[0] + rpos[1]*m_Size[0]; + if (pointIdx[rpos[2]][mesh_idx]<0) + pointIdx[rpos[2]][mesh_idx] = (int)points->InsertNextPoint(m_mesh[0][rpos[0]],m_mesh[1][rpos[1]],m_mesh[2][pos[2]+rpos[2]]); + poly->InsertCellPoint(pointIdx[rpos[2]][mesh_idx]); + + ++rpos[nP]; + mesh_idx = rpos[0] + rpos[1]*m_Size[0]; + if (pointIdx[rpos[2]][mesh_idx]<0) + pointIdx[rpos[2]][mesh_idx] = (int)points->InsertNextPoint(m_mesh[0][rpos[0]],m_mesh[1][rpos[1]],m_mesh[2][pos[2]+rpos[2]]); + poly->InsertCellPoint(pointIdx[rpos[2]][mesh_idx]); + + --rpos[nPP]; + mesh_idx = rpos[0] + rpos[1]*m_Size[0]; + if (pointIdx[rpos[2]][mesh_idx]<0) + pointIdx[rpos[2]][mesh_idx] = (int)points->InsertNextPoint(m_mesh[0][rpos[0]],m_mesh[1][rpos[1]],m_mesh[2][pos[2]+rpos[2]]); + poly->InsertCellPoint(pointIdx[rpos[2]][mesh_idx]); + } + } + } + } + delete[] pointIdx[0]; + delete[] pointIdx[1]; + + polydata->SetPoints(points); + points->Delete(); + polydata->SetPolys(poly); + poly->Delete(); + + return polydata; +} diff --git a/CSXCAD/src/CSPropDiscMaterial.h b/CSXCAD/src/CSPropDiscMaterial.h new file mode 100644 index 0000000..5317ac7 --- /dev/null +++ b/CSXCAD/src/CSPropDiscMaterial.h @@ -0,0 +1,88 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSProperties.h" +#include "CSPropMaterial.h" + +typedef unsigned char uint8; + +class vtkPolyData; + +//! Continuous Structure Discrete Material Property +/*! + This Property reads a discrete material distribution from a file. (currently only HDF5) + */ +class CSXCAD_EXPORT CSPropDiscMaterial : public CSPropMaterial +{ +public: + CSPropDiscMaterial(ParameterSet* paraSet); + CSPropDiscMaterial(CSProperties* prop); + CSPropDiscMaterial(unsigned int ID, ParameterSet* paraSet); + virtual ~CSPropDiscMaterial(); + + virtual const std::string GetTypeXMLString() const {return std::string("Discrete-Material");} + + virtual double GetEpsilonWeighted(int ny, const double* coords); + virtual double GetMueWeighted(int ny, const double* coords); + virtual double GetKappaWeighted(int ny, const double* coords); + virtual double GetSigmaWeighted(int ny, const double* coords); + + virtual double GetDensityWeighted(const double* coords); + + //! Set true if database index 0 is used as background material (default), or false if CSPropMaterial should be used as index 0 + virtual void SetUseDataBaseForBackground(bool val) {m_DB_Background=val;} + + CSTransform* GetTransform() {return m_Transform;} + + double GetScale() {return m_Scale;} + + virtual void Init(); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + + bool ReadHDF5(std::string filename); + + virtual void ShowPropertyStatus(std::ostream& stream); + + //! Create a vtkPolyData surface that separates the discrete material from background material + virtual vtkPolyData* CreatePolyDataModel() const; + +protected: + unsigned int GetWeightingPos(const double* coords); + int GetDBPos(const double* coords); + + int m_FileType; + std::string m_Filename; + unsigned int m_Size[3]; + unsigned int m_DB_size; + uint8* m_Disc_Ind; + float *m_mesh[3]; + float *m_Disc_epsR; + float *m_Disc_kappa; + float *m_Disc_mueR; + float *m_Disc_sigma; + float *m_Disc_Density; + double m_Scale; + bool m_DB_Background; + CSTransform* m_Transform; + + void* ReadDataSet(std::string filename, std::string d_name, int type_id, int &rank, unsigned int &size, bool debug=false); +}; + diff --git a/CSXCAD/src/CSPropDispersiveMaterial.cpp b/CSXCAD/src/CSPropDispersiveMaterial.cpp new file mode 100644 index 0000000..43922f6 --- /dev/null +++ b/CSXCAD/src/CSPropDispersiveMaterial.cpp @@ -0,0 +1,40 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropDispersiveMaterial.h" + +CSPropDispersiveMaterial::CSPropDispersiveMaterial(ParameterSet* paraSet) : CSPropMaterial(paraSet) {m_Order=0;Type=(CSProperties::PropertyType)(DISPERSIVEMATERIAL | MATERIAL);} +CSPropDispersiveMaterial::CSPropDispersiveMaterial(CSProperties* prop) : CSPropMaterial(prop) {m_Order=0;Type=(CSProperties::PropertyType)(DISPERSIVEMATERIAL | MATERIAL);} +CSPropDispersiveMaterial::CSPropDispersiveMaterial(unsigned int ID, ParameterSet* paraSet) : CSPropMaterial(ID,paraSet) {m_Order=0;Type=(CSProperties::PropertyType)(DISPERSIVEMATERIAL | MATERIAL);} +CSPropDispersiveMaterial::~CSPropDispersiveMaterial() {} + +bool CSPropDispersiveMaterial::Update(std::string *ErrStr) +{ + return CSPropMaterial::Update(ErrStr); +} + +bool CSPropDispersiveMaterial::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + return CSPropMaterial::Write2XML(root,parameterised,sparse); +} + +bool CSPropDispersiveMaterial::ReadFromXML(TiXmlNode &root) +{ + return CSPropMaterial::ReadFromXML(root); +} diff --git a/CSXCAD/src/CSPropDispersiveMaterial.h b/CSXCAD/src/CSPropDispersiveMaterial.h new file mode 100644 index 0000000..196653f --- /dev/null +++ b/CSXCAD/src/CSPropDispersiveMaterial.h @@ -0,0 +1,49 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSProperties.h" +#include "CSPropMaterial.h" + +//! Continuous Structure Dispersive Material Property +/*! + This abstarct Property can hold information about the special properties of dispersive materials. + */ +class CSXCAD_EXPORT CSPropDispersiveMaterial : public CSPropMaterial +{ +public: + virtual ~CSPropDispersiveMaterial(); + + //! Get the dispersion order + virtual int GetDispersionOrder() {return m_Order;} + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("DispersiveMaterial");} + +protected: + int m_Order; + + virtual bool Update(std::string *ErrStr=NULL); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + + CSPropDispersiveMaterial(ParameterSet* paraSet); + CSPropDispersiveMaterial(CSProperties* prop); + CSPropDispersiveMaterial(unsigned int ID, ParameterSet* paraSet); +}; diff --git a/CSXCAD/src/CSPropDumpBox.cpp b/CSXCAD/src/CSPropDumpBox.cpp new file mode 100644 index 0000000..6cccce6 --- /dev/null +++ b/CSXCAD/src/CSPropDumpBox.cpp @@ -0,0 +1,158 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropDumpBox.h" + +CSPropDumpBox::CSPropDumpBox(ParameterSet* paraSet) : CSPropProbeBox(paraSet) {Type=DUMPBOX;Init();} +CSPropDumpBox::CSPropDumpBox(CSProperties* prop) : CSPropProbeBox(prop) {Type=DUMPBOX;Init();} +CSPropDumpBox::CSPropDumpBox(unsigned int ID, ParameterSet* paraSet) : CSPropProbeBox(ID,paraSet) {Type=DUMPBOX;Init();} +CSPropDumpBox::~CSPropDumpBox() {} + +void CSPropDumpBox::Init() +{ + DumpType = 0; + DumpMode = 0; + FileType = 0; + MultiGridLevel = 0; + m_SubSampling=false; + SubSampling[0]=1; + SubSampling[1]=1; + SubSampling[2]=1; + m_OptResolution=false; + OptResolution[0]=1; + OptResolution[1]=1; + OptResolution[2]=1; +} + +void CSPropDumpBox::SetSubSampling(int ny, unsigned int val) +{ + if ((ny<0) || (ny>2)) return; + if (val<1) return; + SubSampling[ny] = val; +} + +void CSPropDumpBox::SetSubSampling(unsigned int val[]) +{ + for (int ny=0;ny<3;++ny) + SetSubSampling(ny,val[ny]); +} + +void CSPropDumpBox::SetSubSampling(const char* vals) +{ + if (vals==NULL) return; + m_SubSampling=true; + std::vector values = SplitString2Int(std::string(vals),','); + for (int ny=0;ny<3 && ny<(int)values.size();++ny) + SetSubSampling(ny,values.at(ny)); +} + +unsigned int CSPropDumpBox::GetSubSampling(int ny) +{ + if ((ny<0) || (ny>2)) return 1; + return SubSampling[ny]; +} + +void CSPropDumpBox::SetOptResolution(int ny, double val) +{ + if ((ny<0) || (ny>2)) return; + if (val<0) return; + OptResolution[ny] = val; +} + +void CSPropDumpBox::SetOptResolution(double val[]) +{ + for (int ny=0;ny<3;++ny) + SetOptResolution(ny,val[ny]); +} + +void CSPropDumpBox::SetOptResolution(const char* vals) +{ + if (vals==NULL) return; + m_OptResolution=true; + std::vector values = SplitString2Double(std::string(vals),','); + if (values.size()==1) //allow one resolution for all directions + { + for (int ny=0;ny<3;++ny) + SetOptResolution(ny,values.at(0)); + return; + } + for (int ny=0;ny<3 && ny<(int)values.size();++ny) + SetOptResolution(ny,values.at(ny)); +} + +double CSPropDumpBox::GetOptResolution(int ny) +{ + if ((ny<0) || (ny>2)) return 1; + return OptResolution[ny]; +} + +bool CSPropDumpBox::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSPropProbeBox::Write2XML(root,parameterised,sparse) == false) return false; + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + prop->SetAttribute("DumpType",DumpType); + prop->SetAttribute("DumpMode",DumpMode); + prop->SetAttribute("FileType",FileType); + prop->SetAttribute("MultiGridLevel",MultiGridLevel); + + if (m_SubSampling) + { + std::stringstream ss; + ss << GetSubSampling(0) << "," << GetSubSampling(1) << "," << GetSubSampling(2) ; + prop->SetAttribute("SubSampling",ss.str().c_str()); + } + if (m_OptResolution) + { + std::stringstream ss; + ss << GetOptResolution(0) << "," << GetOptResolution(1) << "," << GetOptResolution(2) ; + prop->SetAttribute("OptResolution",ss.str().c_str()); + } + + return true; +} + +bool CSPropDumpBox::ReadFromXML(TiXmlNode &root) +{ + if (CSPropProbeBox::ReadFromXML(root)==false) return false; + + TiXmlElement *prop = root.ToElement(); + if (prop==NULL) return false; + + if (prop->QueryIntAttribute("DumpType",&DumpType)!=TIXML_SUCCESS) DumpType=0; + if (prop->QueryIntAttribute("DumpMode",&DumpMode)!=TIXML_SUCCESS) DumpMode=0; + if (prop->QueryIntAttribute("FileType",&FileType)!=TIXML_SUCCESS) FileType=0; + if (prop->QueryIntAttribute("MultiGridLevel",&MultiGridLevel)!=TIXML_SUCCESS) MultiGridLevel=0; + + SetSubSampling(prop->Attribute("SubSampling")); + SetOptResolution(prop->Attribute("OptResolution")); + + return true; +} + +void CSPropDumpBox::ShowPropertyStatus(std::ostream& stream) +{ + //skip output of prarent CSPropProbeBox + CSProperties::ShowPropertyStatus(stream); + stream << " --- Dump Properties --- " << std::endl; + stream << " DumpType: " << DumpType << " DumpMode: " << DumpMode << " FileType: " << FileType << " MultiGridLevel: " << MultiGridLevel << std::endl; + if (m_FD_Samples.size()>0) + stream << " Dump Frequencies: " << CombineVector2String(m_FD_Samples,',') << std::endl; +} diff --git a/CSXCAD/src/CSPropDumpBox.h b/CSXCAD/src/CSPropDumpBox.h new file mode 100644 index 0000000..424be2b --- /dev/null +++ b/CSXCAD/src/CSPropDumpBox.h @@ -0,0 +1,98 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSPropProbeBox.h" + + +//! Continuous Structure Dump Property +/*! + This Property defines an area (box) designated for field dumps. + */ +class CSXCAD_EXPORT CSPropDumpBox : public CSPropProbeBox +{ +public: + CSPropDumpBox(ParameterSet* paraSet); + CSPropDumpBox(CSProperties* prop); + CSPropDumpBox(unsigned int ID, ParameterSet* paraSet); + virtual ~CSPropDumpBox(); + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("DumpBox");} + + //! Define an arbitrary dump-type \sa GetDumpType + void SetDumpType(int type) {DumpType=type;} + //! Get the arbitrary dump-type \sa SetDumpType + int GetDumpType() {return DumpType;} + + //! Define an arbitrary dump-mode \sa GetDumpMode + void SetDumpMode(int mode) {DumpMode=mode;} + //! Get the arbitrary dump-mode \sa SetDumpMode + int GetDumpMode() {return DumpMode;} + + //! Define an arbitrary file-type \sa GetFileType + void SetFileType(int ftype) {FileType=ftype;} + //! Get the arbitrary file-type \sa SetFileType + int GetFileType() {return FileType;} + + //! Set the multi grid level to use (default is 0) \sa GetMultiGridLevel + void SetMultiGridLevel(int mgl) {MultiGridLevel=mgl;} + //! Get the multi grid level to use \sa SetMultiGridLevel + int GetMultiGridLevel() {return MultiGridLevel;} + + bool GetSubSampling() {return m_SubSampling;} + void SetSubSampling(bool val) {m_SubSampling=val;} + void SetSubSampling(int ny, unsigned int val); + void SetSubSampling(unsigned int val[]); + void SetSubSampling(const char* vals); + unsigned int GetSubSampling(int ny); + + //! Get status of opt resolution flag + bool GetOptResolution() {return m_OptResolution;} + //! Set status of opt resolution flag + void SetOptResolution(bool val) {m_OptResolution=val;} + //! Set the opt resoultion for a given direction + void SetOptResolution(int ny, double val); + //! Set the opt resoultion for all directions + void SetOptResolution(double val[]); + //! Set the opt resoultion for all directions as string + void SetOptResolution(const char* vals); + //! Get the optimal resolution for a given direction + double GetOptResolution(int ny); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void Init(); + + virtual void ShowPropertyStatus(std::ostream& stream); + +protected: + int DumpType; + int DumpMode; + int FileType; + int MultiGridLevel; + + //sub-sampling + bool m_SubSampling; + unsigned int SubSampling[3]; + + //sub-sampling + bool m_OptResolution; + double OptResolution[3]; +}; diff --git a/CSXCAD/src/CSPropExcitation.cpp b/CSXCAD/src/CSPropExcitation.cpp new file mode 100644 index 0000000..8d498ad --- /dev/null +++ b/CSXCAD/src/CSPropExcitation.cpp @@ -0,0 +1,278 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropExcitation.h" + +CSPropExcitation::CSPropExcitation(ParameterSet* paraSet,unsigned int number) : CSProperties(paraSet) {Type=EXCITATION;Init();uiNumber=number;} +CSPropExcitation::CSPropExcitation(CSProperties* prop) : CSProperties(prop) {Type=EXCITATION;Init();} +CSPropExcitation::CSPropExcitation(unsigned int ID, ParameterSet* paraSet) : CSProperties(ID,paraSet) {Type=EXCITATION;Init();} +CSPropExcitation::~CSPropExcitation() {} + +void CSPropExcitation::SetNumber(unsigned int val) {uiNumber=val;} +unsigned int CSPropExcitation::GetNumber() {return uiNumber;} + +void CSPropExcitation::SetExcitType(int val) {iExcitType=val;} +int CSPropExcitation::GetExcitType() {return iExcitType;} + +void CSPropExcitation::SetExcitation(double val, int Component) +{ + if ((Component<0) || (Component>=3)) return; + Excitation[Component].SetValue(val); +} + +void CSPropExcitation::SetExcitation(const std::string val, int Component) +{ + if ((Component<0) || (Component>=3)) return; + Excitation[Component].SetValue(val); +} + +double CSPropExcitation::GetExcitation(int Component) +{ + if ((Component<0) || (Component>=3)) return 0; + return Excitation[Component].GetValue(); +} + +const std::string CSPropExcitation::GetExcitationString(int Comp) +{ + if ((Comp<0) || (Comp>=3)) return NULL; + return Excitation[Comp].GetString(); +} + +void CSPropExcitation::SetActiveDir(bool active, int Component) +{ + if ((Component<0) || (Component>=3)) return; + ActiveDir[Component]=active; +} + +bool CSPropExcitation::GetActiveDir(int Component) +{ + if ((Component<0) || (Component>=3)) return false; + return ActiveDir[Component]; +} + +int CSPropExcitation::SetWeightFunction(const std::string fct, int ny) +{ + if ((ny>=0) && (ny<3)) + return WeightFct[ny].SetValue(fct); + return 0; +} + +const std::string CSPropExcitation::GetWeightFunction(int ny) {if ((ny>=0) && (ny<3)) {return WeightFct[ny].GetString();} else return std::string();} + +double CSPropExcitation::GetWeightedExcitation(int ny, const double* coords) +{ + if ((ny<0) || (ny>=3)) return 0; + //Warning: this is not reentrant....!!!! + double loc_coords[3] = {coords[0],coords[1],coords[2]}; + double r,rho,alpha,theta; + if (coordInputType==1) + { + loc_coords[0] = coords[0]*cos(coords[1]); + loc_coords[1] = coords[0]*sin(coords[1]); + rho = coords[0]; + alpha=coords[1]; + r = sqrt(pow(coords[0],2)+pow(coords[2],2)); + theta=asin(1)-atan(coords[2]/rho); + } + else + { + alpha=atan2(coords[1],coords[0]); + rho = sqrt(pow(coords[0],2)+pow(coords[1],2)); + r = sqrt(pow(coords[0],2)+pow(coords[1],2)+pow(coords[2],2)); + theta=asin(1)-atan(coords[2]/rho); + } + coordPara[0]->SetValue(loc_coords[0]); + coordPara[1]->SetValue(loc_coords[1]); + coordPara[2]->SetValue(loc_coords[2]); + coordPara[3]->SetValue(rho); //rho + coordPara[4]->SetValue(r); //r + coordPara[5]->SetValue(alpha); + coordPara[6]->SetValue(theta); //theta + int EC = WeightFct[ny].Evaluate(); + if (EC) + { + std::cerr << "CSPropExcitation::GetWeightedExcitation: Error evaluating the weighting function (ID: " << this->GetID() << ", n=" << ny << "): " << PSErrorCode2Msg(EC) << std::endl; + } + + return WeightFct[ny].GetValue()*GetExcitation(ny); +} + +void CSPropExcitation::SetDelay(double val) {Delay.SetValue(val);} + +void CSPropExcitation::SetDelay(const std::string val) {Delay.SetValue(val);} + +double CSPropExcitation::GetDelay(){return Delay.GetValue();} + +const std::string CSPropExcitation::GetDelayString(){return Delay.GetString();} + +void CSPropExcitation::Init() +{ + uiNumber=0; + iExcitType=1; + coordInputType=UNDEFINED_CS; + m_Frequency.SetValue(0.0); + for (unsigned int i=0;i<3;++i) + { + ActiveDir[i]=true; + Excitation[i].SetValue(0.0); + Excitation[i].SetParameterSet(clParaSet); + WeightFct[i].SetValue(1.0); + WeightFct[i].SetParameterSet(coordParaSet); + Delay.SetValue(0.0); + Delay.SetParameterSet(clParaSet); + } +} + +void CSPropExcitation::SetPropagationDir(double val, int Component) +{ + if ((Component<0) || (Component>=3)) return; + PropagationDir[Component].SetValue(val); +} + +void CSPropExcitation::SetPropagationDir(const std::string val, int Component) +{ + if ((Component<0) || (Component>=3)) return; + PropagationDir[Component].SetValue(val); +} + +double CSPropExcitation::GetPropagationDir(int Component) +{ + if ((Component<0) || (Component>=3)) return 0; + return PropagationDir[Component].GetValue(); +} + +const std::string CSPropExcitation::GetPropagationDirString(int Comp) +{ + if ((Comp<0) || (Comp>=3)) return NULL; + return PropagationDir[Comp].GetString(); +} + + +bool CSPropExcitation::Update(std::string *ErrStr) +{ + bool bOK=true; + int EC=0; + 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)) + { + std::stringstream stream; + stream << std::endl << "Error in Excitation-Property Excitaion-Value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=PropagationDir[i].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Excitation-Property PropagationDir-Value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + } + EC=m_Frequency.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Excitation-Property Frequency-Value"; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=Delay.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Excitation-Property Delay-Value"; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + return bOK; +} + +bool CSPropExcitation::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSProperties::Write2XML(root,parameterised,sparse) == false) return false; + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + prop->SetAttribute("Number",(int)uiNumber); + WriteTerm(m_Frequency,*prop,"Frequency",parameterised); + WriteTerm(Delay,*prop,"Delay",parameterised); + + prop->SetAttribute("Type",iExcitType); + WriteVectorTerm(Excitation,*prop,"Excite",parameterised); + + TiXmlElement Weight("Weight"); + WriteTerm(WeightFct[0],Weight,"X",parameterised); + WriteTerm(WeightFct[1],Weight,"Y",parameterised); + WriteTerm(WeightFct[2],Weight,"Z",parameterised); + prop->InsertEndChild(Weight); + + WriteVectorTerm(PropagationDir,*prop,"PropDir",parameterised); + + return true; +} + +bool CSPropExcitation::ReadFromXML(TiXmlNode &root) +{ + if (CSProperties::ReadFromXML(root)==false) return false; + + TiXmlElement *prop = root.ToElement(); + if (prop==NULL) return false; + + int iHelp; + if (prop->QueryIntAttribute("Number",&iHelp)!=TIXML_SUCCESS) uiNumber=0; + else uiNumber=(unsigned int)iHelp; + + if (prop->QueryIntAttribute("Type",&iExcitType)!=TIXML_SUCCESS) return false; + + if (ReadVectorTerm(Excitation,*prop,"Excite",0.0)==false) return false; + + ReadTerm(m_Frequency,*prop,"Frequency"); + ReadTerm(Delay,*prop,"Delay"); + + TiXmlElement *weight = prop->FirstChildElement("Weight"); + if (weight!=NULL) + { + ReadTerm(WeightFct[0],*weight,"X"); + ReadTerm(WeightFct[1],*weight,"Y"); + ReadTerm(WeightFct[2],*weight,"Z"); + } + + ReadVectorTerm(PropagationDir,*prop,"PropDir",0.0); + + return true; +} + +void CSPropExcitation::ShowPropertyStatus(std::ostream& stream) +{ + CSProperties::ShowPropertyStatus(stream); + stream << " --- Excitation Properties --- " << std::endl; + stream << " Type: " << iExcitType << std::endl; + stream << " Active directions: " << ActiveDir[0] << "," << ActiveDir[1] << "," << ActiveDir[2] << std::endl; + stream << " Excitation\t: " << Excitation[0].GetValueString() << ", " << Excitation[1].GetValueString() << ", " << Excitation[2].GetValueString() << std::endl; + stream << " Weighting\t: " << WeightFct[0].GetValueString() << ", " << WeightFct[1].GetValueString() << ", " << WeightFct[2].GetValueString() << std::endl; + stream << " Propagation Dir: " << PropagationDir[0].GetValueString() << ", " << PropagationDir[1].GetValueString() << ", " << PropagationDir[2].GetValueString() << std::endl; + stream << " Delay\t\t: " << Delay.GetValueString() << std::endl; +} diff --git a/CSXCAD/src/CSPropExcitation.h b/CSXCAD/src/CSPropExcitation.h new file mode 100644 index 0000000..5cd166c --- /dev/null +++ b/CSXCAD/src/CSPropExcitation.h @@ -0,0 +1,114 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSProperties.h" + +//! Continuous Structure Excitation Property +/*! + This Property defines an excitation which can be location and direction dependent. + */ +class CSXCAD_EXPORT CSPropExcitation : public CSProperties +{ +public: + CSPropExcitation(ParameterSet* paraSet,unsigned int number=0); + CSPropExcitation(CSProperties* prop); + CSPropExcitation(unsigned int ID, ParameterSet* paraSet); + virtual ~CSPropExcitation(); + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("Excitation");} + + //! Set the number for this excitation + void SetNumber(unsigned int val); + //! Get the number for this excitation + unsigned int GetNumber(); + + //! Set the excitation type + void SetExcitType(int val); + //! Get the excitation type + int GetExcitType(); + + //! Set the active direction for the source, only necessary with hard sources (by default all active) + void SetActiveDir(bool active, int Component=0); + //! Get the active direction for the source, only necessary with hard sources (by default all active) + bool GetActiveDir(int Component=0); + + //! Set the excitation frequency + void SetFrequency(double val) {m_Frequency.SetValue(val);} + //! Set the excitation frequency + void SetFrequency(const std::string val) {m_Frequency.SetValue(val);} + //! Get the excitation frequency + double GetFrequency() {return m_Frequency.GetValue();} + //! Get the excitation frequency as a string + const std::string GetFrequencyString() {return m_Frequency.GetValueString();} + + //! Set the excitation amplitude for a given component + void SetExcitation(double val, int Component=0); + //! Set the excitation amplitude for a given component + void SetExcitation(const std::string val, int Component=0); + //! Get the excitation amplitude for a given component + double GetExcitation(int Component=0); + //! Get the excitation amplitude as a string for a given component + const std::string GetExcitationString(int Comp=0); + + //! Set a weighting factor for the given component. This will override the weighting function! + void SetWeight(double val, int ny); + //! Set a weighting function for the given excitation component + int SetWeightFunction(const std::string fct, int ny); + //! Get the weighting function for the given excitation component + const std::string GetWeightFunction(int ny); + + double GetWeightedExcitation(int ny, const double* coords); + + //! Set the propagation direction for a given component + void SetPropagationDir(double val, int Component=0); + //! Set the propagation direction for a given component + void SetPropagationDir(const std::string val, int Component=0); + //! Get the propagation direction for a given component + double GetPropagationDir(int Component=0); + //! Get the propagation direction as a string for a given component + const std::string GetPropagationDirString(int Comp=0); + + //! Set the excitation delay + void SetDelay(double val); + //! Set the excitation delay + void SetDelay(const std::string val); + //! Get the excitation delay + double GetDelay(); + //! Get the excitation delay as a string + const std::string GetDelayString(); + + virtual void Init(); + virtual bool Update(std::string *ErrStr=NULL); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPropertyStatus(std::ostream& stream); + +protected: + unsigned int uiNumber; + int iExcitType; + bool ActiveDir[3]; + ParameterScalar m_Frequency; + ParameterScalar Excitation[3]; // excitation amplitude vector + ParameterScalar WeightFct[3]; // excitation amplitude weighting function + ParameterScalar PropagationDir[3]; // direction of propagation (should be a unit vector), needed for plane wave excitations + ParameterScalar Delay; // excitation delay only, for time-domain solver e.g. FDTD +}; diff --git a/CSXCAD/src/CSPropLorentzMaterial.cpp b/CSXCAD/src/CSPropLorentzMaterial.cpp new file mode 100644 index 0000000..73cda4a --- /dev/null +++ b/CSXCAD/src/CSPropLorentzMaterial.cpp @@ -0,0 +1,416 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropLorentzMaterial.h" + +CSPropLorentzMaterial::CSPropLorentzMaterial(ParameterSet* paraSet) : CSPropDispersiveMaterial(paraSet) {Type=(CSProperties::PropertyType)(LORENTZMATERIAL | DISPERSIVEMATERIAL | MATERIAL);Init();} +CSPropLorentzMaterial::CSPropLorentzMaterial(CSProperties* prop) : CSPropDispersiveMaterial(prop) {Type=(CSProperties::PropertyType)(LORENTZMATERIAL | DISPERSIVEMATERIAL | MATERIAL);Init();} +CSPropLorentzMaterial::CSPropLorentzMaterial(unsigned int ID, ParameterSet* paraSet) : CSPropDispersiveMaterial(ID,paraSet) {Type=(CSProperties::PropertyType)(LORENTZMATERIAL | DISPERSIVEMATERIAL | MATERIAL);Init();} + +CSPropLorentzMaterial::~CSPropLorentzMaterial() +{ + DeleteValues(); + m_Order = 0; +} + +void CSPropLorentzMaterial::Init() +{ + m_Order = 0; + EpsPlasma=NULL; + MuePlasma=NULL; + WeightEpsPlasma=NULL; + WeightMuePlasma=NULL; + EpsLorPole=NULL; + MueLorPole=NULL; + WeightEpsLorPole=NULL; + WeightMueLorPole=NULL; + EpsRelaxTime=NULL; + MueRelaxTime=NULL; + WeightEpsRelaxTime=NULL; + WeightMueRelaxTime=NULL; + InitValues(); + CSPropDispersiveMaterial::Init(); +} + +void CSPropLorentzMaterial::DeleteValues() +{ + for (int o=0;oappend(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=MuePlasma[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Lorentz Material-Property mue plasma frequency value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + EC=WeightEpsPlasma[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Lorentz Material-Property epsilon plasma frequency weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=WeightMuePlasma[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Lorentz Material-Property mue plasma frequency value weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + EC=EpsLorPole[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Lorentz Material-Property epsilon lorentz pole frequency value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=MueLorPole[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Lorentz Material-Property mue lorentz pole frequency value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + EC=WeightEpsLorPole[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Lorentz Material-Property epsilon lorentz pole frequency weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=WeightMueLorPole[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Lorentz Material-Property mue lorentz pole frequency value weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + EC=EpsRelaxTime[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Lorentz Material-Property epsilon relaxation time value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=MueRelaxTime[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Lorentz Material-Property mue relaxation time value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + EC=WeightEpsRelaxTime[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Lorentz Material-Property epsilon relaxation time weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=WeightMueRelaxTime[o][n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Lorentz Material-Property mue relaxation time value weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + } + } + return bOK & CSPropDispersiveMaterial::Update(ErrStr); +} + +bool CSPropLorentzMaterial::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSPropDispersiveMaterial::Write2XML(root,parameterised,sparse) == false) return false; + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + std::string suffix; + for (int o=0;oFirstChildElement("Property"); + if (value==NULL) + return false; + WriteVectorTerm(EpsPlasma[o],*value,"EpsilonPlasmaFrequency_"+suffix,parameterised); + WriteVectorTerm(MuePlasma[o],*value,"MuePlasmaFrequency_"+suffix,parameterised); + WriteVectorTerm(EpsLorPole[o],*value,"EpsilonLorPoleFrequency_"+suffix,parameterised); + WriteVectorTerm(MueLorPole[o],*value,"MueLorPoleFrequency_"+suffix,parameterised); + WriteVectorTerm(EpsRelaxTime[o],*value,"EpsilonRelaxTime_"+suffix,parameterised); + WriteVectorTerm(MueRelaxTime[o],*value,"MueRelaxTime_"+suffix,parameterised); + + TiXmlElement* weight=prop->FirstChildElement("Weight"); + if (weight==NULL) + return false; + WriteVectorTerm(WeightEpsPlasma[o],*weight,"EpsilonPlasmaFrequency_"+suffix,parameterised); + WriteVectorTerm(WeightMuePlasma[o],*weight,"MuePlasmaFrequency_"+suffix,parameterised); + WriteVectorTerm(WeightEpsLorPole[o],*weight,"EpsilonLorPoleFrequency_"+suffix,parameterised); + WriteVectorTerm(WeightMueLorPole[o],*weight,"MueLorPoleFrequency_"+suffix,parameterised); + WriteVectorTerm(WeightEpsRelaxTime[o],*weight,"EpsilonRelaxTime_"+suffix,parameterised); + WriteVectorTerm(WeightMueRelaxTime[o],*weight,"MueRelaxTime_"+suffix,parameterised); + } + return true; +} + +bool CSPropLorentzMaterial::ReadFromXML(TiXmlNode &root) +{ + if (CSPropDispersiveMaterial::ReadFromXML(root)==false) return false; + TiXmlElement* prop=root.ToElement(); + + if (prop==NULL) return false; + + // count m_Order + TiXmlElement* matProp=prop->FirstChildElement("Property"); + if (matProp!=NULL) + { + m_Order=1; + while (1) + { + if (matProp->Attribute("EpsilonPlasmaFrequency_"+ConvertInt(m_Order+1))) + ++m_Order; + else if (matProp->Attribute("MuePlasmaFrequency_"+ConvertInt(m_Order+1))) + ++m_Order; + else + break; + } + } + else + return false; + + InitValues(); + + if (ReadVectorTerm(EpsPlasma[0],*matProp,"EpsilonPlasmaFrequency_1",0.0)==false) + ReadVectorTerm(EpsPlasma[0],*matProp,"EpsilonPlasmaFrequency",0.0); + if (ReadVectorTerm(MuePlasma[0],*matProp,"MuePlasmaFrequency_1",0.0)==false) + ReadVectorTerm(MuePlasma[0],*matProp,"MuePlasmaFrequency",0.0); + + if (ReadVectorTerm(EpsLorPole[0],*matProp,"EpsilonLorPoleFrequency_1",0.0)==false) + ReadVectorTerm(EpsLorPole[0],*matProp,"EpsilonLorPoleFrequency",0.0); + if (ReadVectorTerm(MueLorPole[0],*matProp,"MueLorPoleFrequency_1",0.0)==false) + ReadVectorTerm(MueLorPole[0],*matProp,"MueLorPoleFrequency",0.0); + + if (ReadVectorTerm(EpsRelaxTime[0],*matProp,"EpsilonRelaxTime_1",0.0)==false) + ReadVectorTerm(EpsRelaxTime[0],*matProp,"EpsilonRelaxTime",0.0); + if (ReadVectorTerm(MueRelaxTime[0],*matProp,"MueRelaxTime_1",0.0)==false) + ReadVectorTerm(MueRelaxTime[0],*matProp,"MueRelaxTime",0.0); + + TiXmlElement* weightProp=prop->FirstChildElement("Weight"); + if (weightProp) + { + if (ReadVectorTerm(WeightEpsPlasma[0],*weightProp,"EpsilonPlasmaFrequency_1",1.0)==false) + ReadVectorTerm(WeightEpsPlasma[0],*weightProp,"EpsilonPlasmaFrequency",1.0); + if (ReadVectorTerm(WeightMuePlasma[0],*weightProp,"MuePlasmaFrequency_1",1.0)==false) + ReadVectorTerm(WeightMuePlasma[0],*weightProp,"MuePlasmaFrequency",1.0); + + if (ReadVectorTerm(WeightEpsLorPole[0],*weightProp,"EpsilonLorPoleFrequency_1",1.0)==false) + ReadVectorTerm(WeightEpsLorPole[0],*weightProp,"EpsilonLorPoleFrequency",1.0); + if (ReadVectorTerm(WeightMueLorPole[0],*weightProp,"MueLorPoleFrequency_1",1.0)==false) + ReadVectorTerm(WeightMueLorPole[0],*weightProp,"MueLorPoleFrequency",1.0); + + if (ReadVectorTerm(WeightEpsRelaxTime[0],*weightProp,"EpsilonRelaxTime_1",1.0)==false) + ReadVectorTerm(WeightEpsRelaxTime[0],*weightProp,"EpsilonRelaxTime",1.0); + if (ReadVectorTerm(WeightMueRelaxTime[0],*weightProp,"MueRelaxTime_1",1.0)==false) + ReadVectorTerm(WeightMueRelaxTime[0],*weightProp,"MueRelaxTime",1.0); + } + + for (int o=1;o. +*/ + +#pragma once + +#include "CSProperties.h" +#include "CSPropDispersiveMaterial.h" + +//! Continuous Structure Lorentz/ Drude Dispersive Material Property +/*! + This Property can hold information about the special properties of Lorentz or Drude dispersive materials. + The Drude material model is a special case of the Lorentz material model. + \todo Add all the other parameter needed by this model + */ +class CSXCAD_EXPORT CSPropLorentzMaterial : public CSPropDispersiveMaterial +{ +public: + CSPropLorentzMaterial(ParameterSet* paraSet); + CSPropLorentzMaterial(CSProperties* prop); + CSPropLorentzMaterial(unsigned int ID, ParameterSet* paraSet); + virtual ~CSPropLorentzMaterial(); + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("LorentzMaterial");} + + //! Set the epsilon plasma frequency + void SetEpsPlasmaFreq(int order, double val, int ny=0) {SetValue(val,EpsPlasma[order],ny);} + //! Set the epsilon plasma frequency + int SetEpsPlasmaFreq(int order, const std::string val, int ny=0) {return SetValue(val,EpsPlasma[order],ny);} + //! Get the epsilon plasma frequency + double GetEpsPlasmaFreq(int order, int ny=0) {return GetValue(EpsPlasma[order],ny);} + //! Get the epsilon plasma frequency as a string + const std::string GetEpsPlasmaFreqTerm(int order, int ny=0) {return GetTerm(EpsPlasma[order],ny);} + + //! Set the epsilon plasma frequency weighting + int SetEpsPlasmaFreqWeightFunction(int order, const std::string val, int ny) {return SetValue(val,WeightEpsPlasma[order],ny);} + //! Get the epsilon plasma frequency weighting string + const std::string GetEpsPlasmaFreqWeightFunction(int order, int ny) {return GetTerm(WeightEpsPlasma[order],ny);} + //! Get the epsilon plasma frequency weighting + double GetEpsPlasmaFreqWeighted(int order, int ny, const double* coords) {return GetWeight(WeightEpsPlasma[order],ny,coords)*GetEpsPlasmaFreq(order,ny);} + + //! Set the epsilon lorentz pole frequency + void SetEpsLorPoleFreq(int order, double val, int ny=0) {SetValue(val,EpsLorPole[order],ny);} + //! Set the epsilon lorentz pole frequency + int SetEpsLorPoleFreq(int order, const std::string val, int ny=0) {return SetValue(val,EpsLorPole[order],ny);} + //! Get the epsilon lorentz pole frequency + double GetEpsLorPoleFreq(int order, int ny=0) {return GetValue(EpsLorPole[order],ny);} + //! Get the epsilon lorentz pole frequency as a string + const std::string GetEpsLorPoleFreqTerm(int order, int ny=0) {return GetTerm(EpsLorPole[order],ny);} + + //! Set the epsilon lorentz pole frequency weighting + int SetEpsLorPoleFreqWeightFunction(int order, const std::string val, int ny) {return SetValue(val,WeightEpsLorPole[order],ny);} + //! Get the epsilon lorentz pole frequency weighting string + const std::string GetEpsLorPoleFreqWeightFunction(int order, int ny) {return GetTerm(WeightEpsLorPole[order],ny);} + //! Get the epsilon lorentz pole frequency weighting + double GetEpsLorPoleFreqWeighted(int order, int ny, const double* coords) {return GetWeight(WeightEpsLorPole[order],ny,coords)*GetEpsLorPoleFreq(order,ny);} + + //! Set the epsilon relaxation time + void SetEpsRelaxTime(int order, double val, int ny=0) {SetValue(val,EpsRelaxTime[order],ny);} + //! Set the epsilon relaxation time + int SetEpsRelaxTime(int order, const std::string val, int ny=0) {return SetValue(val,EpsRelaxTime[order],ny);} + //! Get the epsilon relaxation time + double GetEpsRelaxTime(int order, int ny=0) {return GetValue(EpsRelaxTime[order],ny);} + //! Get the epsilon relaxation time as a string + const std::string GetEpsRelaxTimeTerm(int order, int ny=0) {return GetTerm(EpsRelaxTime[order],ny);} + + //! Set the epsilon relaxation time weighting + int SetEpsRelaxTimeWeightFunction(int order, const std::string val, int ny) {return SetValue(val,WeightEpsRelaxTime[order],ny);} + //! Get the epsilon relaxation time weighting string + const std::string GetEpsRelaxTimeWeightFunction(int order, int ny) {return GetTerm(WeightEpsRelaxTime[order],ny);} + //! Get the epsilon relaxation time weighting + double GetEpsRelaxTimeWeighted(int order, int ny, const double* coords) {return GetWeight(WeightEpsRelaxTime[order],ny,coords)*GetEpsRelaxTime(order,ny);} + + //! Set the mue plasma frequency + void SetMuePlasmaFreq(int order, double val, int ny=0) {SetValue(val,MuePlasma[order],ny);} + //! Set the mue plasma frequency + int SetMuePlasmaFreq(int order, const std::string val, int ny=0) {return SetValue(val,MuePlasma[order],ny);} + //! Get the mue plasma frequency + double GetMuePlasmaFreq(int order, int ny=0) {return GetValue(MuePlasma[order],ny);} + //! Get the mue plasma frequency string + const std::string GetMueTermPlasmaFreq(int order, int ny=0) {return GetTerm(MuePlasma[order],ny);} + + //! Set the mue plasma frequency weighting + int SetMuePlasmaFreqWeightFunction(int order, const std::string val, int ny) {return SetValue(val,WeightMuePlasma[order],ny);} + //! Get the mue plasma frequency weighting string + const std::string GetMuePlasmaFreqWeightFunction(int order, int ny) {return GetTerm(WeightMuePlasma[order],ny);} + //! Get the mue plasma frequency weighting + double GetMuePlasmaFreqWeighted(int order, int ny, const double* coords) {return GetWeight(WeightMuePlasma[order],ny,coords)*GetMuePlasmaFreq(order,ny);} + + //! Set the mue lorentz pole frequency + void SetMueLorPoleFreq(int order, double val, int ny=0) {SetValue(val,MueLorPole[order],ny);} + //! Set the mue lorentz pole frequency + int SetMueLorPoleFreq(int order, const std::string val, int ny=0) {return SetValue(val,MueLorPole[order],ny);} + //! Get the mue lorentz pole frequency + double GetMueLorPoleFreq(int order, int ny=0) {return GetValue(MueLorPole[order],ny);} + //! Get the mue lorentz pole frequency string + const std::string GetMueTermLorPoleFreq(int order, int ny=0) {return GetTerm(MueLorPole[order],ny);} + + //! Set the mue lorentz pole frequency weighting + int SetMueLorPoleFreqWeightFunction(int order, const std::string val, int ny) {return SetValue(val,WeightMueLorPole[order],ny);} + //! Get the mue lorentz pole frequency weighting string + const std::string GetMueLorPoleFreqWeightFunction(int order, int ny) {return GetTerm(WeightMueLorPole[order],ny);} + //! Get the mue lorentz pole frequency weighting + double GetMueLorPoleFreqWeighted(int order, int ny, const double* coords) {return GetWeight(WeightMueLorPole[order],ny,coords)*GetMueLorPoleFreq(order,ny);} + + //! Set the mue relaxation time + void SetMueRelaxTime(int order, double val, int ny=0) {SetValue(val,MueRelaxTime[order],ny);} + //! Set the mue relaxation time + int SetMueRelaxTime(int order, const std::string val, int ny=0) {return SetValue(val,MueRelaxTime[order],ny);} + //! Get the mue relaxation time + double GetMueRelaxTime(int order, int ny=0) {return GetValue(MueRelaxTime[order],ny);} + //! Get the mue relaxation time string + const std::string GetMueTermRelaxTime(int order, int ny=0) {return GetTerm(MueRelaxTime[order],ny);} + + //! Set the mue relaxation time weighting + int SetMueRelaxTimeWeightFunction(int order, const std::string val, int ny) {return SetValue(val,WeightMueRelaxTime[order],ny);} + //! Get the mue relaxation time weighting string + const std::string GetMueRelaxTimeWeightFunction(int order, int ny) {return GetTerm(WeightMueRelaxTime[order],ny);} + //! Get the mue relaxation time weighting + double GetMueRelaxTimeWeighted(int order, int ny, const double* coords) {return GetWeight(WeightMueRelaxTime[order],ny,coords)*GetMueRelaxTime(order,ny);} + + virtual void Init(); + virtual bool Update(std::string *ErrStr=NULL); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPropertyStatus(std::ostream& stream); + +protected: + virtual void InitValues(); + virtual void DeleteValues(); + //! Epsilon and mue plasma frequncies + ParameterScalar** EpsPlasma; + ParameterScalar** MuePlasma; + //! Epsilon and mue plasma frequncies weighting functions + ParameterScalar** WeightEpsPlasma; + ParameterScalar** WeightMuePlasma; + + //! Epsilon and mue lorentz pole frequncies + ParameterScalar** EpsLorPole; + ParameterScalar** MueLorPole; + //! Epsilon and mue lorentz pole frequncies weighting functions + ParameterScalar** WeightEpsLorPole; + ParameterScalar** WeightMueLorPole; + + //! Relaxation times for epsilon and mue + ParameterScalar** EpsRelaxTime; + ParameterScalar** MueRelaxTime; + //! Relaxation times for epsilon and mue weighting functions + ParameterScalar** WeightEpsRelaxTime; + ParameterScalar** WeightMueRelaxTime; +}; diff --git a/CSXCAD/src/CSPropLumpedElement.cpp b/CSXCAD/src/CSPropLumpedElement.cpp new file mode 100644 index 0000000..f4dc602 --- /dev/null +++ b/CSXCAD/src/CSPropLumpedElement.cpp @@ -0,0 +1,128 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropLumpedElement.h" + +CSPropLumpedElement::CSPropLumpedElement(ParameterSet* paraSet) : CSProperties(paraSet) {Type=LUMPED_ELEMENT;Init();} +CSPropLumpedElement::CSPropLumpedElement(CSProperties* prop) : CSProperties(prop) {Type=LUMPED_ELEMENT;Init();} +CSPropLumpedElement::CSPropLumpedElement(unsigned int ID, ParameterSet* paraSet) : CSProperties(ID,paraSet) {Type=LUMPED_ELEMENT;Init();} +CSPropLumpedElement::~CSPropLumpedElement() {} + +void CSPropLumpedElement::Init() +{ + m_ny=-1; + m_Caps=true; + m_R.SetValue(NAN); + m_C.SetValue(NAN); + m_L.SetValue(NAN); +} + +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)) + { + std::stringstream stream; + stream << std::endl << "Error in LumpedElement-Property Resistance-Value"; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + //cout << EC << std::endl; + } + + EC=m_C.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in LumpedElement-Property Capacitor-Value"; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + //cout << EC << std::endl; + } + + EC=m_L.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in LumpedElement-Property Inductance-Value"; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + //cout << EC << std::endl; + } + + return bOK & CSProperties::Update(ErrStr); +} + +void CSPropLumpedElement::SetDirection(int ny) +{ + if ((ny<0) || (ny>2)) return; + m_ny = ny; +} + +bool CSPropLumpedElement::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSProperties::Write2XML(root,parameterised,sparse)==false) return false; + + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + prop->SetAttribute("Direction",m_ny); + prop->SetAttribute("Caps",(int)m_Caps); + + WriteTerm(m_R,*prop,"R",parameterised); + WriteTerm(m_C,*prop,"C",parameterised); + WriteTerm(m_L,*prop,"L",parameterised); + + return true; +} + +bool CSPropLumpedElement::ReadFromXML(TiXmlNode &root) +{ + if (CSProperties::ReadFromXML(root)==false) return false; + + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + if (prop->QueryIntAttribute("Direction",&m_ny)!=TIXML_SUCCESS) m_ny=-1; + int caps=0; + if (prop->QueryIntAttribute("Caps",&caps)!=TIXML_SUCCESS) m_Caps=true; + else + m_Caps = (bool)caps; + + if (ReadTerm(m_R,*prop,"R")==false) + m_R.SetValue(NAN); + if (ReadTerm(m_C,*prop,"C")==false) + m_C.SetValue(NAN); + if (ReadTerm(m_L,*prop,"L")==false) + m_L.SetValue(NAN); + return true; +} + +void CSPropLumpedElement::ShowPropertyStatus(std::ostream& stream) +{ + CSProperties::ShowPropertyStatus(stream); + stream << " --- Lumped Element Properties --- " << std::endl; + stream << " Direction: " << m_ny << std::endl; + stream << " Resistance: " << m_R.GetValueString() << std::endl; + stream << " Capacity: " << m_C.GetValueString() << std::endl; + stream << " Inductance: " << m_L.GetValueString() << std::endl; +} diff --git a/CSXCAD/src/CSPropLumpedElement.h b/CSXCAD/src/CSPropLumpedElement.h new file mode 100644 index 0000000..6ce61e3 --- /dev/null +++ b/CSXCAD/src/CSPropLumpedElement.h @@ -0,0 +1,71 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSProperties.h" + +//! Continuous Structure Lumped Element Property +/*! + This property represents lumped elements, e.g. smd capacitors etc. + */ +class CSXCAD_EXPORT CSPropLumpedElement : public CSProperties +{ +public: + CSPropLumpedElement(ParameterSet* paraSet); + CSPropLumpedElement(CSProperties* prop); + CSPropLumpedElement(unsigned int ID, ParameterSet* paraSet); + virtual ~CSPropLumpedElement(); + + virtual void Init(); + + void SetResistance(double val) {m_R.SetValue(val);} + int SetResistance(const std::string val) {return m_R.SetValue(val);} + double GetResistance() const {return m_R.GetValue();} + const std::string GetResistanceTerm() const {return m_R.GetString();} + + void SetCapacity(double val) {m_C.SetValue(val);} + int SetCapacity(const std::string val) {return m_C.SetValue(val);} + double GetCapacity() const {return m_C.GetValue();} + const std::string GetCapacityTerm() const {return m_C.GetString();} + + void SetInductance(double val) {m_L.SetValue(val);} + int SetInductance(const std::string val) {return m_L.SetValue(val);} + double GetInductance() const {return m_L.GetValue();} + const std::string GetInductanceTerm() const {return m_L.GetString();} + + void SetDirection(int ny); + int GetDirection() const {return m_ny;} + + void SetCaps(bool val) {m_Caps=val;} + int GetCaps() const {return m_Caps;} + + virtual void ShowPropertyStatus(std::ostream& stream); + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("LumpedElement");} + +protected: + int m_ny; + bool m_Caps; + ParameterScalar m_R,m_C,m_L; + virtual bool Update(std::string *ErrStr=NULL); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); +}; + diff --git a/CSXCAD/src/CSPropMaterial.cpp b/CSXCAD/src/CSPropMaterial.cpp new file mode 100644 index 0000000..7fd2415 --- /dev/null +++ b/CSXCAD/src/CSPropMaterial.cpp @@ -0,0 +1,304 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropMaterial.h" + +CSPropMaterial::CSPropMaterial(ParameterSet* paraSet) : CSProperties(paraSet) {Type=MATERIAL;Init();} +CSPropMaterial::CSPropMaterial(CSProperties* prop) : CSProperties(prop) {Type=MATERIAL;Init();} +CSPropMaterial::CSPropMaterial(unsigned int ID, ParameterSet* paraSet) : CSProperties(ID,paraSet) {Type=MATERIAL;Init();} +CSPropMaterial::~CSPropMaterial() {} + +double CSPropMaterial::GetValue(ParameterScalar *ps, int ny) +{ + if (bIsotropy) ny=0; + if ((ny>2) || (ny<0)) return 0; + return ps[ny].GetValue(); +} + +std::string CSPropMaterial::GetTerm(ParameterScalar *ps, int ny) +{ + if (bIsotropy) ny=0; + if ((ny>2) || (ny<0)) return 0; + return ps[ny].GetString(); +} + +void CSPropMaterial::SetValue(double val, ParameterScalar *ps, int ny) +{ + if ((ny>2) || (ny<0)) return; + ps[ny].SetValue(val); +} + +int CSPropMaterial::SetValue(std::string val, ParameterScalar *ps, int ny) +{ + if ((ny>2) || (ny<0)) return 0; + return ps[ny].SetValue(val); +} + +double CSPropMaterial::GetWeight(ParameterScalar *ps, int ny, const double* coords) +{ + if (bIsotropy) ny=0; + if ((ny>2) || (ny<0)) return 0; + return GetWeight(ps[ny],coords); +} + +double CSPropMaterial::GetWeight(ParameterScalar &ps, const double* coords) +{ + double paraVal[7]; + if (coordInputType==1) + { + double rho = coords[0]; + double alpha=coords[1]; + paraVal[0] = rho*cos(alpha); + paraVal[1] = rho*sin(alpha); + paraVal[2] = coords[2]; //z + paraVal[3] = rho; + paraVal[4] = sqrt(pow(rho,2)+pow(coords[2],2)); // r + paraVal[5] = alpha; //alpha + paraVal[6] = asin(1)-atan(coords[2]/rho); //theta + } + else + { + paraVal[0] = coords[0]; //x + paraVal[1] = coords[1]; //y + paraVal[2] = coords[2]; //z + paraVal[3] = sqrt(pow(coords[0],2)+pow(coords[1],2)); //rho + paraVal[4] = sqrt(pow(coords[0],2)+pow(coords[1],2)+pow(coords[2],2)); // r + paraVal[5] = atan2(coords[1],coords[0]); //alpha + paraVal[6] = asin(1)-atan(coords[2]/paraVal[3]); //theta + } + + int EC=0; + double value = ps.GetEvaluated(paraVal,EC); + if (EC) + { + std::cerr << "CSPropMaterial::GetWeight: Error evaluating the weighting function (ID: " << this->GetID() << "): " << PSErrorCode2Msg(EC) << std::endl; + } + return value; +} + +void CSPropMaterial::Init() +{ + bIsotropy = true; + bMaterial=true; + for (int n=0;n<3;++n) + { + Epsilon[n].SetValue(1); + Epsilon[n].SetParameterSet(clParaSet); + Mue[n].SetValue(1); + Mue[n].SetParameterSet(clParaSet); + Kappa[n].SetValue(0.0); + Kappa[n].SetParameterSet(clParaSet); + Sigma[n].SetValue(0.0); + Sigma[n].SetParameterSet(clParaSet); + WeightEpsilon[n].SetValue(1); + WeightEpsilon[n].SetParameterSet(coordParaSet); + WeightMue[n].SetValue(1); + WeightMue[n].SetParameterSet(coordParaSet); + WeightKappa[n].SetValue(1.0); + WeightKappa[n].SetParameterSet(coordParaSet); + WeightSigma[n].SetValue(1.0); + WeightSigma[n].SetParameterSet(coordParaSet); + } + Density.SetValue(0); + WeightDensity.SetValue(1.0); + FillColor.a=EdgeColor.a=123; + bVisisble=true; +} + +bool CSPropMaterial::Update(std::string *ErrStr) +{ + bool bOK=true; + int EC=0; + 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)) + { + std::stringstream stream; + stream << std::endl << "Error in Material-Property Epsilon-Value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=Mue[n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Material-Property Mue-Value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=Kappa[n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Material-Property Kappa-Value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=Sigma[n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Material-Property Sigma-Value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=WeightEpsilon[n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Material-Property Epsilon-Value weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=WeightMue[n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Material-Property Mue-Value weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=WeightKappa[n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Material-Property Kappa-Value weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=WeightSigma[n].Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Material-Property Sigma-Value weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + } + + EC=Density.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Material-Property Density-Value (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + EC=WeightDensity.Evaluate(); + if (EC!=ParameterScalar::NO_ERROR) bOK=false; + if ((EC!=ParameterScalar::NO_ERROR) && (ErrStr!=NULL)) + { + std::stringstream stream; + stream << std::endl << "Error in Material-Property Density weighting function (ID: " << uiID << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + + return bOK; +} + +bool CSPropMaterial::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSProperties::Write2XML(root,parameterised,sparse) == false) return false; + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + prop->SetAttribute("Isotropy",bIsotropy); + + /*************** 3D - Properties *****************/ + TiXmlElement value("Property"); + WriteVectorTerm(Epsilon,value,"Epsilon",parameterised); + WriteVectorTerm(Mue,value,"Mue",parameterised); + WriteVectorTerm(Kappa,value,"Kappa",parameterised); + WriteVectorTerm(Sigma,value,"Sigma",parameterised); + /*************** 1D - Properties *****************/ + WriteTerm(Density,value,"Density",parameterised); + prop->InsertEndChild(value); + + /********** 3D - Properties Weight **************/ + TiXmlElement Weight("Weight"); + WriteVectorTerm(WeightEpsilon,Weight,"Epsilon",parameterised); + WriteVectorTerm(WeightMue,Weight,"Mue",parameterised); + WriteVectorTerm(WeightKappa,Weight,"Kappa",parameterised); + WriteVectorTerm(WeightSigma,Weight,"Sigma",parameterised); + /********** 1D - Properties Weight **************/ + WriteTerm(WeightDensity,Weight,"Density",parameterised); + prop->InsertEndChild(Weight); + + return true; +} + +bool CSPropMaterial::ReadFromXML(TiXmlNode &root) +{ + if (CSProperties::ReadFromXML(root)==false) return false; + TiXmlElement* prop=root.ToElement(); + + if (prop==NULL) return false; + + int attr=1; + prop->QueryIntAttribute("Isotropy",&attr); + bIsotropy = attr>0; + + /*************** 3D - Properties *****************/ + TiXmlElement* matProp=prop->FirstChildElement("Property"); + if (matProp!=NULL) + { + ReadVectorTerm(Epsilon,*matProp,"Epsilon",1.0); + ReadVectorTerm(Mue,*matProp,"Mue",1.0); + ReadVectorTerm(Kappa,*matProp,"Kappa"); + ReadVectorTerm(Sigma,*matProp,"Sigma"); + ReadTerm(Density,*matProp,"Density",0.0); + } + + /********** 3D - Properties Weight **************/ + TiXmlElement *weight = prop->FirstChildElement("Weight"); + if (weight!=NULL) + { + ReadVectorTerm(WeightEpsilon,*weight,"Epsilon",1.0); + ReadVectorTerm(WeightMue,*weight,"Mue",1.0); + ReadVectorTerm(WeightKappa,*weight,"Kappa",1.0); + ReadVectorTerm(WeightSigma,*weight,"Sigma",1.0); + ReadTerm(WeightDensity,*weight,"Density",1.0); + } + + return true; +} + +void CSPropMaterial::ShowPropertyStatus(std::ostream& stream) +{ + CSProperties::ShowPropertyStatus(stream); + stream << " --- " << GetTypeString() << " --- " << std::endl; + stream << " Isotropy\t: " << bIsotropy << std::endl; + stream << " Epsilon_R\t: " << Epsilon[0].GetValueString() << ", " << Epsilon[1].GetValueString() << ", " << Epsilon[2].GetValueString() << std::endl; + stream << " Kappa\t\t: " << Kappa[0].GetValueString() << ", " << Kappa[1].GetValueString() << ", " << Kappa[2].GetValueString() << std::endl; + stream << " Mue_R\t\t: " << Mue[0].GetValueString() << ", " << Mue[1].GetValueString() << ", " << Mue[2].GetValueString() << std::endl; + stream << " Sigma\t\t: " << Sigma[0].GetValueString() << ", " << Sigma[1].GetValueString() << ", " << Sigma[2].GetValueString() << std::endl; + stream << " Density\t: " << Density.GetValueString() << std::endl; + +} diff --git a/CSXCAD/src/CSPropMaterial.h b/CSXCAD/src/CSPropMaterial.h new file mode 100644 index 0000000..0201f3c --- /dev/null +++ b/CSXCAD/src/CSPropMaterial.h @@ -0,0 +1,111 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSProperties.h" + + +//! Continuous Structure Material Property +/*! + This Property can hold information about the properties of materials, such as epsilon, mue, kappa or sigma (aka. magnetic losses in FDTD). + The material can be location dependent and unisotropic. + */ +class CSXCAD_EXPORT CSPropMaterial : public CSProperties +{ +public: + CSPropMaterial(ParameterSet* paraSet); + CSPropMaterial(CSProperties* prop); + CSPropMaterial(unsigned int ID, ParameterSet* paraSet); + virtual ~CSPropMaterial(); + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("Material");} + + void SetEpsilon(double val, int ny=0) {SetValue(val,Epsilon,ny);} + int SetEpsilon(const std::string val, int ny=0) {return SetValue(val,Epsilon,ny);} + double GetEpsilon(int ny=0) {return GetValue(Epsilon,ny);} + const std::string GetEpsilonTerm(int ny=0) {return GetTerm(Epsilon,ny);} + + int SetEpsilonWeightFunction(const std::string fct, int ny) {return SetValue(fct,WeightEpsilon,ny);} + const std::string GetEpsilonWeightFunction(int ny) {return GetTerm(WeightEpsilon,ny);} + virtual double GetEpsilonWeighted(int ny, const double* coords) {return GetWeight(WeightEpsilon,ny,coords)*GetEpsilon(ny);} + + void SetMue(double val, int ny=0) {SetValue(val,Mue,ny);} + int SetMue(const std::string val, int ny=0) {return SetValue(val,Mue,ny);} + double GetMue(int ny=0) {return GetValue(Mue,ny);} + const std::string GetMueTerm(int ny=0) {return GetTerm(Mue,ny);} + + int SetMueWeightFunction(const std::string fct, int ny) {return SetValue(fct,WeightMue,ny);} + const std::string GetMueWeightFunction(int ny) {return GetTerm(WeightMue,ny);} + virtual double GetMueWeighted(int ny, const double* coords) {return GetWeight(WeightMue,ny,coords)*GetMue(ny);} + + void SetKappa(double val, int ny=0) {SetValue(val,Kappa,ny);} + int SetKappa(const std::string val, int ny=0) {return SetValue(val,Kappa,ny);} + double GetKappa(int ny=0) {return GetValue(Kappa,ny);} + const std::string GetKappaTerm(int ny=0) {return GetTerm(Kappa,ny);} + + int SetKappaWeightFunction(const std::string fct, int ny) {return SetValue(fct,WeightKappa,ny);} + const std::string GetKappaWeightFunction(int ny) {return GetTerm(WeightKappa,ny);} + virtual double GetKappaWeighted(int ny, const double* coords) {return GetWeight(WeightKappa,ny,coords)*GetKappa(ny);} + + void SetSigma(double val, int ny=0) {SetValue(val,Sigma,ny);} + int SetSigma(const std::string val, int ny=0) {return SetValue(val,Sigma,ny);} + double GetSigma(int ny=0) {return GetValue(Sigma,ny);} + const std::string GetSigmaTerm(int ny=0) {return GetTerm(Sigma,ny);} + + int SetSigmaWeightFunction(const std::string fct, int ny) {return SetValue(fct,WeightSigma,ny);} + const std::string GetSigmaWeightFunction(int ny) {return GetTerm(WeightSigma,ny);} + virtual double GetSigmaWeighted(int ny, const double* coords) {return GetWeight(WeightSigma,ny,coords)*GetSigma(ny);} + + void SetDensity(double val) {Density.SetValue(val);} + int SetDensity(const std::string val) {return Density.SetValue(val);} + double GetDensity() {return Density.GetValue();} + const std::string GetDensityTerm() {return Density.GetString();} + + int SetDensityWeightFunction(const std::string fct) {return WeightDensity.SetValue(fct);} + const std::string GetDensityWeightFunction() {return WeightDensity.GetString();} + virtual double GetDensityWeighted(const double* coords) {return GetWeight(WeightDensity,coords)*GetDensity();} + + void SetIsotropy(bool val) {bIsotropy=val;} + bool GetIsotropy() {return bIsotropy;} + + virtual void Init(); + virtual bool Update(std::string *ErrStr=NULL); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + + virtual void ShowPropertyStatus(std::ostream& stream); + +protected: + double GetValue(ParameterScalar *ps, int ny); + std::string GetTerm(ParameterScalar *ps, int ny); + void SetValue(double val, ParameterScalar *ps, int ny); + int SetValue(std::string val, ParameterScalar *ps, int ny); + + //electro-magnetic properties + ParameterScalar Epsilon[3],Mue[3],Kappa[3],Sigma[3]; + ParameterScalar WeightEpsilon[3],WeightMue[3],WeightKappa[3],WeightSigma[3]; + + //other physical properties + ParameterScalar Density, WeightDensity; + + double GetWeight(ParameterScalar &ps, const double* coords); + double GetWeight(ParameterScalar *ps, int ny, const double* coords); + bool bIsotropy; +}; diff --git a/CSXCAD/src/CSPropMetal.cpp b/CSXCAD/src/CSPropMetal.cpp new file mode 100644 index 0000000..8acb728 --- /dev/null +++ b/CSXCAD/src/CSPropMetal.cpp @@ -0,0 +1,39 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropMetal.h" + +CSPropMetal::CSPropMetal(ParameterSet* paraSet) : CSProperties(paraSet) {Type=METAL;bMaterial=true;} +CSPropMetal::CSPropMetal(CSProperties* prop) : CSProperties(prop) {Type=METAL;bMaterial=true;} +CSPropMetal::CSPropMetal(unsigned int ID, ParameterSet* paraSet) : CSProperties(ID,paraSet) {Type=METAL;bMaterial=true;} +CSPropMetal::~CSPropMetal() {} + +bool CSPropMetal::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSProperties::Write2XML(root,parameterised,sparse) == false) return false; + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + return true; +} + +bool CSPropMetal::ReadFromXML(TiXmlNode &root) +{ + return CSProperties::ReadFromXML(root); +} diff --git a/CSXCAD/src/CSPropMetal.h b/CSXCAD/src/CSPropMetal.h new file mode 100644 index 0000000..a5b1ace --- /dev/null +++ b/CSXCAD/src/CSPropMetal.h @@ -0,0 +1,39 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSProperties.h" + +//! Continuous Structure Metal Property +/*! + This Property defines a metal property (aka. PEC). + */ +class CSXCAD_EXPORT CSPropMetal : public CSProperties +{ +public: + CSPropMetal(ParameterSet* paraSet); + CSPropMetal(CSProperties* prop); + CSPropMetal(unsigned int ID, ParameterSet* paraSet); + virtual ~CSPropMetal(); + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("Metal");} + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); +}; diff --git a/CSXCAD/src/CSPropProbeBox.cpp b/CSXCAD/src/CSPropProbeBox.cpp new file mode 100644 index 0000000..b7c87da --- /dev/null +++ b/CSXCAD/src/CSPropProbeBox.cpp @@ -0,0 +1,102 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropProbeBox.h" + +CSPropProbeBox::CSPropProbeBox(ParameterSet* paraSet) : CSProperties(paraSet) {Type=PROBEBOX;uiNumber=0;m_NormDir=-1;ProbeType=0;m_weight=1;bVisisble=false;startTime=0;stopTime=0;} +CSPropProbeBox::CSPropProbeBox(CSProperties* prop) : CSProperties(prop) {Type=PROBEBOX;uiNumber=0;m_NormDir=-1;ProbeType=0;m_weight=1;bVisisble=false;startTime=0;stopTime=0;} +CSPropProbeBox::CSPropProbeBox(unsigned int ID, ParameterSet* paraSet) : CSProperties(ID,paraSet) {Type=PROBEBOX;uiNumber=0;m_NormDir=-1;ProbeType=0;m_weight=1;bVisisble=false;startTime=0;stopTime=0;} +CSPropProbeBox::~CSPropProbeBox() {} + +void CSPropProbeBox::SetNumber(unsigned int val) {uiNumber=val;} +unsigned int CSPropProbeBox::GetNumber() {return uiNumber;} + +void CSPropProbeBox::AddFDSample(std::vector *freqs) +{ + for (size_t n=0;nsize();++n) + AddFDSample(freqs->at(n)); +} + +void CSPropProbeBox::AddFDSample(std::string freqs) +{ + std::vector v_freqs = SplitString2Double(freqs, ','); + AddFDSample(&v_freqs); +} + +bool CSPropProbeBox::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSProperties::Write2XML(root,parameterised,sparse) == false) return false; + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + prop->SetAttribute("Number",(int)uiNumber); + if ((m_NormDir>0) && (m_NormDir<3)) + prop->SetAttribute("NormDir",(int)uiNumber); + prop->SetAttribute("Type",ProbeType); + prop->SetAttribute("Weight",m_weight); + prop->SetAttribute("StartTime",startTime); + prop->SetAttribute("StopTime" ,stopTime ); + + if (m_FD_Samples.size()) + { + std::string fdSamples = CombineVector2String(m_FD_Samples,','); + + TiXmlElement FDS_Elem("FD_Samples"); + TiXmlText FDS_Text(fdSamples.c_str()); + FDS_Elem.InsertEndChild(FDS_Text); + prop->InsertEndChild(FDS_Elem); + } + + return true; +} + +bool CSPropProbeBox::ReadFromXML(TiXmlNode &root) +{ + if (CSProperties::ReadFromXML(root)==false) return false; + + TiXmlElement *prop = root.ToElement(); + if (prop==NULL) return false; + + int iHelp; + if (prop->QueryIntAttribute("Number",&iHelp)!=TIXML_SUCCESS) uiNumber=0; + else uiNumber=(unsigned int)iHelp; + + if (prop->QueryIntAttribute("NormDir",&m_NormDir)!=TIXML_SUCCESS) m_NormDir=-1; + + if (prop->QueryIntAttribute("Type",&ProbeType)!=TIXML_SUCCESS) ProbeType=0; + + if (prop->QueryDoubleAttribute("Weight",&m_weight)!=TIXML_SUCCESS) m_weight=1; + + if (prop->QueryDoubleAttribute("StartTime",&startTime)!=TIXML_SUCCESS) startTime=0; + if (prop->QueryDoubleAttribute("StopTime" ,&stopTime )!=TIXML_SUCCESS) stopTime =0; + + TiXmlElement* FDSamples = prop->FirstChildElement("FD_Samples"); + if (FDSamples!=NULL) + { + TiXmlNode* node = FDSamples->FirstChild(); + if (node) + { + TiXmlText* text = node->ToText(); + if (text) + this->AddFDSample(text->Value()); + } + } + + return true; +} diff --git a/CSXCAD/src/CSPropProbeBox.h b/CSXCAD/src/CSPropProbeBox.h new file mode 100644 index 0000000..a8997d7 --- /dev/null +++ b/CSXCAD/src/CSPropProbeBox.h @@ -0,0 +1,86 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSProperties.h" + + +//! Continuous Structure Probe Property for calculating integral properties +/*! + CSProbProbeBox is a class for calculating integral properties such as (static) charges, voltages or currents. +*/ +class CSXCAD_EXPORT CSPropProbeBox : public CSProperties +{ +public: + CSPropProbeBox(ParameterSet* paraSet); + CSPropProbeBox(CSProperties* prop); + CSPropProbeBox(unsigned int ID, ParameterSet* paraSet); + virtual ~CSPropProbeBox(); + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("ProbeBox");} + + //! Define a number for this probe property \sa GetNumber + void SetNumber(unsigned int val); + //! Get the number designated to this probe property \sa SetNumber + unsigned int GetNumber(); + + //! Get the normal direction of this probe box (required by some types of probes) + int GetNormalDir() const {return m_NormDir;} + //! Set the normal direction of this probe box (required by some types of probes) + void SetNormalDir(unsigned int ndir) {m_NormDir=ndir;} + + //! Define/Set the probe weighting \sa GetWeighting + void SetWeighting(double weight) {m_weight=weight;} + //! Get the probe weighting \sa GetWeighting + double GetWeighting() {return m_weight;} + + //! Define the probe type (e.g. type=0 for a charge integration, can/must be defined by the user interface) \sa GetProbeType + void SetProbeType(int type) {ProbeType=type;} + //! Get the probe type \sa SetProbeType + int GetProbeType() {return ProbeType;} + + //! Set the probe start time + void SetStartTime(float value) {startTime=value;} + //! Get the probe start time + double GetStartTime() {return startTime;} + + //! Set the probe stop time + void SetStopTime(float value) {stopTime=value;} + //! Get the probe stop time + double GetStopTime() {return stopTime;} + + size_t CountFDSamples() {return m_FD_Samples.size();} + std::vector *GetFDSamples() {return &m_FD_Samples;} + void ClearFDSamples() {m_FD_Samples.clear();} + void AddFDSample(double freq) {m_FD_Samples.push_back(freq);} + void AddFDSample(std::vector *freqs); + void AddFDSample(std::string freqs); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + +protected: + unsigned int uiNumber; + int m_NormDir; + double m_weight; + int ProbeType; + std::vector m_FD_Samples; + double startTime, stopTime; +}; + diff --git a/CSXCAD/src/CSPropResBox.cpp b/CSXCAD/src/CSPropResBox.cpp new file mode 100644 index 0000000..201aec8 --- /dev/null +++ b/CSXCAD/src/CSPropResBox.cpp @@ -0,0 +1,53 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropResBox.h" + +CSPropResBox::CSPropResBox(ParameterSet* paraSet) : CSProperties(paraSet) {Type=RESBOX;uiFactor=1;bVisisble=false;} +CSPropResBox::CSPropResBox(CSProperties* prop) : CSProperties(prop) {Type=RESBOX;uiFactor=1;bVisisble=false;} +CSPropResBox::CSPropResBox(unsigned int ID, ParameterSet* paraSet) : CSProperties(ID,paraSet) {Type=RESBOX;uiFactor=1;bVisisble=false;} +CSPropResBox::~CSPropResBox() {}; + +void CSPropResBox::SetResFactor(unsigned int val) {uiFactor=val;} +unsigned int CSPropResBox::GetResFactor() {return uiFactor;} + +bool CSPropResBox::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSProperties::Write2XML(root,parameterised,sparse) == false) return false; + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + prop->SetAttribute("Factor",(int)uiFactor); + + return true; +} + +bool CSPropResBox::ReadFromXML(TiXmlNode &root) +{ + if (CSProperties::ReadFromXML(root)==false) return false; + + TiXmlElement *prop = root.ToElement(); + if (prop==NULL) return false; + + int iHelp; + if (prop->QueryIntAttribute("Factor",&iHelp)!=TIXML_SUCCESS) uiFactor=1; + else uiFactor=(unsigned int)iHelp; + + return true; +} diff --git a/CSXCAD/src/CSPropResBox.h b/CSXCAD/src/CSPropResBox.h new file mode 100644 index 0000000..e98d8ef --- /dev/null +++ b/CSXCAD/src/CSPropResBox.h @@ -0,0 +1,45 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSProperties.h" + +//! Continuous Structure Resolution Property +/*! + This Property defines a refined mesh area. + */ +class CSXCAD_EXPORT CSPropResBox : public CSProperties +{ +public: + CSPropResBox(ParameterSet* paraSet); + CSPropResBox(CSProperties* prop); + CSPropResBox(unsigned int ID, ParameterSet* paraSet); + virtual ~CSPropResBox(); + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("ResBox");} + + void SetResFactor(unsigned int val); + unsigned int GetResFactor(); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + +protected: + unsigned int uiFactor; +}; diff --git a/CSXCAD/src/CSPropUnknown.cpp b/CSXCAD/src/CSPropUnknown.cpp new file mode 100644 index 0000000..e5e4cfc --- /dev/null +++ b/CSXCAD/src/CSPropUnknown.cpp @@ -0,0 +1,52 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#include "tinyxml.h" + +#include "CSPropUnknown.h" + +CSPropUnknown::CSPropUnknown(ParameterSet* paraSet) : CSProperties(paraSet) {Type=UNKNOWN;bVisisble=false;} +CSPropUnknown::CSPropUnknown(unsigned int ID, ParameterSet* paraSet) : CSProperties(ID,paraSet) {Type=UNKNOWN;bVisisble=false;} +CSPropUnknown::CSPropUnknown(CSProperties* prop) : CSProperties(prop) {Type=UNKNOWN;bVisisble=false;} +CSPropUnknown::~CSPropUnknown() {} + +void CSPropUnknown::SetProperty(const std::string val) {sUnknownProperty=std::string(val);} +const std::string CSPropUnknown::GetProperty() {return sUnknownProperty;} + + +bool CSPropUnknown::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + if (CSProperties::Write2XML(root,parameterised,sparse) == false) return false; + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + prop->SetAttribute("Property",sUnknownProperty.c_str()); + + return true; +} + +bool CSPropUnknown::ReadFromXML(TiXmlNode &root) +{ + if (CSProperties::ReadFromXML(root)==false) return false; + TiXmlElement* prob=root.ToElement(); + + const char* chProp=prob->Attribute("Property"); + if (chProp==NULL) + sUnknownProperty=std::string("unknown"); + else sUnknownProperty=std::string(chProp); + return true; +} diff --git a/CSXCAD/src/CSPropUnknown.h b/CSXCAD/src/CSPropUnknown.h new file mode 100644 index 0000000..2bc6d08 --- /dev/null +++ b/CSXCAD/src/CSPropUnknown.h @@ -0,0 +1,45 @@ +/* +* Copyright (C) 2008-2012 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 . +*/ + +#pragma once + +#include "CSProperties.h" + +//! Continuous Structure Unknown Property +/*! + This is a property that is getting designated for new properties which are unknown so far (e.g. written by a newer version of CSXCAD) +*/ +class CSXCAD_EXPORT CSPropUnknown : public CSProperties +{ +public: + CSPropUnknown(ParameterSet* paraSet); + CSPropUnknown(unsigned int ID, ParameterSet* paraSet); + CSPropUnknown(CSProperties* prop); + virtual ~CSPropUnknown(); + + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("Unknown");} + + void SetProperty(const std::string val); + const std::string GetProperty(); + + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + virtual bool ReadFromXML(TiXmlNode &root); + +protected: + std::string sUnknownProperty; +}; diff --git a/CSXCAD/src/CSProperties.cpp b/CSXCAD/src/CSProperties.cpp new file mode 100644 index 0000000..605b0be --- /dev/null +++ b/CSXCAD/src/CSProperties.cpp @@ -0,0 +1,399 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include "CSProperties.h" +#include "CSPropUnknown.h" +#include "CSPropMaterial.h" +#include "CSPropDispersiveMaterial.h" +#include "CSPropLorentzMaterial.h" +#include "CSPropDebyeMaterial.h" +#include "CSPropDiscMaterial.h" +#include "CSPropLumpedElement.h" +#include "CSPropMetal.h" +#include "CSPropConductingSheet.h" +#include "CSPropExcitation.h" +#include "CSPropProbeBox.h" +#include "CSPropDumpBox.h" +#include "CSPropResBox.h" + +#include "CSPrimitives.h" +#include +#include +#include "tinyxml.h" + +/*********************CSProperties********************************************************************/ +CSProperties::CSProperties(CSProperties* prop) +{ + uiID=prop->uiID; + bMaterial=prop->bMaterial; + coordInputType=prop->coordInputType; + clParaSet=prop->clParaSet; + FillColor=prop->FillColor; + EdgeColor=prop->EdgeColor; + bVisisble=prop->bVisisble; + sName=std::string(prop->sName); + for (size_t i=0;ivPrimitives.size();++i) + { + vPrimitives.push_back(prop->vPrimitives.at(i)); + } + InitCoordParameter(); +} + +CSProperties::CSProperties(ParameterSet* paraSet) +{ + uiID=0; + bMaterial=false; + coordInputType=CARTESIAN; + clParaSet=paraSet; + FillColor.R=(rand()%256); + FillColor.G=(rand()%256); + FillColor.B=(rand()%256); + EdgeColor.R=FillColor.R; + EdgeColor.G=FillColor.G; + EdgeColor.B=FillColor.B; + FillColor.a=EdgeColor.a=255; + bVisisble=true; + Type=ANY; + InitCoordParameter(); +} + +CSProperties::CSProperties(unsigned int ID, ParameterSet* paraSet) +{ + uiID=ID; + bMaterial=false; + coordInputType=CARTESIAN; + clParaSet=paraSet; + FillColor.R=(rand()%256); + FillColor.G=(rand()%256); + FillColor.B=(rand()%256); + EdgeColor.R=FillColor.R; + EdgeColor.G=FillColor.G; + EdgeColor.B=FillColor.B; + FillColor.a=EdgeColor.a=255; + bVisisble=true; + Type=ANY; + InitCoordParameter(); +} + + +CSProperties::~CSProperties() +{ + while (vPrimitives.size()>0) + DeletePrimitive(vPrimitives.back()); + delete coordParaSet; + coordParaSet=NULL; +} + +void CSProperties::SetCoordInputType(CoordinateSystem type, bool CopyToPrimitives) +{ + coordInputType = type; + if (CopyToPrimitives==false) + return; + for (size_t i=0;iSetCoordInputType(type); +} + +void CSProperties::InitCoordParameter() +{ + coordParaSet = new ParameterSet(); + + coordPara[0]=new Parameter("x",0); + coordPara[1]=new Parameter("y",0); + coordPara[2]=new Parameter("z",0); + coordPara[3]=new Parameter("rho",0); + coordPara[4]=new Parameter("r",0); + coordPara[5]=new Parameter("a",0); + coordPara[6]=new Parameter("t",0); + + for (int i=0;i<7;++i) + coordParaSet->LinkParameter(coordPara[i]); //the Paraset will take care of deletion... +} + +int CSProperties::GetType() {return Type;} + +unsigned int CSProperties::GetID() {return uiID;} +void CSProperties::SetID(unsigned int ID) {uiID=ID;} + +unsigned int CSProperties::GetUniqueID() {return UniqueID;} +void CSProperties::SetUniqueID(unsigned int uID) {UniqueID=uID;} + +void CSProperties::SetName(const std::string name) {sName=std::string(name);} +const std::string CSProperties::GetName() {return sName;} + +bool CSProperties::ExistAttribute(std::string name) +{ + for (size_t n=0;n(this); } +CSPropMaterial* CSProperties::ToMaterial() { return dynamic_cast(this); } +CSPropLorentzMaterial* CSProperties::ToLorentzMaterial() { return dynamic_cast(this); } +CSPropDebyeMaterial* CSProperties::ToDebyeMaterial() { return dynamic_cast(this); } +CSPropDiscMaterial* CSProperties::ToDiscMaterial() { return dynamic_cast(this); } +CSPropMetal* CSProperties::ToMetal() { return dynamic_cast(this); } +CSPropConductingSheet* CSProperties::ToConductingSheet() { return dynamic_cast(this); } +CSPropExcitation* CSProperties::ToExcitation() { return dynamic_cast(this); } +CSPropProbeBox* CSProperties::ToProbeBox() { return dynamic_cast(this); } +CSPropResBox* CSProperties::ToResBox() { return dynamic_cast(this); } +CSPropDumpBox* CSProperties::ToDumpBox() { return dynamic_cast(this); } + +bool CSProperties::Update(std::string */*ErrStr*/) {return true;} + +bool CSProperties::Write2XML(TiXmlNode& root, bool parameterised, bool sparse) +{ + TiXmlElement* prop=root.ToElement(); + if (prop==NULL) return false; + + prop->SetAttribute("ID",uiID); + prop->SetAttribute("Name",sName.c_str()); + + if (!sparse) + { + TiXmlElement FC("FillColor"); + FC.SetAttribute("R",FillColor.R); + FC.SetAttribute("G",FillColor.G); + FC.SetAttribute("B",FillColor.B); + FC.SetAttribute("a",FillColor.a); + prop->InsertEndChild(FC); + TiXmlElement EC("EdgeColor"); + EC.SetAttribute("R",EdgeColor.R); + EC.SetAttribute("G",EdgeColor.G); + EC.SetAttribute("B",EdgeColor.B); + EC.SetAttribute("a",EdgeColor.a); + prop->InsertEndChild(EC); + } + + if (m_Attribute_Name.size()) + { + TiXmlElement Attributes("Attributes"); + for (size_t n=0;nInsertEndChild(Attributes); + } + + TiXmlElement Primitives("Primitives"); + for (size_t i=0;iGetTypeName().c_str()); + vPrimitives.at(i)->Write2XML(PrimElem,parameterised); + Primitives.InsertEndChild(PrimElem); + } + prop->InsertEndChild(Primitives); + + return true; +} + +void CSProperties::AddPrimitive(CSPrimitives *prim) +{ + if (HasPrimitive(prim)==true) + { + std::cerr << __func__ << ": Error, primitive is already owned by this property!" << std::endl; + return; + } + vPrimitives.push_back(prim); + prim->SetProperty(this); +} + +bool CSProperties::HasPrimitive(CSPrimitives *prim) +{ + if (prim==NULL) + return false; + for (size_t i=0; i::iterator iter=vPrimitives.begin()+i; + vPrimitives.erase(iter); + prim->SetProperty(NULL); + return; + } + } +} + +void CSProperties::DeletePrimitive(CSPrimitives *prim) +{ + if (!HasPrimitive(prim)) + { + std::cerr << __func__ << ": Error, primitive not found, can't delete it! Skipping." << std::endl; + return; + } + RemovePrimitive(prim); + delete prim; +} + +CSPrimitives* CSProperties::TakePrimitive(size_t index) +{ + if (index>=vPrimitives.size()) return NULL; + CSPrimitives* prim=vPrimitives.at(index); + std::vector::iterator iter=vPrimitives.begin()+index; + vPrimitives.erase(iter); + return prim; +} + +CSPrimitives* CSProperties::CheckCoordInPrimitive(const double *coord, int &priority, bool markFoundAsUsed, double tol) +{ + priority=0; + CSPrimitives* found_CSPrim = NULL; + bool found=false; + for (size_t i=0; iIsInside(coord,tol)==true) + { + if (found==false) + { + priority=vPrimitives.at(i)->GetPriority()-1; + found_CSPrim = vPrimitives.at(i); + } + found=true; + if (vPrimitives.at(i)->GetPriority()>priority) + { + priority=vPrimitives.at(i)->GetPriority(); + found_CSPrim = vPrimitives.at(i); + } + } + } + if ((markFoundAsUsed) && (found_CSPrim)) + found_CSPrim->SetPrimitiveUsed(true); + return found_CSPrim; +} + +void CSProperties::WarnUnusedPrimitves(std::ostream& stream) +{ + if (vPrimitives.size()==0) + { + stream << "Warning: No primitives found in property: " << GetName() << "!" << std::endl; + return; + } + for (size_t i=0; iGetPrimitiveUsed()==false) + { + stream << "Warning: Unused primitive (type: " << vPrimitives.at(i)->GetTypeName() << ") detected in property: " << GetName() << "!" << std::endl; + } + } +} + +void CSProperties::ShowPropertyStatus(std::ostream& stream) +{ + stream << " Property #" << GetID() << " Type: \"" << GetTypeString() << "\" Name: \"" << GetName() << "\"" << std::endl; + stream << " Primitive Count \t: " << vPrimitives.size() << std::endl; + stream << " Coordinate System \t: " << coordInputType << std::endl; + + stream << " -- Primitives: --" << std::endl; + for (size_t i=0; iShowPrimitiveStatus(stream); + if (iQueryIntAttribute("ID",&help)==TIXML_SUCCESS) + uiID=help; + + const char* cHelp=prop->Attribute("Name"); + if (cHelp!=NULL) sName=std::string(cHelp); + else sName.clear(); + + TiXmlElement* FC = root.FirstChildElement("FillColor"); + if (FC!=NULL) + { + if (FC->QueryIntAttribute("R",&help)==TIXML_SUCCESS) + FillColor.R=(unsigned char) help; + if (FC->QueryIntAttribute("G",&help)==TIXML_SUCCESS) + FillColor.G=(unsigned char) help; + if (FC->QueryIntAttribute("B",&help)==TIXML_SUCCESS) + FillColor.B=(unsigned char) help; + if (FC->QueryIntAttribute("a",&help)==TIXML_SUCCESS) + FillColor.a=(unsigned char) help; + } + + TiXmlElement* EC = root.FirstChildElement("EdgeColor"); + if (EC!=NULL) + { + if (EC->QueryIntAttribute("R",&help)==TIXML_SUCCESS) + EdgeColor.R=(unsigned char) help; + if (EC->QueryIntAttribute("G",&help)==TIXML_SUCCESS) + EdgeColor.G=(unsigned char) help; + if (EC->QueryIntAttribute("B",&help)==TIXML_SUCCESS) + EdgeColor.B=(unsigned char) help; + if (EC->QueryIntAttribute("a",&help)==TIXML_SUCCESS) + EdgeColor.a=(unsigned char) help; + } + + TiXmlElement* att_root = root.FirstChildElement("Attributes"); + if (att_root) + { + TiXmlAttribute* att = att_root->FirstAttribute(); + while (att) + { + AddAttribute(att->Name(),att->Value()); + att = att->Next(); + } + } + + return true; +} diff --git a/CSXCAD/src/CSProperties.h b/CSXCAD/src/CSProperties.h new file mode 100644 index 0000000..d8757ee --- /dev/null +++ b/CSXCAD/src/CSProperties.h @@ -0,0 +1,222 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#pragma once +/* + * Author: Thorsten Liebig + * Date: 03-12-2008 + * Lib: CSXCAD + * Version: 0.1a + */ + +#include +#include +#include +#include +#include "ParameterObjects.h" +#include "CSTransform.h" +#include "CSXCAD_Global.h" +#include "CSUseful.h" + +#include +#include +#include +#include +#include + +class CSPrimitives; + +class CSPropUnknown; +class CSPropMaterial; + class CSPropDispersiveMaterial; + class CSPropLorentzMaterial; + class CSPropDebyeMaterial; + class CSPropDiscMaterial; +class CSPropLumpedElement; +class CSPropMetal; + class CSPropConductingSheet; +class CSPropExcitation; +class CSPropProbeBox; + class CSPropDumpBox; +class CSPropResBox; + +class TiXmlNode; + +typedef struct +{ + unsigned char R,G,B,a; +} RGBa; + +//! Continuous Structure (CS)Properties (layer) +/*! + CSProperties is a class that contains geometrical primitive structures as boxes, spheres, cylinders etc. (CSPrimitives) + All values in this class can contain parameters and mathematical equations. + This absract base-class contains basic property methodes, e.g. set/get primitives, mesh-relations, color-information etc. +*/ +class CSXCAD_EXPORT CSProperties +{ +public: + virtual ~CSProperties(); + //! Copy constructor + CSProperties(CSProperties* prop); + //! 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, */ + DISPERSIVEMATERIAL = 0x100, LORENTZMATERIAL = 0x200, DEBYEMATERIAL = 0x400, + DISCRETE_MATERIAL = 0x1000, LUMPED_ELEMENT = 0x2000, CONDUCTINGSHEET = 0x4000 + }; + + //! Get PropertyType \sa PropertyType + int GetType(); + //! Get PropertyType as a xml element name \sa PropertyType and GetType + virtual const std::string GetTypeXMLString() const {return std::string("Any");} + + //! Get Property Type as a string. (default is the xml element name) + virtual const std::string GetTypeString() const {return GetTypeXMLString();} + + //! 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 + unsigned int GetID(); + //!Set ID to this property. USE ONLY WHEN YOU KNOW WHAT YOU ARE DOING!!!! \sa GetID + void SetID(unsigned int ID); + + //!Get unique ID of this property. Used internally. \sa SetUniqueID + unsigned int GetUniqueID(); + //!Set unique ID of this property. Used internally. USE ONLY WHEN YOU KNOW WHAT YOU ARE DOING!!!! \sa GetUniqueID + void SetUniqueID(unsigned int uID); + + //! Set Name for this Property. \sa GetName + void SetName(const std::string name); + //! Get Name for this Property. \sa SetName + const std::string GetName(); + + //! Check if given attribute exists + bool ExistAttribute(std::string name); + //! Get the value of a given attribute + std::string GetAttributeValue(std::string name); + //! Add a new attribute + void AddAttribute(std::string name, std::string value); + + //! Add a primitive to this Propertie. Takes ownership of this primitive! \sa CSPrimitives, RemovePrimitive, TakePrimitive + void AddPrimitive(CSPrimitives *prim); + //! Check if primitive is owned by this Propertie. \sa CSPrimitives, AddPrimitive, RemovePrimitive, TakePrimitive + bool HasPrimitive(CSPrimitives *prim); + //! Removes a primitive of this Property. Caller must take ownership! \sa CSPrimitives, AddPrimitive, TakePrimitive + void RemovePrimitive(CSPrimitives *prim); + //! Removes and deletes a primitive of this Property. \sa CSPrimitives, RemovePrimitive, AddPrimitive, TakePrimitive + void DeletePrimitive(CSPrimitives *prim); + //! Take a primitive of this Propertie at index. Releases ownership of this primitive to caller! \sa CSPrimitives, RemovePrimitive, AddPrimitive \return NULL if not found! + CSPrimitives* TakePrimitive(size_t index); + + //! Check whether the given coord is inside of a primitive assigned to this property and return the found primitive and \a priority. + CSPrimitives* CheckCoordInPrimitive(const double *coord, int &priority, bool markFoundAsUsed=false, double tol=0); + + //! Get the quentity of primitives assigned to this property! \return Number of primitives in this property + size_t GetQtyPrimitives(); + + //! Get the Primitive at certain index position. \sa GetQtyPrimitives + CSPrimitives* GetPrimitive(size_t index); + + //! Get all Primitives \sa GetPrimitive + std::vector GetAllPrimitives() {return vPrimitives;} + + //! Set a fill-color for this property. \sa GetFillColor + void SetFillColor(RGBa color); + //! 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); + //! Get a fill-color for this property. \sa GetEdgeColor \return RGBa color object. + RGBa GetEdgeColor(); + + //! Get visibility for this property. \sa SetVisibility + bool GetVisibility(); + //! Set visibility for this property. \sa GetVisibility + void SetVisibility(bool val); + + //! Convert to Unknown Property, returns NULL if type is different! \return Returns a CSPropUnknown* or NULL if type is different! + CSPropUnknown* ToUnknown(); + //! Convert to Material Property, returns NULL if type is different! \return Returns a CSPropMaterial* or NULL if type is different! + CSPropMaterial* ToMaterial(); + //! Convert to Lorentzs-Material Property, returns NULL if type is different! \return Returns a CSPropLorentzMaterial* or NULL if type is different! + CSPropLorentzMaterial* ToLorentzMaterial(); + //! Convert to Debye-Material Property, returns NULL if type is different! \return Returns a CSPropDebyeMaterial* or NULL if type is different! + CSPropDebyeMaterial* ToDebyeMaterial(); + //! Convert to Discrete-Material Property, returns NULL if type is different! \return Returns a CSPropDiscMaterial* or NULL if type is different! + CSPropDiscMaterial* ToDiscMaterial(); + //! Convert to Metal Property, returns NULL if type is different! \return Returns a CSPropMetal* or NULL if type is different! + CSPropMetal* ToMetal(); + //! Convert to Conducting Sheet Property, returns NULL if type is different! \return Returns a CSPropConductingSheet* or NULL if type is different! + CSPropConductingSheet* ToConductingSheet(); + //! Convert to Excitation Property, returns NULL if type is different! \return Returns a CSPropExcitation* or NULL if type is different! + CSPropExcitation* ToExcitation(); + //! Convert to ProbeBox Property, returns NULL if type is different! \return Returns a CSPropProbeBox* or NULL if type is different! + CSPropProbeBox* ToProbeBox(); + //! Convert to ResBox Property, returns NULL if type is different! \return Returns a CSPropResBox* or NULL if type is different! + CSPropResBox* ToResBox(); + //! Convert to DumpBox Property, returns NULL if type is different! \return Returns a CSPropDumpBox* or NULL if type is different! + CSPropDumpBox* ToDumpBox(); + + //! Update all parameters. Nothing to do in this base class. \param ErrStr Methode writes error messages to this string! \return Update success + virtual bool Update(std::string *ErrStr=NULL); + + //! Write this property to a xml-node. \param parameterised Use false if parameters should be written as values. Parameters are lost! + virtual bool Write2XML(TiXmlNode& root, bool parameterised=true, bool sparse=false); + //! Read property from xml-node. \return Successful read-operation. + virtual bool ReadFromXML(TiXmlNode &root); + + //! Define the input type for the weighting coordinate system 0=cartesian, 1=cylindrical, 2=spherical + void SetCoordInputType(CoordinateSystem type, bool CopyToPrimitives=true); + //! Get the input type for the weighting coordinate system 0=cartesian, 1=cylindrical, 2=spherical + int GetCoordInputType() const {return coordInputType;} + + //! Check and warn for unused primitives + void WarnUnusedPrimitves(std::ostream& stream); + + //! Show status of this property, incl. all primitives + virtual void ShowPropertyStatus(std::ostream& stream); + +protected: + CSProperties(ParameterSet* paraSet); + CSProperties(unsigned int ID, ParameterSet* paraSet); + ParameterSet* clParaSet; + ParameterSet* coordParaSet; + //! x,y,z,rho,r,a,t one for all coord-systems (rho distance to z-axis (cylinder-coords), r for distance to origin) + void InitCoordParameter(); + Parameter* coordPara[7]; + CoordinateSystem coordInputType; + PropertyType Type; + bool bMaterial; + unsigned int uiID; + unsigned int UniqueID; + std::string sName; + std::string sType; + RGBa FillColor; + RGBa EdgeColor; + + bool bVisisble; + + std::vector vPrimitives; + + //! List of additional attribute names + std::vector m_Attribute_Name; + //! List of additional attribute values + std::vector m_Attribute_Value; +}; diff --git a/CSXCAD/src/CSRectGrid.cpp b/CSXCAD/src/CSRectGrid.cpp new file mode 100644 index 0000000..50f2947 --- /dev/null +++ b/CSXCAD/src/CSRectGrid.cpp @@ -0,0 +1,340 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include "CSRectGrid.h" +#include "CSUseful.h" +#include "tinyxml.h" +#include "CSFunctionParser.h" +#include +#include +#include + +CSRectGrid::CSRectGrid(void) +{ + dDeltaUnit=1; + m_meshType = CARTESIAN; +} + +CSRectGrid::~CSRectGrid(void) +{ +} + +CSRectGrid* CSRectGrid::Clone(CSRectGrid* original) +{ + CSRectGrid* clone = new CSRectGrid(); + clone->dDeltaUnit = original->dDeltaUnit; + for (int i=0;i<3;++i) + clone->Lines[i] = original->Lines[i]; + for (int i=0;i<6;++i) + clone->SimBox[i] = original->SimBox[i]; + return clone; +} + +void CSRectGrid::AddDiscLine(int direct, double val) +{ + if ((direct>=0)&&(direct<3)) Lines[direct].push_back(val); +} + +void CSRectGrid::AddDiscLines(int direct, int numLines, double* vals) +{ + for (int n=0;n=3)) return std::string("Unknown grid direction!"); + if (DistFunction.empty()==false) + { + CSFunctionParser fParse; + std::string dirVar; + switch (direct) + { + case 0: + dirVar = "x"; + break; + case 1: + dirVar = "y"; + break; + case 2: + dirVar = "z"; + break; + } + fParse.Parse(DistFunction,dirVar); + if (fParse.GetParseErrorType()!=FunctionParser::FP_NO_ERROR) + return std::string("An error occured parsing f(") + dirVar + std::string(") - Parser message:\n") + std::string(fParse.ErrorMsg()); + + double dValue=0; + bool error=false; + for (int n=0;n=3)) return false; + if ((index>=(int)Lines[direct].size()) || (index<0)) return false; + std::vector::iterator vIter=Lines[direct].begin(); + Lines[direct].erase(vIter+index); + return true; +} + +bool CSRectGrid::RemoveDiscLine(int direct, double val) +{ + if ((direct<0) || (direct>=3)) return false; + for (size_t i=0;i=3)) return; + Lines[direct].clear(); +} + +bool CSRectGrid::SetLine(int direct, size_t Index, double value) +{ + if ((direct<0) || (direct>=3)) return false; + if (Lines[direct].size()<=Index) return false; + Lines[direct].at(Index) = value; + return true; +} + +double CSRectGrid::GetLine(int direct, size_t Index) +{ + if ((direct<0) || (direct>=3)) return 0; + if (Lines[direct].size()<=Index) return 0; + return Lines[direct].at(Index); +} + +double* CSRectGrid::GetLines(int direct, double *array, unsigned int &qty, bool sorted) +{ + if ((direct<0) || (direct>=3)) return 0; + if (sorted) Sort(direct); + delete[] array; + array = new double[Lines[direct].size()]; + for (size_t i=0;i=3)) return xStr.str(); + if (Lines[direct].size()>0) + { + for (size_t i=0;i0) xStr << ", "; + xStr<2)) + return -1; + if (Lines[ny].size()==0) + return -1; + if (valueLines[ny].at(Lines[ny].size()-1)) + return Lines[ny].size()-1; + inside = true; + for (size_t n=0;n1) ++dim; + if (Lines[1].size()>1) ++dim; + if (Lines[2].size()>1) ++dim; + return dim; +} + +void CSRectGrid::IncreaseResolution(int nu, int factor) +{ + if ((nu<0) || (nu>=GetDimension())) return; + if ((factor<=1) && (factor>9)) return; + size_t size=Lines[nu].size(); + for (size_t i=0;i=3)) return; + std::vector::iterator start = Lines[direct].begin(); + std::vector::iterator end = Lines[direct].end(); + sort(start,end); + end=unique(start,end); + Lines[direct].erase(end,Lines[direct].end()); +} + +double* CSRectGrid::GetSimArea() +{ + for (int i=0;i<3;++i) + { + if (Lines[i].size()!=0) + { + SimBox[2*i]=*min_element(Lines[i].begin(),Lines[i].end()); + SimBox[2*i+1]=*max_element(Lines[i].begin(),Lines[i].end()); + } + else SimBox[2*i]=SimBox[2*i+1]=0; + } + return SimBox; +} + +bool CSRectGrid::isValid() +{ + for (int n=0;n<3;++n) + if (GetQtyLines(n)<2) + return false; + return true; +} + + +bool CSRectGrid::Write2XML(TiXmlNode &root, bool sorted) +{ + if (sorted) {Sort(0);Sort(1);Sort(2);} + TiXmlElement grid("RectilinearGrid"); + + grid.SetDoubleAttribute("DeltaUnit",dDeltaUnit); + + TiXmlElement XLines("XLines"); + XLines.SetAttribute("Qty",(int)Lines[0].size()); + if (Lines[0].size()>0) + { + TiXmlText XText(CombineVector2String(Lines[0],',')); + XLines.InsertEndChild(XText); + } + grid.InsertEndChild(XLines); + + TiXmlElement YLines("YLines"); + YLines.SetAttribute("Qty",(int)Lines[1].size()); + if (Lines[1].size()>0) + { + TiXmlText YText(CombineVector2String(Lines[1],',')); + YLines.InsertEndChild(YText); + } + grid.InsertEndChild(YLines); + + TiXmlElement ZLines("ZLines"); + ZLines.SetAttribute("Qty",(int)Lines[2].size()); + if (Lines[2].size()>0) + { + TiXmlText ZText(CombineVector2String(Lines[2],',')); + ZLines.InsertEndChild(ZText); + } + grid.InsertEndChild(ZLines); + + root.InsertEndChild(grid); + + return true; +} + +bool CSRectGrid::ReadFromXML(TiXmlNode &root) +{ + TiXmlElement* Lines=root.ToElement(); + if (Lines->QueryDoubleAttribute("DeltaUnit",&dDeltaUnit)!=TIXML_SUCCESS) dDeltaUnit=1.0; + + int help; + if (Lines->QueryIntAttribute("CoordSystem",&help)==TIXML_SUCCESS) + SetMeshType((CoordinateSystem)help); + + TiXmlNode* FN=NULL; + TiXmlText* Text=NULL; + std::string LineStr[3]; + + Lines = root.FirstChildElement("XLines"); + if (Lines==NULL) return false; + FN = Lines->FirstChild(); + if (FN!=NULL) + { + Text = FN->ToText(); + if (Text!=NULL) LineStr[0]=std::string(Text->Value()); + } + + Lines = root.FirstChildElement("YLines"); + if (Lines==NULL) return false; + FN = Lines->FirstChild(); + if (FN!=NULL) + { + Text = FN->ToText(); + if (Text!=NULL) LineStr[1]=std::string(Text->Value()); + } + + Lines = root.FirstChildElement("ZLines"); + if (Lines==NULL) return false; + FN = Lines->FirstChild(); + if (FN!=NULL) + { + Text = FN->ToText(); + if (Text!=NULL) LineStr[2]=std::string(Text->Value()); + } + + for (int i=0;i<3;++i) + { + std::vector lines = SplitString2Double(LineStr[i],','); + for (size_t n=0;n. +*/ + +#pragma once +/* + * Author: Thorsten Liebig + * Date: 03-12-2008 + * Lib: CSXCAD + * Version: 0.1a + */ + +#include +#include +#include +#include +#include +#include +#include "ParameterObjects.h" +#include "CSXCAD_Global.h" + +class TiXmlNode; + +//! CSRectGrid is managing a rectilinear graded mesh. +class CSXCAD_EXPORT CSRectGrid +{ +public: + //! Create an empty grid. + CSRectGrid(void); + //! Deconstruct the grid. + ~CSRectGrid(void); + + static CSRectGrid* Clone(CSRectGrid* original); + + //! Add a disc-line in the given direction. + void AddDiscLine(int direct, double val); + void AddDiscLines(int direct, int numLines, double* vals); + std::string AddDiscLines(int direct, int numLines, double* vals, std::string DistFunction); + + //! Remove the disc-line at certain index and direction. + bool RemoveDiscLine(int direct, int index); + //! Remove the disc-line at certain value and direction. + bool RemoveDiscLine(int direct, double val); + + //! Remove all lines and reset to an empty grid. + void clear(); + //! Clear all lines in a given direction. + void ClearLines(int direct); + + //! Set the drawing unit. e.g. 1e-3 for mm as drawing unit. + void SetDeltaUnit(double val) {dDeltaUnit=val;} + //! Get the current drawing unit. + double GetDeltaUnit() {return dDeltaUnit;} + + //! Set a disc-line in a certain direction at a given index. Will return true on success. + bool SetLine(int direct, size_t Index, double value); + + //! Get an array of discretization lines in a certain direction. + /*! + \param direct The direction of interest. + \param array The array in which the lines will be stored. Can be NULL. Caller has to delete the array. + \param qty Methode will return the number of lines in this direction. + \param sorted Define here whether the lines shall be in increasing order (default) or as currently stored (unknown order). + */ + double* GetLines(int direct, double *array, unsigned int &qty, bool sorted=true); + //! Get quantity of lines in certain direction. + size_t GetQtyLines(int direct) {if ((direct>=0) && (direct<3)) return Lines[direct].size(); else return 0;} + //! Get a disc-line in a certain direction an at given index. + double GetLine(int direct, size_t Index); + //! Get disc-lines as a comma-seperated string for given direction + std::string GetLinesAsString(int direct); + + //! Snap a given value to a grid line for the given direction + unsigned int Snap2LineNumber(int ny, double value, bool &inside) const; + + //! Write the grid to a given XML-node. + bool Write2XML(TiXmlNode &root, bool sorted=false); + //! Read the grid from a given XML-node. + bool ReadFromXML(TiXmlNode &root); + + //! Get the dimension of current grid. \return 0,1,2 or 3. Returns -1 if one or more directions have no disc-line at all. + int GetDimension(); + + //! Set the type of mesh (e.g. Cartesian or Cylindrical mesh) + void SetMeshType(CoordinateSystem type) {m_meshType=type;} + + //! Get the type of mesh (e.g. Cartesian or Cylindrical mesh) + CoordinateSystem GetMeshType() {return m_meshType;} + + //! Increase the resolution in the specified direction by the given factor. + void IncreaseResolution(int nu, int factor); + + //! Sort the lines in a given direction. + void Sort(int direct); + + //! Get the bounding box of the area defined by the disc-lines. + double* GetSimArea(); + + //! This will check if the given mesh is a valid 3D mesh (at least 2 lines in all directions); + bool isValid(); + +protected: + std::vector Lines[3]; + double dDeltaUnit; + double SimBox[6]; + CoordinateSystem m_meshType; +}; diff --git a/CSXCAD/src/CSTransform.cpp b/CSXCAD/src/CSTransform.cpp new file mode 100644 index 0000000..d71cb4e --- /dev/null +++ b/CSXCAD/src/CSTransform.cpp @@ -0,0 +1,762 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "CSTransform.h" + +#include "CSUseful.h" +#include "tinyxml.h" + +#include +#include + +#include "vtkMatrix4x4.h" + +#define PI 3.141592653589793238462643383279 + +CSTransform::CSTransform() +{ + Reset(); + SetParameterSet(NULL); +} + +CSTransform::CSTransform(CSTransform* transform) +{ + if (transform==NULL) + { + Reset(); + SetParameterSet(NULL); + return; + } + m_PostMultiply = transform->m_PostMultiply; + m_AngleRadian = transform->m_AngleRadian; + m_TransformList = transform->m_TransformList; + m_TransformArguments = transform->m_TransformArguments; + SetParameterSet(transform->m_ParaSet); + for (int n=0;n<16;++n) + { + m_TMatrix[n] = transform->m_TMatrix[n]; + m_Inv_TMatrix[n] = transform->m_Inv_TMatrix[n]; + } +} + +CSTransform::CSTransform(ParameterSet* paraSet) +{ + Reset(); + SetParameterSet(paraSet); +} + +CSTransform::~CSTransform() +{ +} + +void CSTransform::Reset() +{ + m_PostMultiply = true; + m_AngleRadian=true; + m_TransformList.clear(); + m_TransformArguments.clear(); + MakeUnitMatrix(m_TMatrix); + MakeUnitMatrix(m_Inv_TMatrix); +} + +bool CSTransform::HasTransform() +{ + return (m_TransformList.size()>0); +} + +void CSTransform::Invert() +{ + //make sure the inverse matrix is up to date... + UpdateInverse(); + //switch matrices + double help; + for (int n=0;n<16;++n) + { + help = m_TMatrix[n]; + m_TMatrix[n] = m_Inv_TMatrix[n]; + m_Inv_TMatrix[n]=help; + } +} + +void CSTransform::UpdateInverse() +{ + // use vtk to do the matrix inversion + vtkMatrix4x4::Invert(m_TMatrix, m_Inv_TMatrix); +} + +double* CSTransform::Transform(const double inCoords[3], double outCoords[3]) const +{ + double coords[4] = {inCoords[0],inCoords[1],inCoords[2],1}; + for (int m=0;m<3;++m) + { + outCoords[m] = 0; + for (int n=0;n<4;++n) + { + outCoords[m] += m_TMatrix[4*m+n]*coords[n]; + } + } + return outCoords; +} + +double* CSTransform::InvertTransform(const double inCoords[3], double outCoords[3]) const +{ + double coords[4] = {inCoords[0],inCoords[1],inCoords[2],1}; + for (int m=0;m<3;++m) + { + outCoords[m] = 0; + for (int n=0;n<4;++n) + { + outCoords[m] += m_Inv_TMatrix[4*m+n]*coords[n]; + } + } + return outCoords; +} + +void CSTransform::SetMatrix(const double matrix[16], bool concatenate) +{ + ApplyMatrix(matrix,concatenate); + AppendList(MATRIX,matrix,16); +} + +bool CSTransform::SetMatrix(std::string matrix, bool concatenate) +{ + std::vector mat_vec = SplitString2Vector(matrix, ','); + ParameterScalar ps_matrix[16]; + + double d_matrix[16]; + if (mat_vec.size()>16) + std::cerr << "CSTransform::SetMatrix: Warning: Number of arguments for operation: \"Matrix\" with arguments: \"" << matrix << "\" is larger than expected, skipping unneeded! " << std::endl; + else if (mat_vec.size()<16) + { + std::cerr << "CSTransform::SetMatrix: Error: Number of arguments for operation: \"Matrix\" with arguments: \"" << matrix << "\" is invalid! Skipping" << std::endl; + return false; + } + + for (int n=0;n<16;++n) + { + ps_matrix[n].SetParameterSet(m_ParaSet); + ps_matrix[n].SetValue(mat_vec.at(n)); + int EC = ps_matrix[n].Evaluate(); + if (EC!=0) + return false; + d_matrix[n]=ps_matrix[n].GetValue(); + } + + ApplyMatrix(d_matrix,concatenate); + AppendList(MATRIX,ps_matrix,16); + return true; +} + +bool CSTransform::TranslateMatrix(double matrix[16], const double translate[3]) +{ + MakeUnitMatrix(matrix); + //put translate vector into the last column + for (int n=0;n<3;++n) + matrix[4*n+3] = translate[n]; + return true; +} + +void CSTransform::Translate(const double translate[3], bool concatenate) +{ + double matrix[16]; + + if (TranslateMatrix(matrix, translate)==false) + return; + + ApplyMatrix(matrix,concatenate); + AppendList(TRANSLATE,translate,3); +} + +bool CSTransform::Translate(std::string translate, bool concatenate) +{ + double matrix[16]; + + std::vector tl_vec = SplitString2Vector(translate, ','); + ParameterScalar ps_translate[3]; + double tl_double_vec[3]; + if (tl_vec.size()>3) + std::cerr << "CSTransform::Translate: Warning: Number of arguments for operation: \"Translate\" with arguments: \"" << translate << "\" is larger than expected, skipping unneeded! " << std::endl; + else if (tl_vec.size()<3) + { + std::cerr << "CSTransform::Translate: Error: Number of arguments for operation: \"Translate\" with arguments: \"" << translate << "\" is invalid! Skipping" << std::endl; + return false; + } + + for (int n=0;n<3;++n) + { + ps_translate[n].SetParameterSet(m_ParaSet); + ps_translate[n].SetValue(tl_vec.at(n)); + int EC = ps_translate[n].Evaluate(); + if (EC!=0) + return false; + tl_double_vec[n]=ps_translate[n].GetValue(); + } + + if (TranslateMatrix(matrix, tl_double_vec)==false) + return false; + + ApplyMatrix(matrix,concatenate); + AppendList(TRANSLATE,ps_translate,3); + return true; +} + +bool CSTransform::RotateOriginMatrix(double matrix[16], const double XYZ_A[4]) +{ + double length = sqrt(XYZ_A[0]*XYZ_A[0]+XYZ_A[1]*XYZ_A[1]+XYZ_A[2]*XYZ_A[2]); + if (length==0) + { + std::cerr << "CSTransform::RotateOriginVector: Warning: vector length is zero! skipping" << std::endl; + return false; + } + + for (int n=0;n<16;++n) + matrix[n]=0; + matrix[15] = 1; + + double angle = XYZ_A[3]; + if (m_AngleRadian==false) + angle *= PI/180; + + double unit_vec[3] = {XYZ_A[0]/length,XYZ_A[1]/length,XYZ_A[2]/length}; + + for (int n=0;n<3;++n) + { + int nP = (n+1)%3; + int nM = (n+2)%3; + //diagonal + matrix[4*n+n] += unit_vec[n]*unit_vec[n]+(1-unit_vec[n]*unit_vec[n])*cos(angle); + //diagonal + 1 + matrix[4*n+nP] += unit_vec[n]*unit_vec[nP]*(1-cos(angle))-unit_vec[nM]*sin(angle); + //diagonal + 2 + matrix[4*n+nM] += unit_vec[n]*unit_vec[nM]*(1-cos(angle))+unit_vec[nP]*sin(angle); + } + + return true; +} + +void CSTransform::RotateOrigin(const double vector[3], double angle, bool concatenate) +{ + double XYZ_A[4]={vector[0],vector[1],vector[2],angle}; + + double matrix[16]; + if (RotateOriginMatrix(matrix, XYZ_A)==false) + return; + + ApplyMatrix(matrix,concatenate); + AppendList(ROTATE_ORIGIN,XYZ_A,4); +} + +bool CSTransform::RotateOrigin(std::string XYZ_A, bool concatenate) +{ + double matrix[16]; + + std::vector rot_vec = SplitString2Vector(XYZ_A, ','); + ParameterScalar ps_rotate[4]; + double rot_double_vec[4]; + if (rot_vec.size()>4) + std::cerr << "CSTransform::RotateOrigin: Warning: Number of arguments for operation: \"RotateOrigin\" with arguments: \"" << XYZ_A << "\" is larger than expected, skipping unneeded! " << std::endl; + else if (rot_vec.size()<4) + { + std::cerr << "CSTransform::RotateOrigin: Error: Number of arguments for operation: \"RotateOrigin\" with arguments: \"" << XYZ_A << "\" is invalid! Skipping" << std::endl; + return false; + } + + for (int n=0;n<4;++n) + { + ps_rotate[n].SetParameterSet(m_ParaSet); + ps_rotate[n].SetValue(rot_vec.at(n)); + int EC = ps_rotate[n].Evaluate(); + if (EC!=0) + return false; + rot_double_vec[n]=ps_rotate[n].GetValue(); + } + + if (RotateOriginMatrix(matrix, rot_double_vec)==false) + return false; + + ApplyMatrix(matrix,concatenate); + AppendList(ROTATE_ORIGIN,ps_rotate,4); + return true; +} + +void CSTransform::RotateXYZ(int dir, double angle, bool concatenate) +{ + if ((dir<0) || (dir>3)) + return; + + double vec[4]={0,0,0,angle}; + vec[dir] = 1; + + double matrix[16]; + if (RotateOriginMatrix(matrix, vec)==false) + return; + + ApplyMatrix(matrix,concatenate); + TransformType type = (TransformType)((int)ROTATE_X + dir); + AppendList(type,&angle,1); +} + +bool CSTransform::RotateXYZ(int dir, std::string angle, bool concatenate) +{ + if ((dir<0) || (dir>3)) + return false; + + ParameterScalar ps_angle(m_ParaSet, angle); + int EC = ps_angle.Evaluate(); + if (EC!=0) + return false; + double vec[4]={0,0,0,ps_angle.GetValue()}; + vec[dir] = 1; + + double matrix[16]; + if (RotateOriginMatrix(matrix, vec)==false) + return false; + + ApplyMatrix(matrix,concatenate); + TransformType type = (TransformType)((int)ROTATE_X + dir); + AppendList(type,&ps_angle,1); + return true; +} + +void CSTransform::RotateX(double angle, bool concatenate) +{ + return RotateXYZ(0,angle,concatenate); +} + +bool CSTransform::RotateX(std::string angle, bool concatenate) +{ + return RotateXYZ(0,angle,concatenate); +} + +void CSTransform::RotateY(double angle, bool concatenate) +{ + return RotateXYZ(1,angle,concatenate); +} + +bool CSTransform::RotateY(std::string angle, bool concatenate) +{ + return RotateXYZ(1,angle,concatenate); +} + +void CSTransform::RotateZ(double angle, bool concatenate) +{ + return RotateXYZ(2,angle,concatenate); +} + +bool CSTransform::RotateZ(std::string angle, bool concatenate) +{ + return RotateXYZ(2,angle,concatenate); +} + +bool CSTransform::ScaleMatrix(double matrix[16], double scale) +{ + MakeUnitMatrix(matrix); + for (int n=0;n<3;++n) + matrix[4*n+n] = scale; + return true; +} + +bool CSTransform::ScaleMatrix(double matrix[16], const double scale[3]) +{ + MakeUnitMatrix(matrix); + for (int n=0;n<3;++n) + matrix[4*n+n] = scale[n]; + return true; +} + +void CSTransform::Scale(double scale, bool concatenate) +{ + double matrix[16]; + + if (ScaleMatrix(matrix, scale)==false) + return; + + ApplyMatrix(matrix,concatenate); + AppendList(SCALE,&scale,1); +} + +void CSTransform::Scale(const double scale[3], bool concatenate) +{ + double matrix[16]; + + if (ScaleMatrix(matrix, scale)==false) + return; + + ApplyMatrix(matrix,concatenate); + AppendList(SCALE3,scale,3); +} + +bool CSTransform::Scale(std::string scale, bool concatenate) +{ + double matrix[16]; + + std::vector scale_vec = SplitString2Vector(scale, ','); + + if ((scale_vec.size()>1) && (scale_vec.size()!=3)) + std::cerr << "CSTransform::Scale: Warning: Number of arguments for operation: \"Scale\" with arguments: \"" << scale << "\" is larger than expected, skipping unneeded! " << std::endl; + else if (scale_vec.size()<1) + { + std::cerr << "CSTransform::Scale: Error: Number of arguments for operation: \"Scale\" with arguments: \"" << scale << "\" is invalid! Skipping" << std::endl; + return false; + } + + if (scale_vec.size()>=3) + { + ParameterScalar ps_scale[3]; + double scale_double_vec[3]; + for (int n=0;n<3;++n) + { + ps_scale[n].SetParameterSet(m_ParaSet); + ps_scale[n].SetValue(scale_vec.at(n)); + int EC = ps_scale[n].Evaluate(); + if (EC!=0) + return false; + scale_double_vec[n]=ps_scale[n].GetValue(); + } + + if (ScaleMatrix(matrix, scale_double_vec)==false) + return false; + + ApplyMatrix(matrix,concatenate); + AppendList(SCALE3,ps_scale,3); + return true; + } + + if(scale_vec.size()>=1) + { + ParameterScalar ps_scale(m_ParaSet, scale); + int EC = ps_scale.Evaluate(); + if (EC!=0) + return false; + + if (ScaleMatrix(matrix, ps_scale.GetValue())==false) + return false; + + ApplyMatrix(matrix,concatenate); + AppendList(SCALE,&ps_scale,1); + return true; + } + + std::cerr << "CSTransform::Scale: Error: Number of arguments for operation: \"Scale\" with arguments: \"" << scale << "\" is invalid! Skipping" << std::endl; + return false; +} + +void CSTransform::ApplyMatrix(const double matrix[16], bool concatenate) +{ + if (concatenate) + { + double new_matrix[16]; + for (int n=0;n<16;++n) + new_matrix[n]=0; + for (int n=0;n<4;++n) + for (int m=0;m<4;++m) + { + for (int k=0;k<4;++k) + if (m_PostMultiply) + new_matrix[4*m+n] += matrix[4*m+k]*m_TMatrix[4*k+n]; + else + new_matrix[4*m+n] += m_TMatrix[4*m+k]*matrix[4*k+n]; + } + for (int n=0;n<16;++n) + m_TMatrix[n]=new_matrix[n]; + } + else + { + m_TransformList.clear(); + m_TransformArguments.clear(); + for (int n=0;n<16;++n) + m_TMatrix[n]=matrix[n]; + } + UpdateInverse(); +} + +bool CSTransform::TransformByString(std::string operation, std::string argument, bool concatenate) +{ + unsigned int numArgs; + int type = GetTypeByName(operation, numArgs); + + if (type<0) + { + std::cerr << "CSTransform::TransformByString: Error, unknown transformation: \"" << operation << "\"" << std::endl; + return false; + } + + return TransformByType((TransformType)type, argument, concatenate); +} + +void CSTransform::TransformByType(TransformType type, std::vector args, bool concatenate) +{ + unsigned int numArgs = args.size(); + double arguments[numArgs]; + for (unsigned int n=0;n argument; + for (size_t n=0;n argument; + for (size_t n=0;nInsertEndChild(Transform); + return true; +} + +bool CSTransform::ReadFromXML(TiXmlNode* root) +{ + TiXmlElement* prop=root->FirstChildElement("Transformation"); + if (prop==NULL) return false; + + TiXmlElement* PropNode = prop->FirstChildElement(); + while (PropNode!=NULL) + { + std::string argument(PropNode->Attribute("Argument")); + if (TransformByString(PropNode->Value(),argument,true)==false) + std::cerr << "CSTransform::ReadFromXML: Warning: Reading of \"" << PropNode->Value() << "\" with arguments: \"" << argument << "\" failed." << std::endl; + PropNode=PropNode->NextSiblingElement(); + } + return true; +} + +CSTransform* CSTransform::New(TiXmlNode* root, ParameterSet* paraSet) +{ + CSTransform* newCST = new CSTransform(paraSet); + if (newCST->ReadFromXML(root)) + return newCST; + delete newCST; + return NULL; +} + +CSTransform* CSTransform::New(CSTransform* cst, ParameterSet* paraSet) +{ + if (cst==NULL) + return NULL; + CSTransform* newCST = new CSTransform(cst); + if (paraSet) + newCST->SetParameterSet(paraSet); + return newCST; +} diff --git a/CSXCAD/src/CSTransform.h b/CSXCAD/src/CSTransform.h new file mode 100644 index 0000000..8fcad90 --- /dev/null +++ b/CSXCAD/src/CSTransform.h @@ -0,0 +1,143 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#ifndef CSTRANSFORM_H +#define CSTRANSFORM_H + +#include +#include +#include +#include +#include +#include + +#include "ParameterObjects.h" + +class CSXCAD_EXPORT CSTransform +{ +public: + CSTransform(); + CSTransform(CSTransform* transform); + CSTransform(ParameterSet* paraSet); + virtual ~CSTransform(); + + void SetParameterSet(ParameterSet* paraset) {m_ParaSet=paraset;} + + enum TransformType + { + SCALE, SCALE3, TRANSLATE, ROTATE_ORIGIN, ROTATE_X, ROTATE_Y, ROTATE_Z, MATRIX + }; //Keep this in sync with GetNameByType and GetTypeByName and TransformByType methods!!! + + double* Transform(const double inCoords[3], double outCoords[3]) const; + double* InvertTransform(const double inCoords[3], double outCoords[3]) const; + + void Invert(); + + double* GetMatrix() {return m_TMatrix;} + + //! Apply a matrix directly + void SetMatrix(const double matrix[16], bool concatenate=true); + bool SetMatrix(std::string matrix, bool concatenate=true); + + //! Create and apply a translation matrix + void Translate(const double translate[3], bool concatenate=true); + bool Translate(std::string translate, bool concatenate=true); + + //! Create and apply a rotation matrix around the given vector and angle + void RotateOrigin(const double vector[3], double angle, bool concatenate=true); + bool RotateOrigin(std::string XYZ_A, bool concatenate=true); + + void RotateX(double angle, bool concatenate=true); + bool RotateX(std::string angle, bool concatenate=true); + + void RotateY(double angle, bool concatenate=true); + bool RotateY(std::string angle, bool concatenate=true); + + void RotateZ(double angle, bool concatenate=true); + bool RotateZ(std::string angle, bool concatenate=true); + + void RotateXYZ(int dir, double angle, bool concatenate=true); + bool RotateXYZ(int dir, std::string angle, bool concatenate=true); + + void Scale(double scale, bool concatenate=true); + void Scale(const double scale[3], bool concatenate=true); + bool Scale(std::string scale, bool concatenate=true); + + bool TransformByString(std::string operation, std::string argument, bool concatenate=true); + + void TransformByType(TransformType type, std::vector args, bool concatenate=true); + void TransformByType(TransformType type, const double* args, bool concatenate=true); + bool TransformByType(TransformType type, std::string args, bool concatenate=true); + + void Reset(); + + //! Check if this CSTransform has any transformations + bool HasTransform(); + + //! All subsequent operations will be occur before the previous operations (not the default). + void SetPreMultiply() {m_PostMultiply=false;} + //! All subsequent operations will be after the previous operations (default). + void SetPostMultiply() {m_PostMultiply=true;} + + void SetAngleDegree() {m_AngleRadian=false;} + void SetAngleRadian() {m_AngleRadian=true;} + + double* MakeUnitMatrix(double matrix[16]) const; + + std::string GetNameByType(TransformType type) const; + std::string GetNameByType(TransformType type, unsigned int &numArgs) const; + int GetTypeByName(std::string name, unsigned int &numArgs) const; + + void PrintMatrix(std::ostream& stream); + + void PrintTransformations(std::ostream& stream, std::string prefix=""); + + //! Write this transformations to a xml-node. \param parameterised Use false if parameters should be written as values. Parameters are lost! + virtual bool Write2XML(TiXmlNode* root, bool parameterised=true, bool sparse=false); + //! Read transformations from xml-node. \return Successful read-operation. + virtual bool ReadFromXML(TiXmlNode* root); + + static CSTransform* New(TiXmlNode* root, ParameterSet* paraSet=NULL); + static CSTransform* New(CSTransform* cst, ParameterSet* paraSet=NULL); + +protected: + //transform matrix + double m_TMatrix[16]; + //inverse transform matrix + double m_Inv_TMatrix[16]; + + void UpdateInverse(); + + bool m_PostMultiply; + bool m_AngleRadian; + + ParameterSet* m_ParaSet; + + void ApplyMatrix(const double matrix[16], bool concatenate); + + bool RotateOriginMatrix(double matrix[16], const double XYZ_A[4]); + bool ScaleMatrix(double matrix[16], double scale); + bool ScaleMatrix(double matrix[16], const double scale[3]); + bool TranslateMatrix(double matrix[16], const double translate[3]); + + void AppendList(TransformType type, const double* args, size_t numArgs ); + void AppendList(TransformType type, const ParameterScalar* args, size_t numArgs ); + std::vector m_TransformList; + std::vector > m_TransformArguments; +}; + +#endif // CSTRANSFORM_H diff --git a/CSXCAD/src/CSUseful.cpp b/CSXCAD/src/CSUseful.cpp new file mode 100644 index 0000000..8d56c42 --- /dev/null +++ b/CSXCAD/src/CSUseful.cpp @@ -0,0 +1,178 @@ +/* +* Copyright (C) 2011,2012 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 . +*/ + +#include "CSUseful.h" +#include +#include +#include +#include + +std::string ConvertInt(int number) +{ + std::stringstream ss; + ss << number; + return ss.str(); +} + +int String2Int(std::string number) +{ + int val; + std::stringstream ss(number); + ss >> val; + return val; +} + +double String2Double(std::string number, bool &ok, int accurarcy) +{ + double val; + std::stringstream ss(number); + ss.precision(accurarcy); + ss >> val; + ok = ss.eof() && !ss.fail(); + return val; +} + +std::vector SplitString2Double(std::string str, const char delimiter) +{ + size_t pos=0; + std::string sub; + std::vector values; + bool ok; + double val; + do + { + pos=str.find_first_of(delimiter); + if (pos==std::string::npos) pos=str.size(); + sub=str.substr(0,pos); + if (sub.empty()==false) + { + val = String2Double(sub, ok); + if (ok) + values.push_back(val); + } + str.erase(0,pos+1); + } while (str.size()>0); + return values; +} + +std::vector SplitString2Vector(std::string str, const char delimiter) +{ + size_t pos=0; + std::string sub; + std::vector values; + do + { + pos=str.find_first_of(delimiter); + if (pos==std::string::npos) + { + pos=str.size(); + sub=str.substr(0,pos); + } + else + { + sub=str.substr(0,pos); + ++pos; + } + if (sub.empty()==false) values.push_back(sub); + str.erase(0,pos); + } while (str.size()>0); + return values; +} + + +std::string CombineVector2String(std::vector values, const char delimiter, int accurarcy) +{ + std::stringstream ss; + ss.precision( accurarcy ); + for (size_t i=0;i0) ss << delimiter; + ss<0) ss << delimiter; + ss<0) ss << delimiter; + ss<0) ss << delimiter; + ss< SplitString2Int(std::string str, const char delimiter) +{ + size_t pos=0; + std::string sub; + std::vector values; + do + { + pos=str.find_first_of(delimiter); + if (pos==std::string::npos) pos=str.size(); + else ++pos; + sub=str.substr(0,pos); + if (sub.empty()==false) values.push_back(String2Int(sub)); + str.erase(0,pos); + } while (str.size()>0); + return values; +} + +CSDebug::CSDebug() +{ + m_level = 0; +} + +void CSDebug::Debug(int on_level, const char* message) +{ + Debug(on_level,std::string(message)); +} + +void CSDebug::Debug(int on_level, std::string message) +{ + if (on_level<=0) return; //no debug message for debug level smaller or equal zero + if (on_level>=m_level) + std::cerr << message << std::endl; +} + diff --git a/CSXCAD/src/CSUseful.h b/CSXCAD/src/CSUseful.h new file mode 100644 index 0000000..bcb64cb --- /dev/null +++ b/CSXCAD/src/CSUseful.h @@ -0,0 +1,41 @@ +#ifndef CSUSEFUL_H +#define CSUSEFUL_H + +class CSDebug; + +#include "CSXCAD_Global.h" +#include +#include +#include +#include +#include + +std::string CSXCAD_EXPORT ConvertInt(int number); +int CSXCAD_EXPORT String2Int(std::string number); +double CSXCAD_EXPORT String2Double(std::string number, bool &ok, int accurarcy=15); +std::vector CSXCAD_EXPORT SplitString2Double(std::string str, const char delimiter); +std::vector CSXCAD_EXPORT SplitString2Vector(std::string str, const char delimiter); +std::string CSXCAD_EXPORT CombineVector2String(std::vector values, const char delimiter, int accurarcy=15); +std::string CSXCAD_EXPORT CombineArray2String(double* values, unsigned int numVal, const char delimiter, int accurarcy=15); +std::string CSXCAD_EXPORT CombineArray2String(float* values, unsigned int numVal, const char delimiter, int accurarcy=15); +std::string CSXCAD_EXPORT CombineArray2String(int* values, unsigned int numVal, const char delimiter, int accurarcy=15); + +std::vector CSXCAD_EXPORT SplitString2Int(std::string str, const char delimiter); + +class CSXCAD_EXPORT CSDebug +{ +public: + CSDebug(); + + void SetLevel(int level) {m_level=level;} + + void Debug(int on_level, const char* message); + void Debug(int on_level, std::string message); + +protected: + int m_level; +}; + +static CSDebug g_CSDebug; + +#endif // CSUSEFUL_H diff --git a/CSXCAD/src/CSXCAD_Global.h b/CSXCAD/src/CSXCAD_Global.h new file mode 100644 index 0000000..15f1b32 --- /dev/null +++ b/CSXCAD/src/CSXCAD_Global.h @@ -0,0 +1,46 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#ifndef CSXCAD_GLOBAL_H_ +#define CSXCAD_GLOBAL_H_ + +#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_MAIL_ "Thorsten.Liebig@gmx.de" +#define _CSXCAD_VERSION_ GIT_VERSION +#define _CSXCAD_LICENSE_ "LGPL v3" + +#if defined(WIN32) + #ifdef BUILD_CSXCAD_LIB + #define CSXCAD_EXPORT __declspec(dllexport) + #else + #define CSXCAD_EXPORT __declspec(dllimport) + #endif +#else +#define CSXCAD_EXPORT +#endif + +// declare a parameter as unused +#define UNUSED(x) (void)(x); + +enum CoordinateSystem +{ + CARTESIAN, CYLINDRICAL, UNDEFINED_CS +}; + +#endif /*CSXCAD_GLOBAL_H_*/ diff --git a/CSXCAD/src/ContinuousStructure.cpp b/CSXCAD/src/ContinuousStructure.cpp new file mode 100644 index 0000000..a0c17a1 --- /dev/null +++ b/CSXCAD/src/ContinuousStructure.cpp @@ -0,0 +1,660 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include "ContinuousStructure.h" + +#include "CSPrimPoint.h" +#include "CSPrimBox.h" +#include "CSPrimMultiBox.h" +#include "CSPrimSphere.h" +#include "CSPrimSphericalShell.h" +#include "CSPrimCylinder.h" +#include "CSPrimCylindricalShell.h" +#include "CSPrimPolygon.h" +#include "CSPrimLinPoly.h" +#include "CSPrimRotPoly.h" +#include "CSPrimPolyhedron.h" +#include "CSPrimPolyhedronReader.h" +#include "CSPrimCurve.h" +#include "CSPrimWire.h" +#include "CSPrimUserDefined.h" + +#include "CSPropUnknown.h" +#include "CSPropMaterial.h" +#include "CSPropDispersiveMaterial.h" +#include "CSPropLorentzMaterial.h" +#include "CSPropDebyeMaterial.h" +#include "CSPropDiscMaterial.h" +#include "CSPropLumpedElement.h" +#include "CSPropMetal.h" +#include "CSPropConductingSheet.h" +#include "CSPropExcitation.h" +#include "CSPropProbeBox.h" +#include "CSPropDumpBox.h" +#include "CSPropResBox.h" + +#include "tinyxml.h" + +/*********************ContinuousStructure********************************************************************/ +ContinuousStructure::ContinuousStructure(void) +{ + clParaSet = new ParameterSet(); + //init datastructures... + clear(); +} + +ContinuousStructure::~ContinuousStructure(void) +{ + clear(); + delete clParaSet; + clParaSet=NULL; +} + +void ContinuousStructure::AddProperty(CSProperties* prop) +{ + if (prop==NULL) return; + prop->SetCoordInputType(m_MeshType); + prop->Update(&ErrString); + vProperties.push_back(prop); + prop->SetUniqueID(UniqueIDCounter++); + this->UpdateIDs(); +} + +bool ContinuousStructure::ReplaceProperty(CSProperties* oldProp, CSProperties* newProp) +{ + std::vector::iterator iter; + for (iter=vProperties.begin();iterGetPrimitive(0); + while (prim!=NULL) + { + newProp->AddPrimitive(prim); + prim->SetProperty(newProp); + prim=oldProp->GetPrimitive(0); + } + delete *iter; + *iter=newProp; + newProp->SetUniqueID(UniqueIDCounter++); + return true; + } + } + return false; +} + +void ContinuousStructure::DeleteProperty(size_t index) +{ + if (index>=vProperties.size()) return; + std::vector::iterator iter=vProperties.begin(); + delete vProperties.at(index); + vProperties.erase(iter+index); + this->UpdateIDs(); +} + +void ContinuousStructure::DeleteProperty(CSProperties* prop) +{ + std::vector::iterator iter; + for (iter=vProperties.begin();iterUpdateIDs(); +} + +int ContinuousStructure::GetIndex(CSProperties* prop) +{ + if (prop==NULL) return -1; + for (size_t i=0;iGetType() & type) ++count; + return count; +} + +std::vector ContinuousStructure::GetPropertyByType(CSProperties::PropertyType type) +{ + std::vector found; + for (size_t i=0;iGetType() & type) + found.push_back(vProperties.at(i)); + return found; +} + +size_t ContinuousStructure::GetQtyPrimitives(CSProperties::PropertyType type) +{ + size_t count = 0; + for (size_t i=0;iGetType() & type) + count+=vProperties.at(i)->GetQtyPrimitives(); + return count; +} + +bool sortPrimByPrio(CSPrimitives* a, CSPrimitives* b) +{ + return a->GetPriority()GetPriority(); +} + +std::vector ContinuousStructure::GetAllPrimitives(bool sorted, CSProperties::PropertyType type) +{ + std::vector props = this->GetPropertyByType(type); + std::vector vPrim; + vPrim.reserve(GetQtyPrimitives(type)); + for (size_t i=0;i prop_prims = props.at(i)->GetAllPrimitives(); + vPrim.insert(vPrim.end(),prop_prims.begin(),prop_prims.end()); + } + if (sorted) + sort(vPrim.rbegin(), vPrim.rend(), sortPrimByPrio); + return vPrim; +} + +CSProperties* ContinuousStructure::HasPrimitive(CSPrimitives* prim) +{ + for (size_t i=0;iHasPrimitive(prim)) + return vProperties.at(i); + return NULL; +} + +void ContinuousStructure::DeletePrimitive(CSPrimitives* prim) +{ + // no special handling is necessary, deleted primitive will release itself from its owning property + delete prim; +} + +std::vector ContinuousStructure::GetPrimitivesByType(CSPrimitives::PrimitiveType type) +{ + UNUSED(type); + std::vector vPrim; + std::cerr << __func__ << ": Error, not yet implemented!" << std::endl; + return vPrim; +} + +std::vector ContinuousStructure::GetPrimitivesByBoundBox(const double* boundbox, bool sorted, CSProperties::PropertyType type) +{ + std::vector out_list; + std::vector prims =this->GetAllPrimitives(sorted, type); + for (size_t j=0;jIsInsideBox(boundbox)>=0) + out_list.push_back(prims.at(j)); + } + return out_list; +} + +bool ContinuousStructure::InsertEdges2Grid(int nu) +{ + if (nu<0) return false; + if (nu>2) return false; + double box[6] = {0,0,0,0,0,0}; + bool accBound=false; + std::vector vPrimitives=GetAllPrimitives(); + for (size_t i=0;iGetBoundBox(box); + if (accBound) + { + clGrid.AddDiscLine(nu,box[2*nu]); + clGrid.AddDiscLine(nu,box[2*nu+1]); + } + } + clGrid.Sort(nu); + return true; +} + +CSPrimitives* ContinuousStructure::GetPrimitiveByID(unsigned int ID) +{ + std::vector vPrimitives=GetAllPrimitives(); + for (size_t i=0;iGetID()==ID) + return vPrimitives.at(i); + return NULL; +} + +std::vector ContinuousStructure::GetPropertiesByName(std::string name) +{ + std::vector vProp; + for (size_t i=0;iGetName())==0) + vProp.push_back(vProperties.at(i)); + return vProp; +} + +CSProperties* ContinuousStructure::GetProperty(size_t index) +{ + if (indexGetType() & type)) + { + locPrim = vProperties.at(i)->CheckCoordInPrimitive(coord,locPrio,dDrawingTol); + if (locPrim) + { + if (winProp==NULL) + { + winPrio=locPrio; + winProp=vProperties.at(i); + winPrim=locPrim; + } + else if (locPrio>winPrio) + { + winPrio=locPrio; + winProp=vProperties.at(i); + winPrim=locPrim; + } + } + } + } + if ((markFoundAsUsed) && (winPrim)) + winPrim->SetPrimitiveUsed(true); + if (foundPrimitive) + *foundPrimitive=winPrim; + return winProp; +} + + +CSProperties** ContinuousStructure::GetPropertiesByCoordsPriority(const double* /*coords*/, CSProperties::PropertyType /*type*/, bool /*markFoundAsUsed*/) +{ + std::cerr << "ContinuousStructure::GetPropertiesByCoordsPriority --> This methode has not been implemented yet!!! return NULL" << std::endl; + return NULL; +} + +CSProperties* ContinuousStructure::GetPropertyByCoordPriority(const double* coord, std::vector primList, bool markFoundAsUsed, CSPrimitives** foundPrimitive) +{ + CSProperties* prop = NULL; + // search in all given primitives if coordinate given is inside + for (size_t i=0;iIsInside(coord)) + { + if (foundPrimitive) + *foundPrimitive = primList.at(i); + prop = primList.at(i)->GetProperty(); + if (markFoundAsUsed) + primList.at(i)->SetPrimitiveUsed(true); + // break as soon as a primitive is found since it is expected that the vPrim vector is priority sorted! + break; + } + return prop; +} + +void ContinuousStructure::WarnUnusedPrimitves(std::ostream& stream, CSProperties::PropertyType type) +{ + for (size_t i=0;iGetType() & type)) + { + vProperties.at(i)->WarnUnusedPrimitves(stream); + } + } +} + +void ContinuousStructure::ShowPropertyStatus(std::ostream& stream, CSProperties::PropertyType type) +{ + for (size_t i=0;iGetType() & type)) + { + stream << "-----------------------------------------" << std::endl; + vProperties.at(i)->ShowPropertyStatus(stream); + } + } +} + +void ContinuousStructure::SetCoordInputType(CoordinateSystem type) +{ + m_MeshType = type; + for (size_t i=0;iSetCoordInputType(type); + } +} + +bool ContinuousStructure::isGeometryValid() +{ + if (GetQtyProperties()<=0) return false; + if (GetQtyPrimitives()<=0) return false; + if (clGrid.GetQtyLines(0)<=1) return false; + if (clGrid.GetQtyLines(1)<=1) return false; + if (clGrid.GetQtyLines(2)<=0) return false; + + std::vector vPrimitives=GetAllPrimitives(); + for (size_t i=0;iUpdate()==false) + return false; + } + + int excit=0; + for (size_t i=0;iUpdate()==false) return false; + if (vProperties.at(i)->GetType()==CSProperties::EXCITATION) + { + if (vProperties.at(i)->GetQtyPrimitives()>0) ++excit; + } + } + if (excit==0) return false; + return true; +} + +double* ContinuousStructure::GetObjectArea() +{ + CSPrimitives* prim=NULL; + bool AccBound; + std::vector vPrimitives=GetAllPrimitives(); + for (size_t i=0;iGetBoundBox(box); + if (box!=NULL && AccBound) + { + if (i==0) for (int i=0;i<6;++i) ObjArea[i]=box[i]; + else + { + for (int i=0;i<3;++i) + { + if (ObjArea[2*i]>box[2*i]) ObjArea[2*i]=box[2*i]; + if (ObjArea[2*i+1]Update(&ErrString); + + std::vector vPrimitives=GetAllPrimitives(); + for (size_t i=0;iUpdate(&ErrString); + + return std::string(ErrString); +} + +void ContinuousStructure::clear() +{ + UniqueIDCounter=0; + dDrawingTol=0; + maxID=0; + m_BG_Mat.Reset(); + for (unsigned int n=0;nclear(); + clGrid.clear(); +} + +bool ContinuousStructure::Write2XML(TiXmlNode* rootNode, bool parameterised, bool sparse) +{ + if (rootNode==NULL) return false; + + TiXmlElement Struct("ContinuousStructure"); + + Struct.SetAttribute("CoordSystem",GetCoordInputType()); + + clGrid.Write2XML(Struct,false); + + m_BG_Mat.Write2XML(Struct, false); + + clParaSet->Write2XML(Struct); + + TiXmlElement Properties("Properties"); + for (size_t i=0;iGetTypeXMLString().c_str()); + vProperties.at(i)->Write2XML(PropElem,parameterised,sparse); + Properties.InsertEndChild(PropElem); + } + Struct.InsertEndChild(Properties); + + rootNode->InsertEndChild(Struct); + + return true; +} + +bool ContinuousStructure::Write2XML(const char* file, bool parameterised, bool sparse) +{ + return this->Write2XML(std::string(file), parameterised, sparse); +} + +bool ContinuousStructure::Write2XML(std::string file, bool parameterised, bool sparse) +{ + TiXmlDocument doc(file); + doc.InsertEndChild(TiXmlDeclaration("1.0","UTF-8","yes")); + + if (Write2XML(&doc,parameterised,sparse)==false) return false; + + doc.SaveFile(); + return doc.SaveFile(); +} + +const char* ContinuousStructure::ReadFromXML(TiXmlNode* rootNode) +{ + clear(); + TiXmlNode* root = rootNode->FirstChild("ContinuousStructure"); + if (root==NULL) { ErrString.append("Error: No ContinuousStructure found!!!\n"); return ErrString.c_str();} + + TiXmlElement* rootElem = root->ToElement(); + if (rootElem) + { + int CS_mesh = 0; + if (rootElem->QueryIntAttribute("CoordSystem",&CS_mesh) == TIXML_SUCCESS) + SetCoordInputType((CoordinateSystem)CS_mesh); + } + + TiXmlNode* bg_node = root->FirstChild("BackgroundMaterial"); + if (bg_node==NULL) + m_BG_Mat.Reset(); //reset to default; + else + if (m_BG_Mat.ReadFromXML(*bg_node)==false) + { + ErrString.append("Error: BackgroundMaterial invalid!!!\n"); + return ErrString.c_str(); + } + + TiXmlNode* grid = root->FirstChild("RectilinearGrid"); + if (grid==NULL) { ErrString.append("Error: No RectilinearGrid found!!!\n"); return ErrString.c_str();} + if (clGrid.ReadFromXML(*grid)==false) { ErrString.append("Error: RectilinearGrid invalid!!!\n"); return ErrString.c_str();} + + TiXmlNode* paraSet = root->FirstChild("ParameterSet"); + if (paraSet!=NULL) if (clParaSet->ReadFromXML(*paraSet)==false) { ErrString.append("Warning: ParameterSet reading failed!!!\n");} + + /***Properties***/ + TiXmlNode* probs = root->FirstChild("Properties"); + if (probs==NULL) { ErrString.append("Warning: Properties not found!!!\n"); return ErrString.c_str();} + + TiXmlElement* PropNode = probs->FirstChildElement(); + CSProperties* newProp=NULL; + while (PropNode!=NULL) + { + const char* cProp=PropNode->Value(); + if (strcmp(cProp,"Unknown")==0) newProp = new CSPropUnknown(clParaSet); + else if (strcmp(cProp,"Material")==0) newProp = new CSPropMaterial(clParaSet); + else if (strcmp(cProp,"DiscMaterial")==0) newProp = new CSPropDiscMaterial(clParaSet); + else if (strcmp(cProp,"LorentzMaterial")==0) newProp = new CSPropLorentzMaterial(clParaSet); + else if (strcmp(cProp,"DebyeMaterial")==0) newProp = new CSPropDebyeMaterial(clParaSet); + else if (strcmp(cProp,"LumpedElement")==0) newProp = new CSPropLumpedElement(clParaSet); + else if (strcmp(cProp,"Metal")==0) newProp = new CSPropMetal(clParaSet); + else if (strcmp(cProp,"ConductingSheet")==0) newProp = new CSPropConductingSheet(clParaSet); + else if (strcmp(cProp,"Excitation")==0) newProp = new CSPropExcitation(clParaSet); + else if (strcmp(cProp,"ProbeBox")==0) newProp = new CSPropProbeBox(clParaSet); + else if (strcmp(cProp,"ChargeBox")==0) newProp = new CSPropProbeBox(clParaSet); //old version support + else if (strcmp(cProp,"ResBox")==0) newProp = new CSPropResBox(clParaSet); + else if (strcmp(cProp,"DumpBox")==0) newProp = new CSPropDumpBox(clParaSet); + else + { + std::cerr << "ContinuousStructure::ReadFromXML: Property with type: " << cProp << " is unknown... " << std::endl; + newProp=NULL; + } + if (newProp) + { + if (newProp->ReadFromXML(*PropNode)) + { + AddProperty(newProp); + ReadPropertyPrimitives(PropNode,newProp); + } + else + { + delete newProp; + newProp = new CSPropUnknown(clParaSet); + if (newProp->ReadFromXML(*PropNode)) + { + AddProperty(newProp); + ReadPropertyPrimitives(PropNode,newProp); + ErrString.append("Warning: Unknown Property found!!!\n"); + } + else + { + ErrString.append("Warning: invalid Property found!!!\n"); + delete newProp; + newProp=NULL; + } + } + } + PropNode=PropNode->NextSiblingElement(); + } + return ErrString.c_str(); +} + +bool ContinuousStructure::ReadPropertyPrimitives(TiXmlElement* PropNode, CSProperties* prop) +{ + /***Primitives***/ + TiXmlNode* prims = PropNode->FirstChild("Primitives"); + if (prims==NULL) + { + ErrString.append("Warning: No primitives found in property: "); + ErrString.append(prop->GetName()); + ErrString.append("!\n"); + return false; + } + + TiXmlElement* PrimNode = prims->FirstChildElement(); + CSPrimitives* newPrim=NULL; + while (PrimNode!=NULL) + { + const char* cPrim=PrimNode->Value(); + if (strcmp(cPrim,"Box")==0) newPrim = new CSPrimBox(clParaSet,prop); + else if (strcmp(cPrim,"MultiBox")==0) newPrim = new CSPrimMultiBox(clParaSet,prop); + else if (strcmp(cPrim,"Sphere")==0) newPrim = new CSPrimSphere(clParaSet,prop); + else if (strcmp(cPrim,"SphericalShell")==0) newPrim = new CSPrimSphericalShell(clParaSet,prop); + else if (strcmp(cPrim,"Cylinder")==0) newPrim = new CSPrimCylinder(clParaSet,prop); + else if (strcmp(cPrim,"CylindricalShell")==0) newPrim = new CSPrimCylindricalShell(clParaSet,prop); + else if (strcmp(cPrim,"Polygon")==0) newPrim = new CSPrimPolygon(clParaSet,prop); + else if (strcmp(cPrim,"LinPoly")==0) newPrim = new CSPrimLinPoly(clParaSet,prop); + else if (strcmp(cPrim,"RotPoly")==0) newPrim = new CSPrimRotPoly(clParaSet,prop); + else if (strcmp(cPrim,"Polyhedron")==0) newPrim = new CSPrimPolyhedron(clParaSet,prop); + else if (strcmp(cPrim,"PolyhedronReader")==0) newPrim = new CSPrimPolyhedronReader(clParaSet,prop); + else if (strcmp(cPrim,"Curve")==0) newPrim = new CSPrimCurve(clParaSet,prop); + else if (strcmp(cPrim,"Wire")==0) newPrim = new CSPrimWire(clParaSet,prop); + else if (strcmp(cPrim,"UserDefined")==0) newPrim = new CSPrimUserDefined(clParaSet,prop); + else if (strcmp(cPrim,"Point")==0) newPrim = new CSPrimPoint(clParaSet,prop); + else + { + std::cerr << "ContinuousStructure::ReadFromXML: Primitive with type: " << cPrim << " is unknown... " << std::endl; + newPrim=NULL; + } + if (newPrim) + { + if (newPrim->ReadFromXML(*PrimNode)) + { + newPrim->SetCoordInputType(m_MeshType, false); + newPrim->Update(&ErrString); + } + else + { + delete newPrim; + ErrString.append("Warning: Invalid primitive found in property: "); + ErrString.append(prop->GetName()); + ErrString.append("!\n"); + } + } + PrimNode=PrimNode->NextSiblingElement(); + } + + return true; +} + +const char* ContinuousStructure::ReadFromXML(const char* file) +{ + ErrString.clear(); + + TiXmlDocument doc(file); + if (!doc.LoadFile(TIXML_ENCODING_UTF8)) { ErrString.append("Error: File-Loading failed!!! File: ");ErrString.append(file); return ErrString.c_str();} + + return ReadFromXML(&doc); +} + +void ContinuousStructure::UpdateIDs() +{ + for (size_t i=0;iSetID((unsigned int)i); +} + +std::string ContinuousStructure::GetInfoLine(bool shortInfo) +{ + if (shortInfo) + { + std::string InfoLine = std::string(_CSXCAD_LIB_NAME_SHORT_) + +std::string(" -- Version: ") + std::string(_CSXCAD_VERSION_); + return InfoLine; + } + + std::string InfoLine = std::string(_CSXCAD_LIB_NAME_) + +std::string("\nAuthor: ") + std::string(_CSXCAD_AUTHOR_) + +std::string("\nMail: ") +std::string(_CSXCAD_AUTHOR_MAIL_) + +std::string("\nVersion: ") + std::string(_CSXCAD_VERSION_) + +std::string("\tBuild: ") + std::string(__DATE__) + std::string(" ") + std::string(__TIME__) + +std::string("\nLicense: ") + std::string(_CSXCAD_LICENSE_); + return InfoLine; +} + + + + diff --git a/CSXCAD/src/ContinuousStructure.h b/CSXCAD/src/ContinuousStructure.h new file mode 100644 index 0000000..aa986c5 --- /dev/null +++ b/CSXCAD/src/ContinuousStructure.h @@ -0,0 +1,218 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#pragma once +/* + * Author: Thorsten Liebig + * Date: 03-12-2008 + * Lib: CSXCAD + * Version: 0.1a + */ + +#include +#include +#include +#include +#include +#include "CSXCAD_Global.h" +#include "CSProperties.h" +#include "CSPrimitives.h" +#include "CSRectGrid.h" +#include "CSBackgroundMaterial.h" +#include "ParameterObjects.h" +#include "CSUseful.h" + +class TiXmlNode; + +//! Continuous Structure containing properties (layer) and primitives. +/*! + ContinuousStructure is a class that contains certain property objects containing geometrical primitive structures as boxes, spheres, cylinders etc. + All values in this class can contain parameters and mathematical equations. +*/ +class CSXCAD_EXPORT ContinuousStructure +{ +public: + //! Create an empty structure + ContinuousStructure(void); + //! Deconstructor. Will delete all properties and primitives it contains! + virtual ~ContinuousStructure(void); + + //! Get the ParameterSet created by this Structure. Needed for creation of any property or primitive! + /*! + \return ParameterSet owned by this class. + */ + ParameterSet* GetParameterSet() {return clParaSet;} + + //! Get the Grid of this Structure. + CSRectGrid* GetGrid() {return &clGrid;} + + //! Get the background material + CSBackgroundMaterial* GetBackgroundMaterial() {return &m_BG_Mat;} + + //! Add an existing CSProperty. Class takes ownership! + void AddProperty(CSProperties* prop); + + //! Replace an existing property with a new one. \sa AddProperty, DeleteProperty + bool ReplaceProperty(CSProperties* oldProp, CSProperties* newProp); + + //! Remove and delete Property at known index + void DeleteProperty(size_t index); + + //! Remove and delete a known Property + void DeleteProperty(CSProperties* prop); + + //! Get a primitive by its unique ID. + CSPrimitives* GetPrimitiveByID(unsigned int ID); + + //! Get all primitives with the given name + std::vector GetPropertiesByName(std::string name); + + //! Get a property by its internal index number. \sa GetQtyProperties + CSProperties* GetProperty(size_t index); + + //! Define the input type for the CSProperties weighting coordinate system 0=cartesian, 1=cylindrical, 2=spherical + void SetCoordInputType(CoordinateSystem type); + + CoordinateSystem GetCoordInputType() const {return m_MeshType;} + + //! Set a drawing tolerance. /sa GetPropertyByCoordPriority /sa GetPropertiesByCoordsPriority + void SetDrawingTolerance(double val) {dDrawingTol=val;} + + //! Get a property by its priority at a given coordinate and property type. + /*! + \param coord Give a 3-element array with a 3D-coordinate set (x,y,z). + \param type Specify the type searched for. (Default is ANY-type) + \param markFoundAsUsed Mark the found primitives as beeing used. \sa WarnUnusedPrimitves + \param foundPrimitive return the found primitive, set to NULL if none was found + \return Returns NULL if coordinate is outside the mesh, no mesh is defined or no property is found. + */ + CSProperties* GetPropertyByCoordPriority(const double* coord, CSProperties::PropertyType type=CSProperties::ANY, bool markFoundAsUsed=false, CSPrimitives** foundPrimitive=NULL); + + //! Get properties by its priority at given coordinates and property type. + /*! + \sa GetPropertyByCoordPriority + \param coords Give a 3*n-element array with the 3D-coordinate set (e.g. x1,y1,z1,x2,y2,z2,...) + \param type Specify the type searched for. (Default is ANY-type) + \param markFoundAsUsed Mark the found primitives as beeing used. \sa WarnUnusedPrimitves + \return Returns an array of n properties. NULL if coordinate is outside the mesh, no mesh is defined or no property is found. + */ + CSProperties** GetPropertiesByCoordsPriority(const double* coords, CSProperties::PropertyType type=CSProperties::ANY, bool markFoundAsUsed=false); + + CSProperties* GetPropertyByCoordPriority(const double* coord, std::vector primList, bool markFoundAsUsed=false, CSPrimitives** foundPrimitive=NULL); + + //! Check and warn for unused primitives in properties of given type + void WarnUnusedPrimitves(std::ostream& stream, CSProperties::PropertyType type=CSProperties::ANY); + + //! Show status of all properties with given type + void ShowPropertyStatus(std::ostream& stream, CSProperties::PropertyType type=CSProperties::ANY); + + //! Find the property owning the given primitive or return NULL if primitive is not to be found + CSProperties* HasPrimitive(CSPrimitives* prim); + + //! Delete the given primitive + void DeletePrimitive(CSPrimitives* prim); + + //! Get the quantity of primitives included in this structure. + size_t GetQtyPrimitives(CSProperties::PropertyType type=CSProperties::ANY); + + //! Get a primitives array + std::vector GetAllPrimitives(bool sorted=false, CSProperties::PropertyType type=CSProperties::ANY); + + //! Get a primitives array of a certian type + std::vector GetPrimitivesByType(CSPrimitives::PrimitiveType type); + + + //! Get a primitives array inside a bounding box and with a certian property type (default is any) + std::vector GetPrimitivesByBoundBox(const double* boundbox, bool sorted=false, CSProperties::PropertyType type=CSProperties::ANY); + + //! Get the internal index of the property. + int GetIndex(CSProperties* prop); + + //! Get the quantity of properties included in this structure. + size_t GetQtyProperties() {return vProperties.size();} + + //! Get the quantity of properties of a certain type included in this structure. + size_t GetQtyPropertyType(CSProperties::PropertyType type); + + //! Get a properties array of a certian type + std::vector GetPropertyByType(CSProperties::PropertyType type); + + //! Get the edges of all includes primitives and add to the desired grid direction. \param nu Direction of grid (x=0,y=1,z=2). + bool InsertEdges2Grid(int nu); + + //! Check whether the structure is valid. + virtual bool isGeometryValid(); + //! Update all primitives and properties e.g. with respect to changed parameter settings. \return Gives an error message in case of a found error. + std::string Update(); + + //! Get an array containing the absolute size of the current structure. + double* GetObjectArea(); + + //! Delete and clear all objects includes. This will result in an empty structure. + void clear(); + + //! Write this structure to an existing XML-node. + /*! + \param rootNode XML-Node to write this structure into. + \param parameterised Include full parameters (default) or parameter-values only. + */ + virtual bool Write2XML(TiXmlNode* rootNode, bool parameterised=true, bool sparse=false); + //! Write this structure to a file. + /*! + \param file Filename to write this structure into. Will create a new file or overwrite an existing one! + \param parameterised Include full parameters (default) or parameter-values only. + */ + virtual bool Write2XML(const char* file, bool parameterised=true, bool sparse=false); + virtual bool Write2XML(std::string file, bool parameterised=true, bool sparse=false); + + //! Read a structure from file. + /*! + \return Will return a string with possible error-messages! + \param file Filename to read this structure from. + */ + const char* ReadFromXML(const char* 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. + */ + const char* ReadFromXML(TiXmlNode* rootNode); + + //! Get a Info-Line containing lib-name, -version etc. + static std::string GetInfoLine(bool shortInfo=false); + +protected: + ParameterSet* clParaSet; + CSRectGrid clGrid; + CSBackgroundMaterial m_BG_Mat; + std::vector vProperties; + bool ReadPropertyPrimitives(TiXmlElement* PropNode, CSProperties* prop); + + void UpdateIDs(); + + CoordinateSystem m_MeshType; + + unsigned int maxID; + + double ObjArea[6]; + double dDrawingTol; + + std::string ErrString; + unsigned int UniqueIDCounter; +}; + + diff --git a/CSXCAD/src/ParameterCoord.cpp b/CSXCAD/src/ParameterCoord.cpp new file mode 100644 index 0000000..62da688 --- /dev/null +++ b/CSXCAD/src/ParameterCoord.cpp @@ -0,0 +1,261 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "ParameterCoord.h" +#include "tinyxml.h" +#include + +double* TransformCoordSystem(const double* inCoord, double* out, CoordinateSystem CS_In, CoordinateSystem CS_out) +{ + double in[3] = {inCoord[0],inCoord[1],inCoord[2]}; + switch (CS_In) + { + case CARTESIAN: //input coords are cartesian + switch (CS_out) + { + default: //unknown transform --> just copy + case CARTESIAN: // transform cartesian --> cartesian + for (int n=0;n<3;++n) + out[n] = in[n]; //just copy + break; + case CYLINDRICAL: // transform cartesian --> cylindrical + out[0] = sqrt(in[0]*in[0]+in[1]*in[1]); // r = sqrt(x²+y²) + out[1] = atan2(in[1],in[0]); //alpha = atan2(y,x) + out[2] = in[2]; //z==z + break; + } + break; + case CYLINDRICAL: //input coords are cylindrical + switch (CS_out) + { + case CARTESIAN: // transform cylindrical --> cartesian + out[0] = in[0] * cos(in[1]); // x = r * cos(alpha) + out[1] = in[0] * sin(in[1]); // y = r * sin(alpha) + out[2] = in[2]; // z = z + break; + default: //unknown transform --> just copy + case CYLINDRICAL: // transform cylindrical --> cylindrical + for (int n=0;n<3;++n) + out[n] = in[n]; //just copy + break; + } + break; + default: //unknown transform --> just copy + for (int n=0;n<3;++n) + out[n] = in[n]; //just copy + } + return out; +} + +ParameterCoord::ParameterCoord() +{ + m_CoordSystem = UNDEFINED_CS; + for (int n=0;n<3;++n) + m_Coords[n] = new ParameterScalar(); + Update(); +} + +ParameterCoord::ParameterCoord(ParameterSet* ParaSet) +{ + m_CoordSystem = UNDEFINED_CS; + for (int n=0;n<3;++n) + m_Coords[n] = new ParameterScalar(ParaSet,0); + Update(); +} + +ParameterCoord::ParameterCoord(CoordinateSystem cs) +{ + m_CoordSystem = cs; + for (int n=0;n<3;++n) + m_Coords[n] = new ParameterScalar(); + Update(); +} + +ParameterCoord::ParameterCoord(ParameterSet* ParaSet, const double value[3]) +{ + m_CoordSystem = UNDEFINED_CS; + for (int n=0;n<3;++n) + m_Coords[n] = new ParameterScalar(ParaSet, value[n]); + Update(); +} + +ParameterCoord::ParameterCoord(ParameterSet* ParaSet, const std::string value[3]) +{ + m_CoordSystem = UNDEFINED_CS; + for (int n=0;n<3;++n) + m_Coords[n] = new ParameterScalar(ParaSet, value[n]); + Update(); +} + +ParameterCoord::ParameterCoord(ParameterCoord* pc) +{ + m_CoordSystem = UNDEFINED_CS; + for (int n=0;n<3;++n) + m_Coords[n]=NULL; + Copy(pc); +} + +ParameterCoord::~ParameterCoord() +{ + for (int n=0;n<3;++n) + { + delete m_Coords[n]; + m_Coords[n]=NULL; + } +} + +void ParameterCoord::SetParameterSet(ParameterSet *paraSet) +{ + for (int n=0;n<3;++n) + m_Coords[n]->SetParameterSet(paraSet); + Update(); +} + +void ParameterCoord::SetCoordinateSystem(CoordinateSystem cs, CoordinateSystem fallBack_cs) +{ + if (cs!=UNDEFINED_CS) + return SetCoordinateSystem(cs); + return SetCoordinateSystem(fallBack_cs); +} + +int ParameterCoord::SetValue(int ny, std::string value) +{ + if ((ny<0) || (ny>2)) + return -1; + int EC = m_Coords[ny]->SetValue(value); + Update(); + return EC; +} + +void ParameterCoord::SetValue(int ny, double value) +{ + if ((ny<0) || (ny>2)) + return; + m_Coords[ny]->SetValue(value); + Update(); +} + +double ParameterCoord::GetValue(int ny) +{ + if ((ny<0) || (ny>2)) + return nan(""); + return m_Coords[ny]->GetValue(); +} + +const std::string ParameterCoord::GetValueString(int ny) const +{ + if ((ny<0) || (ny>2)) + return "nan"; + return m_Coords[ny]->GetValueString(); +} + +double ParameterCoord::GetCoordValue(int ny, CoordinateSystem cs) +{ + if ((ny<0) || (ny>2)) + return nan(""); + return GetCoords(cs)[ny]; +} + +ParameterScalar* ParameterCoord::GetCoordPS(int ny) +{ + if ((ny>=0) && (ny<3)) + return m_Coords[ny]; + return 0; +} + +const double* ParameterCoord::GetNativeCoords() const +{ + switch (m_CoordSystem) + { + default: + case CARTESIAN: + return GetCartesianCoords(); + case CYLINDRICAL: + return GetCylindricalCoords(); + } + return NULL; //this should not happen... +} + +const double* ParameterCoord::GetCoords(CoordinateSystem cs) const +{ + switch (cs) + { + case CARTESIAN: + return GetCartesianCoords(); + case CYLINDRICAL: + return GetCylindricalCoords(); + default: + return GetNativeCoords(); + } +} + +bool ParameterCoord::Evaluate(std::string *ErrStr) +{ + int EC=0; + bool bOK=true; + 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)) + { + std::stringstream stream; + stream << std::endl << "Error in ParameterCoord (component: " << i << "): "; + ErrStr->append(stream.str()); + PSErrorCode2Msg(EC,ErrStr); + } + } + return bOK; +} + +void ParameterCoord::Copy(ParameterCoord* pc) +{ + m_CoordSystem = pc->m_CoordSystem; + for (int n=0;n<3;++n) + { + delete m_Coords[n]; + m_Coords[n] = new ParameterScalar(pc->m_Coords[n]); + } + Update(); +} + +void ParameterCoord::Update() +{ + double coords[3] = {m_Coords[0]->GetValue(),m_Coords[1]->GetValue(),m_Coords[2]->GetValue()}; + TransformCoordSystem(coords, m_CartesianCoords, m_CoordSystem, CARTESIAN); + TransformCoordSystem(coords, m_CylindricalCoords, m_CoordSystem, CYLINDRICAL); +} + +bool ParameterCoord::Write2XML(TiXmlElement *elem, bool parameterised) +{ + if (elem==NULL) + return false; + WriteTerm(*m_Coords[0],*elem,"X",parameterised); + WriteTerm(*m_Coords[1],*elem,"Y",parameterised); + WriteTerm(*m_Coords[2],*elem,"Z",parameterised); + return true; +} + +bool ParameterCoord::ReadFromXML(TiXmlElement *elem) +{ + if (elem==NULL) + return false; + if (ReadTerm(*m_Coords[0],*elem,"X")==false) return false; + if (ReadTerm(*m_Coords[1],*elem,"Y")==false) return false; + if (ReadTerm(*m_Coords[2],*elem,"Z")==false) return false; + return true; +} diff --git a/CSXCAD/src/ParameterCoord.h b/CSXCAD/src/ParameterCoord.h new file mode 100644 index 0000000..3a101dc --- /dev/null +++ b/CSXCAD/src/ParameterCoord.h @@ -0,0 +1,90 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef PARAMETERCOORD_H +#define PARAMETERCOORD_H + +#include "ParameterObjects.h" + +//! This class can hold a parameterized coordinate, defined in different coordinate systems. +class CSXCAD_EXPORT ParameterCoord +{ +public: + ParameterCoord(); + ParameterCoord(ParameterSet* ParaSet); + ParameterCoord(CoordinateSystem cs); + ParameterCoord(ParameterSet* ParaSet, const double value[3]); + ParameterCoord(ParameterSet* ParaSet, const std::string value[3]); + ParameterCoord(ParameterCoord* pc); + ~ParameterCoord(); + + void SetParameterSet(ParameterSet *paraSet); + + //! Set the coordinate system used for this coordinates + void SetCoordinateSystem(CoordinateSystem cs) {m_CoordSystem=cs; Update();} + //! Convienient method to set the coordinate system, including a fall back if primary coordinate system is undefined. + void SetCoordinateSystem(CoordinateSystem cs, CoordinateSystem fallBack_cs); + //! Get the coordinate system that has been set for this coordinate + CoordinateSystem GetCoordinateSystem() const {return m_CoordSystem;} + + int SetValue(int ny, std::string value); + void SetValue(int ny, double value); + + //! Get the native coordinate values + double GetValue(int ny); + //! Get the native coordinate values as string + const std::string GetValueString(int ny) const; + //! Get the internal scalar parameter, use carefully... + ParameterScalar* GetCoordPS(int ny); + + //! Get the coordinate in the given coordinate system + double GetCoordValue(int ny, CoordinateSystem cs); + + const double* GetNativeCoords() const; + const double* GetCartesianCoords() const {return m_CartesianCoords;} + const double* GetCylindricalCoords() const {return m_CylindricalCoords;} + const double* GetCoords(CoordinateSystem cs) const; + + //! Evaluate the parametric coordinates and return an error message. This methode should be called before requesting coordinate values to check for valid parametric coordinates. + bool Evaluate(std::string *ErrStr); + + // Copy all values and parameter from pc to this. + void Copy(ParameterCoord* pc); + + //! Write this coords to a XML-node. + bool Write2XML(TiXmlElement *elem, bool parameterised=true); + //! Read coords from a XML-node. + bool ReadFromXML(TiXmlElement *elem); + +protected: + //! Update/evaluate the internal data structure + void Update(); + ParameterScalar* m_Coords[3]; + + //! Coordinate system used for this coordinate + CoordinateSystem m_CoordSystem; + + //! evaluated cartesian coords + double m_CartesianCoords[3]; + //! evaluated cylindrical coords + double m_CylindricalCoords[3]; +}; + +//! Convert a given coordinate into another coordinate system +double* CSXCAD_EXPORT TransformCoordSystem(const double* in, double* out, CoordinateSystem CS_In, CoordinateSystem CS_out); + +#endif // PARAMETERCOORD_H diff --git a/CSXCAD/src/ParameterObjects.cpp b/CSXCAD/src/ParameterObjects.cpp new file mode 100644 index 0000000..161d4dd --- /dev/null +++ b/CSXCAD/src/ParameterObjects.cpp @@ -0,0 +1,713 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include "ParameterObjects.h" +#include +#include +#include "tinyxml.h" +#include "CSFunctionParser.h" +#include "CSUseful.h" + +bool ReadTerm(ParameterScalar &PS, TiXmlElement &elem, const char* attr, double val) +{ + double dHelp; + + PS.SetValue(val); // set default value + const char* chHelp=elem.Attribute(attr); + if (chHelp==NULL) + return false; + PS.SetValue(chHelp); // set string value if found + return true; +} + +void WriteTerm(ParameterScalar &PS, TiXmlElement &elem, const char* attr, bool mode, bool scientific) +{ + if (PS.GetMode() && mode) + elem.SetAttribute(attr,PS.GetString().c_str()); + else + { + if (PS.GetValue()==NAN) + return; + if (scientific) + { + char doubleVal[50]; + sprintf(doubleVal,"%e",PS.GetValue()); + elem.SetAttribute(attr,doubleVal); + } + else + elem.SetDoubleAttribute(attr,PS.GetValue()); + } +} + +bool ReadVectorTerm(ParameterScalar PS[3], TiXmlElement &elem, std::string attr, double val, const char delimiter) +{ + return ReadVectorTerm(PS, elem, attr.c_str(), val, delimiter); +} + +bool ReadVectorTerm(ParameterScalar PS[3], TiXmlElement &elem, const char* attr, double val, const char delimiter) +{ + //initialize with default value + for (int n=0;n<3;++n) + PS[n].SetValue(val); + + const char* values = elem.Attribute(attr); + if (values==NULL) + return false; + std::vector val_list = SplitString2Vector(values, delimiter); + if (val_list.size()>3) + return false; + + for (int n=0;n<3;++n) + PS[n].SetValue(val); + for (int n=0;n<(int)val_list.size();++n) + { + std::string sHelp=val_list.at(n); + bool ok; + double val = String2Double(sHelp, ok); + if (ok) + PS[n].SetValue(val); + else + PS[n].SetValue(sHelp.c_str()); + } + return true; +} + +void WriteVectorTerm(ParameterScalar PS[3], TiXmlElement &elem, std::string attr, bool mode, bool scientific, const char delimiter) +{ + WriteVectorTerm(PS, elem, attr.c_str(), mode, scientific, delimiter); +} + +void WriteVectorTerm(ParameterScalar PS[3], TiXmlElement &elem, const char* attr, bool mode, bool sci, const char delimiter) +{ + std::stringstream ss; + if (sci) + ss << std::scientific; + for (int i=0;i<3;++i) + { + if (PS[i].GetMode() && mode) + ss << PS[i].GetString(); + else if (PS[i].GetValue()==NAN) + ss << "NAN" << std::endl; + else + ss << PS[i].GetValue(); + if (i<2) + ss << delimiter; + } + elem.SetAttribute(attr,ss.str().c_str()); +} + +Parameter::Parameter() +{ + bModified=true; + dValue=0; + Type=Const; + bSweep=true; +// Set=NULL; +} + +Parameter::Parameter(const std::string Paraname, double val) +{ + sName=Paraname; + SetValue(val); + Type=Const; + bSweep=true; +// Set=NULL; +} + +Parameter::~Parameter() +{ +// if (Set!=NULL) Set->RemoveParameter(this); +} + + +void Parameter::PrintSelf(FILE* /*out*/) +{ + fprintf(stderr," Parameter: %s Value: %f Type %d\n\n",sName.c_str(),dValue,Type); +} + +bool Parameter::Write2XML(TiXmlNode& root) +{ + TiXmlElement *elem=NULL; + if (Type==Const) + { + elem = new TiXmlElement("Parameter"); + elem->SetAttribute("Type","Const"); + } + else elem = root.ToElement(); + if (elem==NULL) return false; + elem->SetAttribute("name",sName.c_str()); + elem->SetAttribute("Sweep",bSweep); + elem->SetDoubleAttribute("value",dValue); + if (Type==Const) root.LinkEndChild(elem); + return true; +} + +bool Parameter::ReadFromXML(TiXmlNode &root) +{ + TiXmlElement *elem = root.ToElement(); + if (elem==NULL) return false; + + int iAtt=0; + if (elem->QueryIntAttribute("Sweep",&iAtt)!=TIXML_SUCCESS) bSweep=true; + else if (iAtt>0) bSweep=true; + else bSweep=false; + + double val=0; + if (elem->QueryDoubleAttribute("value",&val)!=TIXML_SUCCESS) return false; + SetValue(val); + + const char* att=elem->Attribute("name"); + if (att==NULL) sName=std::string(); + else sName=std::string(att); + + return true; +} + +Parameter* Parameter::GetParameterFromXML(TiXmlNode &/*root*/) +{ + return NULL; +} + +LinearParameter::LinearParameter() : Parameter() +{ + Type=Linear; + dMin=dMax=dStep=0; +} + +LinearParameter::LinearParameter(const std::string Paraname, double val, double min, double max, double step) : Parameter(Paraname,val) +{ + //sName=string(Paraname); + if (maxType==Linear) + { + dMin=parameter->dMin; + dMax=parameter->dMax; + dStep=parameter->dStep; + } + else + { + Type=Linear; + dMin=dMax=dStep=0; + } + SetValue(dValue); +} + +void LinearParameter::SetValue(double val) +{ + if (val>dMax) val=dMax; + else if (valdMax) dValue=dValue-dStep; + } + bModified=true; +} + +bool LinearParameter::IncreaseStep() +{ + if (dValue+dStep>dMax) return false; + SetValue(dValue+dStep); + return true; +} + +void LinearParameter::PrintSelf(FILE* /*out*/) +{ + fprintf(stderr," Parameter: %s Value: %f\n from %f to %f; Stepsize: %f\n",sName.c_str(),dValue,dMin,dMax,dStep); +} + +bool LinearParameter::Write2XML(TiXmlNode& root) +{ + TiXmlElement para("Parameter"); + para.SetAttribute("Type","Linear"); + Parameter::Write2XML(para); + para.SetDoubleAttribute("min",dMin); + para.SetDoubleAttribute("max",dMax); + para.SetDoubleAttribute("step",dStep); + root.InsertEndChild(para); + return true; +} + +bool LinearParameter::ReadFromXML(TiXmlNode &root) +{ + TiXmlElement *elem = root.ToElement(); + if (elem==NULL) return false; + + if (elem->QueryDoubleAttribute("min",&dMin)!=TIXML_SUCCESS) return false; + if (elem->QueryDoubleAttribute("max",&dMax)!=TIXML_SUCCESS) return false; + if (elem->QueryDoubleAttribute("step",&dStep)!=TIXML_SUCCESS) return false; + + if (Parameter::ReadFromXML(root)==false) return false; +// const char* att=elem->Attribute("name"); +// if (att==NULL) return false; +// sName=string(att); + +// if (elem->QueryDoubleAttribute("value",&dValue)!=TIXML_SUCCESS) return false; + + return true; +} + + +ParameterSet::ParameterSet(void) +{ + bModified=true; +} + +ParameterSet::~ParameterSet(void) +{ + clear(); +} + +size_t ParameterSet::LinkParameter(Parameter* newPara) +{ + vParameter.push_back(newPara); +// newPara->ParameterSet(this); + return vParameter.size(); +} + +size_t ParameterSet::DeleteParameter(size_t index) +{ + if (index>=vParameter.size()) return vParameter.size(); + std::vector::iterator pIter=vParameter.begin(); + vParameter.erase(pIter+index); + + return vParameter.size(); +} + +size_t ParameterSet::DeleteParameter(Parameter* para) +{ + std::vector::iterator pIter=vParameter.begin(); + while (pIter!=vParameter.end()) + { + if (*pIter==para) + { + vParameter.erase(pIter); + return vParameter.size(); + } + ++pIter; + } + return vParameter.size(); +} + +void ParameterSet::clear() +{ + for (size_t i=0; iGetModified()==true) return true; + return false; +} + +void ParameterSet::SetModified(bool mod) +{ + if (mod==true) + { + bModified=true; + return; + } + bModified=false; + for (size_t i=0; iSetModified(false); +} + +double* ParameterSet::GetValueArray(double *array) +{ + if (array==NULL) return array; + for (size_t i=0; iGetValue(); + } + return array; +} + +int ParameterSet::CountSweepSteps(int SweepMode) +{ + int count=0; + switch (SweepMode) + { + case 1: + for (size_t i=0; iGetSweep()) + { + if (count==0) count=vParameter.at(i)->CountSteps(); + else count*=vParameter.at(i)->CountSteps(); + } + return count; + break; + case 2: + for (size_t i=0; iGetSweep()) count+=vParameter.at(i)->CountSteps(); + return count; + break; + } + return 0; +} + +void ParameterSet::InitSweep() +{ + for (size_t i=0; iGetSweep()) + { + vParameter.at(i)->Save(); + vParameter.at(i)->InitSweep(); + } + SweepPara=0; +} + +void ParameterSet::EndSweep() +{ + for (size_t i=0; iGetSweep()) + { + vParameter.at(i)->Restore(); + } +} + +bool ParameterSet::NextSweepPos(int SweepMode) +{ + switch (SweepMode) + { + case 1: + { + int level=vParameter.size()-1; + while (level>=0) + { + if (vParameter.at(level)->GetSweep()) + { + if (vParameter.at(level)->IncreaseStep()) return true; + else + { + vParameter.at(level)->InitSweep(); + --level; + } + } + else --level; + } + return false; + break; + } + case 2: + if ((unsigned int)SweepPara>=vParameter.size()) return false; + if (vParameter.at(SweepPara)->GetSweep()) + { + if (vParameter.at(SweepPara)->IncreaseStep()) return true; + else ++SweepPara; + return NextSweepPos(SweepMode); + } + else + { + ++SweepPara; + return NextSweepPos(SweepMode); + } + break; + } + return false; +} + + +const std::string ParameterSet::GetParameterString(const std::string spacer) +{ + std::string ParameterString; + for (size_t i=0; i0) ParameterString+=spacer; + ParameterString+=vParameter.at(i)->GetName(); + } + return ParameterString; +} + +const std::string ParameterSet::GetParameterValueString(const std::string spacer, bool ValuesOnly) +{ + std::string ParameterValueString; + for (size_t i=0; i0) ParameterValueString+=spacer; + if (!ValuesOnly) + { + ParameterValueString+=vParameter.at(i)->GetName(); + ParameterValueString+="="; + } + std::ostringstream os; + os << vParameter.at(i)->GetValue(); + ParameterValueString+=os.str(); + } + return ParameterValueString.c_str(); +} + +void ParameterSet::PrintSelf(FILE* out) +{ + fprintf(out," Parameter-Set Printout, Qty of Parameter: %d\n",(int)vParameter.size()); + for (size_t i=0; iPrintSelf(out); + } +} + +bool ParameterSet::Write2XML(TiXmlNode& root) +{ + TiXmlElement pSet("ParameterSet"); + //pSet.SetAttribute("QtyParameter",(int)vParameter.size()); + for (size_t i=0;iWrite2XML(pSet); + + root.InsertEndChild(pSet); + return true; +} + +bool ParameterSet::ReadFromXML(TiXmlNode &root) +{ + TiXmlNode* paraNode = root.FirstChild("Parameter"); + while (paraNode!=NULL) + { + TiXmlElement *elem = paraNode->ToElement(); + if (elem!=NULL) + { + const char* att=elem->Attribute("Type"); + if (att!=NULL) + { + Parameter* newPara=NULL; + if (strcmp(att,"Const")==0) newPara = new Parameter(); + else if (strcmp(att,"Linear")==0) newPara = new LinearParameter(); + if (newPara!=NULL) + { + if (newPara->ReadFromXML(*elem)==true) this->InsertParameter(newPara); + } + } + } + paraNode=paraNode->NextSiblingElement("Parameter"); + }; + return true; +} + + +ParameterScalar::ParameterScalar() +{ + clParaSet=NULL; + bModified=true; + ParameterMode=false; + sValue.clear(); + dValue=0; +} + +ParameterScalar::ParameterScalar(ParameterSet* ParaSet, const std::string value) +{ + SetParameterSet(ParaSet); + SetValue(value); +} + +ParameterScalar::ParameterScalar(ParameterSet* ParaSet, double value) +{ + SetParameterSet(ParaSet); + bModified=true; + SetValue(value); +} + +ParameterScalar::ParameterScalar(ParameterScalar* ps) +{ + Copy(ps); +} + +ParameterScalar::~ParameterScalar() +{ +} + +void ParameterScalar::SetParameterSet(ParameterSet *paraSet) +{ + clParaSet=paraSet; +} + +int ParameterScalar::SetValue(const std::string value, bool Eval) +{ + if (value.empty()) return -1; + + //check if string is only a plain double + char *pEnd; + double val = strtod(value.c_str(),&pEnd); + if (*pEnd == 0) + SetValue(val); + + ParameterMode=true; + bModified=true; + sValue=value; + + if (Eval) return Evaluate(); + + return 0; +} + +void ParameterScalar::SetValue(double value) +{ + ParameterMode=false; + dValue=value; + sValue.clear(); +} + +double ParameterScalar::GetValue() const +{ + return dValue; +} + +const std::string ParameterScalar::GetValueString() const +{ + if (ParameterMode) + return sValue; + std::stringstream numString; + numString << dValue; + return numString.str(); +} + +int ParameterScalar::Evaluate() +{ + if (ParameterMode==false) return 0; + if (clParaSet!=NULL) + bModified = bModified || clParaSet->GetModified(); + if (bModified==false) + return 0; + + CSFunctionParser fParse; + dValue=0; + + if (clParaSet!=NULL) + fParse.Parse(sValue,clParaSet->GetParameterString()); + else + fParse.Parse(sValue,""); + + if (fParse.GetParseErrorType()!=FunctionParser::FP_NO_ERROR) return fParse.GetParseErrorType()+100; + bModified=false; + + if (clParaSet!=NULL) + { + double *vars = new double[clParaSet->GetQtyParameter()]; + vars=clParaSet->GetValueArray(vars); + dValue=fParse.Eval(vars); + delete[] vars;vars=NULL; + } + else + dValue=fParse.Eval(NULL); + return fParse.EvalError(); +} + +double ParameterScalar::GetEvaluated(double* ParaValues, int &EC) +{ + if (ParameterMode==false) return dValue; + CSFunctionParser fParse; + fParse.Parse(sValue,clParaSet->GetParameterString()); + if (fParse.GetParseErrorType()!=FunctionParser::FP_NO_ERROR) + { + EC = fParse.GetParseErrorType()+100; + return 0; + } + double dvalue = fParse.Eval(ParaValues); + EC = fParse.EvalError(); + return dvalue; +} + +void ParameterScalar::Copy(ParameterScalar* ps) +{ + SetParameterSet(ps->clParaSet); + bModified=ps->bModified; + ParameterMode=ps->ParameterMode; + sValue=std::string(ps->sValue); + dValue=ps->dValue; +} + +std::string PSErrorCode2Msg(int code) +{ + std::string msg; + PSErrorCode2Msg(code,&msg); + return msg; +} + +void PSErrorCode2Msg(int code, std::string *msg) +{ + switch (code) + { + case -1: + msg->append("Internal Error"); + break; + case 0: + msg->append("No Error"); + break; + case 1: + msg->append("Division by zero"); + break; + case 2: + msg->append("sqrt error (sqrt of a negative value)"); + break; + case 3: + msg->append("log error (logarithm of a negative value)"); + break; + case 4: + msg->append("trigonometric error (asin or acos of illegal value)"); + break; + case 5: + msg->append("Maximum recursion level reached"); + break; + case 100: + msg->append("Syntax error (check Parameter)"); + break; + case 101: + msg->append("Mismatched parenthesis"); + break; + case 102: + msg->append("Missing \')\'"); + break; + case 103: + msg->append("Empty parentheses"); + break; + case 104: + msg->append("Syntax error: Operator expected"); + break; + case 105: + msg->append("Not enough memory"); + break; + case 106: + msg->append("An unexpected error occurred"); + break; + case 107: + msg->append("Syntax error in parameters"); + break; + case 108: + msg->append("Illegal number of parameters to function"); + break; + case 109: + msg->append("Syntax error: Premature end of string"); + break; + case 110: + msg->append("Syntax error: Expecting ( after function"); + break; + }; +} diff --git a/CSXCAD/src/ParameterObjects.h b/CSXCAD/src/ParameterObjects.h new file mode 100644 index 0000000..9e9da49 --- /dev/null +++ b/CSXCAD/src/ParameterObjects.h @@ -0,0 +1,251 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#ifndef _PARAMETEROBJECTS_H_ +#define _PARAMETEROBJECTS_H_ +/* + * Author: Thorsten Liebig + * Date: 03-12-2008 + * Lib: CSXCAD + * Version: 0.1a + */ + +#include +#include +#include +#include +#include +#include "CSXCAD_Global.h" + +class Parameter; +class LinearParameter; +class ParameterSet; +class ParameterScalar; +class TiXmlNode; +class TiXmlElement; + +bool ReadTerm(ParameterScalar &PS, TiXmlElement &elem, const char* attr, double val=0.0); +void WriteTerm(ParameterScalar &PS, TiXmlElement &elem, const char* attr, bool mode, bool scientific=true); + +bool ReadVectorTerm(ParameterScalar PS[3], TiXmlElement &elem, std::string attr, double val=0.0, const char delimiter=','); +bool ReadVectorTerm(ParameterScalar PS[3], TiXmlElement &elem, const char* attr, double val=0.0, const char delimiter=','); +void WriteVectorTerm(ParameterScalar PS[3], TiXmlElement &elem, std::string attr, bool mode, bool scientific=true, const char delimiter=','); +void WriteVectorTerm(ParameterScalar PS[3], TiXmlElement &elem, const char* attr, bool mode, bool scientific=true, const char delimiter=','); + +class CSXCAD_EXPORT Parameter +{ +public: + Parameter(); + Parameter(const std::string Paraname, double val); + Parameter(const Parameter* parameter) {sName=std::string(parameter->sName);dValue=parameter->dValue;bModified=true;Type=parameter->Type;bSweep=parameter->bSweep;} + virtual ~Parameter(); + enum ParameterType + { + Const, Linear + }; + ParameterType GetType() {return Type;} + + const std::string GetName() {return sName;} + void SetName(const std::string Paraname) {sName=std::string(Paraname);bModified=true;} + + virtual double GetValue() {return dValue;} + virtual void SetValue(double val) {dValue=val;bModified=true;} + + bool GetModified() {return bModified;} + void SetModified(bool mod) {bModified=mod;} + + virtual bool GetSweep() {return false;} ///const parameter can't sweep + void SetSweep(bool mod) {bSweep=mod;} + + virtual void InitSweep() {} + void Save() {dValueSaved=dValue;} + void Restore() {dValue=dValueSaved;} + + virtual bool IncreaseStep() {return false;} ///return false if no more sweep step available + virtual int CountSteps() {return 1;} + + virtual void PrintSelf(FILE* out=stdout); + + virtual bool Write2XML(TiXmlNode& root); + virtual bool ReadFromXML(TiXmlNode &root); + Parameter* GetParameterFromXML(TiXmlNode &root); + + virtual Parameter* Clone() {return new Parameter(this);} + + Parameter* ToConst() { return ( this && Type == Const ) ? this : 0; } /// Cast Parameter to a more defined type. Will return null if not of the requested type. + LinearParameter* ToLinear() { return ( this && Type == Linear ) ? (LinearParameter*) this : 0; } /// Cast Parameter to a more defined type. Will return null if not of the requested type. + +protected: + std::string sName; + double dValue; + double dValueSaved; + bool bModified; + bool bSweep; + ParameterType Type; +}; + +class CSXCAD_EXPORT LinearParameter : public Parameter +{ +public: + LinearParameter(); + LinearParameter(const std::string Paraname, double val, double min, double max, double step); + //copy-constructor + LinearParameter(const LinearParameter *parameter); + virtual ~LinearParameter(void) {} + + virtual void SetValue(double val); + + virtual bool GetSweep() {return bSweep;} + + virtual void InitSweep() {dValue=dMin;} + + virtual bool IncreaseStep(); + virtual int CountSteps() {return (int)((dMax-dMin)/dStep)+1;} + + double GetMin() {return dMin;} + void SetMin(double min) {dMin=min; if (dMaxClone());} + //! This will add/link the given parameter into the ParameterSet and take ownership \return number of current parameter + virtual size_t LinkParameter(Parameter* newPara); + //! Same as LinkParameter \sa LinkParameter \return number of current parameter + virtual size_t AddParameter(Parameter* newPara) {return LinkParameter(newPara);} + //! Delete a Parameter at given index \return number of current parameter + virtual size_t DeleteParameter(size_t index); + //! Delete a given Parameter \return number of current parameter + virtual size_t DeleteParameter(Parameter* para); + //! Get the Parameter at the given index + Parameter* GetParameter(size_t index) {if (index vParameter; + bool bModified; + int SweepPara; +}; + +void PSErrorCode2Msg(int code, std::string* msg); +std::string PSErrorCode2Msg(int code); + +class CSXCAD_EXPORT ParameterScalar +{ +public: + enum EvaluateErrorType + { + NO_ERROR + }; + ParameterScalar(); + ParameterScalar(ParameterSet* ParaSet, double value); + ParameterScalar(ParameterSet* ParaSet, const std::string value); + ParameterScalar(ParameterScalar* ps); + ~ParameterScalar(); + + void SetParameterSet(ParameterSet *paraSet); + + int SetValue(const std::string value, bool Eval=true); ///returns eval-error-code + void SetValue(double value); + + bool GetMode() const {return ParameterMode;} + const std::string GetString() const {return sValue;} + + double GetValue() const; + + const std::string GetValueString() const; + + //returns error-code + int Evaluate(); + + double GetEvaluated(double* ParaValues, int &EC); + + // Copy all values and parameter from ps to this. + void Copy(ParameterScalar* ps); + +protected: + ParameterSet* clParaSet; + bool bModified; + bool ParameterMode; + std::string sValue; + double dValue; +}; + +#endif diff --git a/CTB/AddElement2Port.m b/CTB/AddElement2Port.m new file mode 100644 index 0000000..36019b2 --- /dev/null +++ b/CTB/AddElement2Port.m @@ -0,0 +1,83 @@ +function net = AddElement2Port(net, port, type, value, varargin) +% function net = AddElement2Port(net, port, type, value, varargin) +% +% Add a linear network element to the given ports +% +% arguments: +% port: number of ports to apply the element +% type: type of network element: +% 'C_se' : series capacity +% 'C_sh' : shunt capacity +% 'L_se' : series inductance +% 'L_sh' : shunt inductance +% 'R_se' : series resistance +% 'R_sh' : shunt resistance +% 'Z_se' : series impedance +% 'Y_se' : shunt addmitance +% +% See also: InitNetwork, SetPortTermination, ApplyCurrent2Port, +% ApplyRFPower2Port +% +% ------ +% Cuicuit Toolbox (https://github.com/thliebig/CTB) +% (c) Thorsten Liebig, 2013 + +if (numel(port)>1) + if (numel(value)==1) + value = value*ones(size(port)); + end + for n=1:numel(port) + net = AddElement2Port(net, port(n), type, value(n), varargin); + end + return; +end + +if ((port<1) || (port>net.numPorts)) + error 'invalid port number' +end + +if iscell(type) + for n=1:numel(type) + net = AddElement2Port(net, port, type{n}, value(n), varargin{:}); + end + return +end + +Y = []; +Z = []; + +if (strcmpi(type, 'C_se')) + Z = 1./(2j*pi*net.f*value); +elseif (strcmpi(type, 'C_sh')) + Y = 2j*pi*net.f*value; +elseif (strcmpi(type, 'L_se')) + Z = 2j*pi*net.f*value; +elseif (strcmpi(type, 'L_sh')) + Y = 1./(2j*pi*net.f*value); +elseif (strcmpi(type, 'R_se')) + Z = value*ones(size(net.f)); +elseif (strcmpi(type, 'R_sh')) + Y = 1/value*ones(size(net.f)); +elseif (strcmpi(type, 'Z_se')) + Z = value; +elseif (strcmpi(type, 'Y_sh')) + Y = value; +else + error 'unknown element type' +end + +if (~isempty(Y)) + net.ABCD{port} = a_mul(net.ABCD{port}, a_shunt(Y)); + Y = reshape(Y,1,1,numel(net.f)); + net.y(port,port,:) = net.y(port,port,:) + Y(1,1,:); + net.s = y2s(net.y, net.Z0); + net.z = y2z(net.y); +elseif (~isempty(Z)) + net.ABCD{port} = a_mul(net.ABCD{port}, a_series(Z)); + Z = reshape(Z,1,1,numel(net.f)); + net.z(port,port,:) = net.z(port,port,:) + Z(1,1,:); + net.s = z2s(net.z, net.Z0); + net.y = z2y(net.z); +else + error 'internal error' +end diff --git a/CTB/ApplyCurrent2Port.m b/CTB/ApplyCurrent2Port.m new file mode 100644 index 0000000..6628714 --- /dev/null +++ b/CTB/ApplyCurrent2Port.m @@ -0,0 +1,69 @@ +function [I_port I_orig_port] = ApplyCurrent2Port(net, port, current, varargin) +% function I_port = ApplyCurrent2Port(net, port, current, varargin) +% +% Apply a total current to a given port of your network +% +% arguments: +% port: number of ports to apply the power to +% current: applied total current +% +% output: +% I_port: Total currents going into the ports +% +% See also: InitNetwork, SetPortTermination, AddElement2Port, +% ApplyRFPower2Port +% +% ------ +% Cuicuit Toolbox (https://github.com/thliebig/CTB) +% (c) Thorsten Liebig, 2013 + +if (numel(port)>1) + I_port = zeros(net.numPorts,net.numFreq); + I_orig_port = zeros(net.numPorts,net.numFreq); + for n=1:numel(port) + [I_p I_op] = ApplyCurrent2Port(net, port(n), current(n), varargin{:}); + I_port = I_port + I_p; + I_orig_port = I_orig_port + I_op; + end + return +end + +if ((port<1) || (port>net.numPorts)) + error 'invalid port number' +end + +if (numel(current)==1) + current = current*ones(size(net.f)) +end + +if (numel(net.Z0)==1) + Z0 = net.Z0*ones(net.numPorts,1); +else + Z0 = net.Z0; +end + +z_term = net.z; +for n=1:net.numPorts + z_term(n,n,:) = z_term(n,n,:) + Z0(n); +end + +z_mat = z_term; +z_mat(port,:,:) = []; +z_mat(:,port,:) = []; + +port_other = 1:net.numPorts; +port_other(port) = []; + +I_port(port,:) = current; + +for fn = 1:numel(net.f) + z_port_vec = -1*squeeze(z_term(port_other,port,fn)); + I_port(port_other,fn) = squeeze(z_mat(:,:,fn))\z_port_vec * current(fn); +end + +I_orig_port=I_port*0; +for n=1:net.numPorts + C = reshape(net.ABCD{n}(2,1,:),1,numel(net.f)); + D = reshape(net.ABCD{n}(2,2,:),1,numel(net.f)); + I_orig_port(n,:) = (Z0(n)*C + D) .* I_port(n,:); +end diff --git a/CTB/ApplyRFPower2Port.m b/CTB/ApplyRFPower2Port.m new file mode 100644 index 0000000..2464038 --- /dev/null +++ b/CTB/ApplyRFPower2Port.m @@ -0,0 +1,43 @@ +function [I_port I_orig_port] = ApplyRFPower2Port(net, port, power, varargin) +% function I_port = ApplyRFPower2Port(net, port, power, varargin) +% +% Apply a RF power to a given port of your network +% +% arguments: +% port: number of ports to apply the power to +% power: applied power in W +% +% output: +% I_port: Total currents going into the ports +% +% See also: InitNetwork, SetPortTermination, AddElement2Port, +% ApplyCurrent2Port +% +% ------ +% Cuicuit Toolbox (https://github.com/thliebig/CTB) +% (c) Thorsten Liebig, 2013 + +if (numel(port)>1) + I_port = zeros(net.numPorts,net.numFreq); + I_orig_port = zeros(net.numPorts,net.numFreq); + for n=1:numel(port) + [I_p I_op] = ApplyRFPower2Port(net, port(n), power(n), varargin{:}); + I_port = I_port + I_p; + I_orig_port = I_orig_port + I_op; + end + return +end + +if ((port<1) || (port>net.numPorts)) + error 'invalid port number' +end + +if (numel(net.Z0)==1) + Z0 = net.Z0*ones(net.numPorts,1); +else + Z0 = net.Z0; +end + +I_tot = sqrt(2*abs(power)/Z0(port)) * (1-squeeze(net.s(port,port,:))) * exp(1j*angle(power)); + +[I_port I_orig_port] = ApplyCurrent2Port(net, port, I_tot, varargin); diff --git a/CTB/InitNetwork.m b/CTB/InitNetwork.m new file mode 100644 index 0000000..960f24e --- /dev/null +++ b/CTB/InitNetwork.m @@ -0,0 +1,53 @@ +function net = InitNetwork(freq, s_para, varargin) +% function net = InitNetwork(freq, s_para, varargin) +% +% Init a new network with a given frequncy vector and scattering parameter set +% +% arguments: +% freq: frequncy vector +% s_para: scattering parameter +% +% example: +% % read some touchstone s-parameter file +% [type,freq,data,ref]=read_touchstone('test.s3p'); +% +% % init network +% net = InitNetwork(freq, data); +% % attach a series capacity to port 2 +% net = AddElement2Port(net, 2, 'C_se', 1e-12); +% % terminate all ports with 50 Ohms +% net = AddElement2Port(net, 1:3, 'R_se', 50); +% % apply 1mW to port 1 and get port currents +% I_tot = ApplyRFPower2Port(net, 1, 1e-3); +% +% See also AddElement2Port, ApplyCurrent2Port, ApplyRFPower2Port, +% read_touchstone, write_touchstone +% +% ------ +% Cuicuit Toolbox (https://github.com/thliebig/CTB) +% (c) Thorsten Liebig, 2013 + +net.Z0 = 50; +net.numFreq = numel(freq); +net.numPorts = size(s_para, 1); +net.f = freq; +net.s = s_para; +net.orig.s = s_para; +net.z = s2z(net.s, net.Z0); +net.y = s2y(net.s, net.Z0); + +ABCD(1,1,1:net.numFreq) = 1; +ABCD(2,2,:) = 1; + +% networks attached to each port +for n=1:net.numPorts + net.ABCD{n} = ABCD; +end + +if (size(s_para, 1) ~= size(s_para, 2)) + error 'n unequal m' +end + +if (size(s_para, 3) ~= net.numFreq) + error 'number of frequencies do not match' +end diff --git a/CTB/Makefile b/CTB/Makefile new file mode 100644 index 0000000..f11dbe8 --- /dev/null +++ b/CTB/Makefile @@ -0,0 +1,14 @@ + +####### Compiler, tools and options +MKDIR = mkdir -p +COPY = cp -at + +# default install path +PREFIX = /usr/local + +INSTALL_PATH = $(PREFIX)/share/CTB + +all: + +install: + $(MKDIR) "$(INSTALL_PATH)/matlab" && $(COPY) "$(INSTALL_PATH)/matlab" *.m && $(COPY) "$(INSTALL_PATH)" license.txt readme.txt diff --git a/CTB/SetPortTermination.m b/CTB/SetPortTermination.m new file mode 100644 index 0000000..f66e9a6 --- /dev/null +++ b/CTB/SetPortTermination.m @@ -0,0 +1,45 @@ +function net = SetPortTermination(net, port, Z0, varargin) +% function net = SetPortTermination(net, port, Z0, varargin) +% +% Set the given port impedance/termination +% +% arguments: +% port: number of ports to apply the termination +% Z0: port impedance +% +% See also: InitNetwork, AddElement2Port, ApplyCurrent2Port, +% ApplyRFPower2Port +% +% ------ +% Cuicuit Toolbox (https://github.com/thliebig/CTB) +% (c) Thorsten Liebig, 2013 + +if (numel(port)>1) + if (numel(Z0)==1) + Z0 = Z0*ones(1,size(port)); + end + for n=1:numel(port) + net = SetPortTermination(net, port(n), Z0(n), varargin); + end + return; +end + +if ((port<1) || (port>net.numPorts)) + error 'invalid port number' +end + +if (numel(net.Z0)==1) + if (net.Z0==Z0) + % nothing needs to be done + return + end + net.Z0 = net.Z0*ones(1,net.numPorts); +end + +if (net.Z0(port)==Z0) + % nothing needs to be done + return +end + +net.Z0(port)=Z0; +net.s = z2s(net.z, net.Z0); diff --git a/CTB/a2s.m b/CTB/a2s.m new file mode 100644 index 0000000..5e55ae4 --- /dev/null +++ b/CTB/a2s.m @@ -0,0 +1,31 @@ +function s = a2s(a,ref) +% s = a2s(a [,ref]) +% +% ABCD to Scattering Matrix transformation (only for 2x2xf matrices) +% +% input: +% a: ABCD matrix 2x2xf (f: number of frequencies) +% ref: (optional) reference impedance (default 50 Ohm) +% +% output: +% s: S-matrix 2x2xf normalized to ref Ohm +% +% Reference: David M. Pozar "Microwave Engineering" +% +% Sebastian Held +% Sep 1 2010 + +if nargin < 2 + Z0 = 50; +else + Z0 = ref; +end + +A = squeeze(a(1,1,:)); +B = squeeze(a(1,2,:)); +C = squeeze(a(2,1,:)); +D = squeeze(a(2,2,:)); +s(1,1,:) = (A + B./Z0 - C.*Z0 - D) ./ (A + B./Z0 + C.*Z0 + D); +s(1,2,:) = 2*(A.*D - B.*C) ./ (A + B./Z0 + C.*Z0 + D); +s(2,1,:) = 2 ./ (A + B./Z0 + C.*Z0 + D); +s(2,2,:) = (-A + B./Z0 - C.*Z0 + D) ./ (A + B./Z0 + C.*Z0 + D); diff --git a/CTB/a_PI.m b/CTB/a_PI.m new file mode 100644 index 0000000..3ae4db8 --- /dev/null +++ b/CTB/a_PI.m @@ -0,0 +1,15 @@ +function a = a_PI(Y1,Y2,Y3) +% a = a_PI(Y1,Y2,Y3) +% +% calculate the ABCD matrix from a PI-circuit +% +% Reference: David M. Pozar "Microwave Engineering" +% +% Thorsten Liebig +% Feb. 2013 + + +a(1,1,:) = 1+Y2./Y3; +a(1,2,:) = 1./Y3; +a(2,1,:) = Y1+Y2+Y1.Y2./Y3; +a(2,2,:) = 1+Y1./Y3; diff --git a/CTB/a_T.m b/CTB/a_T.m new file mode 100644 index 0000000..49a2d30 --- /dev/null +++ b/CTB/a_T.m @@ -0,0 +1,14 @@ +function a = a_T(Z1,Z2,Z3) +% a = a_T(Z1,Z2,Z3) +% +% calculate the ABCD matrix from a T-circuit +% +% Reference: David M. Pozar "Microwave Engineering" +% +% Thorsten Liebig +% Feb. 2013 + +a(1,1,:) = 1+Z1./Z2; +a(1,2,:) = Z1+Z2+Z1.*Z2./Z3; +a(2,1,:) = 1./Z3; +a(2,2,:) = 1+Z2./Z3; diff --git a/CTB/a_mul.m b/CTB/a_mul.m new file mode 100644 index 0000000..c1d2130 --- /dev/null +++ b/CTB/a_mul.m @@ -0,0 +1,28 @@ +function a = a_mul(varargin) +% a = a_mul(varargin) +% +% multiply a number of ABCD matricies +% +% example: +% +% a = a_mul(a1,a2); which is a = a1 * a2; +% +% a = a_mul(a1,a2,a3,a4); which is a = a1 * a2 * a3 * a4; +% +% Reference: David M. Pozar "Microwave Engineering" +% +% Thorsten Liebig +% Feb. 2013 + +if nargin<1 + error 'no argument is given' +end + +a = varargin{1}; + +for n=2:numel(varargin) + a2 = varargin{n}; + for f=1:size(a,3) + a(:,:,f) = a(:,:,f)*a2(:,:,f); + end +end diff --git a/CTB/a_series.m b/CTB/a_series.m new file mode 100644 index 0000000..b8a2de1 --- /dev/null +++ b/CTB/a_series.m @@ -0,0 +1,22 @@ +function a = a_series(Z) +% a = a_series(Z) +% +% create the ABCD matrix of a series impedance +% +% example: +% C = 1e-12; aka 1pF +% f = linspace(0,2e9,201); +% Z = 2j*pi*f*C; +% +% %ABCD matrix of a series capacitor +% a = a_series(Z); +% +% Reference: David M. Pozar "Microwave Engineering" +% +% Thorsten Liebig +% Feb. 2013 + +a(1,2,:) = Z; +a(1,1,:) = 1; +a(2,1,:) = 0; +a(2,2,:) = 1; diff --git a/CTB/a_shunt.m b/CTB/a_shunt.m new file mode 100644 index 0000000..13bc993 --- /dev/null +++ b/CTB/a_shunt.m @@ -0,0 +1,22 @@ +function a = a_shunt(Y) +% a = a_shunt(Y) +% +% create the ABCD matrix of a shunt admittance +% +% example: +% C = 1e-12; aka 1pF +% f = linspace(0,2e9,201); +% Y = 1./(2j*pi*f*C); +% +% %ABCD matrix of a shunt capacitor +% a = a_shunt(Y); +% +% Reference: David M. Pozar "Microwave Engineering" +% +% Thorsten Liebig +% Feb. 2013 + +a(2,1,:) = Y; +a(1,2,:) = 0; +a(1,1,:) = 1; +a(2,2,:) = 1; diff --git a/CTB/license.txt b/CTB/license.txt new file mode 100644 index 0000000..266f365 --- /dev/null +++ b/CTB/license.txt @@ -0,0 +1,22 @@ +Copyright (c) 2006-2013 Sebastian Held, Thorsten Liebig. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/CTB/read_touchstone.m b/CTB/read_touchstone.m new file mode 100644 index 0000000..dd30548 --- /dev/null +++ b/CTB/read_touchstone.m @@ -0,0 +1,150 @@ +function [type,freq,data,ref,comment]=read_touchstone( filename ) +% [type,freq,data,ref]=read_touchstone( filename ) - read touchstone-file +% type (lowercase) 'z' for Z-Parameter touchstone-file +% freq vector of frequencies (in Hz) +% data (numports x numports x numfreq) matrix +% filename filename of the file to read +% ref reference impedance +% comment cell array of comment lines +% +% Version 16. Jun 2010 +% 18. Aug 2010: comment lines +% 1. Sep 2010: BUGFIX: two-port files had S12 and S21 swapped!!!!! +% ATTENTION: higher than two-ports must be validated again!!!!!!!!!1 + +[fid, message] = fopen( filename, 'rt' ); +if fid == -1 + error( message ); +end + +comment = {}; + +% constants +DB = 0; +MA = 1; +RI = 2; + +% number of ports (extract extension) +temp = lower(filename); +k = strfind(temp,'.'); +if isempty(k) + error( 'filename has no extension' ); +end +last_dot = k(length(k)); +if length(temp) <= k + error( 'filename ends with "."' ); +end +extension = temp(last_dot+1:length(temp)); +if (lower(extension(1)) ~= 's') && (lower(extension(length(extension))) ~= 'p') + error( 'filename must have an extension like .s2p' ); +end +num_ports = str2double(extension(2:length(extension)-1)); + +parameters_found = 0; +freq_nr = 1; +tline = fgetl(fid); +while ischar(tline) + tline = strtrim(tline); + if isempty(tline) || (tline(1) == '!') + % comment + if ~isempty(tline) + comment{end+1} = tline; + end + tline = fgetl(fid); + continue + end + if tline(1) == '#' + % found parameters + if parameters_found == 1 + warning( 'additional parameter line found; expect garbage!' ); + end + parameters_found = 1; + % parse parameters + [~,remain] = strtok(tline); % token is now '#' + [token,remain] = strtok(remain); % token is now the unit + unit = lower(token); + if strcmp(unit,'hz') + freq_mul = 1; + elseif strcmp(unit,'khz') + freq_mul = 1e3; + elseif strcmp(unit,'mhz') + freq_mul = 1e6; + elseif strcmp(unit,'ghz') + freq_mul = 1e9; + else + error( ['wrong unit: "' token '"'] ); + end + [token,remain] = strtok(remain); % token is now the parameter type + type = lower(token); + [token,remain] = strtok(remain); % token is now the complex format + format = lower(token); + if strcmp(format,'ri') + format = RI; + elseif strcmp(format,'ma') + format = MA; + elseif strcmp(format,'db') + format = DB; + else + error( ['wrong complex format: "' format '"'] ); + end + [token,remain] = strtok(remain); % token must be 'R' + if lower(token) ~= 'r' + error( 'incorrect file format' ); + end + token = strtok(remain); % token is reference impedance + ref = str2double(token); + tline = fgetl(fid); + continue + end + % read data + clear 'cell_array'; + cell_array = split( tline ); + while length(cell_array) < 2*num_ports^2 + 1 + temp_tline = fgetl(fid); %FIXME comments? empty lines? + cell_array = [cell_array,split( temp_tline )]; + end + % now we have (at least) num_values values in cell_array + temp_freq = str2double(cell_array(1)) * freq_mul; + temp_data = zeros(num_ports); + for source = 1:num_ports + for dest = 1:num_ports + if num_ports ~= 2 + pos = ((source-1)*num_ports + dest)*2; + else + % special file format for two-ports + pos = ((source-1)*2 + dest)*2; + end + if format == RI + temp_data(dest,source) = str2double(cell_array(pos)) + 1i*str2double(cell_array(pos+1)); + elseif format == MA + temp_data(dest,source) = str2double(cell_array(pos)) * exp(1i*str2double(cell_array(pos+1))/180*pi); + %disp( [tline ' ### freq: ' num2str(temp_freq/1e9) ' S' num2str(source) num2str(dest) ' ' num2str(temp_data(dest,source))] ); + %disp( ['pos: ' num2str(pos) ' cell_array: ' char(cell_array(pos))] ); + elseif format == DB + temp_data(dest,source) = 10^(str2double(cell_array(pos))/20) * exp(1i*str2double(cell_array(pos+1))/180*pi); + end + end + end + % values are parsed, insert them into the freq and data arrays + freq(freq_nr) = temp_freq; + data(:,:,freq_nr) = temp_data; + freq_nr = freq_nr + 1; + +% disp( ['frequency f=' num2str(temp_freq/1e9)] ); + tline = fgetl(fid); +end + +fclose( fid ); + +end %read_touchstone() + + + +function cell_array=split( str ) + cell_array = cell(0); + [token,remain] = strtok(str); + while ~isempty(token) + cell_array = [cell_array token]; + [token,remain] = strtok(remain); + end +end diff --git a/CTB/readme.txt b/CTB/readme.txt new file mode 100644 index 0000000..8b8cef9 --- /dev/null +++ b/CTB/readme.txt @@ -0,0 +1,29 @@ +Circuit Toolbox for Matlab/Octave +--------------------------------- + +Small collection of useful functions to convert n-port network parameter +such as scattering parameter, Z- or Y-parameter. + +Read/Write to touchstone file format to read with Qucs: http://qucs.sourceforge.net + +--- +Examples: +addpath('path/to/CTB'); +% create ABCD matrix of a series C, shunt R and shunt L +f = linspace(0,1e9,201); % frequency vector +a = a_series(1./(2j*pi*f*10e-12)); % create ABCD matrix for a series capacity of 10pF +a = a_mul(a, a_shunt(1/50*ones(size(f)))); % append a 50 Ohms shunt resistance +a = a_mul(a, a_series(2j*pi*f*20e-9)); % append a 20nH series inductance +s = a2s(a); % convert to s-parameter + +figure +plot(f,20*log10(squeeze(abs(s(1,1,:))))); +hold on; +grid on; +plot(f,20*log10(squeeze(abs(s(2,1,:)))),'r--'); +ylim([-20 0]); +legend('s11','s21'); + +--- +Copyright (c) 2006-2013 Sebastian Held, Thorsten Liebig. +All rights reserved. diff --git a/CTB/s2a.m b/CTB/s2a.m new file mode 100644 index 0000000..4f795ef --- /dev/null +++ b/CTB/s2a.m @@ -0,0 +1,31 @@ +function a = s2a(s,ref) +% a = s2a(s [,ref]) +% +% Scattering to ABCD transformation (only for 2x2xf matrices) +% +% input: +% s: S-matrix matrix 2x2xf (f: number of frequencies) +% ref: (optional) reference impedance (default 50 Ohm) +% +% output: +% a: ABCD 2x2xf +% +% Reference: David M. Pozar "Microwave Engineering" +% +% Sebastian Held +% Sep 1 2010 + +if nargin < 2 + Z0 = 50; +else + Z0 = ref; +end + +S11 = squeeze(s(1,1,:)); +S12 = squeeze(s(1,2,:)); +S21 = squeeze(s(2,1,:)); +S22 = squeeze(s(2,2,:)); +a(1,1,:) = ((1+S11).*(1-S22) + S12.*S21) ./ (2*S21); +a(1,2,:) = Z0 .* ((1+S11).*(1+S22) - S12.*S21) ./ (2*S21); +a(2,1,:) = 1./Z0 .* ((1-S11).*(1-S22) - S12.*S21) ./ (2*S21); +a(2,2,:) = ((1-S11).*(1+S22) + S12.*S21) ./ (2*S21); diff --git a/CTB/s2y.m b/CTB/s2y.m new file mode 100644 index 0000000..c3cbd23 --- /dev/null +++ b/CTB/s2y.m @@ -0,0 +1,43 @@ +function y = s2y(s,ref) +% y = s2y(s [,ref]) +% +% Scattering to Y transformation +% +% input: +% s: S-matrix matrix nxnxf (f: number of frequencies) +% ref: (optional) reference impedance (default 50 Ohm) +% +% output: +% y: Y-matrix nxnxf +% +% Reference: http://qucs.sourceforge.net/tech/node98.html +% +% Thorsten Liebig +% Feb. 2013 + +if nargin < 2 + Z0 = 50; +else + Z0 = ref; +end + +N = size(s,1); +Nf = size(s,3); + +if (numel(Z0)==1) + Z0 = Z0*ones(N,1); +end + +E = eye(N); +Zref = zeros(N,N); +G = Zref; +for n=1:N + Zref(n,n) = Z0(n); + G(n,n) = 1/sqrt(real(Z0(n))); +end + +y=zeros(N,N,Nf); %preallocate + +for f=1:Nf + y(:,:,f) = G\(Zref\((s(:,:,f)+E)\(E-s(:,:,f))))*G; +end diff --git a/CTB/s2z.m b/CTB/s2z.m new file mode 100644 index 0000000..0a76f09 --- /dev/null +++ b/CTB/s2z.m @@ -0,0 +1,43 @@ +function z = s2z(s,ref) +% z = s2z(s [,ref]) +% +% Scattering to Z transformation +% +% input: +% s: S-matrix matrix nxnxf (f: number of frequencies) +% ref: (optional) reference impedance (default 50 Ohm) +% +% output: +% z: Z-matrix nxnxf +% +% Reference: http://qucs.sourceforge.net/tech/node98.html +% +% Thorsten Liebig +% Feb. 2013 + +if nargin < 2 + Z0 = 50; +else + Z0 = ref; +end + +N = size(s,1); +Nf = size(s,3); + +if (numel(Z0)==1) + Z0 = Z0*ones(N,1); +end + +E = eye(N); +Zref = zeros(N,N); +G = Zref; +for n=1:N + Zref(n,n) = Z0(n); + G(n,n) = 1/sqrt(real(Z0(n))); +end + +z=zeros(N,N,Nf); %preallocate + +for f=1:Nf + z(:,:,f) = G\ ((E-s(:,:,f))\(s(:,:,f)+E))*Zref*G; +end diff --git a/CTB/s_renorm.m b/CTB/s_renorm.m new file mode 100644 index 0000000..2d887e0 --- /dev/null +++ b/CTB/s_renorm.m @@ -0,0 +1,19 @@ +function s_new = s_renorm(s, Z, Z_new) +% s_new = s_renorm(s, Z, Z_new) +% +% scattering matrix renormalization +% +% input: +% s: scattering matrix nxnxf (f: number of frequencies) +% Z: old reference impedance +% Z_new: new reference impedance +% +% output: +% s: renormalized scattering-matrix nxnxf +% +% Thorsten Liebig +% (c) Jan. 2014 + +z = s2z(s, Z); +s_new = z2s(z, Z_new); + diff --git a/CTB/write_touchstone.m b/CTB/write_touchstone.m new file mode 100644 index 0000000..c695669 --- /dev/null +++ b/CTB/write_touchstone.m @@ -0,0 +1,87 @@ +function write_touchstone( type, freq, data, filename, ref, comment ) +% write_touchstone( type, freq, data, filename [,ref [,comment]] ) - write touchstone-file +% for ADS +% type 'z' for Z-Parameter touchstone-file +% 'y' for Y-Parameter touchstone-file +% 's' for S-Parameter touchstone-file +% freq vector of frequencies (in Hz) +% data (numports x numports x numfreq) matrix +% filename filename of the file to create +% ref (optional) reference impedance +% comment (optional) written in the header +% +% (C) Sebastian Held +% Version 21. Feb 2006 + +if lower(type) == 'z' + par_type = 'Z'; + if nargin < 5; ref = 1; end +elseif lower(type) == 'y' + par_type = 'Y'; + if nargin < 5; ref = 1; end +elseif lower(type) == 's' + par_type = 'S'; + if nargin < 5; ref = 50; end +else + error( 'only z-, y- and s-parameters supported by now' ); +end + +if nargin < 6 + comment = ''; +end + +num_rows = size( data, 1 ); +num_columns = size( data, 2 ); +if num_rows ~= num_columns + error( 'number of rows and columns do not agree' ); +end + +[fid, message] = fopen( filename, 'wt' ); +if fid == -1 + error( message ); +end + +fprintf( fid, '%s\n', ['# Hz ' par_type ' RI R ' num2str(ref)] ); +fprintf( fid, '%s\n', ['! ' comment] ); + +if size( data, 1 ) == 1 || size( data, 1 ) >= 3 + write_data_1(data, fid, freq); +elseif size( data, 1 ) == 2 + write_data_2(data, fid, freq); +else + error( 'FIXME - unhandled dimension' ); +end + +fclose( fid ); +return; +end %write_touchstone() + +function write_data_1(data, fid, freq) +num_rows = size( data, 1 ); +num_columns = size( data, 2 ); +% for more than 3-port devices +for f=1:length(freq) + fprintf( fid, '%e ', freq(f) ); %Frequenz + for row = 1:num_rows + column = 1; + while column <= num_columns + for z=1:min( 4, num_columns-column+1 ); % nur maximal 4 Parameter in einer Zeile! (ADS-Begrenzung) + fprintf( fid, '% e % e ', real( data(row,column,f) ), imag( data(row,column,f) ) ); + column = column + 1; + end + fprintf( fid, '\n ' ); % Zeilenende + end + end + fprintf( fid, '\n' ); +end +end %write_data_1() + +function write_data_2(data, fid, freq) +% for 2-port devices +% ADS uses different format (what a mess) +for f=1:length(freq) + fprintf( fid, '%e % e % e % e % e % e % e % e % e\n', freq(f), ... + real(data(1,1,f)), imag(data(1,1,f)), real(data(2,1,f)), imag(data(2,1,f)), ... + real(data(1,2,f)), imag(data(1,2,f)), real(data(2,2,f)), imag(data(2,2,f)) ); %Frequenz +end +end %write_data_2() diff --git a/CTB/y2s.m b/CTB/y2s.m new file mode 100644 index 0000000..f2b3cac --- /dev/null +++ b/CTB/y2s.m @@ -0,0 +1,43 @@ +function s = y2s(y,ref) +% s = y2s(y [,ref]) +% +% Y-matrix to scattering transformation +% +% input: +% y: Y-matrix matrix nxnxf (f: number of frequencies) +% ref: (optional) reference impedance (default 50 Ohm) +% +% output: +% s: S-matrix nxnxf +% +% Reference: http://qucs.sourceforge.net/tech/node98.html +% +% Thorsten Liebig +% Feb. 2013 + +if nargin < 2 + Z0 = 50; +else + Z0 = ref; +end + +N = size(y,1); +Nf = size(y,3); + +if (numel(Z0)==1) + Z0 = Z0*ones(N,1); +end + +E = eye(N); +Zref = zeros(N,N); +G = Zref; +for n=1:N + Zref(n,n) = Z0(n); + G(n,n) = 1/sqrt(real(Z0(n))); +end + +s=zeros(N,N,Nf); %preallocate + +for f=1:Nf + s(:,:,f) = G*((E-Zref*y(:,:,f))/(E+Zref*y(:,:,f)))/G; +end diff --git a/CTB/y2z.m b/CTB/y2z.m new file mode 100644 index 0000000..b7b54ac --- /dev/null +++ b/CTB/y2z.m @@ -0,0 +1,22 @@ +function z = y2z(y) +% z = y2z(y) +% +% Y-matrix to Z-matrix +% +% input: +% y: Y-matrix matrix nxnxf (f: number of frequencies) +% +% output: +% z: Z-matrix nxnxf +% +% Reference: http://qucs.sourceforge.net/tech/node98.html +% +% Thorsten Liebig +% (c) 2013 + +Nf = size(y,3); + +z = y*0; % init +for f=1:Nf + z(:,:,f) = inv(y(:,:,f)); +end diff --git a/CTB/z2s.m b/CTB/z2s.m new file mode 100644 index 0000000..9f2e165 --- /dev/null +++ b/CTB/z2s.m @@ -0,0 +1,44 @@ +function s = z2s(z,ref) +% s = z2s(z [,ref]) +% +% Z-matrix to scattering transformation +% +% input: +% z: Z-matrix matrix nxnxf (f: number of frequencies) +% ref: (optional) reference impedance (default 50 Ohm) +% +% output: +% s: S-matrix nxnxf +% +% Reference: http://qucs.sourceforge.net/tech/node98.html +% +% Thorsten Liebig +% Feb. 2013 + +if nargin < 2 + Z0 = 50; +else + Z0 = ref; +end + +N = size(z,1); +Nf = size(z,3); + +if (numel(Z0)==1) + Z0 = Z0*ones(N,1); +end + +E = eye(N); +Zref = zeros(N,N); +G = Zref; + +for n=1:N + Zref(n,n) = Z0(n); + G(n,n) = 1/sqrt(real(Z0(n))); +end + +s=zeros(N,N,Nf); %preallocate + +for f=1:Nf + s(:,:,f) = G*(z(:,:,f)-Zref)/(z(:,:,f)+Zref)/G; +end diff --git a/CTB/z2y.m b/CTB/z2y.m new file mode 100644 index 0000000..f8666a3 --- /dev/null +++ b/CTB/z2y.m @@ -0,0 +1,18 @@ +function y = z2y(z) +% y = z2y(z) +% +% Z-matrix to Y-matrix +% +% input: +% z: Z-matrix matrix nxnxf (f: number of frequencies) +% +% output: +% y: Y-matrix nxnxf +% +% Reference: http://qucs.sourceforge.net/tech/node98.html +% +% Thorsten Liebig +% (c) 2013 + +% y2z is just doing the invertion ... +y = y2z(z); diff --git a/QCSXCAD/CMakeLists.txt b/QCSXCAD/CMakeLists.txt new file mode 100644 index 0000000..73b96a6 --- /dev/null +++ b/QCSXCAD/CMakeLists.txt @@ -0,0 +1,199 @@ + +# define build type +IF( DEFINED CMAKE_BUILD_TYPE ) + SET( CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Set to either \"Release\" or \"Debug\"" ) +ELSE() + SET( CMAKE_BUILD_TYPE Release CACHE STRING "Set to either \"Release\" or \"Debug\"" ) +ENDIF() + +PROJECT( QCSXCAD CXX) + +cmake_minimum_required(VERSION 2.8) + +# https://cmake.org/cmake/help/v3.0/policy/CMP0020.html +if(POLICY CMP0020) + cmake_policy(SET CMP0020 OLD) +endif() + +IF(EXISTS ${PROJECT_SOURCE_DIR}/localConfig.cmake) + include(${PROJECT_SOURCE_DIR}/localConfig.cmake) +ENDIF() + +# default +set(LIB_VERSION_MAJOR 0) +set(LIB_VERSION_MINOR 6) +set(LIB_VERSION_PATCH 2) +set(LIB_VERSION_STRING ${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}) + +set(VERSION "v${LIB_VERSION_STRING}") + +# add git revision +# add git revision +IF(EXISTS ${PROJECT_SOURCE_DIR}/.git ) + FIND_PACKAGE(Git) + # Get the latest abbreviated commit hash of the working branch + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE GITREV + ) + set(VERSION ${GITREV}) + string(STRIP ${VERSION} VERSION) + message(STATUS "Found Git repository, ${PROJECT_NAME} version tag: ${VERSION}") +ENDIF() + +ADD_DEFINITIONS(-DGIT_VERSION=\"${VERSION}\") + +if (WIN32) + ADD_DEFINITIONS( -DBUILD_QCSXCAD_LIB ) +endif (WIN32) + + +# +# Set up RPATH for the project +# +option(ENABLE_RPATH "Enable rpath support on Linux and Mac" ON) +if(NOT CMAKE_INSTALL_RPATH) + set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") +endif() +if(APPLE AND NOT CMAKE_INSTALL_NAME_DIR) + set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") +endif() +if(UNIX AND ENABLE_RPATH) + set(CMAKE_SKIP_BUILD_RPATH FALSE) + set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +endif() + +# Set locations of extra CMake modules +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${openEMS_SOURCE_DIR}/cmake/Modules/") + +# CSXCAD +# $ cmake -DCSXCAD_ROOT_DIR=~/opt/openEMS . +# SET(CSXCAD_ROOT_DIR ~/opt/openEMS) +find_library(CSXCAD_LIBRARIES + NAMES CSXCAD + HINTS ${CSXCAD_ROOT_DIR}/lib${LIB_SUFFIX} + NO_CMAKE_FIND_ROOT_PATH +) +message(STATUS "CSXCAD_LIBRARIES: ${CSXCAD_LIBRARIES}" ) +#TODO test if CSXCADs was found +find_path(CSXCAD_INCLUDE_DIR + NAMES ContinuousStructure.h + HINTS ${CSXCAD_ROOT_DIR}/include + PATH_SUFFIXES "CSXCAD" ${CSXCAD_INCLUDE_DIR} + NO_CMAKE_FIND_ROOT_PATH +) +message(STATUS "CSXCAD_INCLUDE_DIR: ${CSXCAD_INCLUDE_DIR}" ) +INCLUDE_DIRECTORIES( ${CSXCAD_INCLUDE_DIR} ) + +# Set locations of CMake modules +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${QCSXCAD_SOURCE_DIR}/cmake/Modules/") + +# TinyXML module from https://github.com/ros/cmake_modules +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() + +message(STATUS "Found package VTK. Using version " ${VTK_VERSION}) +include(${VTK_USE_FILE}) +INCLUDE_DIRECTORIES (${VTK_INCLUDE_DIRS}) + +# Qt +SET(RESOURCES resources.qrc) +set(CMAKE_AUTOMOC ON) +if(${VTK_VERSION} VERSION_GREATER "6" AND VTK_QT_VERSION VERSION_GREATER "4") + find_package(Qt5Widgets REQUIRED) + include_directories(${Qt5Widgets_INCLUDE_DIRS}) + find_package(Qt5Xml REQUIRED) + include_directories(${Qt5Xml_INCLUDE_DIRS}) + INCLUDE_DIRECTORIES(${Qt5_INCLUDE_DIRS}) + set(CMAKE_CXX_FLAGS "${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}") + QT5_ADD_RESOURCES(RESOURCES_SRCS ${RESOURCES}) +else() + FIND_PACKAGE(Qt4 REQUIRED QtCore QtGui QtXml) + INCLUDE( ${QT_USE_FILE} ) + QT4_ADD_RESOURCES(RESOURCES_SRCS ${RESOURCES}) +endif() + +if("${VTK_MAJOR_VERSION}" GREATER 5) + set( vtk_LIBS ${VTK_LIBRARIES} ) +else() + set( vtk_LIBS + vtkCommon + vtkFiltering + vtkGraphics + vtkHybrid + vtkIO + vtkRendering + vtkWidgets + QVTK + ) +endif() +message(STATUS "vtk libraries " ${vtk_LIBS}) + +set( SOURCES + QCSXCAD.cpp + QCSGridEditor.cpp + QCSPrimEditor.cpp + QCSPropEditor.cpp + QCSTreeWidget.cpp + QParameterGui.cpp + QVTKStructure.cpp + VTKPrimitives.cpp + export_x3d.cpp + export_pov.cpp + QCSXCAD_Global.cpp + vtkInteractorStyleRubberBand2DPlane.cpp +) + +set(PUB_HEADERS + QCSXCAD.h + QCSGridEditor.h + QCSPrimEditor.h + QCSPropEditor.h + QCSTreeWidget.h + QParameterGui.h + QVTKStructure.h + VTKPrimitives.h + QCSXCAD_Global.h + export_x3d.h + export_pov.h + vtkInteractorStyleRubberBand2DPlane.h +) + +# CSXCAD library +add_library( QCSXCAD SHARED + ${SOURCES} + ${MOC_SRCS} + ${RESOURCES_SRCS} +) + +if(Qt5Widgets_FOUND) + qt5_use_modules(QCSXCAD Widgets Xml) +endif() + +TARGET_LINK_LIBRARIES( QCSXCAD + ${CSXCAD_LIBRARIES} + tinyxml + ${vtk_LIBS} + ${QT_LIBRARIES} +) + +set_target_properties(QCSXCAD PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_MAJOR}) + +INSTALL(TARGETS QCSXCAD DESTINATION lib${LIB_SUFFIX}) + +INSTALL(FILES ${PUB_HEADERS} DESTINATION include/QCSXCAD) + +#TODO tarball, debug, release diff --git a/QCSXCAD/COPYING b/QCSXCAD/COPYING new file mode 100644 index 0000000..cca7fc2 --- /dev/null +++ b/QCSXCAD/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/QCSXCAD/INSTALL b/QCSXCAD/INSTALL new file mode 100644 index 0000000..b878959 --- /dev/null +++ b/QCSXCAD/INSTALL @@ -0,0 +1,21 @@ +Install instructions for the QCSXCAD library: +--------------------------------------------- + +1) Prerequirements: + QCSXCAD relies on a number of libraries: + - CSXCAD (http://openEMS.de) + - Qt (http://qt-project.org/) + +2) Build: + - change directory to QCSXCAD + - build: + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX= -DCSXCAD_ROOT_DIR= + make + make install (may require root) + + Note: + - all path informations may be stored in a localConfig.cmake + - the default "prefix" is /usr/local + diff --git a/QCSXCAD/NEWS b/QCSXCAD/NEWS new file mode 100644 index 0000000..19519af --- /dev/null +++ b/QCSXCAD/NEWS @@ -0,0 +1,6 @@ +Changes in v0.5.0 +------------------------------- +- use a level of detail actor for faster rendering +- new and rewritten 2D view mode, now based on vtk as well +- render discrete material models +- code cleanup diff --git a/QCSXCAD/QCSGridEditor.cpp b/QCSXCAD/QCSGridEditor.cpp new file mode 100644 index 0000000..4e2210c --- /dev/null +++ b/QCSXCAD/QCSGridEditor.cpp @@ -0,0 +1,640 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "QCSGridEditor.h" +#include "CSRectGrid.h" +#include "QCSXCAD_Global.h" + +QCSGridEditor::QCSGridEditor(CSRectGrid* grid, QWidget* parent) : QWidget(parent) +{ + clGrid=grid; + QGridLayout* lay = new QGridLayout(); + setLayout(lay); + + //lay->addWidget(new QLabel(tr("Direction")),0,0); + lay->addWidget(new QLabel(tr("Min")),0,1); + lay->addWidget(new QLabel(tr("Max")),0,2); + lay->addWidget(new QLabel(tr("Lines")),0,3); + + for (int n=0;n<3;++n) + { + m_DirNames[n] = new QLabel(GetDirName(n)); + lay->addWidget(m_DirNames[n],n+1,0); + } + + QLabel* label=NULL; + for (unsigned int i=0;i<6;++i) + { + label=new QLabel("0"); + lay->addWidget(label,i/2+1,i%2+1); + lay->setAlignment(label,Qt::AlignCenter); + SimBox.append(label); + } + + for (unsigned int i=0;i<3;++i) + { + label=new QLabel("0"); + lay->addWidget(label,i+1,3); + lay->setAlignment(label,Qt::AlignCenter); + NodeQty.append(label); + } + + QString EditText = tr("Edit"); + if (QCSX_Settings.GetEdit()==false) + EditText = tr("View"); + QPushButton* PB = new QPushButton(QIcon(":/images/edit.png"),EditText); + QObject::connect(PB,SIGNAL(clicked()),this,SLOT(EditX())); + lay->addWidget(PB,1,4); + + PB = new QPushButton(QIcon(":/images/edit.png"),EditText); + QObject::connect(PB,SIGNAL(clicked()),this,SLOT(EditY())); + lay->addWidget(PB,2,4); + + PB = new QPushButton(QIcon(":/images/edit.png"),EditText); + QObject::connect(PB,SIGNAL(clicked()),this,SLOT(EditZ())); + lay->addWidget(PB,3,4); + + lay->addWidget(new QLabel(tr("Drawing unit [m]:")),4,0,1,2); + UnitLength = new QLineEdit("1"); + UnitLength->setEnabled(QCSX_Settings.GetEdit()); + QObject::connect(UnitLength,SIGNAL(textEdited(QString)),this,SLOT(SetDeltaUnit(QString))); + lay->addWidget(UnitLength,4,2,1,3); + + OpacitySlider = new QSlider(Qt::Horizontal); + OpacitySlider->setRange(0,255); + QObject::connect(OpacitySlider,SIGNAL(valueChanged(int)),this,SIGNAL(OpacityChange(int))); + lay->addWidget(new QLabel(tr("Grid opacity")),5,0,1,3); + lay->addWidget(OpacitySlider,5,2,1,3); + + lay->setRowStretch(6,1); + lay->setColumnStretch(5,1); +} + +QCSGridEditor::~QCSGridEditor() +{ +} + +QToolBar* QCSGridEditor::BuildToolbar() +{ + QToolBar *TB = new QToolBar(tr("Discretisation")); + TB->setObjectName("Discretisation_ToolBar"); + TB->addAction(tr("homo\nDisc"),this,SLOT(BuildHomogenDisc())); + TB->addAction(tr("inhomo\nDisc"),this,SLOT(BuildInHomogenDisc())); + TB->addAction(tr("increase \nDisc"),this,SLOT(IncreaseResolution())); + TB->addAction(tr("detect \nedges"),this,SLOT(DetectEdges())); + return TB; +} + +QWidget* QCSGridEditor::BuildPlanePosWidget() +{ + QWidget* PPWid = new QWidget(); + QGridLayout* lay = new QGridLayout(); + + for (int n=0;n<3;++n) + { + m_NormNames[n] = new QLabel(GetNormName(n)+ tr(" plane:")); + lay->addWidget( m_NormNames[n] ,n,0); + m_PlanePos[n] = new QSlider(); + m_PlanePos[n]->setOrientation(Qt::Horizontal); + lay->addWidget(m_PlanePos[n],n,1); + m_PlanePosValue[n] = new QLabel(); + lay->addWidget(m_PlanePosValue[n],n,2); + } + QObject::connect(m_PlanePos[0],SIGNAL(valueChanged(int)),this,SIGNAL(GridPlaneXChanged(int))); + QObject::connect(m_PlanePos[1],SIGNAL(valueChanged(int)),this,SIGNAL(GridPlaneYChanged(int))); + QObject::connect(m_PlanePos[2],SIGNAL(valueChanged(int)),this,SIGNAL(GridPlaneZChanged(int))); + + QObject::connect(m_PlanePos[0],SIGNAL(valueChanged(int)),this,SLOT(SetGridPlaneX(int))); + QObject::connect(m_PlanePos[1],SIGNAL(valueChanged(int)),this,SLOT(SetGridPlaneY(int))); + QObject::connect(m_PlanePos[2],SIGNAL(valueChanged(int)),this,SLOT(SetGridPlaneZ(int))); + + PPWid->setLayout(lay); + return PPWid; +} + +void QCSGridEditor::SetGridPlaneX(int pos) +{ + m_PlanePosValue[0]->setText(QString("%1 = %2").arg(GetDirName(0)).arg(clGrid->GetLine(0,pos))); +} + +void QCSGridEditor::SetGridPlaneY(int pos) +{ + m_PlanePosValue[1]->setText(QString("%1 = %2").arg(GetDirName(1)).arg(clGrid->GetLine(1,pos))); +} + +void QCSGridEditor::SetGridPlaneZ(int pos) +{ + m_PlanePosValue[2]->setText(QString("%1 = %2").arg(GetDirName(2)).arg(clGrid->GetLine(2,pos))); +} + +void QCSGridEditor::BuildInHomogenDisc() +{ + QDialog* HomogenDisc = new QDialog(); + QGridLayout* lay = new QGridLayout(); + + lay->addWidget(new QLabel(tr("Create inhomogenous discretisation:")),0,0,1,3); + + QCheckBox* DelOldGrid = new QCheckBox(tr("Clear old mesh")); + DelOldGrid->setChecked(true); + lay->addWidget(DelOldGrid,0,5); + + lay->addWidget(new QLabel(tr("min")),1,1); + lay->addWidget(new QLabel(tr("max")),1,2); + lay->addWidget(new QLabel(tr("lines")),1,3); + lay->addWidget(new QLabel(tr("grid distribution function:")),1,4,1,2); +// lay->addWidget(new QLabel(tr("X")),2,0); +// lay->addWidget(new QLabel(tr("Y")),3,0); +// lay->addWidget(new QLabel(tr("Z")),4,0); + QLineEdit* function[3]; + function[0] = new QLineEdit(GetDirName(0)); + function[1] = new QLineEdit(GetDirName(1)); + function[2] = new QLineEdit(GetDirName(2)); + lay->addWidget(new QLabel("X:"),2,0); + lay->addWidget(new QLabel("f(x)="),2,4); + lay->addWidget(function[0],2,5); + lay->addWidget(new QLabel("Y:"),3,0); + lay->addWidget(new QLabel("f(y)="),3,4); + lay->addWidget(function[1],3,5); + lay->addWidget(new QLabel("Z:"),4,0); + lay->addWidget(new QLabel("f(z)="),4,4); + lay->addWidget(function[2],4,5); + QLineEdit* BoxLine[6]; + QSpinBox* Nodes[3]; + for (int i=0;i<3;++i) + { + BoxLine[2*i]= new QLineEdit(QString("0")); + lay->addWidget(BoxLine[2*i],i+2,1); + BoxLine[2*i+1]= new QLineEdit(QString("1")); + lay->addWidget(BoxLine[2*i+1],i+2,2); + Nodes[i] = new QSpinBox(); + Nodes[i]->setRange(0,9999); + Nodes[i]->setValue(0); + lay->addWidget(Nodes[i],i+2,3); + } + + QPushButton* PB = new QPushButton(tr("Ok")); + QObject::connect(PB,SIGNAL(clicked()),HomogenDisc,SLOT(accept())); + QPushButton* PBcancel = new QPushButton(tr("Cancel")); + QObject::connect(PBcancel,SIGNAL(clicked()),HomogenDisc,SLOT(reject())); + + QHBoxLayout* hLay = new QHBoxLayout(); + hLay->addStretch(1); + hLay->addWidget(PB); + hLay->addWidget(PBcancel); + hLay->addStretch(1); + + lay->addLayout(hLay,5,0,1,6); + + HomogenDisc->setLayout(lay); + if (HomogenDisc->exec()==QDialog::Accepted) + { + double dSimBox[6]; + for (int i=0;i<6;++i) dSimBox[i]=BoxLine[i]->text().toDouble(); + for (int i=0;i<3;++i) + { +// if ((Check[i]->checkState()==Qt::Checked))// && (dSimBox[2*i+1]>dSimBox[2*i])) +// { +// FunctionParser fParse; +// fParse.AddConstant("pi", 3.1415926535897932); +// fParse.Parse(function[i]->text().toStdString(),coordVars.at(i).toStdString()); +// if (fParse.GetParseErrorType()!=FunctionParser::FP_NO_ERROR) +// QMessageBox::warning(HomogenDisc,tr("Error reading grid function!"),QString(tr("fparser error message:\n%1").arg(fParse.ErrorMsg()))); +// else +// { +// double dStep=0; +// if (Nodes[i]->value()>1) dStep=(dSimBox[2*i+1]-dSimBox[2*i])/(Nodes[i]->value()-1); +// if (DelOldGrid->isChecked()) clGrid->ClearLines(i); +// double dValue=0; +// double dPos=0; +// bool error=false; +// for (int n=0;nvalue();++n) +// { +// dPos=dSimBox[2*i]+n*dStep; +// dValue=fParse.Eval(&dPos); +// if (fParse.EvalError()!=0) error=true; +// clGrid->AddDiscLine(i,dValue); +// } +// if (error) QMessageBox::warning(HomogenDisc,tr("Error evaluation grid function!"),QString(tr("An error occured evaluation the grid function f(%1)!").arg(coordVars.at(i)))); +// } +// clGrid->Sort(i); +// } + if (Nodes[i]->value()>0)// && (dSimBox[2*i+1]>dSimBox[2*i])) + { + double dStep=0; + if (Nodes[i]->value()>1) dStep=(dSimBox[2*i+1]-dSimBox[2*i])/(Nodes[i]->value()-1); + if (DelOldGrid->isChecked()) clGrid->ClearLines(i); + double* dValue=new double[Nodes[i]->value()]; + for (int n=0;nvalue();++n) + dValue[n]=dSimBox[2*i]+n*dStep; + std::string error = clGrid->AddDiscLines(i,Nodes[i]->value(),dValue,function[i]->text().toStdString()); + delete[] dValue; + if (error.empty()==false) QMessageBox::warning(HomogenDisc,tr("Error evaluation grid function!"),QString(error.c_str())); + } + clGrid->Sort(i); + } + } + delete HomogenDisc; + Update(); +} + +void QCSGridEditor::BuildHomogenDisc() +{ + QDialog* HomogenDisc = new QDialog(); + QGridLayout* lay = new QGridLayout(); + + lay->addWidget(new QLabel(tr("Create homogenous discretisation:")),0,0,1,3); + QCheckBox* DelOldGrid = new QCheckBox(tr("Clear old mesh")); + DelOldGrid->setChecked(true); + lay->addWidget(DelOldGrid,0,3); + + lay->addWidget(new QLabel(tr("Min")),1,1); + lay->addWidget(new QLabel(tr("Max")),1,2); + lay->addWidget(new QLabel(tr("Lines")),1,3); +// lay->addWidget(new QLabel(tr("X")),2,0); +// lay->addWidget(new QLabel(tr("Y")),3,0); +// lay->addWidget(new QLabel(tr("Z")),4,0); + QCheckBox* Check[3]; + Check[0] = new QCheckBox(GetDirName(0)); + lay->addWidget(Check[0],2,0); + Check[1] = new QCheckBox(GetDirName(1)); + lay->addWidget(Check[1],3,0); + Check[2] = new QCheckBox(GetDirName(2)); + lay->addWidget(Check[2],4,0); + QLineEdit* BoxLine[6]; + QSpinBox* Nodes[3]; + for (int i=0;i<3;++i) + { + BoxLine[2*i]= new QLineEdit(QString("%1").arg(clGrid->GetLine(i,0))); + lay->addWidget(BoxLine[2*i],i+2,1); + BoxLine[2*i+1]= new QLineEdit(QString("%1").arg(clGrid->GetLine(i,clGrid->GetQtyLines(i)-1))); + lay->addWidget(BoxLine[2*i+1],i+2,2); + Nodes[i] = new QSpinBox(); + Nodes[i]->setRange(1,9999); + Nodes[i]->setValue(clGrid->GetQtyLines(i)); + lay->addWidget(Nodes[i],i+2,3); + Check[i]->setChecked(true); + } + QPushButton* PB = new QPushButton(tr("Ok")); + QObject::connect(PB,SIGNAL(clicked()),HomogenDisc,SLOT(accept())); + QPushButton* PBcancel = new QPushButton(tr("Cancel")); + QObject::connect(PBcancel,SIGNAL(clicked()),HomogenDisc,SLOT(reject())); + + QHBoxLayout* hLay = new QHBoxLayout(); + hLay->addStretch(1); + hLay->addWidget(PB); + hLay->addWidget(PBcancel); + hLay->addStretch(1); + + lay->addLayout(hLay,5,0,1,4); + + HomogenDisc->setLayout(lay); + if (HomogenDisc->exec()==QDialog::Accepted) + { + double dSimBox[6]; + for (int i=0;i<6;++i) dSimBox[i]=BoxLine[i]->text().toDouble(); + for (int i=0;i<3;++i) + { + if ((Check[i]->checkState()==Qt::Checked))// && (dSimBox[2*i+1]>dSimBox[2*i])) + { + double dStep=0; + if (Nodes[i]->value()>1) dStep=(dSimBox[2*i+1]-dSimBox[2*i])/(Nodes[i]->value()-1); + if (DelOldGrid->isChecked()) clGrid->ClearLines(i); + for (int n=0;nvalue();++n) clGrid->AddDiscLine(i,dSimBox[2*i]+n*dStep); + clGrid->Sort(i); + } +// else if (Check[i]->checkState()==Qt::Checked) +// { +// clGrid->ClearLines(i); +// if (Nodes[i]->value()>0) clGrid->AddDiscLine(i,dSimBox[2*i]); +// } + } + } + delete HomogenDisc; + Update(); +} + +void QCSGridEditor::IncreaseResolution() +{ + QDialog* DiscInc = new QDialog(); + QGridLayout* lay = new QGridLayout(); + + lay->addWidget(new QLabel(tr("Increase Resolution of Discretisation:")),0,0,1,2); + + QCheckBox* Check[3]; + QSpinBox* Spin[3]; + Check[0] = new QCheckBox(tr("X - Factor: ")); + Check[0]->setChecked(true); + Spin[0]=new QSpinBox();Spin[0]->setRange(2,9); + lay->addWidget(Check[0],2,0); + lay->addWidget(Spin[0],2,1); + Check[1] = new QCheckBox(tr("Y - Factor: ")); + Check[1]->setChecked(true); + Spin[1]=new QSpinBox();Spin[1]->setRange(2,9); + lay->addWidget(Check[1],3,0); + lay->addWidget(Spin[1],3,1); + Check[2] = new QCheckBox(tr("Z - Factor: ")); + Check[2]->setChecked(true); + Spin[2]=new QSpinBox();Spin[2]->setRange(2,9); + lay->addWidget(Check[2],4,0); + lay->addWidget(Spin[2],4,1); + + QPushButton* PB = new QPushButton(tr("Ok")); + QObject::connect(PB,SIGNAL(clicked()),DiscInc,SLOT(accept())); + QPushButton* PBcancel = new QPushButton(tr("Cancel")); + QObject::connect(PBcancel,SIGNAL(clicked()),DiscInc,SLOT(reject())); + + QHBoxLayout* hLay = new QHBoxLayout(); + hLay->addStretch(1); + hLay->addWidget(PB); + hLay->addWidget(PBcancel); + hLay->addStretch(1); + + lay->addLayout(hLay,5,0,1,2); + + DiscInc->setLayout(lay); + + if (DiscInc->exec()==QDialog::Accepted) + { + for (int i=0;i<3;++i) + if (Check[i]->checkState()==Qt::Checked) + { + clGrid->IncreaseResolution(i,Spin[i]->value()); + } + } + Update(); +} + +void QCSGridEditor::EditX() +{ + Edit(0); +} + +void QCSGridEditor::EditY() +{ + Edit(1); +} + +void QCSGridEditor::EditZ() +{ + Edit(2); +} + +double* QCSGridEditor::GetDoubleArrayFromString(int *count, QString qsValue) +{ + double* values=NULL; + *count = 0; + QStringList seq = qsValue.split(":"); + if (seq.size()==3) + { + double start,step,stop; + bool ok; + start = seq.at(0).toDouble(&ok); + if (ok) step = seq.at(1).toDouble(&ok); + if (ok) stop = seq.at(2).toDouble(&ok); + if (ok) + { + int NrSteps = (int)((stop-start)/step); + if ((NrSteps>=0) && (NrSteps<1000)) + { + values = new double[NrSteps+1]; + *count = NrSteps+1; + for (int n=0;n<=NrSteps;++n) + values[n]=start+n*step; + } + } + } + return values; +} + +void QCSGridEditor::Edit(int direct) +{ + QTextEdit *Line = new QTextEdit(clGrid->GetLinesAsString(direct).c_str()); + Line->setReadOnly(QCSX_Settings.GetEdit()==false); + QDialog* EditDisc = new QDialog(this); + + if (QCSX_Settings.GetEdit()) + EditDisc->setWindowTitle(tr("Edit Discratisation")); + else + EditDisc->setWindowTitle(tr("View Discratisation")); + QGridLayout* lay = new QGridLayout(); + + lay->addWidget(Line,0,0,1,4); + + if (QCSX_Settings.GetEdit()) + lay->addWidget(new QLabel(tr("Allowed syntax example: 0,10, 20, 30:1.5e1:100, 50 , sqrt(1000:-10:200)")),1,0,1,4); + QPushButton* PB = new QPushButton(tr("Ok")); + QObject::connect(PB,SIGNAL(clicked()),EditDisc,SLOT(accept())); + lay->addWidget(PB,2,1); + if (QCSX_Settings.GetEdit()) + { + PB = new QPushButton(tr("Cancel")); + QObject::connect(PB,SIGNAL(clicked()),EditDisc,SLOT(reject())); + lay->addWidget(PB,2,2); + } + + lay->setRowStretch(0,1); + lay->setColumnStretch(0,1); + lay->setColumnStretch(3,1); + + EditDisc->setLayout(lay); + if (EditDisc->exec()==QDialog::Accepted && QCSX_Settings.GetEdit()) + { + clGrid->ClearLines(direct); + QStringList gridValues = Line->toPlainText().split(","); + for (int n=0;nAddDiscLine(direct,val); + else + { + QString FloatExp("-?\\d+(.\\d+)?(e-?\\d+)?"); + QRegExp qre(FloatExp + ":" + FloatExp + ":" + FloatExp); + if (qre.exactMatch(qsValue)) + { + int count=0; + double* values = GetDoubleArrayFromString(&count,qsValue); + if (values) clGrid->AddDiscLines(direct,count,values); + } + else if (qsValue.contains(QRegExp(FloatExp + ":" + FloatExp + ":" + FloatExp))) + { + qre.indexIn(qsValue); + QString seq = qre.cap(); +// cerr << "found-->" << seq.toStdString() << endl; + QString function = qsValue.replace(QRegExp(FloatExp + ":" + FloatExp + ":" + FloatExp),GetDirName(direct)); +// cerr << function.toStdString() << endl; + int count=0; + double* values = GetDoubleArrayFromString(&count,seq); + if (values) clGrid->AddDiscLines(direct,count,values,function.toStdString()); + } + } + } + } + Update(); +} + + +void QCSGridEditor::DetectEdges() +{ + QDialog* Edges = new QDialog(); + QGridLayout* lay = new QGridLayout(); + + lay->addWidget(new QLabel(tr("Detect Edges for Discretisation:")),0,0,1,1); + + QCheckBox* Check[3]; + Check[0] = new QCheckBox(tr("X - Active ")); + Check[0]->setChecked(true); + lay->addWidget(Check[0],2,0); + Check[1] = new QCheckBox(tr("Y - Active ")); + Check[1]->setChecked(true); + lay->addWidget(Check[1],3,0); + Check[2] = new QCheckBox(tr("Z - Active ")); + Check[2]->setChecked(true); + lay->addWidget(Check[2],4,0); + + QPushButton* PB = new QPushButton(tr("Ok")); + QObject::connect(PB,SIGNAL(clicked()),Edges,SLOT(accept())); + QPushButton* PBcancel = new QPushButton(tr("Cancel")); + QObject::connect(PBcancel,SIGNAL(clicked()),Edges,SLOT(reject())); + + QHBoxLayout* hLay = new QHBoxLayout(); + hLay->addStretch(1); + hLay->addWidget(PB); + hLay->addWidget(PBcancel); + hLay->addStretch(1); + + lay->addLayout(hLay,5,0,1,1); + + Edges->setLayout(lay); + + if (Edges->exec()==QDialog::Accepted) + { + for (int i=0;i<3;++i) + if (Check[i]->checkState()==Qt::Checked) + { + emit signalDetectEdges(i); + } + } + Update(); +} + +void QCSGridEditor::SetDeltaUnit(QString val) +{ + bool succ=false; + double dDal=val.toDouble(&succ); + if ((val>0) && succ) clGrid->SetDeltaUnit(dDal); +} + +void QCSGridEditor::Update() +{ + clGrid->Sort(0); + clGrid->Sort(1); + clGrid->Sort(2); + for (size_t i=0;i<3;++i) + { + SimBox.at(2*i)->setText(QString("%1").arg(clGrid->GetLine(i,0))); + SimBox.at(2*i+1)->setText(QString("%1").arg(clGrid->GetLine(i,clGrid->GetQtyLines(i)-1))); + NodeQty.at(i)->setText(QString("%1").arg(clGrid->GetQtyLines(i))); + m_DirNames[i]->setText(GetDirName(i)); + m_PlanePos[i]->setRange(0,clGrid->GetQtyLines(i)-1); + m_NormNames[i]->setText(GetNormName(i)+ tr(" plane: ")); + } + SetGridPlaneX(m_PlanePos[0]->value()); + SetGridPlaneY(m_PlanePos[0]->value()); + SetGridPlaneZ(m_PlanePos[0]->value()); + UnitLength->setText(QString("%1").arg(clGrid->GetDeltaUnit())); + emit GridChanged(); +} + +void QCSGridEditor::SetOpacity(int val) +{ + OpacitySlider->setValue(val); +} + +int QCSGridEditor::GetOpacity() +{ + return OpacitySlider->value(); +} + +QString QCSGridEditor::GetDirName(int ny) +{ + if (clGrid->GetMeshType()==0) + { + switch (ny) + { + case 0: + return "x"; + case 1: + return "y"; + case 2: + return "z"; + } + } + if (clGrid->GetMeshType()==1) + { + switch (ny) + { + case 0: + return "r"; + case 1: + return QChar(0xb1, 0x03); + case 2: + return "z"; + } + } + return ""; +} + +QString QCSGridEditor::GetNormName(int ny) +{ + if (clGrid->GetMeshType()==0) + { + switch (ny) + { + case 0: + return "yz"; + case 1: + return "zx"; + case 2: + return "xy"; + } + } + if (clGrid->GetMeshType()==1) + { + switch (ny) + { + case 0: + return QString(QChar(0xb1, 0x03)) + "z"; + case 1: + return "zr"; + case 2: + return "r" + QString(QChar(0xb1, 0x03)); + } + } + return ""; +} diff --git a/QCSXCAD/QCSGridEditor.h b/QCSXCAD/QCSGridEditor.h new file mode 100644 index 0000000..f54bf42 --- /dev/null +++ b/QCSXCAD/QCSGridEditor.h @@ -0,0 +1,87 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#ifndef _QCSGRIDEDITOR_H_ +#define _QCSGRIDEDITOR_H_ + +#include +#include +#include +#include +#include +#include +#include + +class CSRectGrid; + +class QCSGridEditor : public QWidget +{ + Q_OBJECT +public: + QCSGridEditor(CSRectGrid* grid, QWidget* parent = 0); + virtual ~QCSGridEditor(); + + QToolBar* BuildToolbar(); + QWidget* BuildPlanePosWidget(); + + QString GetDirName(int ny); + QString GetNormName(int ny); + + int GetOpacity(); + +signals: + void OpacityChange(int); + void signalDetectEdges(int); + void GridChanged(); + void GridPlaneXChanged(int); + void GridPlaneYChanged(int); + void GridPlaneZChanged(int); + +public slots: + void Update(); + void SetOpacity(int val); + void EditX(); + void EditY(); + void EditZ(); + void Edit(int direct); + void SetGridPlaneX(int pos); + void SetGridPlaneY(int pos); + void SetGridPlaneZ(int pos); + +protected slots: + void BuildHomogenDisc(); + void BuildInHomogenDisc(); + void IncreaseResolution(); + void DetectEdges(); + void SetDeltaUnit(QString val); + +protected: + CSRectGrid* clGrid; + QVector SimBox; + QVector NodeQty; + //QComboBox* UnitLength; + QLineEdit* UnitLength; + QSlider* OpacitySlider; + QLabel* m_DirNames[3]; + QSlider* m_PlanePos[3]; + QLabel* m_NormNames[3]; + QLabel* m_PlanePosValue[3]; + + double* GetDoubleArrayFromString(int *count, QString qsValue); +}; + +#endif //_QCSGRIDEDITOR_H_ diff --git a/QCSXCAD/QCSPrimEditor.cpp b/QCSXCAD/QCSPrimEditor.cpp new file mode 100644 index 0000000..63b4896 --- /dev/null +++ b/QCSXCAD/QCSPrimEditor.cpp @@ -0,0 +1,746 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include +#include +#include +#include +#include + +#include "QCSPrimEditor.h" +#include "QCSXCAD_Global.h" + +#include "CSPrimPoint.h" +#include "CSPrimBox.h" +#include "CSPrimMultiBox.h" +#include "CSPrimSphere.h" +#include "CSPrimSphericalShell.h" +#include "CSPrimCylinder.h" +#include "CSPrimCylindricalShell.h" +#include "CSPrimPolygon.h" +#include "CSPrimLinPoly.h" +#include "CSPrimRotPoly.h" +#include "CSPrimCurve.h" +#include "CSPrimWire.h" +#include "CSPrimUserDefined.h" + +QCSPrimEditor::QCSPrimEditor(ContinuousStructure *CS, CSPrimitives* prim, QWidget* parent) : QDialog(parent) +{ + clCS=CS; + CSPrim=prim; + + MainLayout = new QVBoxLayout(); + + switch (CSPrim->GetType()) + { + case CSPrimitives::BOX: + CSPrimEdit = new QCSPrimBoxLayout(CSPrim->ToBox()); + setWindowTitle(tr("Box Editor")); + break; + case CSPrimitives::MULTIBOX: + CSPrimEdit = new QCSPrimMultiBoxLayout(CSPrim->ToMultiBox()); + setWindowTitle(tr("Multi-Box Editor")); + break; + case CSPrimitives::SPHERE: + CSPrimEdit = new QCSPrimSphereLayout(CSPrim->ToSphere()); + setWindowTitle(tr("Sphere Editor")); + break; + case CSPrimitives::CYLINDER: + CSPrimEdit = new QCSPrimCylinderLayout(CSPrim->ToCylinder()); + setWindowTitle(tr("Cylinder Editor")); + break; + case CSPrimitives::CYLINDRICALSHELL: + CSPrimEdit = new QCSPrimCylindricalShellLayout(CSPrim->ToCylindricalShell()); + setWindowTitle(tr("CylindricalShell Editor")); + break; + case CSPrimitives::POLYGON: + CSPrimEdit = new QCSPrimPolygonLayout(CSPrim->ToPolygon()); + setWindowTitle(tr("Polygon Editor")); + break; + case CSPrimitives::USERDEFINED: + CSPrimEdit = new QCSPrimUserDefinedLayout(CSPrim->ToUserDefined()); + setWindowTitle(tr("User Defined Primitive Editor")); + break; + default: + setWindowTitle(tr("default Editor")); + CSPrimEdit = new QCSPrimitiveLayout(CSPrim); + break; + }; + + MainLayout->addWidget(BuildGeneral()); + + QGroupBox* gb = new QGroupBox(tr("Geometrical Properties")); + gb->setLayout(CSPrimEdit); + + MainLayout->addWidget(gb); + + MainLayout->addStretch(); + + MainLayout->addLayout(BuildButtons()); + + + setLayout(MainLayout); + + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowModality(Qt::ApplicationModal); +} + +QCSPrimEditor::~QCSPrimEditor() +{ +} + +void QCSPrimEditor::Reset() +{ + PrioSpinBox->setValue(CSPrim->GetPriority()); + UpdatePropertyCB(); + CSPrimEdit->GetValues(); +} + +void QCSPrimEditor::Save() +{ + CSPrim->SetPriority(PrioSpinBox->value()); + CSProperties* prop = clCS->GetProperty((unsigned int)PropertiesComboBox->currentIndex()); + if (prop==NULL) + { + std::cerr << __func__ << ": Error, property invalid!" << std::endl; + reject(); + return; + } + if (prop!=CSPrim->GetProperty()) + prop->AddPrimitive(CSPrim); + CSPrimEdit->SetValues(); + accept(); +} + +void QCSPrimEditor::Cancel() +{ + reject(); +} + +QGroupBox* QCSPrimEditor::BuildGeneral() +{ + QGroupBox* box= new QGroupBox("General"); + QGridLayout* grid = new QGridLayout(); + + grid->addWidget(new QLabel(QString(tr("ID: %1")).arg(CSPrim->GetID())),0,0); + + grid->addWidget(new QLabel(tr("Priority: ")),0,1); + PrioSpinBox = new QSpinBox(); + PrioSpinBox->setRange(-1,1000); + PrioSpinBox->setValue(CSPrim->GetPriority()); + PrioSpinBox->setEnabled(QCSX_Settings.GetEdit()); + grid->addWidget(PrioSpinBox,0,2); + PropertiesComboBox = new QComboBox(); + PropertiesComboBox->setEnabled(QCSX_Settings.GetEdit()); + + UpdatePropertyCB(); + + grid->addWidget(new QLabel(QString(tr("Choose Property: "))),1,0); + grid->addWidget(PropertiesComboBox,1,1,1,2); + + box->setLayout(grid); + + return box; +} + +QLayout* QCSPrimEditor::BuildButtons() +{ + QHBoxLayout* lay = new QHBoxLayout(); + + QPushButton* ok = new QPushButton(tr("Ok")); + QObject::connect(ok,SIGNAL(clicked()),this,SLOT(Save())); + lay->addWidget(ok); + if (QCSX_Settings.GetEdit()) + { + QPushButton* reset = new QPushButton(tr("Reset")); + QObject::connect(reset,SIGNAL(clicked()),this,SLOT(Reset())); + lay->addWidget(reset); + QPushButton* cancel = new QPushButton(tr("Cancel")); + QObject::connect(cancel,SIGNAL(clicked()),this,SLOT(Cancel())); + lay->addWidget(cancel); + } + + lay->addStretch(); + return lay; +} + +void QCSPrimEditor::UpdatePropertyCB() +{ + PropertiesComboBox->clear(); + for (size_t i=0;iGetQtyProperties();++i) + { + QString str; + CSProperties* prop=clCS->GetProperty(i); + if (prop==NULL) break; + str=QString(prop->GetName().c_str()); + switch (prop->GetType()) + { + case CSProperties::UNKNOWN: + str+=tr(" (Unknown)"); + break; + case CSProperties::MATERIAL: + str+=tr(" (Material)"); + break; + case CSProperties::METAL: + str+=tr(" (Metal)"); + break; + case CSProperties::EXCITATION: + str+=tr(" (Excitation)"); + break; + case CSProperties::PROBEBOX: + str+=tr(" (Charge-Box)"); + break; + case CSProperties::RESBOX: + str+=tr(" (Res-Box)"); + break; + case CSProperties::DUMPBOX: + str+=tr(" (Dump-Box)"); + break; + }; + PropertiesComboBox->addItem(str); + } + + CSProperties* prop=CSPrim->GetProperty(); + if (prop==NULL) PropertiesComboBox->setCurrentIndex(0); + else PropertiesComboBox->setCurrentIndex(prop->GetID()); +} + +QCSPrimitiveLayout::QCSPrimitiveLayout(CSPrimitives *prim, QWidget *parent) : QGridLayout(parent) +{ + clPrim = prim; +} + +QCSPrimitiveLayout::~QCSPrimitiveLayout() +{ +} + +void QCSPrimitiveLayout::SetValues() +{ +} + +void QCSPrimitiveLayout::GetValues() +{ +} + + +QCSPrimBoxLayout::QCSPrimBoxLayout(CSPrimBox* prim, QWidget *parent) : QCSPrimitiveLayout(prim, parent) +{ + clBox=prim; + + addWidget(new QLabel(tr("1. Point")),0,0,1,6); + addWidget(new QLabel("X:"),1,0); + Lines[0]=new QLineEdit(); + addWidget(Lines[0],1,1); + addWidget(new QLabel("Y:"),1,2); + Lines[2]=new QLineEdit(); + addWidget(Lines[2],1,3); + addWidget(new QLabel("Z:"),1,4); + Lines[4]=new QLineEdit(); + addWidget(Lines[4],1,5); + + addWidget(new QLabel(tr("2. Point")),2,0,1,6); + addWidget(new QLabel("X:"),3,0); + Lines[1]=new QLineEdit();addWidget(Lines[1],3,1); + addWidget(new QLabel("Y:"),3,2); + Lines[3]=new QLineEdit();addWidget(Lines[3],3,3); + addWidget(new QLabel("Z:"),3,4); + Lines[5]=new QLineEdit();addWidget(Lines[5],3,5); + + for (int i=0;i<6;++i) + Lines[i]->setEnabled(QCSX_Settings.GetEdit()); + + GetValues(); +} + +QCSPrimBoxLayout::~QCSPrimBoxLayout() +{ +} + +void QCSPrimBoxLayout::SetValues() +{ + bool bOk; + double dVal; + QString line; + for (size_t i=0; i< 6; ++i) + { + line=Lines[i]->text(); + dVal=line.toDouble(&bOk); + if (bOk) clBox->SetCoord(i,dVal); + else clBox->SetCoord(i,line.toStdString()); + } +} + +void QCSPrimBoxLayout::GetValues() +{ + ParameterScalar* ps; + for (size_t i=0; i< 6; ++i) + { + ps=clBox->GetCoordPS(i); + if (ps->GetMode()) Lines[i]->setText(ps->GetString().c_str()); + else Lines[i]->setText(QString("%1").arg(ps->GetValue())); + } +} + +QCSPrimSphereLayout::QCSPrimSphereLayout(CSPrimSphere* prim, QWidget *parent) : QCSPrimitiveLayout(prim, parent) +{ + clSphere=prim; + + addWidget(new QLabel(tr("Center Point")),0,0,1,6); + addWidget(new QLabel("X:"),1,0); + Lines[0]=new QLineEdit();addWidget(Lines[0],1,1); + addWidget(new QLabel("Y:"),1,2); + Lines[1]=new QLineEdit();addWidget(Lines[1],1,3); + addWidget(new QLabel("Z:"),1,4); + Lines[2]=new QLineEdit();addWidget(Lines[2],1,5); + + addWidget(new QLabel(tr("Radius")),2,0,1,2); + Lines[3]=new QLineEdit();addWidget(Lines[3],2,3,1,4); + + for (int i=0;i<4;++i) + Lines[i]->setEnabled(QCSX_Settings.GetEdit()); + + GetValues(); +} + +QCSPrimSphereLayout::~QCSPrimSphereLayout() +{ +} + +void QCSPrimSphereLayout::SetValues() +{ + bool bOk; + double dVal; + QString line; + for (size_t i=0; i< 3; ++i) + { + line=Lines[i]->text(); + dVal=line.toDouble(&bOk); + if (bOk) clSphere->SetCoord(i,dVal); + else clSphere->SetCoord(i,line.toLatin1().data()); + } + + ParameterScalar* ps=clSphere->GetRadiusPS(); + line=Lines[3]->text(); + dVal=line.toDouble(&bOk); + if (bOk) ps->SetValue(dVal); + else ps->SetValue(line.toLatin1().data()); + +} + +void QCSPrimSphereLayout::GetValues() +{ + ParameterScalar* ps; + for (size_t i=0; i< 3; ++i) + { + ps=clSphere->GetCoordPS(i); + if (ps->GetMode()) Lines[i]->setText(ps->GetString().c_str()); + else Lines[i]->setText(QString("%1").arg(ps->GetValue())); + } + + ps=clSphere->GetRadiusPS(); + if (ps->GetMode()) Lines[3]->setText(ps->GetString().c_str()); + else Lines[3]->setText(QString("%1").arg(ps->GetValue())); +} + +//****Cylinder +QCSPrimCylinderLayout::QCSPrimCylinderLayout(CSPrimCylinder* prim, QWidget *parent) : QCSPrimitiveLayout(prim, parent) +{ + clCylinder=prim; + + addWidget(new QLabel(tr("Start Point")),0,0,1,6); + addWidget(new QLabel("X:"),1,0); + Lines[0]=new QLineEdit();addWidget(Lines[0],1,1); + addWidget(new QLabel("Y:"),1,2); + Lines[2]=new QLineEdit();addWidget(Lines[2],1,3); + addWidget(new QLabel("Z:"),1,4); + Lines[4]=new QLineEdit();addWidget(Lines[4],1,5); + + addWidget(new QLabel(tr("End Point")),2,0,1,6); + addWidget(new QLabel("X:"),3,0); + Lines[1]=new QLineEdit();addWidget(Lines[1],3,1); + addWidget(new QLabel("Y:"),3,2); + Lines[3]=new QLineEdit();addWidget(Lines[3],3,3); + addWidget(new QLabel("Z:"),3,4); + Lines[5]=new QLineEdit();addWidget(Lines[5],3,5); + + addWidget(new QLabel(tr("Radius")),4,0,1,2); + Lines[6]=new QLineEdit();addWidget(Lines[6],4,3,1,4); + + for (int i=0;i<7;++i) + Lines[i]->setEnabled(QCSX_Settings.GetEdit()); + + GetValues(); +} + +QCSPrimCylinderLayout::~QCSPrimCylinderLayout() +{ +} + +void QCSPrimCylinderLayout::SetValues() +{ + bool bOk; + double dVal; + QString line; + for (size_t i=0; i< 6; ++i) + { + line=Lines[i]->text(); + dVal=line.toDouble(&bOk); + if (bOk) clCylinder->SetCoord(i,dVal); + else clCylinder->SetCoord(i,line.toLatin1().data()); + } + + ParameterScalar* ps=clCylinder->GetRadiusPS(); + line=Lines[6]->text(); + dVal=line.toDouble(&bOk); + if (bOk) ps->SetValue(dVal); + else ps->SetValue(line.toLatin1().data()); + +} + +void QCSPrimCylinderLayout::GetValues() +{ + ParameterScalar* ps; + for (size_t i=0; i< 6; ++i) + { + ps=clCylinder->GetCoordPS(i); + if (ps->GetMode()) Lines[i]->setText(ps->GetString().c_str()); + else Lines[i]->setText(QString("%1").arg(ps->GetValue())); + } + ps=clCylinder->GetRadiusPS(); + if (ps->GetMode()) Lines[6]->setText(ps->GetString().c_str()); + else Lines[6]->setText(QString("%1").arg(ps->GetValue())); +} + +//****CylindricalShell +QCSPrimCylindricalShellLayout::QCSPrimCylindricalShellLayout(CSPrimCylindricalShell* prim, QWidget *parent) : QCSPrimCylinderLayout(prim, parent) +{ + clCylindricalShell=prim; + + addWidget(new QLabel(tr("ShellWidth")),5,0,1,2); + m_ShellWidth=new QLineEdit();addWidget(m_ShellWidth,5,3,1,4); + + for (int i=0;i<8;++i) + m_ShellWidth->setEnabled(QCSX_Settings.GetEdit()); + + GetValues(); +} + +QCSPrimCylindricalShellLayout::~QCSPrimCylindricalShellLayout() +{ +} + +void QCSPrimCylindricalShellLayout::SetValues() +{ + QCSPrimCylinderLayout::SetValues(); + + bool bOk; + double dVal; + QString line; + + ParameterScalar* ps = clCylindricalShell->GetShellWidthPS(); + line = m_ShellWidth->text(); + dVal = line.toDouble(&bOk); + if (bOk) + ps->SetValue(dVal); + else + ps->SetValue(line.toLatin1().constData()); +} + +void QCSPrimCylindricalShellLayout::GetValues() +{ + QCSPrimCylinderLayout::GetValues(); + + ParameterScalar* ps = clCylindricalShell->GetShellWidthPS(); + if (ps->GetMode()) + m_ShellWidth->setText(ps->GetString().c_str()); + else + m_ShellWidth->setText(QString("%1").arg(ps->GetValue())); +} + +/*****************MultiBox*****/ +QCSPrimMultiBoxLayout::QCSPrimMultiBoxLayout(CSPrimMultiBox* prim, QWidget *parent) : QCSPrimitiveLayout(prim, parent) +{ + clMultiBox=prim; + + QPushButton *addButton = new QPushButton("Add Box"); + QObject::connect(addButton,SIGNAL(clicked()),this,SLOT(NewBox())); + addWidget(addButton,0,0); + addButton->setEnabled(QCSX_Settings.GetEdit()); + + QPushButton *editButton = new QPushButton("Edit Box"); + QObject::connect(editButton,SIGNAL(clicked()),this,SLOT(EditBox())); + addWidget(editButton,0,1); + editButton->setEnabled(QCSX_Settings.GetEdit()); + + QPushButton *deleteButton = new QPushButton("Delete Box"); + QObject::connect(deleteButton,SIGNAL(clicked()),this,SLOT(DeleteBox())); + addWidget(deleteButton,0,2); + deleteButton->setEnabled(QCSX_Settings.GetEdit()); + + qBoxList = new QListWidget(); + addWidget(qBoxList,1,0,1,3); + for (unsigned int i=0;iGetQtyBoxes();++i) + { + qBoxList->addItem(tr("Box #%1").arg(i)); + } + qBoxList->setEnabled(QCSX_Settings.GetEdit()); + + GetValues(); +} + +QCSPrimMultiBoxLayout::~QCSPrimMultiBoxLayout() +{ +} + +void QCSPrimMultiBoxLayout::SetValues() +{ + + +} + +void QCSPrimMultiBoxLayout::GetValues() +{ + +} + +void QCSPrimMultiBoxLayout::NewBox(QListWidgetItem* item) +{ + UNUSED(item); +// unsigned int nr=qBoxList->count() +// clMultiBox->ClearOverlap(); +// qBoxList->addItem(tr("Box #%1").arg(nr)); +// if (item==NULL) clMultiBox->AddBox(); +// else clMultiBox->AddBox(qBoxList->row(item)); +} + +void QCSPrimMultiBoxLayout::DeleteBox(QListWidgetItem* item) +{ + UNUSED(item); +} + +void QCSPrimMultiBoxLayout::EditBox(QListWidgetItem* item) +{ + UNUSED(item); +} + +//***********************************************************************************// +QCSPrimPolygonLayout::QCSPrimPolygonLayout(CSPrimPolygon* prim, QWidget *parent) : QCSPrimitiveLayout(prim, parent) +{ + clPoly=prim; + + addWidget(new QLabel(tr("Polygon Plane")),0,0); + NormVec = new QComboBox(); + NormVec->addItem(tr("yz-plane")); + NormVec->addItem(tr("zx-plane")); + NormVec->addItem(tr("xy-plane")); + QObject::connect(NormVec,SIGNAL(currentIndexChanged(int)),this,SLOT(NormVecChanged())); + addWidget(NormVec,0,1); + NormVec->setEnabled(QCSX_Settings.GetEdit()); + + addWidget(new QLabel(tr("Polygon Elevation")),1,0); + Elevation = new QLineEdit();; + addWidget(Elevation,1,1); + Elevation->setEnabled(QCSX_Settings.GetEdit()); + + QGroupBox* gb = new QGroupBox(tr("Polygon Vertices")); + QFormLayout* gbl = new QFormLayout(); + gb->setLayout(gbl); + addWidget(gb,2,0,1,2); + + CoordLineX = new QLineEdit(); + gbl->addRow(tr("X_1"),CoordLineX); + CoordLineX->setEnabled(QCSX_Settings.GetEdit()); + CoordLineY = new QLineEdit(); + gbl->addRow(tr("X_2"),CoordLineY); + CoordLineY->setEnabled(QCSX_Settings.GetEdit()); + + GetValues(); +} + +QCSPrimPolygonLayout::~QCSPrimPolygonLayout() +{ +} + +void QCSPrimPolygonLayout::SetValues() +{ + int ind = NormVec->currentIndex(); + clPoly->SetNormDir(ind); + ParameterScalar* ps; + bool bOk; + double dVal; + QString line; + + ps=clPoly->GetElevationPS(); + line=Elevation->text(); + dVal=line.toDouble(&bOk); + if (bOk) ps->SetValue(dVal); + else ps->SetValue(line.toStdString()); + + clPoly->ClearCoords(); + + QStringList strListX = CoordLineX->text().split(",",QString::SkipEmptyParts); + QStringList strListY = CoordLineY->text().split(",",QString::SkipEmptyParts); + + for (int i=0; (iAddCoord(dVal); + else clPoly->AddCoord(line.toStdString()); + + dVal=x2.toDouble(&bOk); + if (bOk) clPoly->AddCoord(dVal); + else clPoly->AddCoord(line.toStdString()); + } +} + +void QCSPrimPolygonLayout::GetValues() +{ + NormVec->setCurrentIndex(clPoly->GetNormDir()); + ParameterScalar* ps; + ps=clPoly->GetElevationPS(); + if (ps->GetMode()) Elevation->setText(ps->GetString().c_str()); + else Elevation->setText(QString("%1").arg(ps->GetValue())); + + QStringList strListX; + QStringList strListY; + + for (size_t i=0; iGetQtyCoords(); ++i) + { + ps=clPoly->GetCoordPS(2*i); + if (ps) + { + if (ps->GetMode()) strListX.append(ps->GetString().c_str()); + else strListX.append(QString("%1").arg(ps->GetValue())); + } + + ps=clPoly->GetCoordPS(2*i+1); + if (ps) + { + if (ps->GetMode()) strListY.append(ps->GetString().c_str()); + else strListY.append(QString("%1").arg(ps->GetValue())); + } + } + CoordLineX->setText(strListX.join(", ")); + CoordLineY->setText(strListY.join(", ")); +} + +void QCSPrimPolygonLayout::NormVecChanged() +{ +// QStringList headers; +// switch (NormVec->currentIndex()) +// { +// case 0: +// headers << "x" << "y"; +// break; +// case 1: +// headers << "y" << "z"; +// break; +// case 2: +// headers << "z" << "x"; +// break; +// default: +// headers << "x" << "y"; +// break; +// } +// CoordTable->setHorizontalHeaderLabels(headers); +} + +//***********************************************************************************// +QCSPrimUserDefinedLayout::QCSPrimUserDefinedLayout(CSPrimUserDefined* prim, QWidget *parent) : QCSPrimitiveLayout(prim, parent) +{ + clUserDef=prim; + + int row=0; + addWidget(new QLabel(tr("Choose Coordinate System")),row++,0); + CoordSystem = new QComboBox(); + CoordSystem->addItem("Cartesian Coord. System (x,y,z)"); + CoordSystem->addItem("Cartesian & Cylindrical Coord. System (x,y,z,r,a)"); + CoordSystem->addItem("Cartesian & Spherical Coord. System (x,y,z,r,a,t)"); + addWidget(CoordSystem,row++,0); + CoordSystem->setEnabled(QCSX_Settings.GetEdit()); + + QGroupBox* SysShiftGrp = new QGroupBox(tr("Shift Coordinate System")); + addWidget(SysShiftGrp,row++,0); + + QGridLayout* lay = new QGridLayout; + SysShiftGrp->setLayout(lay); + + lay->addWidget(new QLabel(tr("X-Shift:")),0,0); + CoordShift[0]=new QLineEdit(); + lay->addWidget(CoordShift[0],0,1); + lay->addWidget(new QLabel(tr("Y-Shift:")),1,0); + CoordShift[1]=new QLineEdit(); + lay->addWidget(CoordShift[1],1,1); + lay->addWidget(new QLabel(tr("Z-Shift:")),2,0); + CoordShift[2]=new QLineEdit(); + lay->addWidget(CoordShift[2],2,1); + for (int i=0;i<3;++i) + CoordShift[i]->setEnabled(QCSX_Settings.GetEdit()); + + addWidget(new QLabel(tr("Define Bool-Function for this Primitive in chosen Coord. System:")),row++,0); + FunctionLine = new QLineEdit(); + addWidget(FunctionLine,row++,0); + FunctionLine->setEnabled(QCSX_Settings.GetEdit()); + + GetValues(); +} + +QCSPrimUserDefinedLayout::~QCSPrimUserDefinedLayout() +{ +} + +void QCSPrimUserDefinedLayout::SetValues() +{ + clUserDef->SetCoordSystem((CSPrimUserDefined::UserDefinedCoordSystem)CoordSystem->currentIndex()); + clUserDef->SetFunction(FunctionLine->text().toStdString().c_str()); + + bool bOk; + double dVal; + QString line; + ParameterScalar* ps; + for (size_t i=0; i< 3; ++i) + { + ps=clUserDef->GetCoordShiftPS(i); + line=CoordShift[i]->text(); + dVal=line.toDouble(&bOk); + if (bOk) ps->SetValue(dVal); + else ps->SetValue(line.toLatin1().data()); + } +} + +void QCSPrimUserDefinedLayout::GetValues() +{ + CoordSystem->setCurrentIndex(clUserDef->GetCoordSystem()); + FunctionLine->setText(clUserDef->GetFunction()); + + ParameterScalar* ps; + for (size_t i=0; i< 3; ++i) + { + ps=clUserDef->GetCoordShiftPS(i); + if (ps==NULL) return; + if (ps->GetMode()) CoordShift[i]->setText(ps->GetString().c_str()); + else CoordShift[i]->setText(QString("%1").arg(ps->GetValue())); + } +} + + diff --git a/QCSXCAD/QCSPrimEditor.h b/QCSXCAD/QCSPrimEditor.h new file mode 100644 index 0000000..19794ee --- /dev/null +++ b/QCSXCAD/QCSPrimEditor.h @@ -0,0 +1,237 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#ifndef _QCSPRIMEDITOR_H_ +#define _QCSPRIMEDITOR_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ContinuousStructure.h" + +class QCSPrimitiveLayout; +class QCSPrimBoxLayout; +class QCSPrimSphereLayout; +class QCSPrimCylinderLayout; +class QCSPrimMultiBoxLayout; +class QCSPrimPolygon; + class QCSPrimLinPoly; + class QCSPrimRotPoly; +class QCSPrimUserDefinedLayout; + +class QCSPrimEditor : public QDialog +{ + Q_OBJECT +public: + QCSPrimEditor(ContinuousStructure *CS, CSPrimitives* prim, QWidget* parent=NULL); + virtual ~QCSPrimEditor(); + +protected slots: + void Reset(); + void Save(); + void Cancel(); + + void UpdatePropertyCB(); + +protected: + QGroupBox* BuildGeneral(); + QLayout* BuildButtons(); + + QSpinBox* PrioSpinBox; + QComboBox* PropertiesComboBox; + + QVBoxLayout* MainLayout; + QCSPrimitiveLayout* CSPrimEdit; + ContinuousStructure *clCS; + CSPrimitives* CSPrim; +}; + +class QCSPrimitiveLayout : public QGridLayout +{ + Q_OBJECT +public: + QCSPrimitiveLayout(CSPrimitives* prim, QWidget *parent=NULL); + virtual ~QCSPrimitiveLayout(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +protected: + CSPrimitives* clPrim; + +}; + + +class QCSPrimBoxLayout : public QCSPrimitiveLayout +{ + Q_OBJECT +public: + QCSPrimBoxLayout(CSPrimBox* prim, QWidget *parent=NULL); + virtual ~QCSPrimBoxLayout(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +protected: + CSPrimBox* clBox; + QLineEdit *Lines[6]; +}; + +class QCSPrimSphereLayout : public QCSPrimitiveLayout +{ + Q_OBJECT +public: + QCSPrimSphereLayout(CSPrimSphere* prim, QWidget *parent=NULL); + virtual ~QCSPrimSphereLayout(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +protected: + CSPrimSphere* clSphere; + QLineEdit *Lines[4]; +}; + +class QCSPrimCylinderLayout : public QCSPrimitiveLayout +{ + Q_OBJECT +public: + QCSPrimCylinderLayout(CSPrimCylinder* prim, QWidget *parent=NULL); + virtual ~QCSPrimCylinderLayout(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +protected: + CSPrimCylinder* clCylinder; + QLineEdit *Lines[7]; +}; + +class QCSPrimCylindricalShellLayout : public QCSPrimCylinderLayout +{ + Q_OBJECT +public: + QCSPrimCylindricalShellLayout(CSPrimCylindricalShell* prim, QWidget *parent=NULL); + virtual ~QCSPrimCylindricalShellLayout(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +protected: + CSPrimCylindricalShell* clCylindricalShell; + QLineEdit *m_ShellWidth; +}; + +class QCSPrimMultiBoxLayout : public QCSPrimitiveLayout +{ + Q_OBJECT +public: + QCSPrimMultiBoxLayout(CSPrimMultiBox* prim, QWidget *parent=NULL); + virtual ~QCSPrimMultiBoxLayout(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +protected slots: + void NewBox(QListWidgetItem* item=NULL); + void DeleteBox(QListWidgetItem* item=NULL); + void EditBox(QListWidgetItem* item=NULL); + +signals: + void modified(); + +protected: + CSPrimMultiBox* clMultiBox; + + QListWidget* qBoxList; + QVector vLines; +}; + +class QCSPrimPolygonLayout : public QCSPrimitiveLayout +{ + Q_OBJECT +public: + QCSPrimPolygonLayout(CSPrimPolygon* prim, QWidget *parent=NULL); + virtual ~QCSPrimPolygonLayout(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +protected slots: + void NormVecChanged(); + +signals: + void modified(); + +protected: + CSPrimPolygon* clPoly; + QComboBox* NormVec; + QLineEdit* Elevation; + QLineEdit* CoordLineX; + QLineEdit* CoordLineY; +}; + +class QCSPrimUserDefinedLayout : public QCSPrimitiveLayout +{ + Q_OBJECT +public: + QCSPrimUserDefinedLayout(CSPrimUserDefined* prim, QWidget *parent=NULL); + virtual ~QCSPrimUserDefinedLayout(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +protected: + CSPrimUserDefined* clUserDef; + QLineEdit *FunctionLine; + QComboBox *CoordSystem; + QLineEdit *CoordShift[3]; +}; + +#endif //_QCSPRIMEDITOR_H_ diff --git a/QCSXCAD/QCSPropEditor.cpp b/QCSXCAD/QCSPropEditor.cpp new file mode 100644 index 0000000..15804e0 --- /dev/null +++ b/QCSXCAD/QCSPropEditor.cpp @@ -0,0 +1,623 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include + +#include "QCSPropEditor.h" +#include "QCSXCAD_Global.h" +#include "iostream" +#include "time.h" + +#include "CSPropUnknown.h" +#include "CSPropMaterial.h" +#include "CSPropDispersiveMaterial.h" +#include "CSPropLorentzMaterial.h" +#include "CSPropDiscMaterial.h" +#include "CSPropLumpedElement.h" +#include "CSPropMetal.h" +#include "CSPropConductingSheet.h" +#include "CSPropExcitation.h" +#include "CSPropProbeBox.h" +#include "CSPropDumpBox.h" +#include "CSPropResBox.h" + +QColorPushButton::QColorPushButton(const QString & text, QWidget * parent ) : QPushButton(text,parent) +{ + setFlat(true); + setAutoFillBackground(true); + QObject::connect(this,SIGNAL(clicked()),this,SLOT(ChangeColor())); + //Color.setAlpha(255); + + RGBa c; + c.R=1 + (rand()%255); + c.G=1 + (rand()%255); + c.B=1 + (rand()%255); + SetColor(c); +} + +QColorPushButton::~QColorPushButton() +{ +} + +void QColorPushButton::SetColor(RGBa c) +{ + QPalette palette; + + Color=QColor(c.R,c.G,c.B,c.a); + + palette.setColor(QPalette::Button,QColor(c.R,c.G,c.B)); + if (c.R+c.G+c.B>(128*3)) palette.setColor(QPalette::ButtonText,QColor(0,0,0)); + else palette.setColor(QPalette::ButtonText,QColor(255,255,255)); + setPalette(palette); +} + +RGBa QColorPushButton::GetColor() +{ + RGBa c; + c.R=Color.red(); + c.G=Color.green(); + c.B=Color.blue(); + c.a=Color.alpha(); + return c; +} + +void QColorPushButton::ChangeColor() +{ + QColor newColor=QColorDialog::getColor(Color,this); + if (newColor.isValid()) + { + int alpha=Color.alpha(); + Color=newColor; + Color.setAlpha(alpha); + QPalette palette; + palette.setColor(QPalette::Button,newColor); + if (Color.red()+Color.blue()+Color.green()>(128*3)) palette.setColor(QPalette::ButtonText,QColor(0,0,0)); + else palette.setColor(QPalette::ButtonText,QColor(255,255,255)); + setPalette(palette); + } +} + +QCSPropEditor::QCSPropEditor(ContinuousStructure *CS, CSProperties* prop, int iSimMode, QWidget* parent) : QDialog(parent) +{ + clCS=CS; + clProp=prop; + saveProp=clProp; + m_SimMode=iSimMode; + + MainLayout = new QVBoxLayout(); + + setWindowTitle(tr("Property Editor")); + + MainLayout->addWidget(BuildGeneral()); + GetValues(); + + + if (propGB!=NULL) + { + MainLayout->addWidget(propGB); + } + + MainLayout->addStretch(); + + MainLayout->addLayout(BuildButtons()); + + + setLayout(MainLayout); + + setAttribute(Qt::WA_DeleteOnClose, true); + setWindowModality(Qt::ApplicationModal); +} + +QCSPropertyGroupBox* QCSPropEditor::BuildPropGroupBox(CSProperties* clProp) +{ + QCSPropertyGroupBox* propGB=NULL; + switch (clProp->GetType()) + { + case CSProperties::MATERIAL: + propGB = new QCSPropMaterialGB(clProp->ToMaterial()); + break; + case CSProperties::METAL: + break; + case CSProperties::EXCITATION: + propGB = new QCSPropExcitationGB(clProp->ToExcitation()); + break; + case CSProperties::PROBEBOX: + propGB = new QCSPropProbeBoxGB(clProp->ToProbeBox()); + break; + case CSProperties::DUMPBOX: + propGB = new QCSPropDumpBoxGB(clProp->ToDumpBox(),m_SimMode); + break; + case CSProperties::RESBOX: + propGB = new QCSPropResBoxGB(clProp->ToResBox()); + break; + case CSProperties::UNKNOWN: + propGB = new QCSPropUnknownGB(clProp->ToUnknown()); + break; + default: + return NULL; + break; + }; + return propGB; +} + + +void QCSPropEditor::Reset() +{ + GetValues(); + if (propGB!=NULL) propGB->GetValues(); +} + +void QCSPropEditor::Save() +{ + SetValues(); + if (propGB!=NULL) propGB->SetValues(); + + accept(); +} + +void QCSPropEditor::Cancel() +{ + reject(); +} + +void QCSPropEditor::ChangeType(int item) +{ + bool ok=false; + int type = TypeCB->itemData(item).toInt(&ok); + if (ok==false) return; + if (type==clProp->GetType()) return; + //if (propGB!=NULL) MainLayout->removeWidget(propGB); + //if (propGB!=savePropGB) delete propGB; + if (clProp!=saveProp) delete clProp; + delete propGB;propGB=NULL; + if (type==saveProp->GetType()) + { + clProp=saveProp; + } + else switch (type) + { + case CSProperties::MATERIAL: + clProp = new CSPropMaterial(saveProp); + break; + case CSProperties::METAL: + clProp = new CSPropMetal(saveProp); + break; + case CSProperties::EXCITATION: + clProp = new CSPropExcitation(saveProp); + break; + case CSProperties::PROBEBOX: + clProp = new CSPropProbeBox(saveProp); + break; + case CSProperties::DUMPBOX: + clProp = new CSPropDumpBox(saveProp); + break; + case CSProperties::RESBOX: + clProp = new CSPropResBox(saveProp); + break; + default: + clProp = new CSPropUnknown(saveProp); + break; + }; + propGB=BuildPropGroupBox(clProp); + if (propGB!=NULL) MainLayout->insertWidget(1,propGB); + setLayout(MainLayout); +} + +void QCSPropEditor::Fill2EdgeColor() +{ + ECButton->SetColor(FCButton->GetColor()); +} + +void QCSPropEditor::Edge2FillColor() +{ + FCButton->SetColor(ECButton->GetColor()); +} + +QGroupBox* QCSPropEditor::BuildGeneral() +{ + QGroupBox* box= new QGroupBox("General"); + QGridLayout* grid = new QGridLayout(); + + Name = new QLineEdit(QString::fromUtf8(clProp->GetName().c_str())); + Name->setEnabled(QCSX_Settings.GetEdit()); + grid->addWidget(new QLabel(tr("Name: ")),0,0); + grid->addWidget(Name,0,1); + grid->addWidget(new QLabel(QString(tr("ID: %1")).arg(clProp->GetID())),0,2); + + grid->addWidget(new QLabel(tr("Type: ")),1,0); + TypeCB = new QComboBox(); + TypeCB->addItem(tr("Unknown"),QVariant(CSProperties::UNKNOWN)); + TypeCB->addItem(tr("Material"),QVariant(CSProperties::MATERIAL)); + TypeCB->addItem(tr("Metal"),QVariant(CSProperties::METAL)); + TypeCB->addItem(tr("Excitation"),QVariant(CSProperties::EXCITATION)); + TypeCB->addItem(tr("Probe Box"),QVariant(CSProperties::PROBEBOX)); + TypeCB->addItem(tr("Res Box"),QVariant(CSProperties::RESBOX)); + TypeCB->addItem(tr("Dump Box"),QVariant(CSProperties::DUMPBOX)); + TypeCB->setEnabled(QCSX_Settings.GetEdit()); + grid->addWidget(TypeCB,1,1,1,2); + QObject::connect(TypeCB,SIGNAL(currentIndexChanged(int)),this,SLOT(ChangeType(int))); + + QHBoxLayout* HLay = new QHBoxLayout(); + HLay->addStretch(1); + FCButton = new QColorPushButton(tr("Change Fill-Color")); + FCButton->setFixedSize(100,50); + HLay->addWidget(FCButton); + + QVBoxLayout* VLay = new QVBoxLayout(); + QPushButton* F2EButton = new QPushButton("-->"); + F2EButton->setFixedSize(30,20); + QObject::connect(F2EButton,SIGNAL(clicked()),this,SLOT(Fill2EdgeColor())); + QPushButton* E2FButton = new QPushButton("<--"); + E2FButton->setFixedSize(30,20); + QObject::connect(E2FButton,SIGNAL(clicked()),this,SLOT(Edge2FillColor())); + VLay->addWidget(F2EButton); + VLay->addWidget(E2FButton); + HLay->addLayout(VLay); + + ECButton = new QColorPushButton(tr("Change Edge-Color")); + ECButton->setFixedSize(100,50); + HLay->addWidget(ECButton); + HLay->addStretch(1); + + grid->addLayout(HLay,2,0,1,3); + box->setLayout(grid); + + return box; +} + +QLayout* QCSPropEditor::BuildButtons() +{ + QHBoxLayout* lay = new QHBoxLayout(); + + QPushButton* ok = new QPushButton(tr("Ok")); + QObject::connect(ok,SIGNAL(clicked()),this,SLOT(Save())); + lay->addWidget(ok); + if (QCSX_Settings.GetEdit()) + { + QPushButton* reset = new QPushButton(tr("Reset")); + QObject::connect(reset,SIGNAL(clicked()),this,SLOT(Reset())); + lay->addWidget(reset); + QPushButton* cancel = new QPushButton(tr("Cancel")); + QObject::connect(cancel,SIGNAL(clicked()),this,SLOT(Cancel())); + lay->addWidget(cancel); + } + lay->addStretch(); + + return lay; +} + +void QCSPropEditor::GetValues() +{ + if (clProp!=saveProp) + { + delete clProp; + delete propGB; + clProp=saveProp; + } + + propGB = BuildPropGroupBox(clProp); + + Name->setText(QString::fromUtf8(clProp->GetName().c_str())); + TypeCB->setCurrentIndex(GetIndexOfType()); + FCButton->SetColor(clProp->GetFillColor()); + ECButton->SetColor(clProp->GetEdgeColor()); +} + +void QCSPropEditor::SetValues() +{ + //RGBa c; + clProp->SetFillColor(FCButton->GetColor()); + clProp->SetEdgeColor(ECButton->GetColor()); + clProp->SetName(Name->text().toLatin1().data()); + + if (saveProp!=clProp) clCS->ReplaceProperty(saveProp,clProp); +} + +int QCSPropEditor::GetIndexOfType() +{ + for (int i=0;icount();++i) + { + if (TypeCB->itemData(i).toInt()==clProp->GetType()) return i; + } + return 0; +} + +/***************************QCSPropertyGroupBox**************************************/ +QCSPropertyGroupBox::QCSPropertyGroupBox(QWidget *parent) : QGroupBox(parent) +{ +} + +QCSPropertyGroupBox::~QCSPropertyGroupBox() +{ +} + +void QCSPropertyGroupBox::SetValues() +{ +} + +void QCSPropertyGroupBox::GetValues() +{ +} + +/***************************QCSPropUnknownGB**************************************/ +QCSPropUnknownGB::QCSPropUnknownGB(CSPropUnknown *prop, QWidget *parent) : QCSPropertyGroupBox(parent) +{ + clProp=prop; + TypeName=QString(tr("Unknown")); + setTitle(tr("Unknown Property")); + + QGridLayout* layout = new QGridLayout(); + + Property = new QLineEdit(); + layout->addWidget(new QLabel(tr("Property: ")),0,0); + layout->addWidget(Property,0,1); + + GetValues(); + + setLayout(layout); +} + +QCSPropUnknownGB::~QCSPropUnknownGB() +{ +} + +void QCSPropUnknownGB::SetValues() +{ + clProp->SetProperty(Property->text().toLatin1().data()); +} + +void QCSPropUnknownGB::GetValues() +{ + Property->setText(clProp->GetProperty().c_str()); +} + + +/***************************QCSPropMaterialGB**************************************/ +QCSPropMaterialGB::QCSPropMaterialGB(CSPropMaterial *prop, QWidget *parent) : QCSPropertyGroupBox(parent) +{ + clProp=prop; + TypeName=QString(tr("Material")); + setTitle(tr("Material Property")); + + QGridLayout* layout = new QGridLayout(); + + GetValues(); + + setLayout(layout); +} + +QCSPropMaterialGB::~QCSPropMaterialGB() +{ +} + +void QCSPropMaterialGB::SetValues() +{ +} + +void QCSPropMaterialGB::GetValues() +{ +} + +/***************************QCSPropExcitationGB**************************************/ +QCSPropExcitationGB::QCSPropExcitationGB(CSPropExcitation *prop, QWidget *parent) : QCSPropertyGroupBox(parent) +{ + clProp=prop; + TypeName=QString(tr("Excitation")); + setTitle(tr("Excitation Property")); + + QGridLayout* layout = new QGridLayout(); + + Number = new QSpinBox(); + Number->setRange(0,999); + Number->setEnabled(QCSX_Settings.GetEdit()); + layout->addWidget(new QLabel(tr("Number: ")),0,0); + layout->addWidget(Number,0,1); + + Type = new QComboBox(); + Type->addItem(tr("Electric field (soft)")); + Type->addItem(tr("Electric field (hard)")); + Type->addItem(tr("Magnetic field (soft)")); + Type->addItem(tr("Magnetic field (hard)")); + Type->setEnabled(QCSX_Settings.GetEdit()); + layout->addWidget(new QLabel(tr("Type: ")),0,2); + layout->addWidget(Type,0,3,1,3); + QObject::connect(Type,SIGNAL(currentIndexChanged(int)),this,SLOT(TypeChanged(int))); + + layout->addWidget(new QLabel(tr("Excitation (X):")),1,0); + Excitation[0] = new QLineEdit(); + layout->addWidget(Excitation[0],1,1); + + layout->addWidget(new QLabel(tr("Excitation Y:")),1,2); + Excitation[1] = new QLineEdit(); + layout->addWidget(Excitation[1],1,3); + + layout->addWidget(new QLabel(tr("Excitation Z:")),1,4); + Excitation[2] = new QLineEdit(); + layout->addWidget(Excitation[2],1,5); + + layout->addWidget(new QLabel(tr("Analytic Fct (X): ")),2,0); + FctLine[0] = new QLineEdit(); + layout->addWidget(FctLine[0],2,1,1,5); + + layout->addWidget(new QLabel(tr("Analytic Fct (Y): ")),3,0); + FctLine[1] = new QLineEdit(); + layout->addWidget(FctLine[1],3,1,1,5); + + layout->addWidget(new QLabel(tr("Analytic Fct (Z): ")),4,0); + FctLine[2] = new QLineEdit(); + layout->addWidget(FctLine[2],4,1,1,5); + + GetValues(); + + setLayout(layout); +} + +QCSPropExcitationGB::~QCSPropExcitationGB() +{ +} + +void QCSPropExcitationGB::SetValues() +{ + bool bOk; + double dVal; + QString line; + + for (unsigned int i=0;i<3;++i) + { + line=Excitation[i]->text(); + dVal=line.toDouble(&bOk); + if (bOk) clProp->SetExcitation(dVal,i); + else clProp->SetExcitation(line.toLatin1().data(),i); + } + clProp->SetNumber((unsigned int)Number->value()); + clProp->SetExcitType(Type->currentIndex()+1); + for (unsigned int i=0;i<3;++i) + clProp->SetWeightFunction(FctLine[i]->text().toLatin1().data(),i); +} + +void QCSPropExcitationGB::GetValues() +{ + std::string line; + + for (unsigned int i=0;i<3;++i) + { + line=clProp->GetExcitationString(i); + if (!line.empty()) Excitation[i]->setText(line.c_str()); + else Excitation[i]->setText(QString("%1").arg(clProp->GetExcitation(i))); + } + + Number->setValue(clProp->GetNumber()); + Type->setCurrentIndex(clProp->GetExcitType()); + TypeChanged(clProp->GetExcitType()); + + for (unsigned int i=0;i<3;++i) + FctLine[i]->setText(clProp->GetWeightFunction(i).c_str()); +} + +void QCSPropExcitationGB::TypeChanged(int index) +{ + //enable/disable certain lines, depending on the excitation typez + switch (index) + { + default: + Excitation[0]->setEnabled(true & QCSX_Settings.GetEdit()); + Excitation[1]->setEnabled(true & QCSX_Settings.GetEdit()); + Excitation[2]->setEnabled(true & QCSX_Settings.GetEdit()); + FctLine[0]->setEnabled(true & QCSX_Settings.GetEdit()); + FctLine[1]->setEnabled(true & QCSX_Settings.GetEdit()); + FctLine[2]->setEnabled(true & QCSX_Settings.GetEdit()); + break; + } +} + +/***************************QCSPropChargeBoxGB**************************************/ +QCSPropProbeBoxGB::QCSPropProbeBoxGB(CSPropProbeBox *prop, QWidget *parent) : QCSPropertyGroupBox(parent) +{ + clProp=prop; + TypeName=QString(tr("Probe Box")); + setTitle(tr("ProbeBox Property")); + + QGridLayout* layout = new QGridLayout(); + + Number = new QSpinBox(); + Number->setRange(0,999); + Number->setEnabled(QCSX_Settings.GetEdit()); + layout->addWidget(new QLabel(tr("Number: ")),0,0); + layout->addWidget(Number,0,1); + + GetValues(); + + setLayout(layout); +} + +QCSPropProbeBoxGB::~QCSPropProbeBoxGB() +{ +} + +void QCSPropProbeBoxGB::SetValues() +{ + clProp->SetNumber((unsigned int)Number->value()); +} + +void QCSPropProbeBoxGB::GetValues() +{ + Number->setValue(clProp->GetNumber()); +} + +/***************************QCSPropResBoxGB**************************************/ +QCSPropResBoxGB::QCSPropResBoxGB(CSPropResBox *prop, QWidget *parent) : QCSPropertyGroupBox(parent) +{ + clProp=prop; + TypeName=QString(tr("Resolution Box")); + setTitle(tr("ResBox Property")); + + QGridLayout* layout = new QGridLayout(); + + Factor = new QSpinBox(); + Factor->setRange(2,16); + Factor->setEnabled(QCSX_Settings.GetEdit()); + layout->addWidget(new QLabel(tr("Resolution Factor: ")),0,0); + layout->addWidget(Factor,0,1); + + GetValues(); + + setLayout(layout); +} + +QCSPropResBoxGB::~QCSPropResBoxGB() +{ +} + +void QCSPropResBoxGB::SetValues() +{ + clProp->SetResFactor((unsigned int)Factor->value()); +} + +void QCSPropResBoxGB::GetValues() +{ + Factor->setValue(clProp->GetResFactor()); +} + + +/***************************QCSPropDumpBoxGB**************************************/ +QCSPropDumpBoxGB::QCSPropDumpBoxGB(CSPropDumpBox *prop, int SimMode, QWidget *parent) : QCSPropertyGroupBox(parent) +{ + UNUSED(SimMode); + + clProp=prop; + TypeName=QString(tr("Dump Box")); + setTitle(tr("Dump Property")); + + QVBoxLayout* layout = new QVBoxLayout(); + + GetValues(); + + setLayout(layout); +} + +QCSPropDumpBoxGB::~QCSPropDumpBoxGB() +{ +} + +void QCSPropDumpBoxGB::SetValues() +{ +} + +void QCSPropDumpBoxGB::GetValues() +{ +} + diff --git a/QCSXCAD/QCSPropEditor.h b/QCSXCAD/QCSPropEditor.h new file mode 100644 index 0000000..d46ce85 --- /dev/null +++ b/QCSXCAD/QCSPropEditor.h @@ -0,0 +1,248 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#ifndef _QCSPROPEDITOR_H_ +#define _QCSPROPEDITOR_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ContinuousStructure.h" + +class QColorPushButton : public QPushButton +{ + Q_OBJECT +public: + QColorPushButton(const QString & text, QWidget * parent = 0 ); + ~QColorPushButton(); + + void SetColor(RGBa c); + RGBa GetColor(); + +protected slots: + void ChangeColor(); + +protected: + QColor Color; +}; + +class QCSPropertyGroupBox; +class QCSPropMaterialGB; + +class QCSPropEditor : public QDialog +{ + Q_OBJECT +public: + QCSPropEditor(ContinuousStructure *CS, CSProperties* prop, int iSimMode, QWidget* parent=NULL); + ~QCSPropEditor() {}; + +protected slots: + void Reset(); + void Save(); + void Cancel(); + + void ChangeType(int item); + + void Fill2EdgeColor(); + void Edge2FillColor(); + + void GetValues(); + void SetValues(); + +protected: + QComboBox* TypeCB; + + QGroupBox* BuildGeneral(); + QLayout* BuildButtons(); + + QVBoxLayout* MainLayout; + //QCSPropertyLayout* CSPropEdit; + ContinuousStructure *clCS; + + QLineEdit* Name; + QLabel* TypeLbl; + + QColorPushButton* FCButton; + QColorPushButton* ECButton; + + CSProperties* clProp; + CSProperties* saveProp; + + QCSPropertyGroupBox* BuildPropGroupBox(CSProperties* clProp); + QCSPropertyGroupBox* propGB; + + int GetIndexOfType(); + + int m_SimMode; +}; + +//dummy class +class QCSPropertyGroupBox : public QGroupBox +{ + Q_OBJECT +public: + virtual ~QCSPropertyGroupBox(); + +protected: + QCSPropertyGroupBox(QWidget *parent=NULL); + + QString TypeName; + QString GetTypeName() {return TypeName;}; + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +}; + +class QCSPropUnknownGB : public QCSPropertyGroupBox +{ + Q_OBJECT +public: + QCSPropUnknownGB(CSPropUnknown *prop, QWidget *parent=NULL); + virtual ~QCSPropUnknownGB(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +protected: + CSPropUnknown* clProp; + + QLineEdit* Property; +}; + + +class QCSPropMaterialGB : public QCSPropertyGroupBox +{ + Q_OBJECT +public: + QCSPropMaterialGB(CSPropMaterial *prop, QWidget *parent=NULL); + virtual ~QCSPropMaterialGB(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +protected: + CSPropMaterial* clProp; +}; + +class QCSPropExcitationGB : public QCSPropertyGroupBox +{ + Q_OBJECT +public: + QCSPropExcitationGB(CSPropExcitation *prop, QWidget *parent=NULL); + virtual ~QCSPropExcitationGB(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +protected slots: + void TypeChanged(int index); + +signals: + void modified(); + +protected: + CSPropExcitation* clProp; + + QLineEdit* FctLine[3]; + + QSpinBox* Number; + QComboBox* Type; + + QLineEdit* Excitation[3]; +}; + +class QCSPropProbeBoxGB : public QCSPropertyGroupBox +{ + Q_OBJECT +public: + QCSPropProbeBoxGB(CSPropProbeBox *prop, QWidget *parent=NULL); + virtual ~QCSPropProbeBoxGB(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +protected: + CSPropProbeBox* clProp; + + QSpinBox* Number; +}; + +class QCSPropResBoxGB : public QCSPropertyGroupBox +{ + Q_OBJECT +public: + QCSPropResBoxGB(CSPropResBox *prop, QWidget *parent=NULL); + virtual ~QCSPropResBoxGB(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +protected: + CSPropResBox* clProp; + + QSpinBox* Factor; +}; + +class QCSPropDumpBoxGB : public QCSPropertyGroupBox +{ + Q_OBJECT +public: + QCSPropDumpBoxGB(CSPropDumpBox *prop, int SimMode, QWidget *parent=NULL); + virtual ~QCSPropDumpBoxGB(); + +public slots: + virtual void SetValues(); + virtual void GetValues(); + +signals: + void modified(); + +protected: + CSPropDumpBox* clProp; +}; + + +#endif //_QCSPROPEDITOR_H_ diff --git a/QCSXCAD/QCSTreeWidget.cpp b/QCSXCAD/QCSTreeWidget.cpp new file mode 100644 index 0000000..e15743d --- /dev/null +++ b/QCSXCAD/QCSTreeWidget.cpp @@ -0,0 +1,242 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include +#include + +#include "QCSTreeWidget.h" +#include "QCSXCAD_Global.h" + +QCSTreeWidget::QCSTreeWidget(ContinuousStructure* CS, QWidget * parent) : QTreeWidget(parent) +{ + clCS=CS; + setColumnCount(2); + setColumnWidth(0,200); +// setColumnWidth(1,16); + setHeaderLabels(QStringList(tr("Properties / Primitives"))<setDragEnabled(true); +// qTree->setAcceptDrops(true); +// qTree->setDropIndicatorShown(true); + QObject::connect(this,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),this,SLOT(Edit(QTreeWidgetItem*,int))); + QObject::connect(this,SIGNAL(itemClicked(QTreeWidgetItem*,int)),this,SLOT(Clicked(QTreeWidgetItem*,int))); +} + +QCSTreeWidget::~QCSTreeWidget() +{ +} + +CSProperties* QCSTreeWidget::GetCurrentProperty() +{ + QTreeWidgetItem* curr=currentItem(); + if (curr==NULL) return NULL; + if (curr->type()==PRIMTYPE) curr=curr->parent(); + if (curr==NULL) return NULL; + return clCS->GetProperty(indexOfTopLevelItem(curr)); +} + +CSPrimitives* QCSTreeWidget::GetCurrentPrimitive() +{ + QTreeWidgetItem* curr=currentItem(); + if (curr==NULL) return NULL; + if (curr->type()!=PRIMTYPE) return NULL; + return clCS->GetPrimitiveByID(curr->data(0,1).toInt()); +} + +void QCSTreeWidget::AddPrimItem(CSPrimitives* prim) +{ + if (prim==NULL) + return; + int propID=clCS->GetIndex(prim->GetProperty()); + if (propID<0) + return; + QTreeWidgetItem* parent = topLevelItem(propID); + if (parent==NULL) + return; + QString str = QString(prim->GetTypeName().c_str()); + + str+=QString(" - ID: %1").arg(prim->GetID()); + QTreeWidgetItem* newPrimItem = new QTreeWidgetItem(parent,QStringList(str),1); + newPrimItem->setData(0,1,QVariant(prim->GetID())); + vPrimItems.push_back(newPrimItem); +} + +void QCSTreeWidget::AddPropItem(CSProperties* prop) +{ + QString str; + if (prop==NULL) return; + str=QString(prop->GetTypeXMLString().c_str())+"::"; + str+=QString::fromUtf8(prop->GetName().c_str()); + + QTreeWidgetItem* newItem = new QTreeWidgetItem(this,QStringList(str),0); + newItem->setFont(0,QFont("Arial",10)); + if (prop->GetVisibility()) newItem->setIcon(1,QIcon(":/images/bulb.png")); + else newItem->setIcon(1,QIcon(":/images/bulb_off.png")); +} + + +QTreeWidgetItem* QCSTreeWidget::GetTreeItemByPrimID(int primID) +{ + for (int n=0;ndata(0,1).toInt()==primID) + return vPrimItems.at(n); + return NULL; +} + +int QCSTreeWidget::GetTreeItemIndexByPrimID(int primID) +{ + for (int n=0;ndata(0,1).toInt()==primID) + return n; + return -1; +} + +void QCSTreeWidget::DeletePrimItem(CSPrimitives* prim) +{ + int index=GetTreeItemIndexByPrimID(prim->GetID()); + QTreeWidgetItem* item; + if ((index>=0) && (indexGetIndex(prop); + + QTreeWidgetItem* parent = topLevelItem(index); + if (parent==NULL) return; + + delete parent; +} + +void QCSTreeWidget::RefreshItem(int index) +{ + CSProperties* prop=clCS->GetProperty(index); + if (prop==NULL) return; + QTreeWidgetItem* item = topLevelItem(index); + if (item==NULL) return; + QString str=QString(prop->GetTypeXMLString().c_str())+"::"; + str+=QString::fromUtf8(prop->GetName().c_str()); + item->setText(0,str); + if (prop->GetVisibility()) item->setIcon(1,QIcon(":/images/bulb.png")); + else item->setIcon(1,QIcon(":/images/bulb_off.png")); +} + + +void QCSTreeWidget::contextMenuEvent(QContextMenuEvent *event) +{ + QMenu menu(this); + if (QCSX_Settings.GetEdit()) + { + QMenu* primM = menu.addMenu(QIcon(":/images/edit_add.png"),tr("New Primitive")); + primM->addAction(tr("Box"),this,SIGNAL(NewBox())); + primM->addAction(tr("Multi-Box"),this,SIGNAL(NewMultiBox())); + primM->addAction(tr("Sphere"),this,SIGNAL(NewSphere())); + primM->addAction(tr("Cylinder"),this,SIGNAL(NewCylinder())); + primM->addAction(tr("User Defined"),this,SIGNAL(NewUserDefined())); + + QMenu* propM = menu.addMenu(QIcon(":/images/edit_add.png"),tr("New Property")); + propM->addAction(tr("Material"),this,SIGNAL(NewMaterial())); + propM->addAction(tr("Metal"),this,SIGNAL(NewMetal())); + propM->addAction(tr("Excitation"),this,SIGNAL(NewExcitation())); + propM->addAction(tr("Probe-Box"),this,SIGNAL(NewChargeBox())); + propM->addAction(tr("Res-Box"),this,SIGNAL(NewResBox())); + propM->addAction(tr("Dump-Box"),this,SIGNAL(NewDumpBox())); + + menu.addSeparator(); + + menu.addAction(QIcon(":/images/edit.png"),tr("Edit"),this,SIGNAL(Edit())); + menu.addAction(QIcon(":/images/editcopy.png"),tr("Copy"),this,SIGNAL(Copy())); + menu.addAction(QIcon(":/images/edit_remove.png"),tr("Delete"),this,SIGNAL(Delete())); + } + else + { + menu.addAction(QIcon(":/images/edit.png"),tr("View"),this,SIGNAL(Edit())); + } + + menu.exec(event->globalPos()); +} + +void QCSTreeWidget::UpdateTree() +{ + ClearTree(); + for (size_t i=0;iGetQtyProperties();++i) + { + QString str; + CSProperties* prop=clCS->GetProperty(i); + if (prop==NULL) break; + AddPropItem(prop); + } + + std::vector vPrims = clCS->GetAllPrimitives(); + for (size_t i=0;iclear(); + vPrimItems.clear(); +} + +void QCSTreeWidget::SwitchProperty(CSPrimitives* prim, CSProperties* newProp) +{ + int index=GetTreeItemIndexByPrimID(prim->GetID()); + QTreeWidgetItem *item=NULL; + if ((index>=0) && (indexparent(); + if (parent==NULL) + return; + QTreeWidgetItem *newParent = topLevelItem(clCS->GetIndex(newProp)); + if (newParent==NULL) + return; + + parent->takeChild(parent->indexOfChild(item)); + newParent->addChild(item); +} + +void QCSTreeWidget::collapseAll() +{ + for (int i=0;itype()!=PRIMTYPE) return; + emit Edit(); +} + +void QCSTreeWidget::Clicked(QTreeWidgetItem * item, int column) +{ + if (item==NULL) return; + if (item->type()!=PROPTYPE) return; + if (column==1) {emit ShowHide();} +} diff --git a/QCSXCAD/QCSTreeWidget.h b/QCSXCAD/QCSTreeWidget.h new file mode 100644 index 0000000..b0a55f2 --- /dev/null +++ b/QCSXCAD/QCSTreeWidget.h @@ -0,0 +1,92 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#ifndef _QCSTREEWIDGET_H_ +#define _QCSTREEWIDGET_H_ + +#include +#include + +#include "ContinuousStructure.h" + +#define PROPTYPE 0 +#define PRIMTYPE 1 + +class QCSTreeWidget : public QTreeWidget +{ + Q_OBJECT +public: + QCSTreeWidget(ContinuousStructure* CS, QWidget * parent = 0); + virtual ~QCSTreeWidget(); + + CSProperties* GetCurrentProperty(); + CSPrimitives* GetCurrentPrimitive(); + + void AddPrimItem(CSPrimitives* prim); + void AddPropItem(CSProperties* prop); + + void DeletePrimItem(CSPrimitives* prim); + void DeletePropItem(CSProperties* prop); + + void RefreshItem(int index); + + void UpdateTree(); + void ClearTree(); + +signals: + void Edit(); + void Copy(); + void ShowHide(); + + void NewBox(); + void NewMultiBox(); + void NewSphere(); + void NewCylinder(); + void NewUserDefined(); + + void NewMaterial(); + void NewMetal(); + void NewExcitation(); + void NewChargeBox(); + void NewResBox(); + void NewDumpBox(); + + void Delete(); + +public slots: + void SwitchProperty(CSPrimitives* prim, CSProperties* newProp); + + void collapseAll(); + void expandAll(); + +protected slots: + void Edit(QTreeWidgetItem * item, int column); + void Clicked(QTreeWidgetItem * item, int column); + +protected: + void contextMenuEvent(QContextMenuEvent *event); + +// void BuildContextMenu(); + ContinuousStructure* clCS; + + QTreeWidgetItem* GetTreeItemByPrimID(int primID); + int GetTreeItemIndexByPrimID(int primID); + QVector vPrimItems; + +}; + +#endif //_QCSTREEWIDGET_H_ diff --git a/QCSXCAD/QCSXCAD.cpp b/QCSXCAD/QCSXCAD.cpp new file mode 100644 index 0000000..4cd4a74 --- /dev/null +++ b/QCSXCAD/QCSXCAD.cpp @@ -0,0 +1,999 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include +#include +#include +#include + +#include "QCSXCAD.h" +#include "QVTKStructure.h" +#include "QCSPrimEditor.h" +#include "QCSPropEditor.h" +#include "QCSTreeWidget.h" +#include "QCSGridEditor.h" +#include "QParameterGui.h" +#include "vtkConfigure.h" +#include "tinyxml.h" +#include + +#include "CSPropUnknown.h" +#include "CSPropMaterial.h" +#include "CSPropDispersiveMaterial.h" +#include "CSPropLorentzMaterial.h" +#include "CSPropDiscMaterial.h" +#include "CSPropLumpedElement.h" +#include "CSPropMetal.h" +#include "CSPropConductingSheet.h" +#include "CSPropExcitation.h" +#include "CSPropProbeBox.h" +#include "CSPropDumpBox.h" +#include "CSPropResBox.h" + +#include "CSPrimPoint.h" +#include "CSPrimBox.h" +#include "CSPrimMultiBox.h" +#include "CSPrimSphere.h" +#include "CSPrimSphericalShell.h" +#include "CSPrimCylinder.h" +#include "CSPrimCylindricalShell.h" +#include "CSPrimPolygon.h" +#include "CSPrimLinPoly.h" +#include "CSPrimRotPoly.h" +#include "CSPrimCurve.h" +#include "CSPrimWire.h" +#include "CSPrimUserDefined.h" + +#include +#include +#include +#include +#include +#include + +// exporter +#include "export_x3d.h" +#include "export_pov.h" + +QCSXCAD::QCSXCAD(QWidget *parent) : QMainWindow(parent) +{ + QStringList argList=qApp->arguments(); + for (int i=1;iSetGeometry(this); + + setCentralWidget(StructureVTK->GetVTKWidget()); + + CSTree = new QCSTreeWidget(this); + QObject::connect(CSTree,SIGNAL(Edit()),this,SLOT(Edit())); + QObject::connect(CSTree,SIGNAL(Copy()),this,SLOT(Copy())); + QObject::connect(CSTree,SIGNAL(ShowHide()),this,SLOT(ShowHide())); + QObject::connect(CSTree,SIGNAL(Delete()),this,SLOT(Delete())); + QObject::connect(CSTree,SIGNAL(NewBox()),this,SLOT(NewBox())); + QObject::connect(CSTree,SIGNAL(NewMultiBox()),this,SLOT(NewMultiBox())); + QObject::connect(CSTree,SIGNAL(NewSphere()),this,SLOT(NewSphere())); + QObject::connect(CSTree,SIGNAL(NewCylinder()),this,SLOT(NewCylinder())); + QObject::connect(CSTree,SIGNAL(NewUserDefined()),this,SLOT(NewUserDefined())); + + QObject::connect(CSTree,SIGNAL(NewMaterial()),this,SLOT(NewMaterial())); + QObject::connect(CSTree,SIGNAL(NewMetal()),this,SLOT(NewMetal())); + QObject::connect(CSTree,SIGNAL(NewExcitation()),this,SLOT(NewExcitation())); + QObject::connect(CSTree,SIGNAL(NewChargeBox()),this,SLOT(NewChargeBox())); + QObject::connect(CSTree,SIGNAL(NewResBox()),this,SLOT(NewResBox())); + QObject::connect(CSTree,SIGNAL(NewDumpBox()),this,SLOT(NewDumpBox())); + + QDockWidget *dock = new QDockWidget(tr("Properties and Structures"),this); + dock->setAllowedAreas(Qt::LeftDockWidgetArea); + dock->setWidget(CSTree); + dock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + dock->setObjectName("Properties_and_Structures_Dock"); + + addDockWidget(Qt::LeftDockWidgetArea,dock); + + GridEditor = new QCSGridEditor(&clGrid); + QObject::connect(GridEditor,SIGNAL(OpacityChange(int)),StructureVTK,SLOT(SetGridOpacity(int))); + QObject::connect(GridEditor,SIGNAL(signalDetectEdges(int)),this,SLOT(DetectEdges(int))); + QObject::connect(GridEditor,SIGNAL(GridChanged()),StructureVTK,SLOT(RenderGrid())); + QObject::connect(GridEditor,SIGNAL(GridPlaneXChanged(int)),StructureVTK,SLOT(RenderGridX(int))); + QObject::connect(GridEditor,SIGNAL(GridPlaneYChanged(int)),StructureVTK,SLOT(RenderGridY(int))); + QObject::connect(GridEditor,SIGNAL(GridPlaneZChanged(int)),StructureVTK,SLOT(RenderGridZ(int))); + + dock = new QDockWidget(tr("Rectilinear Grid"),this); + dock->setAllowedAreas(Qt::LeftDockWidgetArea); + dock->setWidget(GridEditor); + dock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + dock->setObjectName("Rectilinear_Grid_Dock"); + addDockWidget(Qt::LeftDockWidgetArea,dock); + + QParaSet= new QParameterSet(); + QObject::connect(QParaSet,SIGNAL(ParameterChanged()),this,SLOT(CheckGeometry())); + QObject::connect(QParaSet,SIGNAL(ParameterChanged()),this,SLOT(setModified())); + clParaSet=QParaSet; + + dock = new QDockWidget(tr("Rectilinear Grid - Plane Position"),this); + dock->setAllowedAreas(Qt::LeftDockWidgetArea); + dock->setWidget(GridEditor->BuildPlanePosWidget()); + dock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + dock->setObjectName("Grid_Plane_Pos"); + addDockWidget(Qt::LeftDockWidgetArea,dock); + + dock = new QDockWidget(tr("Parameter"),this); + dock->setAllowedAreas(Qt::LeftDockWidgetArea); + dock->setWidget(QParaSet); + dock->setFeatures(QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetMovable); + dock->setObjectName("Parameter_Dock"); + addDockWidget(Qt::LeftDockWidgetArea,dock); + + BuildToolBar(); + + bModified=true; + GridEditor->SetOpacity(30); + Render(); +} + +QCSXCAD::~QCSXCAD() +{ +} + +QString QCSXCAD::GetInfoString() +{ + QString text = QString("%1").arg(_QCSXCAD_LIB_NAME_); + text += QString("
Author: %1
EMail: %2").arg(_QCSXCAD_AUTHOR_).arg(_QCSXCAD_AUTHOR_MAIL_); + text += QString("
Version: %1\t Build: %2 %3").arg(_QCSXCAD_VERSION_).arg(__DATE__).arg(__TIME__); + text += QString("
License: %1").arg(_QCSXCAD_LICENSE_); + return text; +} + +QIcon QCSXCAD::GetLibIcon() +{ + return QIcon(":/images/QCSXCAD_Icon.png"); +} + +void QCSXCAD::aboutQCSXCAD(QWidget* parent) +{ + QDialog infoWidget(parent); + infoWidget.setWindowTitle("Info"); + QLabel *infoLbl = new QLabel(); + infoLbl->setText(GetInfoString()); + infoLbl->setAlignment(Qt::AlignLeft); + + QGroupBox* DependGroup = new QGroupBox(tr("Used Libraries"),&infoWidget); + + QLabel *qtinfo = new QLabel(); + QPushButton* qtButton = new QPushButton(QIcon(":/images/qt-logo.png"),QString()); + qtButton->setToolTip(tr("About Qt")); + qtButton->setIconSize(QSize(50,50)); + QObject::connect(qtButton,SIGNAL(clicked()),qApp,SLOT(aboutQt())); + qtinfo->setText(QString("GUI-Toolkit: Qt by Trolltech (OSS)
Version: %1
http://www.trolltech.com/
License: GNU General Public License (GPL)").arg(QT_VERSION,0,16)); + qtinfo->setAlignment(Qt::AlignLeft); + + QLabel *vtkinfo = new QLabel(); + QPushButton* vtkButton = new QPushButton(QIcon(":/images/vtk-logo.png"),QString()); + vtkButton->setIconSize(QSize(50,50)); + //vtkButton->setToolTip(tr("About Vtk")); + //QObject::connect(vtkButton,SIGNAL(clicked()),qApp,SLOT(aboutQt())); + vtkinfo->setText(QString("3D-Toolkit: Visualization Toolkit (VTK)
Version: %1
http://www.vtk.org/
License: BSD-License").arg(VTK_VERSION)); + vtkinfo->setAlignment(Qt::AlignLeft); + + QLabel *CSXCADinfo = new QLabel(); + CSXCADinfo->setText(ContinuousStructure::GetInfoLine().c_str()); + CSXCADinfo->setAlignment(Qt::AlignLeft); + + QGridLayout *Glay = new QGridLayout(); + Glay->addWidget(qtButton,1,1); + Glay->addWidget(qtinfo,1,2); + Glay->addWidget(vtkButton,2,1); + Glay->addWidget(vtkinfo,2,2); + Glay->addWidget(CSXCADinfo,3,2); + Glay->setColumnStretch(1,0); + Glay->setColumnStretch(2,1); + + DependGroup->setLayout(Glay); + + QGridLayout *infoLayout = new QGridLayout(); + QPushButton* iconButt = new QPushButton(QCSXCAD::GetLibIcon(),""); + iconButt->setFlat(true); + iconButt->setIconSize(QSize(128,128)); + infoLayout->addWidget(iconButt,1,1); + infoLayout->addWidget(infoLbl,1,2,1,3); + infoLayout->addWidget(DependGroup,2,1,1,3); + + QPushButton* OKBut = new QPushButton(tr("Ok")); + QObject::connect(OKBut,SIGNAL(clicked()),&infoWidget,SLOT(accept())); + infoLayout->addWidget(OKBut,3,2); + + infoLayout->setColumnStretch(1,1); + infoLayout->setColumnStretch(3,1); + + infoWidget.setLayout(infoLayout); + +// infoWidget->show(); +// infoWidget->adjustSize(); + infoWidget.exec(); +} + +//void QCSXCAD::SetFile(QString filename) +//{ +// QFilename=filename; +// +// QString file; +// if (QFilename.startsWith("./")) file=relPath+QFilename.mid(2); +// else file=QFilename; +// +// //File_Lbl->setText(QString("Geometry File: %1").arg(file)); +// +// emit FileModified(true); +// setModified(); +// ReadFile(file); +//} +// +//QString QCSXCAD::GetFilename() +//{ +// return QFilename; +//} +// +//QString QCSXCAD::GetGeometry() +//{ +// if (QFilename.startsWith("./")) return relPath+QFilename.mid(2); +// else return QFilename; +//} + +bool QCSXCAD::CheckGeometry() +{ + QString msg = QString::fromStdString(Update()); + if (msg.isEmpty()) + { + return true; + } + + QMessageBox::warning(this,tr("Geometry Edit Warning"),tr("Geometry Edit Warning: Update Error occurred!!\n")+msg,QMessageBox::Ok,QMessageBox::NoButton); + + return false; +} + +TiXmlNode* QCSXCAD::FindRootNode(TiXmlNode* node) +{ + if (node==NULL) return NULL; + TiXmlElement* child = node->FirstChildElement("ContinuousStructure"); + if (child) + return node; + child=node->FirstChildElement(); + TiXmlNode* found=NULL; + while (child!=NULL) + { + if (child->FirstChildElement("ContinuousStructure")) + return child; + found = FindRootNode(child); + if (found) + return found; + child = node->NextSiblingElement(); + } + return NULL; +} + +bool QCSXCAD::ReadNode(TiXmlNode* root) +{ + if (root==NULL) return false; + clear(); + QString msg(ReadFromXML(root)); + if (msg.isEmpty()==false) QMessageBox::warning(this,tr("Geometry read error"),tr("An geometry read error occured!!\n\n")+msg,QMessageBox::Ok,QMessageBox::NoButton); + CSTree->UpdateTree(); + CSTree->expandAll(); + setModified(); + CheckGeometry(); + GridEditor->Update(); + BestView(); + StructureVTK->ResetView(); + return true; +} + +bool QCSXCAD::ReadFile(QString filename) +{ + if (QFile::exists(filename)==false) return false; + + TiXmlDocument doc(filename.toStdString().c_str()); + if (!doc.LoadFile()) { QMessageBox::warning(this,tr("File- Error!!! File: "),tr("File-Loading failed!!!"),QMessageBox::Ok,QMessageBox::NoButton); } + + TiXmlNode* root = 0; + TiXmlElement* openEMS = doc.FirstChildElement("openEMS"); + if (openEMS) + { + root = ReadOpenEMS(openEMS); + } + else + { + //try to find a root node somewhere else... + root = FindRootNode(&doc); + } + if (root==NULL) + { + QMessageBox::warning(this,tr("Geometry read error"),tr("Can't find root CSX node!!"),QMessageBox::Ok,QMessageBox::NoButton); + return false; + } +// QString msg(ReadFromXML(filename.toLatin1().constData())); + QString msg(ReadFromXML(root)); + if (msg.isEmpty()==false) + QMessageBox::warning(this,tr("Geometry read error"),tr("An geometry read error occured!!\n\n")+msg,QMessageBox::Ok,QMessageBox::NoButton); + + CSTree->UpdateTree(); + CSTree->expandAll(); + setModified(); + CheckGeometry(); + GridEditor->Update(); + BestView(); + StructureVTK->ResetView(); + return true; +} + +TiXmlNode* QCSXCAD::ReadOpenEMS(TiXmlNode* openEMS) +{ + // read FDTD options + m_BC.clear(); + TiXmlElement* element = openEMS->FirstChildElement("FDTD"); + if (element) + { + TiXmlElement* BC = element->FirstChildElement("BoundaryCond"); + if (BC) + { + TiXmlAttribute *attr = BC->FirstAttribute(); + while (attr) + { + m_BC[attr->Name()] = attr->Value(); + attr = attr->Next(); + } + } + } + return openEMS; +} + +int QCSXCAD::GetCurrentProperty() +{ + return GetIndex(CSTree->GetCurrentProperty()); +} + +ParameterSet* QCSXCAD::GetParaSet() +{ + return QParaSet; +} + +bool QCSXCAD::Write2XML(TiXmlNode* rootNode, bool parameterised) +{ + return ContinuousStructure::Write2XML(rootNode,parameterised); +} + +bool QCSXCAD::Write2XML(const char* file, bool parameterised) +{ + return ContinuousStructure::Write2XML(file,parameterised); +} + +bool QCSXCAD::Write2XML(QString file, bool parameterised) +{ + return ContinuousStructure::Write2XML(file.toStdString().c_str(),parameterised); +} + +bool QCSXCAD::isGeometryValid() +{ + if (ContinuousStructure::isGeometryValid()==false) return false; + return true; +} + +void QCSXCAD::ImportGeometry() +{ + QString filter; + QString filename=QFileDialog::getOpenFileName(0,tr("Choose geometry file"),NULL,tr("XML-File (*.xml)"),&filter); + if (filename.isEmpty()) + return; + ReadFile(filename); +} + +void QCSXCAD::Edit() +{ + CSPrimitives* prim = CSTree->GetCurrentPrimitive(); + if (prim!=NULL) + { + CSProperties* oldProp=prim->GetProperty(); + QCSPrimEditor* newEdit = new QCSPrimEditor(this,prim); + if (newEdit->exec()==QDialog::Accepted) + { + CSProperties* newProp=prim->GetProperty(); + if (newProp!=oldProp) + CSTree->SwitchProperty(prim,newProp); + setModified(); + //CSTree->UpdateTree(); + } + return; + } + CSProperties* prop = CSTree->GetCurrentProperty(); + if (prop!=NULL) + { + int index=GetIndex(prop); + QCSPropEditor* newEdit = new QCSPropEditor(this,prop,m_SimMode); + if (newEdit->exec()==QDialog::Accepted) + { + CSTree->RefreshItem(index); + setModified(); + } + } +} + +void QCSXCAD::Copy() +{ + CSPrimitives* prim = CSTree->GetCurrentPrimitive(); + if (prim!=NULL) + { + CSPrimitives* newPrim=prim->GetCopy(); + if (newPrim==NULL) + return; + QCSPrimEditor* newEdit = new QCSPrimEditor(this,newPrim); + if (newEdit->exec()==QDialog::Accepted) + { + setModified(); + CSTree->AddPrimItem(newPrim); + } + else + delete newPrim; + } +} + +void QCSXCAD::SetVisibility2All(bool value) +{ + for (size_t n=0; nSetVisibility(value); + CSTree->RefreshItem(GetIndex(prop)); + if (value) StructureVTK->SetPropOpacity(prop->GetUniqueID(),prop->GetFillColor().a); + else StructureVTK->SetPropOpacity(prop->GetUniqueID(),0); + } +} + +void QCSXCAD::HideAll() +{ + SetVisibility2All(false); +} + +void QCSXCAD::ShowAll() +{ + SetVisibility2All(true); +} + +void QCSXCAD::SetParallelProjection(bool val) +{ + StructureVTK->SetParallelProjection(val); +} + +void QCSXCAD::ShowHide() +{ + CSProperties* prop = CSTree->GetCurrentProperty(); + if (prop!=NULL) + { + prop->SetVisibility(!prop->GetVisibility()); + CSTree->RefreshItem(GetIndex(prop)); + if (prop->GetVisibility()) StructureVTK->SetPropOpacity(prop->GetUniqueID(),prop->GetFillColor().a); + else StructureVTK->SetPropOpacity(prop->GetUniqueID(),0); + } +} + +void QCSXCAD::Delete() +{ + CSPrimitives* prim = CSTree->GetCurrentPrimitive(); + if (prim!=NULL) + { + if (QMessageBox::question(this,tr("Delete Primitive"),tr("Delete current Primitive (ID: %1)?").arg(prim->GetID()),QMessageBox::Yes,QMessageBox::No)==QMessageBox::Yes) + { + CSTree->DeletePrimItem(prim); + DeletePrimitive(prim); + setModified(); + } + return; + } + CSProperties* prop = CSTree->GetCurrentProperty(); + if (prop!=NULL) + { + size_t qtyPrim=prop->GetQtyPrimitives(); + if (qtyPrim>0) + { + if (QMessageBox::question(this,tr("Delete Property"),tr("\"%1\" contains Primitive(s)!!\n Delete anyway?").arg(prop->GetName().c_str()),QMessageBox::Yes,QMessageBox::No)!=QMessageBox::Yes) + return; + } + else if (QMessageBox::question(this,tr("Delete Property"),tr("Delete current Property?"),QMessageBox::Yes,QMessageBox::No)!=QMessageBox::Yes) + return; + CSTree->DeletePropItem(prop); + DeleteProperty(prop); + setModified(); + } +} + +void QCSXCAD::NewBox() +{ + NewPrimitive(new CSPrimBox(clParaSet,CSTree->GetCurrentProperty())); +} + +void QCSXCAD::NewMultiBox() +{ + NewPrimitive(new CSPrimMultiBox(clParaSet,CSTree->GetCurrentProperty())); +} + +void QCSXCAD::NewSphere() +{ + NewPrimitive(new CSPrimSphere(clParaSet,CSTree->GetCurrentProperty())); +} + +void QCSXCAD::NewCylinder() +{ + NewPrimitive(new CSPrimCylinder(clParaSet,CSTree->GetCurrentProperty())); +} + +void QCSXCAD::NewPolygon() +{ + NewPrimitive(new CSPrimPolygon(clParaSet,CSTree->GetCurrentProperty())); +} + +void QCSXCAD::NewUserDefined() +{ + NewPrimitive(new CSPrimUserDefined(clParaSet,CSTree->GetCurrentProperty())); +} + + +void QCSXCAD::NewPrimitive(CSPrimitives* newPrim) +{ + if (GetQtyProperties()==0) + { + QMessageBox::question(this,tr("New Primitive"),tr("No Property available. You have to add one first!"),QMessageBox::Ok); + delete newPrim; + return; + } + QCSPrimEditor* newEdit = new QCSPrimEditor(this,newPrim); + + if (newEdit->exec()==QDialog::Accepted) + { + setModified(); + CSTree->AddPrimItem(newPrim); + } + else + delete newPrim; +} + +void QCSXCAD::NewMaterial() +{ + NewProperty(new CSPropMaterial(clParaSet)); +} + +void QCSXCAD::NewMetal() +{ + NewProperty(new CSPropMetal(clParaSet)); +} + +void QCSXCAD::NewExcitation() +{ + NewProperty(new CSPropExcitation(clParaSet,GetQtyPropertyType(CSProperties::EXCITATION))); +} + +void QCSXCAD::NewChargeBox() +{ + NewProperty(new CSPropProbeBox(clParaSet)); +} + +void QCSXCAD::NewResBox() +{ + NewProperty(new CSPropResBox(clParaSet)); +} + +void QCSXCAD::NewDumpBox() +{ + NewProperty(new CSPropDumpBox(clParaSet)); +} + +void QCSXCAD::setModified() +{ + bModified=true; + emit modified(true); + Render(); +} + +void QCSXCAD::DetectEdges(int nu) +{ + InsertEdges2Grid(nu); +} + +void QCSXCAD::BestView() +{ + StructureVTK->ResetView(); +} + +void QCSXCAD::setViewDir(int dir) +{ + switch (dir) + { + default: + case 0: + setYZ(); + return; + case 1: + setZX(); + return; + case 2: + setXY(); + return; + } +} + +void QCSXCAD::setXY() +{ + m_ViewDir = 2; + StructureVTK->setXY(); +} + +void QCSXCAD::setYZ() +{ + m_ViewDir = 0; + StructureVTK->setYZ(); +} + +void QCSXCAD::setZX() +{ + m_ViewDir = 1; + StructureVTK->setZX(); +} + +void QCSXCAD::SetSimMode(int mode) +{ + m_SimMode=mode; +} + +void QCSXCAD::NewProperty(CSProperties* newProp) +{ + QCSPropEditor* newEdit = new QCSPropEditor(this,newProp,m_SimMode); + + if (newEdit->exec()==QDialog::Accepted) + { + AddProperty(newProp); + CSTree->AddPropItem(newProp); + } + else delete newProp; +} + +void QCSXCAD::New() +{ + if (bModified) + { + if (QMessageBox::question(this,tr("New Geometry"),tr("Create empty Geometry??"),QMessageBox::Yes,QMessageBox::No)==QMessageBox::No) + return; + else + clear(); + } +} + +//void QCSXCAD::Load() +//{ +// if (bModified) +// switch (QMessageBox::question(this,tr("Load Geometry"),tr("Save current Geometry??"),QMessageBox::Yes,QMessageBox::No,QMessageBox::Cancel)) +// { +// case QMessageBox::Yes: +// Save(); +// break; +// case QMessageBox::Cancel: +// return; +// break; +// }; +// browseGeometryFile(); +//} + + +//void QCSXCAD::Save() +//{ +// if (QFilename.isEmpty()) {SaveAs(); return;} +// +// CheckGeometry(); +// +// if (QFilename.startsWith("./")) Write2XML((relPath+QFilename.mid(2)).toLatin1().data()); +// else Write2XML(QFilename.toLatin1().data()); +// bModified=false; +//} + +void QCSXCAD::ExportGeometry() +{ + QString qFilename=QFileDialog::getSaveFileName(0,"Choose Geometrie File",NULL,"SimGeometryXML (*.xml)"); + if (qFilename==NULL) return; + if (!qFilename.endsWith(".xml")) qFilename+=".xml"; + + if (Write2XML(qFilename.toLatin1().data())==false) QMessageBox::warning(this,tr("Geometry Export"),tr("Unknown error occured! Geometry Export failed"),1,0); +} + +void QCSXCAD::ExportGeometry_Povray() +{ + QString filename = QFileDialog::getSaveFileName( this, tr("Save Povray file"), QString(), tr("Povray files (*.pov)") ); + if (filename.isEmpty()) + return; + + export_pov pov( this ); + pov.save( filename ); + + // start povray? + int ans = QMessageBox::question( 0, "Start Povray", "Should the file directly be rendered?", "Yes", "No", "", 0, 1 ); + if (ans == 1) + return; + + // start povray + QStringList args; + args << filename; + args << "-W640"; + args << "-H480"; + args << "+A"; + //only valid for povray >3.7.0 args << "+WT4"; + QProcess::startDetached( "povray", args, QFileInfo(filename).absolutePath() ); + return; + + // // Instead of letting renderer to render the scene, we use +// // an exportor to save it to a file. +// vtkPOVExporter *povexp = vtkPOVExporter::New(); +// povexp->SetRenderWindow( ((QVTKWidget*)(StructureVTK->GetVTKWidget()))->GetRenderWindow() ); +// povexp->SetFileName("/tmp/TestPOVExporter.pov"); +// cout << "Writing file TestPOVExporter.pov..." << endl; +// +// povexp->Write(); +// cout << "Done writing file TestPOVExporter.pov..." << endl; +// +// povexp->Delete(); +} + +void QCSXCAD::ExportGeometry_X3D(QString filename) +{ + if (filename.isEmpty()) + filename = QFileDialog::getSaveFileName( this, tr("Save X3D-file"), QString(), tr("X3D files (*.x3d)") ); + if (filename.isEmpty()) + return; + + export_X3D x3d( this ); + x3d.save( filename ); +} + +void QCSXCAD::ExportGeometry(QString dirname, int type) +{ + if (dirname.isEmpty()) + dirname = QFileDialog::getExistingDirectory(this, tr("Choose directory to save data")); + if (dirname.isEmpty()) + return; + int QtyProp = GetQtyProperties(); + for (int i=0;iGetUniqueID(); + + if (prop->GetVisibility()==true) + { + QString filename(dirname); + filename.append("/"); + filename.append(QString::fromUtf8(prop->GetName().c_str())); + switch (type) + { + case 0: + StructureVTK->ExportProperty2PolyDataVTK(uID,filename,clGrid.GetDeltaUnit()); + break; + case 1: + StructureVTK->ExportProperty2STL(uID,filename,clGrid.GetDeltaUnit()); + break; + case 2: + StructureVTK->ExportProperty2PLY(uID,filename,clGrid.GetDeltaUnit()); + break; + default: + QMessageBox::warning(this, "Export Dialog","Unkown export type, skipping..."); + return; + break; + } + } + } +} + +void QCSXCAD::ExportGeometry_PolyDataVTK(QString dirname) +{ + ExportGeometry(dirname, 0); +} + +void QCSXCAD::ExportGeometry_STL(QString dirname) +{ + ExportGeometry(dirname, 1); +} + +void QCSXCAD::ExportGeometry_PLY(QString dirname) +{ + ExportGeometry(dirname, 2); +} + +void QCSXCAD::ExportView2Image() +{ + if (ViewLevel==VIEW_3D) + StructureVTK->ExportView2Image(); + else + QMessageBox::warning(this,tr("PNG export"),tr("Not Yet Implemented for 2D view, use 3D instead."),QMessageBox::Ok,QMessageBox::NoButton); +} + +void QCSXCAD::EnableDiscModelRendering(bool val) +{ + m_RenderDiscModels = val; +} + +void QCSXCAD::GUIUpdate() +{ + CSTree->UpdateTree(); + GridEditor->Update(); + for (int n=0;n<3;++n) + viewPlane[n]->setText(GridEditor->GetNormName(n)); +} + +void QCSXCAD::clear() +{ + ContinuousStructure::clear(); + GUIUpdate(); + setModified(); + bModified=false; +} + +void QCSXCAD::BuildToolBar() +{ + QToolBar *mainTB = addToolBar(tr("General")); + mainTB->setObjectName("General_ToolBar"); + QSize TBIconSize(16,16); + mainTB->setIconSize(TBIconSize); + + if (QCSX_Settings.GetEdit()) + mainTB->addAction(QIcon(":/images/filenew.png"),tr("New"),this,SLOT(New())); + if (QCSX_Settings.GetEdit()) + mainTB->addAction(QIcon(":/images/down.png"),tr("Import"),this,SLOT(ImportGeometry())); + mainTB->addAction(QIcon(":/images/up.png"),tr("Export"),this,SLOT(ExportGeometry())); + + + QToolBar *ItemTB = addToolBar(tr("Item View")); + ItemTB->setIconSize(TBIconSize); + ItemTB->setObjectName("Item_View_ToolBar"); + + ItemTB->addAction(tr("CollapseAll"),CSTree,SLOT(collapseAll())); + ItemTB->addAction(tr("ExpandAll"),CSTree,SLOT(expandAll())); + + ItemTB->addAction(QIcon(":/images/bulb.png"),tr("ShowAll"),this,SLOT(ShowAll())); + ItemTB->addAction(QIcon(":/images/bulb_off.png"),tr("HideAll"),this,SLOT(HideAll())); + + QToolBar *newObjct = NULL; + QAction* newAct = NULL; + + if (QCSX_Settings.GetEdit()) + { + newObjct = addToolBar(tr("add new Primitive")); + newObjct->setObjectName("New_Primitive_ToolBar"); + + newAct = newObjct->addAction(tr("Box"),this,SLOT(NewBox())); + newAct->setToolTip(tr("add new Box")); + + newAct = newObjct->addAction(tr("MultiBox"),this,SLOT(NewMultiBox())); + newAct->setToolTip(tr("add new Multi-Box")); + + newAct = newObjct->addAction(tr("Sphere"),this,SLOT(NewSphere())); + newAct->setToolTip(tr("add new Sphere")); + + newAct = newObjct->addAction(tr("Cylinder"),this,SLOT(NewCylinder())); + newAct->setToolTip(tr("add new Cylinder")); + + newAct = newObjct->addAction(tr("Polygon"),this,SLOT(NewPolygon())); + newAct->setToolTip(tr("add new Polygon")); + + newAct = newObjct->addAction(tr("User Defined"),this,SLOT(NewUserDefined())); + newAct->setToolTip(tr("add new User Definied Primitive")); + + newObjct = addToolBar(tr("add new Property")); + newObjct->setObjectName("New_Property_ToolBar"); + + newAct = newObjct->addAction(tr("Material"),this,SLOT(NewMaterial())); + newAct->setToolTip(tr("add new Material-Property")); + + newAct = newObjct->addAction(tr("Metal"),this,SLOT(NewMetal())); + newAct->setToolTip(tr("add new Metal-Property")); + + newAct = newObjct->addAction(tr("Excitation"),this,SLOT(NewExcitation())); + newAct->setToolTip(tr("add new Excitation-Property")); + + newAct = newObjct->addAction(tr("ProbeBox"),this,SLOT(NewChargeBox())); + newAct->setToolTip(tr("add new Probe-Box-Property")); + + newAct = newObjct->addAction(tr("ResBox"),this,SLOT(NewResBox())); + newAct->setToolTip(tr("add new Res-Box-Property")); + + newAct = newObjct->addAction(tr("DumpBox"),this,SLOT(NewDumpBox())); + newAct->setToolTip(tr("add new Dump-Box-Property")); + } + + newObjct = addToolBar(tr("Zoom")); + newObjct->setIconSize(TBIconSize); + newObjct->setObjectName("Zoom_ToolBar"); + + newAct = newObjct->addAction(QIcon(":/images/viewmagfit.png"),tr("Zoom fit"),this,SLOT(BestView())); + newAct->setToolTip("Zoom to best fit all objects"); + + viewPlane[0] = newObjct->addAction(GridEditor->GetNormName(0),this,SLOT(setYZ())); + viewPlane[0]->setToolTip(tr("Switch to y-z-plane view (x-normal)")); + viewPlane[1] = newObjct->addAction(GridEditor->GetNormName(1),this,SLOT(setZX())); + viewPlane[1]->setToolTip(tr("Switch to z-x-plane view (y-normal)")); + viewPlane[2] = newObjct->addAction(GridEditor->GetNormName(2),this,SLOT(setXY())); + viewPlane[2]->setToolTip(tr("Switch to x-y-plane view (z-normal)")); + + addToolBarBreak(); + + QActionGroup* ActViewGrp = new QActionGroup(this); + newAct = newObjct->addAction(tr("2D"),this,SLOT(View2D())); + newAct->setToolTip(tr("Switch to 2D view mode")); + ActViewGrp->addAction(newAct); + newAct->setCheckable(true); + newAct = newObjct->addAction(tr("3D"),this,SLOT(View3D())); + newAct->setToolTip(tr("Switch to 3D view mode")); + ActViewGrp->addAction(newAct); + newAct->setCheckable(true); + m_PPview = newObjct->addAction(tr("PP")); + m_PPview->setToolTip(tr("Toggle parallel projection view mode")); + QObject::connect(m_PPview,SIGNAL(toggled(bool)),this,SLOT(SetParallelProjection(bool))); + m_PPview->setCheckable(true); + + if (QCSX_Settings.GetEdit()) + addToolBar(GridEditor->BuildToolbar()); +} + +void QCSXCAD::Render() +{ + StructureVTK->RenderGrid(); + StructureVTK->RenderGeometry(); + if (m_RenderDiscModels) + StructureVTK->RenderDiscMaterialModel(); + +} + +void QCSXCAD::View2D() +{ + ViewLevel=VIEW_2D; + StructureVTK->SaveCamData(); + setViewDir(m_ViewDir); + StructureVTK->SetParallelProjection(true, false); + StructureVTK->Set2DInteractionStyle(true); + m_PPview->setDisabled(true); +} + +void QCSXCAD::View3D() +{ + ViewLevel=VIEW_3D; + + m_PPview->setDisabled(false); + StructureVTK->SetParallelProjection(m_PPview->isChecked(), false); + StructureVTK->Set2DInteractionStyle(false, false); + StructureVTK->RestoreCamData(true); +} + +void QCSXCAD::keyPressEvent(QKeyEvent * event) +{ + if (event->key()==Qt::Key_Delete) Delete(); + if (event->key()==Qt::Key_Escape) + CSTree->setCurrentItem(NULL); + QMainWindow::keyPressEvent(event); +} + diff --git a/QCSXCAD/QCSXCAD.h b/QCSXCAD/QCSXCAD.h new file mode 100644 index 0000000..9bebf20 --- /dev/null +++ b/QCSXCAD/QCSXCAD.h @@ -0,0 +1,180 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#ifndef _QCSXCAD_H_ +#define _QCSXCAD_H_ + +#include +#include +#include +#include "QCSXCAD_Global.h" +#include "ContinuousStructure.h" + +class QVTKStructure; +class QCSPrimEditor; +class QCSPropEditor; +class QCSTreeWidget; +class QCSGridEditor; +class QParameterGui; +class QParameterSet; + +class TiXmlNode; + +class QCSXCAD_EXPORT QCSXCAD : public QMainWindow, public ContinuousStructure +{ + Q_OBJECT + friend class export_X3D; + friend class export_pov; +public: + QCSXCAD(QWidget *parent=NULL); + virtual ~QCSXCAD(); + + enum ViewMode + { + VIEW_2D, VIEW_3D + }; + +// void SetFile(QString filename); +// void SetPath(QString path) {relPath=path;}; +// QString GetFilename(); + + //StaticComplexGeometry* GetDiscGeometry() {return SCGeometry;}; + QString GetGeometry(); + + virtual bool isGeometryValid(); + + virtual bool Write2XML(TiXmlNode* rootNode, bool parameterised=true); + virtual bool Write2XML(const char* file, bool parameterised=true); + virtual bool Write2XML(QString file, bool parameterised=true); + + virtual bool ReadFile(QString filename); + bool ReadNode(TiXmlNode* root); + + int GetCurrentProperty(); + + ParameterSet* GetParaSet(); + + static QString GetInfoString(); + static QIcon GetLibIcon(); + + const QHash &Get_BC() const { return m_BC; } + +signals: + void modified(bool val); + +public slots: + bool CheckGeometry(); + + void ImportGeometry(); + void ExportGeometry(); + void ExportGeometry_Povray(); + void ExportGeometry_X3D(QString filename=QString()); + + //! Export geometry into a given directory and type + void ExportGeometry(QString dirname, int type); + void ExportGeometry_PolyDataVTK(QString dirname=QString()); + void ExportGeometry_STL(QString dirname=QString()); + void ExportGeometry_PLY(QString dirname=QString()); + + void ExportView2Image(); + + void EnableDiscModelRendering(bool val=true); + + void Render(); + virtual void clear(); + void New(); + + void HideAll(); + void ShowAll(); + + //! Enable/Disable 3D parallel projection for the 3D vtk viewer + void SetParallelProjection(bool val); + + void BestView(); + void setViewDir(int dir); + void setXY(); + void setYZ(); + void setZX(); + + void SetSimMode(int mode); + + void GUIUpdate(); + + static void aboutQCSXCAD(QWidget* parent=0); + +protected slots: + void Edit(); + void Copy(); + void ShowHide(); + + void Delete(); + + void NewBox(); + void NewMultiBox(); + void NewSphere(); + void NewCylinder(); + void NewPolygon(); + void NewUserDefined(); + + void NewMaterial(); + void NewMetal(); + void NewExcitation(); + void NewChargeBox(); + void NewResBox(); + void NewDumpBox(); + + void setModified(); + + void DetectEdges(int nu); + + void View2D(); + void View3D(); + +protected: + //read supported files, return the root to a CSX + TiXmlNode* ReadOpenEMS(TiXmlNode* openEMS); + + void NewPrimitive(CSPrimitives* newPrim); + void NewProperty(CSProperties* newProp); + + TiXmlNode* FindRootNode(TiXmlNode* node); + + void SetVisibility2All(bool value); + + bool m_RenderDiscModels; + + QCSTreeWidget *CSTree; + QCSGridEditor* GridEditor; + QParameterSet* QParaSet; + + QVTKStructure* StructureVTK; + + QAction* viewPlane[3]; + void BuildToolBar(); + + bool bModified; + ViewMode ViewLevel; + QAction* m_PPview; + int m_ViewDir; + int m_SimMode; + + virtual void keyPressEvent(QKeyEvent * event); + + QHash m_BC; //!< boundary conditions +}; + +#endif //_QCSXCAD_H_ diff --git a/QCSXCAD/QCSXCAD_Global.cpp b/QCSXCAD/QCSXCAD_Global.cpp new file mode 100644 index 0000000..d29175e --- /dev/null +++ b/QCSXCAD/QCSXCAD_Global.cpp @@ -0,0 +1,58 @@ +/* +* Copyright (C) 2012 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 . +*/ + +#include +#include +#include +#include "QCSXCAD_Global.h" + +// create global object +QCSXCAD_Global QCSX_Settings; + +QCSXCAD_Global::QCSXCAD_Global() +{ + m_EnableEdit = true; + m_RenderDiscMat = false; +} + +void QCSXCAD_Global::ShowArguments(std::ostream& ostr, std::string front) +{ + ostr << front << "--disableEdit\tDisable Edit" << std::endl; + ostr << front << "--RenderDiscMaterial\tRender discrete material" << std::endl; +} + +bool QCSXCAD_Global::parseCommandLineArgument( QString argv ) +{ + if (argv.isEmpty()) + return false; + + if (argv.compare("--disableEdit")==0) + { + std::cout << "QCSXCAD - disabling editing" << std::endl; + SetEdit(false); + return true; + } + if (argv.compare("--RenderDiscMaterial")==0) + { + std::cout << "QCSXCAD - Render discrete material" << std::endl; + SetRenderDiscMaterial(true); + return true; + } +// std::cerr << "QCSXCAD_Global::parseCommandLineArgument: Warning, unknown argument: " << argv.toStdString() << std::endl; + return false; +} + diff --git a/QCSXCAD/QCSXCAD_Global.h b/QCSXCAD/QCSXCAD_Global.h new file mode 100644 index 0000000..15ce6ff --- /dev/null +++ b/QCSXCAD/QCSXCAD_Global.h @@ -0,0 +1,58 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#ifndef QCSXCAD_GLOBAL_H_ +#define QCSXCAD_GLOBAL_H_ + +#define _QCSXCAD_LIB_NAME_ "QCSXCAD-Lib: Qt-Gui for Continuous Structure XML - CAD" +#define _QCSXCAD_AUTHOR_ "Thorsten Liebig (2008-2010)" +#define _QCSXCAD_AUTHOR_MAIL_ "Thorsten.Liebig@gmx.de" +#define _QCSXCAD_VERSION_ GIT_VERSION +#define _QCSXCAD_LICENSE_ "LGPL v3" + +#if defined(WIN32) + #ifdef BUILD_QCSXCAD_LIB + #define QCSXCAD_EXPORT Q_DECL_EXPORT + #else + #define QCSXCAD_EXPORT Q_DECL_IMPORT + #endif +#else +#define QCSXCAD_EXPORT +#endif + +class QCSXCAD_EXPORT QCSXCAD_Global +{ +public: + QCSXCAD_Global(); + bool parseCommandLineArgument( QString argv ); + + void ShowArguments(std::ostream& ostr, std::string front=std::string()); + + void SetEdit(bool val) {m_EnableEdit=val;} + bool GetEdit() {return m_EnableEdit;} + + void SetRenderDiscMaterial(bool val) {m_EnableEdit=val;} + bool GetRenderDiscMaterial() {return m_EnableEdit;} + +protected: + bool m_EnableEdit; + bool m_RenderDiscMat; +}; + +extern QCSXCAD_EXPORT QCSXCAD_Global QCSX_Settings; + +#endif /*QCSXCAD_GLOBAL_H_*/ diff --git a/QCSXCAD/QParameterGui.cpp b/QCSXCAD/QParameterGui.cpp new file mode 100644 index 0000000..e5eb8a8 --- /dev/null +++ b/QCSXCAD/QParameterGui.cpp @@ -0,0 +1,401 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include +#include +#include +#include +#include +#include + +#include "QParameterGui.h" +#include "QCSXCAD_Global.h" + +QParameter::QParameter(Parameter* para, QWidget* parent) : QGroupBox(parent) +{ + clPara=para; + Name=new QLabel(""); + Value=new QLineEdit(""); + QObject::connect(Value,SIGNAL(textEdited(QString)),this,SLOT(Changed())); + + + lay = new QGridLayout(); +// lay->addWidget(new QLabel(tr("Name: ")),0,0); +// lay->addWidget(Name,0,1); + + lay->addWidget(new QLabel(tr("Value: ")),0,0); + lay->addWidget(Value,0,1); + + QPushButton* btn = new QPushButton(QIcon(":/images/failed.png"),QString()); + QObject::connect(btn,SIGNAL(clicked()),this,SLOT(deleteLater())); + QObject::connect(btn,SIGNAL(clicked()),this,SLOT(DeleteParameter())); + btn->setToolTip(tr("Delete parameter")); + lay->addWidget(btn,0,3); + + SweepCB = new QCheckBox(); + QObject::connect(SweepCB,SIGNAL(stateChanged(int)),this,SLOT(SweepState(int))); + SweepCB->setToolTip(tr("Sweep this parameter")); + lay->addWidget(SweepCB,0,2); + + setLayout(lay); + //setFrameStyle(QFrame::Box); +} + +QParameter::~QParameter() +{ +} + +void QParameter::DeleteParameter() +{ + emit Delete(clPara); +} + +void QParameter::SweepState(int state) +{ + clPara->SetSweep(state); +} + +void QParameter::Changed() +{ + double val=Value->text().toDouble(); + clPara->SetValue(val); + emit ParameterChanged(); +} + +bool QParameter::Edit() +{ + QDialog* diag = new QDialog(this); + + QGroupBox* Group=new QGroupBox(tr("Edit Constant Parameter")); + + QGridLayout* lay = new QGridLayout(); + + lay->addWidget(new QLabel(tr("Name: ")),0,0); + QLineEdit* eName= new QLineEdit(QString::fromUtf8(clPara->GetName().c_str())); + lay->addWidget(eName,0,1); + + lay->addWidget(new QLabel(tr("Value: ")),1,0); + QLineEdit* eValue=new QLineEdit(QString("%1").arg(clPara->GetValue())); + lay->addWidget(eValue,1,1); + + Group->setLayout(lay); + + QGridLayout* Grid = new QGridLayout(); + Grid->addWidget(Group,0,0,1,2); + + QPushButton* PB = new QPushButton(tr("Ok")); + QObject::connect(PB,SIGNAL(clicked()),diag,SLOT(accept())); + Grid->addWidget(PB,1,0); + PB = new QPushButton(tr("Cancel")); + QObject::connect(PB,SIGNAL(clicked()),diag,SLOT(reject())); + Grid->addWidget(PB,1,1); + + diag->setLayout(Grid); + diag->show(); + diag->setFixedSize(diag->size()); + + if (diag->exec()==QDialog::Accepted) + { + if (eName->text().isEmpty()) + { + QMessageBox::warning(this,tr("Edit Parameter"),tr("Parameter-Name is invalid!")); + return false; + } + clPara->SetName(eName->text().toStdString()); + clPara->SetValue(eValue->text().toDouble()); + Update(); + return true; + } + return false; +} + +void QParameter::Update() +{ + //Name->setText(clPara->GetName()); + setTitle(QString::fromUtf8(clPara->GetName().c_str())); + Value->setText(QString("%1").arg(clPara->GetValue())); + if (clPara->GetSweep()) SweepCB->setCheckState(Qt::Checked); + else SweepCB->setCheckState(Qt::Unchecked); +} + +QLinearParameter::QLinearParameter(LinearParameter* para, QWidget* parent) : QParameter(para,parent) +{ + slider = new QSlider(Qt::Horizontal); + lay->addWidget(slider,1,0,1,3); + Value->setReadOnly(true); + QObject::connect(slider,SIGNAL(valueChanged(int)),this,SLOT(Changed())); + + QPushButton* btn = new QPushButton(QIcon(":/images/edit.png"),QString()); + QObject::connect(btn,SIGNAL(clicked()),this,SLOT(Edit())); + lay->addWidget(btn,1,3); + btn->setToolTip(tr("Edit Parameter")); +} + + +QLinearParameter::~QLinearParameter() +{ +} + +bool QLinearParameter::Edit() +{ + LinearParameter* LP = clPara->ToLinear(); + if (LP==NULL) return false; + + QDialog* diag = new QDialog(this); + + QGroupBox* Group=new QGroupBox(tr("Edit Linear Parameter")); + + QGridLayout* lay = new QGridLayout(); + + lay->addWidget(new QLabel(tr("Name: ")),0,0); + QLineEdit* eName= new QLineEdit(QString::fromUtf8(LP->GetName().c_str())); + lay->addWidget(eName,0,1); + + lay->addWidget(new QLabel(tr("Value: ")),1,0); + QLineEdit* eValue=new QLineEdit(QString("%1").arg(LP->GetValue())); + lay->addWidget(eValue,1,1); + + lay->addWidget(new QLabel(tr("Start: ")),2,0); + QLineEdit* Start=new QLineEdit(QString("%1").arg(LP->GetMin())); + lay->addWidget(Start,2,1); + + lay->addWidget(new QLabel(tr("Stop: ")),3,0); + QLineEdit* Stop=new QLineEdit(QString("%1").arg(LP->GetMax())); + lay->addWidget(Stop,3,1); + + lay->addWidget(new QLabel(tr("Step: ")),4,0); + QLineEdit* Step=new QLineEdit(QString("%1").arg(LP->GetStep())); + lay->addWidget(Step,4,1); + + Group->setLayout(lay); + + QGridLayout* Grid = new QGridLayout(); + Grid->addWidget(Group,0,0,1,2); + + QPushButton* PB = new QPushButton(tr("Ok")); + QObject::connect(PB,SIGNAL(clicked()),diag,SLOT(accept())); + Grid->addWidget(PB,1,0); + PB = new QPushButton(tr("Cancel")); + QObject::connect(PB,SIGNAL(clicked()),diag,SLOT(reject())); + Grid->addWidget(PB,1,1); + + diag->setLayout(Grid); + diag->show(); + diag->setFixedSize(diag->size()); + + if (diag->exec()==QDialog::Accepted) + { + if (eName->text().isEmpty()) + { + QMessageBox::warning(this,tr("Edit Parameter"),tr("Parameter-Name is invalid!")); + return false; + } + LP->SetName(eName->text().toStdString()); + LP->SetMin(Start->text().toDouble()); + LP->SetMax(Stop->text().toDouble()); + LP->SetStep(Step->text().toDouble()); + LP->SetValue(eValue->text().toDouble()); + Update(); + return true; + } + return false; +} + +void QLinearParameter::Update() +{ + QParameter::Update(); + LinearParameter* LP=clPara->ToLinear(); + if (LP==NULL) return; + if ((LP->GetStep()>0) && (LP->GetMax()>LP->GetMin())) + { + double steps=(LP->GetMax()-LP->GetMin())/LP->GetStep(); + double val=(LP->GetValue()-LP->GetMin())/LP->GetStep(); + slider->setRange(1,(int)steps+1); + slider->setValue((int)val+1); + } + else slider->setRange(1,1); +} + +void QLinearParameter::Changed() +{ + LinearParameter* LP=clPara->ToLinear(); + if (LP==NULL) return; + double val=LP->GetMin()+LP->GetStep()*(slider->value()-1); + LP->SetValue(val); + Value->setText(QString("%1").arg(LP->GetValue())); + emit ParameterChanged(); +} + +QParameterSet::QParameterSet(QWidget* parent) : QWidget(parent), ParameterSet() +{ + QGridLayout* grid = new QGridLayout(); + + ParaLay = new QVBoxLayout(); + + QScrollArea* QSA = new QScrollArea(); + QWidget* QW = new QWidget(); + + QVBoxLayout* QVBL = new QVBoxLayout(); + QVBL->addLayout(ParaLay); + QVBL->addStretch(1); + QW->setLayout(QVBL); + QSA->setWidget(QW); + QSA->setWidgetResizable(true); + + grid->addWidget(QSA); +// grid->addLayout(ParaLay,0,0,1,2); + +// grid->setRowStretch(1,1); + + QPushButton* btn = new QPushButton(tr("New")); + QObject::connect(btn,SIGNAL(clicked()),this,SLOT(NewParameter())); + btn->setEnabled(QCSX_Settings.GetEdit()); + grid->addWidget(btn,2,0); + + setLayout(grid); +} + +QParameterSet::~QParameterSet() +{ +} + +void QParameterSet::SetModified(bool mod) +{ + emit ParameterChanged(); + ParameterSet::SetModified(mod); +} + +void QParameterSet::clear() +{ + ParameterSet::clear(); + for (int i=0;isetChecked(true); + BG->addButton(RB,0); + lay->addWidget(RB); + RB = new QRadioButton("Linear"); + BG->addButton(RB,1); + lay->addWidget(RB); + + Group->setLayout(lay); + + QGridLayout* Grid = new QGridLayout(); + Grid->addWidget(Group,0,0,1,2); + + QPushButton* PB = new QPushButton(tr("Ok")); + QObject::connect(PB,SIGNAL(clicked()),diag,SLOT(accept())); + Grid->addWidget(PB,1,0); + PB = new QPushButton(tr("Cancel")); + QObject::connect(PB,SIGNAL(clicked()),diag,SLOT(reject())); + Grid->addWidget(PB,1,1); + + diag->setLayout(Grid); + diag->show(); + diag->setFixedSize(diag->size()); + + if (diag->exec()==QDialog::Accepted) + { + Parameter* newPara=NULL; + QParameter* QPara=NULL; + switch (BG->checkedId()) + { + case 0: + newPara = new Parameter(); + QPara = new QParameter(newPara); + break; + case 1: + newPara = new LinearParameter(); + QPara = new QLinearParameter(newPara->ToLinear()); + break; + } + if (newPara!=NULL) + { + if (QPara->Edit()==true) LinkParameter(newPara); + else + { + delete newPara; + delete QPara; + } + } + } +} + +size_t QParameterSet::DeleteParameter(Parameter* para) +{ + if (para!=NULL) + for (int i=0;iGetParameter()==para) + { + delete QPara; + vecQPara.remove(i); + } + } + return ParameterSet::DeleteParameter(para); +} + +void QParameterSet::AddParaWid(Parameter* newPara) +{ + if (newPara!=NULL) + { + QParameter* QPara=NULL; + switch (newPara->GetType()) + { + case 0: + QPara = new QParameter(newPara); + break; + case 1: + QPara = new QLinearParameter(newPara->ToLinear()); + break; + default: + QPara=NULL; + break; + } + if (QPara!=NULL) + { + ParaLay->addWidget(QPara); + QObject::connect(QPara,SIGNAL(Delete(Parameter*)),this,SLOT(DeleteParameter(Parameter*))); + QObject::connect(QPara,SIGNAL(ParameterChanged()),this,SLOT(SetModified())); + QPara->Update(); + vecQPara.append(QPara); + } + } +} + +size_t QParameterSet::LinkParameter(Parameter* newPara) +{ + AddParaWid(newPara); + return ParameterSet::LinkParameter(newPara); + +} diff --git a/QCSXCAD/QParameterGui.h b/QCSXCAD/QParameterGui.h new file mode 100644 index 0000000..239bde1 --- /dev/null +++ b/QCSXCAD/QParameterGui.h @@ -0,0 +1,107 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#ifndef _QPARAMETERGUI_H_ +#define _QPARAMETERGUI_H_ + +#include +#include +#include +#include +#include +#include + +#include "ParameterObjects.h" + +class QParameter : public QGroupBox +{ + Q_OBJECT +public: + QParameter(Parameter* para, QWidget* parent=NULL); + virtual ~QParameter(); + + Parameter* GetParameter() {return clPara;}; + +signals: + void ParameterChanged(); + void Delete(Parameter* para); + +public slots: + virtual bool Edit(); + virtual void Update(); + void DeleteParameter(); + void SweepState(int state); + +protected slots: + virtual void Changed(); + +protected: + Parameter* clPara; + QLabel* Name; + QLineEdit* Value; + QGridLayout *lay; + QCheckBox* SweepCB; +}; + +class QLinearParameter : public QParameter +{ + Q_OBJECT +public: + QLinearParameter(LinearParameter* para, QWidget* parent=NULL); + virtual ~QLinearParameter(); + +signals: + +public slots: + virtual bool Edit(); + virtual void Update(); + +protected slots: + virtual void Changed(); + +protected: + QSlider* slider; +}; + +class QParameterSet : public QWidget, public ParameterSet +{ + Q_OBJECT +public: + QParameterSet(QWidget* parent=NULL); + virtual ~QParameterSet(); + + virtual size_t LinkParameter(Parameter* newPara); + +signals: + void ParameterChanged(); + +public slots: + void NewParameter(); + virtual void SetModified(bool mod=true); + + virtual void clear(); + +protected slots: + virtual size_t DeleteParameter(Parameter* para); + +protected: + void AddParaWid(Parameter* newPara); + QVBoxLayout* ParaLay; + QVector vecQPara; +}; + +#endif //_QPARAMETERGUI_H_ diff --git a/QCSXCAD/QVTKStructure.cpp b/QCSXCAD/QVTKStructure.cpp new file mode 100644 index 0000000..9482dde --- /dev/null +++ b/QCSXCAD/QVTKStructure.cpp @@ -0,0 +1,873 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#include + +#include "QVTKStructure.h" + +#include "QVTKWidget.h" +#include "vtkRenderWindow.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkRenderer.h" +#include "vtkAxesActor.h" +#include "vtkActor.h" +#include "ContinuousStructure.h" +#include "ParameterCoord.h" +#include "VTKPrimitives.h" +#include "vtkCubeSource.h" +#include "vtkPolyDataMapper.h" +#include "vtkCellArray.h" +#include "vtkActor.h" +#include "vtkLODActor.h" +#include "vtkFollower.h" +#include "vtkAxes.h" +#include "vtkVectorText.h" +#include "vtkFollower.h" +#include "vtkTextProperty.h" +#include "vtkTextActor.h" +#include "vtkCamera.h" +#include "vtkProperty.h" +#include "vtkOrientationMarkerWidget.h" +#include "vtkPropAssembly.h" +#include "vtkTextProperty.h" +#include "vtkCaptionActor2D.h" +#include "vtkRectilinearGrid.h" +#include "vtkRectilinearGridGeometryFilter.h" +#include "vtkDoubleArray.h" +#include "vtkActorCollection.h" +#include "vtkInteractorStyle.h" +#include "vtkCommand.h" +#include "vtkCallbackCommand.h" +#include "vtkWindowToImageFilter.h" +#include "vtkPNGWriter.h" +#include +#include +#include +#include +#include "vtkInteractorStyleRubberBand2DPlane.h" +#include + +#include "CSPrimPoint.h" +#include "CSPrimBox.h" +#include "CSPrimMultiBox.h" +#include "CSPrimSphere.h" +#include "CSPrimSphericalShell.h" +#include "CSPrimCylinder.h" +#include "CSPrimCylindricalShell.h" +#include "CSPrimPolygon.h" +#include "CSPrimLinPoly.h" +#include "CSPrimRotPoly.h" +#include "CSPrimPolyhedron.h" +#include "CSPrimCurve.h" +#include "CSPrimWire.h" +#include "CSPrimUserDefined.h" + +#include "CSPropDiscMaterial.h" + +#include "CSTransform.h" + +QVTKStructure::QVTKStructure() +{ + clCS=NULL; + ActorGridPlane[0]=NULL; + ActorGridPlane[1]=NULL; + ActorGridPlane[2]=NULL; + m_Rect_Grid = NULL; + m_Struct_Grid = NULL; + m_CamData = NULL; + + iResolution=32; + AllowUpdate=true; + + VTKWidget= new QVTKWidget(); + + ren = vtkRenderer::New(); + VTKWidget->GetRenderWindow()->AddRenderer(ren); + + AddAxes(); + SetBackgroundColor(255,255,255); + + SetCallback(VTKWidget->GetRenderWindow()->GetInteractor()); +} + +QVTKStructure::~QVTKStructure() +{ + clear(); +} + +void QVTKStructure::AddAxes() +{ + Axes = vtkAxesActor::New(); + Axes->SetTotalLength(4,4,4); + vtkOrientationMarkerWidget* marker = vtkOrientationMarkerWidget::New(); + vtkPropAssembly* assembly = vtkPropAssembly::New(); + assembly->AddPart(Axes); + + marker->SetOrientationMarker(assembly); + marker->SetViewport(0.0,0.0,0.25,0.25); + + marker->SetInteractor(VTKWidget->GetRenderWindow()->GetInteractor()); + marker->SetEnabled(1); + marker->InteractiveOff(); + + //assembly->Delete(); + //marker->Delete(); +} + +void QVTKStructure::SetBackgroundColor(int r, int g, int b) +{ + double rgb[3]={(double)r/255.0,(double)g/255.0,(double)b/255.0}; + double irgb[3]={1-rgb[0],1-rgb[1],1-rgb[2]}; + ren->SetBackground(rgb); + + Axes->GetXAxisCaptionActor2D()->GetCaptionTextProperty()->SetColor(irgb); + Axes->GetYAxisCaptionActor2D()->GetCaptionTextProperty()->SetColor(irgb); + Axes->GetZAxisCaptionActor2D()->GetCaptionTextProperty()->SetColor(irgb); + + for (int i=0;i<3;++i) + { + if (ActorGridPlane[i]!=NULL) ActorGridPlane[i]->GetProperty()->SetColor(irgb); + } + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); +} + +void QVTKStructure::SetGeometry(ContinuousStructure *CS) +{ + clear(); + clCS=CS; +} + +void QVTKStructure::clear() +{ + for (int i=0;iRemoveActor(ActorGridPlane[i]); + ActorGridPlane[i]->Delete(); + ActorGridPlane[i]=NULL; + } + } + if (m_Rect_Grid) + m_Rect_Grid->Delete(); + m_Rect_Grid=NULL; + if (m_Struct_Grid) + m_Struct_Grid->Delete(); + m_Struct_Grid=NULL; +} + + +void QVTKStructure::RenderGrid() +{ + if (clCS==NULL) return; + CSRectGrid* CSGrid = clCS->GetGrid(); + if (CSGrid->isValid()==false) + return; + + if (CSGrid->GetMeshType()==CARTESIAN) + { + if (m_Rect_Grid) + m_Rect_Grid->Delete(); + m_Rect_Grid = vtkRectilinearGrid::New(); + vtkDoubleArray *Coords[3]; + int iQty[3]; + + for (int n=0;n<3;++n) + { + iQty[n]=CSGrid->GetQtyLines(n); + Coords[n]=vtkDoubleArray::New(); + for (int m=0;mInsertNextValue(CSGrid->GetLine(n,m)); + } + if (iQty[0]*iQty[1]*iQty[2]==0) + { + for (int n=0;n<3;++n) Coords[n]->Delete(); + return; + } + m_Rect_Grid->SetDimensions(iQty[0],iQty[1],iQty[2]); + m_Rect_Grid->SetXCoordinates(Coords[0]); + m_Rect_Grid->SetYCoordinates(Coords[1]); + m_Rect_Grid->SetZCoordinates(Coords[2]); + for (int n=0;n<3;++n) + Coords[n]->Delete(); + } + else if (CSGrid->GetMeshType()==CYLINDRICAL) + { + if (m_Struct_Grid) + m_Struct_Grid->Delete(); + m_Struct_Grid = vtkStructuredGrid::New(); + + unsigned int uiQty[3]; + double* lines[3]={NULL,NULL,NULL}; + for (unsigned int n=0;n<3;++n) + lines[n] = CSGrid->GetLines(n,lines[n],uiQty[n]); + + m_Struct_Grid->SetDimensions(uiQty[0],uiQty[1],uiQty[2]); + vtkPoints *points = vtkPoints::New(); + points->SetNumberOfPoints(uiQty[0]*uiQty[1]*uiQty[2]); + double r[3]; + int id=0; + for (unsigned int k=0; kSetPoint(id++,r); + } + m_Struct_Grid->SetPoints(points); + points->Delete(); + for (unsigned int n=0;n<3;++n) + { + delete[] lines[n]; + lines[n] = NULL; + } + } + else + cerr << "QVTKStructure::RenderGrid(): Error, unknown grid type!" << endl; + + RenderGridDir(0,0); + RenderGridDir(1,0); + RenderGridDir(2,0); +} + +void QVTKStructure::RenderGridX(int plane_pos) +{ + RenderGridDir(0,plane_pos); + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); +} + +void QVTKStructure::RenderGridY(int plane_pos) +{ + RenderGridDir(1,plane_pos); + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); + +} + +void QVTKStructure::RenderGridZ(int plane_pos) +{ + RenderGridDir(2,plane_pos); + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); +} + +void QVTKStructure::RenderGridDir(int dir, unsigned int plane_pos) +{ + if (ActorGridPlane[dir]!=NULL) + { + ren->RemoveActor(ActorGridPlane[dir]); + ActorGridPlane[dir]->Delete(); + } + + ActorGridPlane[dir] = vtkLODActor::New(); + vtkPolyDataMapper *gridMapper = vtkPolyDataMapper::New(); + vtkPolyDataAlgorithm *plane = NULL; + + CSRectGrid* CSGrid = clCS->GetGrid(); + int uiQty[3]; + + for (int n=0;n<3;++n) + uiQty[n]=CSGrid->GetQtyLines(n); + if ((int)plane_pos>=uiQty[dir]) + { + cerr << "QVTKStructure::RenderGridDir: requested plane postion is out of range, resetting to max value!" << endl; + plane_pos = uiQty[dir]-1; + } + + if (CSGrid->GetMeshType()==CARTESIAN) + { + if (m_Rect_Grid==NULL) + { + ActorGridPlane[dir]->Delete(); + gridMapper->Delete(); + ActorGridPlane[dir]=NULL; + cerr << "QVTKStructure::RenderGridDir: Error, rect grid mesh was not created, skipping drawing..." << endl; + return; + } + vtkRectilinearGridGeometryFilter *grid_plane = vtkRectilinearGridGeometryFilter::New(); + plane = grid_plane; +#if VTK_MAJOR_VERSION>=6 + grid_plane->SetInputData(m_Rect_Grid); +#else + grid_plane->SetInput(m_Rect_Grid); +#endif + switch (dir) + { + case 2: + { + grid_plane->SetExtent(0,uiQty[0]-1, 0,uiQty[1]-1, plane_pos,plane_pos); + break; + } + case 1: + { + grid_plane->SetExtent(0,uiQty[0]-1, plane_pos,plane_pos, 0,uiQty[2]-1); + break; + } + case 0: + { + grid_plane->SetExtent(plane_pos,plane_pos, 0,uiQty[1]-1, 0,uiQty[2]-1); + break; + } + } + } + else if (CSGrid->GetMeshType()==CYLINDRICAL) + { + if (m_Struct_Grid==NULL) + { + ActorGridPlane[dir]->Delete(); + gridMapper->Delete(); + ActorGridPlane[dir]=NULL; + cerr << "QVTKStructure::RenderGridDir: Error, structured grid mesh was not created, skipping drawing..." << endl; + return; + } + + vtkStructuredGridGeometryFilter *grid_plane = vtkStructuredGridGeometryFilter::New(); + plane = grid_plane; +#if VTK_MAJOR_VERSION>=6 + grid_plane->SetInputData(m_Struct_Grid); +#else + grid_plane->SetInput(m_Struct_Grid); +#endif + switch (dir) + { + case 2: + { + grid_plane->SetExtent(0,uiQty[0]-1, 0,uiQty[1]-1, plane_pos,plane_pos); + break; + } + case 1: + { + grid_plane->SetExtent(0,uiQty[0]-1, plane_pos,plane_pos, 0,uiQty[2]-1); + break; + } + case 0: + { + grid_plane->SetExtent(plane_pos,plane_pos, 0,uiQty[1]-1, 0,uiQty[2]-1); + break; + } + } + } + else + cerr << "QVTKStructure::RenderGrid(): Error, unknown grid type!" << endl; + + gridMapper->SetInputConnection(plane->GetOutputPort()); + ActorGridPlane[dir]->SetMapper(gridMapper); + ActorGridPlane[dir]->GetProperty()->SetColor(0,0,0); + ActorGridPlane[dir]->GetProperty()->SetDiffuse(0); + ActorGridPlane[dir]->GetProperty()->SetAmbient(1); + ActorGridPlane[dir]->GetProperty()->SetRepresentationToWireframe(); + ActorGridPlane[dir]->GetProperty()->SetOpacity((double)GridOpacity/255.0); + ren->AddActor(ActorGridPlane[dir]); + gridMapper->Delete(); + plane->Delete(); + +} + +void QVTKStructure::SetGridOpacity(int val) +{ + GridOpacity = val; + if (AllowUpdate==false) return; + for (int i=0;i<3;++i) + { + if (ActorGridPlane[i]!=NULL) ActorGridPlane[i]->GetProperty()->SetOpacity((double)val/255.0); + } + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); +} + +void QVTKStructure::ResetView() +{ + ren->ResetCamera(); + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); +} + +void QVTKStructure::setXY() +{ + vtkCamera* cam=ren->GetActiveCamera(); + ren->ResetCamera(); + double fp[3]; + cam->SetViewUp(0.5,0.5,0.5); + cam->GetFocalPoint(fp); + fp[2]+=1; + cam->SetPosition(fp); + cam->SetRoll(0); + ResetView(); +} + +void QVTKStructure::setYZ() +{ + vtkCamera* cam=ren->GetActiveCamera(); + ren->ResetCamera(); + double fp[3]; + cam->SetViewUp(0.5,0.5,0.5); + cam->GetFocalPoint(fp); + fp[0]+=1; + cam->SetPosition(fp); + + cam->SetRoll(-90); + ResetView(); +} + + +void QVTKStructure::setZX() +{ + vtkCamera* cam=ren->GetActiveCamera(); + ren->ResetCamera(); + double fp[3]; + cam->SetViewUp(0.5,0.5,0.5); + cam->GetFocalPoint(fp); + fp[1]+=1; + cam->SetPosition(fp); + cam->SetRoll(90); + ResetView(); +} + +void QVTKStructure::SetPropOpacity(unsigned int uiID, int val) +{ + for (int i=0;iSetOpacity2All((double)val/255.0); + } + } + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); +} + +void QVTKStructure::RenderGeometry() +{ + for (int i=0;iGetQtyProperties(); + for (int i=0;iGetProperty(i); + if (prop==NULL) return; + int QtyPrim=prop->GetQtyPrimitives(); + if (QtyPrim>0) + { + VTKLayerStruct layStruct; + VTKPrimitives* vtkPrims= new VTKPrimitives(ren); + layStruct.VTKProp=vtkPrims; + layStruct.uID=prop->GetUniqueID(); + LayerPrimitives.append(layStruct); + RGBa col=prop->GetFillColor(); + if (prop->GetVisibility()==false) col.a=0; + double rgb[3]={(double)col.R/255.0,(double)col.G/255.0,(double)col.B/255.0}; + for (int n=0;nGetPrimitive(n); + if (prim==NULL) return; + CoordinateSystem primCS = prim->GetCoordinateSystem(); + CSTransform* transform = prim->GetTransform(); + double* transform_matrix = NULL; + if (transform) + transform_matrix = transform->GetMatrix(); + if (primCS==UNDEFINED_CS) + primCS=clCS->GetCoordInputType(); + switch (prim->GetType()) + { + case CSPrimitives::BOX: + { + CSPrimBox* box = prim->ToBox(); + if (primCS==CARTESIAN) + vtkPrims->AddCube(box->GetStartCoord()->GetCartesianCoords(),box->GetStopCoord()->GetCartesianCoords(),rgb,(double)col.a/255.0,transform_matrix); + else if (primCS==CYLINDRICAL) + vtkPrims->AddCylindricalCube(box->GetStartCoord()->GetCylindricalCoords(),box->GetStopCoord()->GetCylindricalCoords(),rgb,(double)col.a/255.0,transform_matrix); + break; + } + case CSPrimitives::MULTIBOX: + { + CSPrimMultiBox* multibox = prim->ToMultiBox(); + int qtyPts=multibox->GetQtyBoxes()*2; + double *coords = new double[qtyPts*3]; + for (int a=0;aGetCoord(3*a); + coords[a+1]=multibox->GetCoord(3*a+1); + coords[qtyPts+a]=multibox->GetCoord(3*a+2); + coords[qtyPts+a+1]=multibox->GetCoord(3*a+3); + coords[2*qtyPts+a]=multibox->GetCoord(3*a+4); + coords[2*qtyPts+a+1]=multibox->GetCoord(3*a+5); + } + vtkPrims->AddDisc(coords,qtyPts,rgb,(double)col.a/255.0,transform_matrix); + delete[] coords; + break; + } + case CSPrimitives::SPHERE: + { + CSPrimSphere* sphere = prim->ToSphere(); + vtkPrims->AddSphere(sphere->GetCenter()->GetCartesianCoords(),sphere->GetRadius(),rgb,(double)col.a/255.0,iResolution,transform_matrix); + break; + } + case CSPrimitives::SPHERICALSHELL: + { + CSPrimSphericalShell* sphereshell = prim->ToSphericalShell(); + const double* center = sphereshell->GetCenter()->GetCartesianCoords(); + const double radius = sphereshell->GetRadius(); + const double shellWidth = sphereshell->GetShellWidth(); + vtkPrims->AddSphericalShell(center, radius-shellWidth/2, radius+shellWidth/2, rgb, (double)col.a/255.0, iResolution, transform_matrix); + break; + } + case CSPrimitives::CYLINDER: + { + CSPrimCylinder* cylinder = prim->ToCylinder(); + vtkPrims->AddCylinder2(cylinder->GetAxisStartCoord()->GetCartesianCoords(),cylinder->GetAxisStopCoord()->GetCartesianCoords(),cylinder->GetRadius(),rgb,(double)col.a/255.0,iResolution,transform_matrix); + break; + } + case CSPrimitives::CYLINDRICALSHELL: + { + CSPrimCylindricalShell* cylinder = prim->ToCylindricalShell(); + const double* start = cylinder->GetAxisStartCoord()->GetCartesianCoords(); + const double* stop = cylinder->GetAxisStopCoord()->GetCartesianCoords(); + const double radius = cylinder->GetRadius(); + const double shellWidth = cylinder->GetShellWidth(); + vtkPrims->AddCylindricalShell( start, stop, radius-shellWidth/2, radius+shellWidth/2, rgb, (double)col.a/255.0, iResolution, transform_matrix ); + break; + } + case CSPrimitives::POLYGON: + case CSPrimitives::LINPOLY: + case CSPrimitives::ROTPOLY: + { + CSPrimPolygon* poly = NULL; + if (prim->GetType()==CSPrimitives::POLYGON) + poly = prim->ToPolygon(); + else if (prim->GetType()==CSPrimitives::LINPOLY) + poly = prim->ToLinPoly(); + else if (prim->GetType()==CSPrimitives::ROTPOLY) + poly = prim->ToRotPoly(); + int normDir = poly->GetNormDir(); + double elev = poly->GetElevation(); + int nP = (normDir+1)%3; + int nPP = (normDir+2)%3; + int nrPts = poly->GetQtyCoords(); + double dCoords[3*nrPts]; + for (int n=0;nGetCoord(2*n); + dCoords[nPP*nrPts + n] = poly->GetCoord(2*n+1); + } + double dVector[6] = {0,0,0,0,0,0}; + if (prim->GetType()==CSPrimitives::POLYGON) + vtkPrims->AddClosedPoly(dCoords,nrPts,dVector,rgb,(double)col.a/255.0,transform_matrix); + if (prim->GetType()==CSPrimitives::LINPOLY) + { + dVector[normDir] = prim->ToLinPoly()->GetLength(); + vtkPrims->AddClosedPoly(dCoords,nrPts,dVector,rgb,(double)col.a/255.0,transform_matrix); + } + if (prim->GetType()==CSPrimitives::ROTPOLY) + { + dVector[2*prim->ToRotPoly()->GetRotAxisDir()+1]=1; + double angles[2] = {prim->ToRotPoly()->GetAngle(0)*180/PI,prim->ToRotPoly()->GetAngle(1)*180/PI}; + vtkPrims->AddRotationalPoly(dCoords,nrPts,dVector,angles,rgb,(double)col.a/255.0,32,transform_matrix); + } + break; + } + case CSPrimitives::POLYHEDRONREADER: + case CSPrimitives::POLYHEDRON: + { + CSPrimPolyhedron* polyhedron = dynamic_cast(prim); + vtkCellArray *poly = vtkCellArray::New(); + vtkPolyData* polydata=vtkPolyData::New(); + vtkPoints *points = vtkPoints::New(); + for (unsigned int i=0; iGetNumVertices();i++) + points->InsertPoint(i,polyhedron->GetVertex(i)); + unsigned int numVertex; + int* vertices; + for (unsigned int i=0; iGetNumFaces();++i) + { + if (polyhedron->GetFaceValid(i)==false) + continue; + vertices=polyhedron->GetFace(i,numVertex); + poly->InsertNextCell(numVertex); + for (unsigned int p=0; pInsertCellPoint(vertices[p]); + } + polydata->SetPoints(points); + polydata->SetPolys(poly); + vtkPrims->AddPolyData(polydata,rgb,(double)col.a/255.0,transform_matrix); + poly->Delete(); + points->Delete(); + polydata->Delete(); + break; + } +// case CSPrimitives::POLYHEDRONREADER: +// { +// CSPrimPolyhedronReader* reader = prim->ToPolyhedronReader(); +// double center[]={0,0,0}; +// vtkPrims->AddSTLObject(reader->GetFilename().c_str(),center,rgb,(double)col.a/255.0,transform_matrix); +// break; +// } + case CSPrimitives::CURVE: + case CSPrimitives::WIRE: + { + CSPrimCurve* curve = NULL; + if (prim->GetType()==CSPrimitives::CURVE) + curve = prim->ToCurve(); + else + curve = prim->ToWire(); + + unsigned int nrP = (unsigned int)curve->GetNumberOfPoints(); + double dCoords[3*nrP]; + double xyz[3]; + bool isCurve = (prim->GetType()==CSPrimitives::CURVE); + for (unsigned int n=0;nGetPoint(n,xyz,CARTESIAN,isCurve); + dCoords[0*nrP+n] = xyz[0]; + dCoords[1*nrP+n] = xyz[1]; + dCoords[2*nrP+n] = xyz[2]; + } + if (isCurve) + vtkPrims->AddLinePoly(dCoords,nrP,1,rgb,(double)col.a/255.0); + else + { + CSPrimWire* wire = prim->ToWire(); + vtkPrims->AddTubePoly(dCoords,nrP,wire->GetWireRadius(),rgb,(double)col.a/255.0,8,transform_matrix); + } + break; + } + } + } + } + } + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); +} + +void QVTKStructure::RenderDiscMaterialModel() +{ + for (int i=0;iGetQtyProperties();++i) + { + CSProperties* prop = clCS->GetProperty(i); + CSPropDiscMaterial* dm_prop = prop->ToDiscMaterial(); + if (dm_prop) + { + VTKDiscModel model; + VTKPrimitives* vtkPrims= new VTKPrimitives(ren); + model.vtk_model = vtkPrims; + model.uID = dm_prop->GetUniqueID(); + m_DiscMatModels.append(model); + vtkPolyData* polydata = dm_prop->CreatePolyDataModel(); + + double rgb[3] = {1,1,1}; + CSTransform* transform = new CSTransform(dm_prop->GetTransform()); + transform->SetPreMultiply(); + transform->Scale(dm_prop->GetScale()); + double* transform_matrix = NULL; + if (transform) + transform_matrix = transform->GetMatrix(); + vtkPrims->AddPolyData(polydata,rgb,1.0,transform_matrix); + delete transform; + } + } + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); +} + +void QVTKStructure::SetParallelProjection(bool val, bool render) +{ + vtkCamera* cam = ren->GetActiveCamera(); + cam->SetParallelProjection(val); + + if (render) + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); +} + +void QVTKStructure::Set2DInteractionStyle(bool val, bool render) +{ + if (val) + VTKWidget->GetRenderWindow()->GetInteractor()->SetInteractorStyle(vtkInteractorStyleRubberBand2DPlane::New()); + else + VTKWidget->GetRenderWindow()->GetInteractor()->SetInteractorStyle(vtkInteractorStyleTrackballCamera::New()); + + if (render) + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); +} + +void QVTKStructure::SaveCamData() +{ + if (m_CamData==NULL) + m_CamData = new CamData; + + vtkCamera *Camera = ren->GetActiveCamera(); + + Camera->GetPosition(m_CamData->pos); + Camera->GetFocalPoint(m_CamData->focalPoint); + Camera->GetViewUp(m_CamData->viewUp); + m_CamData->viewAngle = Camera->GetViewAngle(); +} + +void QVTKStructure::RestoreCamData(bool render) +{ + if (m_CamData==NULL) + return; + + vtkCamera *Camera = ren->GetActiveCamera(); + Camera->SetPosition( m_CamData->pos ); + Camera->SetFocalPoint( m_CamData->focalPoint ); + Camera->SetViewUp( m_CamData->viewUp ); + Camera->SetViewAngle( m_CamData->viewAngle ); + Camera->Modified(); + + if (render) + VTKWidget->GetRenderWindow()->GetInteractor()->Render(); +} + + +void QVTKStructure::ExportView2Image() +{ + QString filename = QFileDialog::getSaveFileName(VTKWidget, tr("Choose file to save image"), QString(), tr("Images (*.png)")); + + if (filename.isEmpty()) + return; + + vtkWindowToImageFilter* filter = vtkWindowToImageFilter::New(); + filter->SetInput(VTKWidget->GetRenderWindow()); + + vtkPNGWriter* png_writer= vtkPNGWriter::New(); + png_writer->SetInputConnection(filter->GetOutputPort()); + //png_writer->SetQuality(100); + png_writer->SetFileName(filename.toStdString().c_str()); + png_writer->Write(); +} + +void QVTKStructure::ExportProperty2PolyDataVTK(unsigned int uiID, QString filename, double scale) +{ + for (int i=0;iWritePolyData2File(name.toStdString().c_str(), scale); + } + } + } + + for (int i=0;iWritePolyData2File(name.toStdString().c_str(), scale); + } + } + } +} + +void QVTKStructure::ExportProperty2STL(unsigned int uiID, QString filename, double scale) +{ + for (int i=0;iWritePolyData2STL(name.toStdString().c_str(), scale); + } + } + } +} + +void QVTKStructure::ExportProperty2PLY(unsigned int uiID, QString filename, double scale) +{ + for (int i=0;iWritePolyData2PLY(name.toStdString().c_str(), scale); + } + } + } +} + +void QVTKStructure::KeyPress(vtkObject *caller, unsigned long eid, void *clientdata, void *calldata) +{ + UNUSED(caller); + UNUSED(eid); + UNUSED(calldata); + + //vtkInteractorStyle * istyle = (vtkInteractorStyle *) caller; + vtkRenderWindowInteractor * iren = ((KeyPressData *)clientdata)->iren; + //vtkRenderWindow *renWin = iren->GetRenderWindow(); + vtkActor **GridPlanes = ((KeyPressData *)clientdata)->GridPlanes; + //vtkRenderer *ren = ((KeyPressData *)clientdata)->ren; + int key; + key=iren->GetKeyCode(); + // fprintf(stderr,"Event... EiD: %d Key: %d OpenGL?: %d\n",eid,key,renWin->SupportsOpenGL()); + switch(key) + { + case 's': + { + for (int n=0;n<3;++n) + { + if (GridPlanes[n]) + GridPlanes[n]->GetProperty()->SetRepresentationToWireframe(); + } + iren->Render(); + break; + } + } +} + +void QVTKStructure::SetCallback(vtkRenderWindowInteractor *iren) +{ + ren->GetActiveCamera()->SetFocalPoint(0,0,0); + //Callback + KeyPressData *cbData = new KeyPressData; + cbData->GridPlanes=ActorGridPlane; + cbData->ren=ren; + cbData->iren=iren; + + vtkCallbackCommand *cb = vtkCallbackCommand::New(); + cb->SetCallback(KeyPress); + cb->SetClientData((void *)cbData); + iren->AddObserver(vtkCommand::KeyReleaseEvent, cb); + //VTKWidget->GetRenderWindow()->GetInteractor()->AddObserver(vtkCommand::KeyReleaseEvent, cb); + + cb->Delete(); + // free(cbData); +} diff --git a/QCSXCAD/QVTKStructure.h b/QCSXCAD/QVTKStructure.h new file mode 100644 index 0000000..2809e8a --- /dev/null +++ b/QCSXCAD/QVTKStructure.h @@ -0,0 +1,143 @@ +/* +* Copyright (C) 2008,2009,2010 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 . +*/ + +#ifndef _QVTKSTRUCTURE_H_ +#define _QVTKSTRUCTURE_H_ + +#include + +class QVTKWidget; +class vtkRenderWindow; +class vtkRenderWindowInteractor; +class vtkRenderer; +class vtkAxesActor; +class vtkActor; +class ContinuousStructure; +class VTKPrimitives; +class vtkObject; +class vtkRectilinearGrid; +class vtkStructuredGrid; + +class QVTKStructure : public QObject +{ + Q_OBJECT +public: + QVTKStructure(); + virtual ~QVTKStructure(); + + QWidget* GetVTKWidget() {return (QWidget *)VTKWidget;}; + + void AddAxes(); + + void SetGeometry(ContinuousStructure *CS); + void clear(); + + void SetBackgroundColor(int r, int g, int b); + + //! Set the update mode to false if this widget should not be rendered e.g. because it is hidden + void SetUpdateMode(bool mode) {AllowUpdate=mode;} + + //Callback + void SetCallback(vtkRenderWindowInteractor *iren); + +public slots: + void SetGridOpacity(int val); + void ResetView(); + void setXY(); + void setYZ(); + void setZX(); + void SetPropOpacity(unsigned int uiID, int val); + void RenderGrid(); + void RenderGridX(int plane_pos); + void RenderGridY(int plane_pos); + void RenderGridZ(int plane_pos); + void RenderGeometry(); + + //! Enable/Disable 3D parallel projection + void SetParallelProjection(bool val, bool render=true); + + //! Enable/Disable 2D interaction style + void Set2DInteractionStyle(bool val, bool render=true); + + void SaveCamData(); + void RestoreCamData(bool render); + + void RenderDiscMaterialModel(); + + //! Export the current view to an image file (currently only png) + void ExportView2Image(); + + void ExportProperty2PolyDataVTK(unsigned int uiID, QString filename, double scale = 1.0); + void ExportProperty2STL(unsigned int uiID, QString filename, double scale = 1.0); + void ExportProperty2PLY(unsigned int uiID, QString filename, double scale = 1.0); + +protected slots: + void RenderGridDir(int dir, unsigned int plane_pos); + +protected: + typedef struct + { + VTKPrimitives* VTKProp; + unsigned int uID; + } VTKLayerStruct; + + QVTKWidget *VTKWidget; + + //set to false if this widget is hidden + bool AllowUpdate; + + vtkRenderer *ren; + + vtkAxesActor* Axes; + + ContinuousStructure* clCS; + QVector LayerPrimitives; + + vtkRectilinearGrid *m_Rect_Grid; + vtkStructuredGrid *m_Struct_Grid; + vtkActor* ActorGridPlane[3]; + int GridOpacity; //remember the grid opacity + + int iResolution; + + typedef struct + { + VTKPrimitives* vtk_model; + unsigned int uID; + } VTKDiscModel; + QVector m_DiscMatModels; + + typedef struct + { + double pos[3]; + double focalPoint[3]; + double viewUp[3]; + double viewAngle; + } CamData; + CamData* m_CamData; + + struct KeyPressData + { + vtkActor **GridPlanes; + vtkRenderer *ren; + vtkRenderWindowInteractor * iren; + }; + + static void KeyPress(vtkObject *caller, unsigned long eid, void *clientdata, void *calldata); +}; + +#endif //_QVTKSTRUCTURE_H_ diff --git a/QCSXCAD/README b/QCSXCAD/README new file mode 100644 index 0000000..50a82cd --- /dev/null +++ b/QCSXCAD/README @@ -0,0 +1,7 @@ +* +* QCSXCAD - Qt-GUI for CSXCAD +* + +QCSXCAD the Qt-GUI for CSXCAD, a C++ library to describe geometrical objects and their physical or non-physical properties. +QCSXCAD is licensed under the terms of the LGPLv3. + diff --git a/QCSXCAD/VTKPrimitives.cpp b/QCSXCAD/VTKPrimitives.cpp new file mode 100644 index 0000000..61c7c20 --- /dev/null +++ b/QCSXCAD/VTKPrimitives.cpp @@ -0,0 +1,1019 @@ +/* +* Copyright (C) 2005,2006,2007,2008,2009,2010 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 . +*/ + +#include "VTKPrimitives.h" +#include "vtkRenderer.h" +#include "vtkActorCollection.h" + +#include "vtkPolyDataMapper.h" +#include "vtkDoubleArray.h" +#include "vtkLODActor.h" +#include "vtkActor.h" +#include "vtkProperty.h" +#include "vtkCamera.h" +#include "vtkCubeSource.h" +#include "vtkPlaneSource.h" +#include "vtkCylinderSource.h" +#include "vtkLineSource.h" +#include "vtkSphereSource.h" +#include "vtkPoints.h" +#include "vtkCellArray.h" +#include "vtkRotationalExtrusionFilter.h" +#include "vtkLinearExtrusionFilter.h" +#include "vtkArrowSource.h" +#include "vtkSTLReader.h" +#include "vtkVectorText.h" +#include "vtkFollower.h" +#include "vtkTriangleFilter.h" +#include "vtkFloatArray.h" +#include "vtkPointData.h" +#include "vtkTransform.h" +#include "vtkTransformPolyDataFilter.h" +#include "vtkCollectionIterator.h" +#include "vtkConeSource.h" +#include "vtkTubeFilter.h" +#include "vtkAppendPolyData.h" +#include "vtkXMLPolyDataWriter.h" +#include "vtkSTLWriter.h" +#include "vtkDiskSource.h" +#include "vtkPLYWriter.h" + +#if (VTK_MAJOR_VERSION==5 && VTK_MINOR_VERSION>=10) || (VTK_MAJOR_VERSION>=6) +#include "vtkBooleanOperationPolyDataFilter.h" +#endif + +VTKPrimitives::VTKPrimitives(vtkRenderer *Renderer) +{ + ren = Renderer; + + ActorColl = vtkActorCollection::New(); + + m_PolyDataCollection = vtkAppendPolyData::New(); + m_ArcDelta = 3.0/180.0*PI; // default of 5° resolution for representing angles +} + +VTKPrimitives::~VTKPrimitives() +{ + ActorColl->InitTraversal(); + vtkActor* act=NULL; + while ((act=ActorColl->GetNextActor())) + { + ren->RemoveActor(act); + act->Delete(); + } + ActorColl->Delete(); + ActorColl=NULL; + + if (m_PolyDataCollection) + m_PolyDataCollection->Delete(); + m_PolyDataCollection=NULL; +} + +VTKPrimitives::VTKPrimitives() +{ +} + +void VTKPrimitives::AddCube(const double *start, const double *stop, double *dRGB, double dOpacity, const double* tf_matrix) +{ + double coords[6] = {start[0],stop[0],start[1],stop[1],start[2],stop[2]}; + double help; + int dim=0; + //swap start stop if start>stop + for (int n=0;n<3;++n) + { + if (coords[2*n]>coords[2*n+1]) + { + help=coords[2*n+1]; + coords[2*n+1]=coords[2*n]; + coords[2*n]=help; + } + if (coords[2*n]!=coords[2*n+1]) + ++dim; + } + if (dim==0) + { + cerr << "VTKPrimitives::AddCube: Warning, can't draw a Point Box... skipping" << endl; + return; + } + if (dim==1) + return AddLinePoly(coords,2,1,dRGB,dOpacity); + AddCube(coords,dRGB,dOpacity,tf_matrix); +} + +void VTKPrimitives::AddCube(double *dCoords, double *dRGB, double dOpacity, const double* tf_matrix) +{ + //create a simple cartesian cube... + vtkCubeSource *Source = vtkCubeSource::New(); + Source->SetBounds(dCoords); + + AddPolyData(Source->GetOutputPort(), dRGB, dOpacity, tf_matrix); + Source->Delete(); +} + +void VTKPrimitives::AddCylindricalCube(const double *start, const double *stop, double *dRGB, double dOpacity, const double* tf_matrix) +{ + double coords[6] = {start[0],stop[0],start[1],stop[1],start[2],stop[2]}; + double help; + //swap start stop if start>stop + for (int n=0;n<3;++n) + { + if (coords[2*n]>coords[2*n+1]) + { + help=coords[2*n+1]; + coords[2*n+1]=coords[2*n]; + coords[2*n]=help; + } + } + AddCylindricalCube(coords,dRGB,dOpacity,tf_matrix); +} + +void VTKPrimitives::AddCylindricalCube(double *dCoords, double *dRGB, double dOpacity, const double* tf_matrix) +{ + vtkPolyDataAlgorithm* PDSource = NULL; + vtkPolyDataAlgorithm* PDFilter = NULL; + + if ( (dCoords[2]!=dCoords[3]) ) + { + if ((dCoords[0]!=dCoords[1]) && ((dCoords[4]!=dCoords[5]))) //3D object + { + double dO[3] = {dCoords[0],dCoords[2],dCoords[4]}; + double dP1[3] = {dCoords[0],dCoords[2],dCoords[5]}; + double dP2[3] = {dCoords[1],dCoords[2],dCoords[4]}; + double out[3]; + vtkPlaneSource *Source = vtkPlaneSource::New(); + Source->SetOrigin(TransformCylindricalCoords(dO,out)); + Source->SetPoint1(TransformCylindricalCoords(dP1,out)); + Source->SetPoint2(TransformCylindricalCoords(dP2,out)); + PDSource = Source; + } + else if (dCoords[4]!=dCoords[5]) // alpha-z plane + { + double dP1[3] = {dCoords[0],dCoords[2],dCoords[4]}; + double dP2[3] = {dCoords[0],dCoords[2],dCoords[5]}; + double out[3]; + + vtkLineSource *Source = vtkLineSource::New(); + Source->SetPoint1(TransformCylindricalCoords(dP1,out)); + Source->SetPoint2(TransformCylindricalCoords(dP2,out)); + PDSource = Source; + } + else if (dCoords[0]!=dCoords[1]) // alpha-r plane + { + double dP1[3] = {dCoords[0],dCoords[2],dCoords[4]}; + double dP2[3] = {dCoords[1],dCoords[2],dCoords[4]}; + double out[3]; + + vtkLineSource *Source = vtkLineSource::New(); + Source->SetPoint1(TransformCylindricalCoords(dP1,out)); + Source->SetPoint2(TransformCylindricalCoords(dP2,out)); + PDSource = Source; + } + else //line in a-direction + { + double out[6]; + return AddLinePoly(TransformCylindricalCoords(dCoords,out,2),2,1,dRGB,dOpacity); + } + + if (PDSource==NULL) + return; + + vtkRotationalExtrusionFilter *extrude = vtkRotationalExtrusionFilter::New(); +#if VTK_MAJOR_VERSION>=6 + extrude->SetInputConnection(PDSource->GetOutputPort()); +#else + extrude->SetInput(PDSource->GetOutput()); +#endif + int nrSteps = ceil(fabs(dCoords[3]-dCoords[2])/m_ArcDelta); + extrude->SetResolution(nrSteps); + extrude->SetAngle( (dCoords[3]-dCoords[2])*180/PI ); + PDFilter = extrude; + } + else //rz-plane or line + { + if (dCoords[0]==dCoords[1]) //line in z-direction + { + double out[6]; + return AddLinePoly(TransformCylindricalCoords(dCoords,out,2),2,1,dRGB,dOpacity); + } + if (dCoords[4]==dCoords[5]) //line in r-direction + { + double out[6]; + return AddLinePoly(TransformCylindricalCoords(dCoords,out,2),2,1,dRGB,dOpacity); + } + + //rz-plane + double dO[3] = {dCoords[0],dCoords[2],dCoords[4]}; + double dP1[3] = {dCoords[0],dCoords[2],dCoords[5]}; + double dP2[3] = {dCoords[1],dCoords[2],dCoords[4]}; + double out[3]; + vtkPlaneSource *Source = vtkPlaneSource::New(); + Source->SetOrigin(TransformCylindricalCoords(dO,out)); + Source->SetPoint1(TransformCylindricalCoords(dP1,out)); + Source->SetPoint2(TransformCylindricalCoords(dP2,out)); + PDFilter = Source; + } + + if (PDFilter==NULL) + return; + + AddPolyData(PDFilter->GetOutputPort(), dRGB, dOpacity, tf_matrix); + if (PDSource) + PDSource->Delete(); + PDFilter->Delete(); +} + +void VTKPrimitives::AddPlane(double *dOrigin, double* dP1, double* dP2, double *dRGB, double dOpacity, const double* tf_matrix) +{ + double out[3]; + vtkPlaneSource *Source = vtkPlaneSource::New(); + Source->SetOrigin(TransformCylindricalCoords(dOrigin,out)); + Source->SetPoint1(TransformCylindricalCoords(dP1,out)); + Source->SetPoint2(TransformCylindricalCoords(dP2,out)); + + AddPolyData(Source->GetOutputPort(), dRGB, dOpacity, tf_matrix); + Source->Delete(); +} + +void VTKPrimitives::AddDisc(double *dCoords, unsigned int uiQtyCoords, double *dRGB, double dOpacity, const double* tf_matrix) +{ + unsigned int i=0,j=0;//,h=0;//,k=0; + vtkPoints *points = vtkPoints::New(); + vtkCellArray *poly = vtkCellArray::New(); + vtkPolyData *profile = vtkPolyData::New(); + for (i=0; iInsertPoint(j++,dCoords[i],dCoords[uiQtyCoords+i],dCoords[2*uiQtyCoords+i]);//0 + points->InsertPoint(j++,dCoords[i+1],dCoords[uiQtyCoords+i],dCoords[2*uiQtyCoords+i]);//1 + points->InsertPoint(j++,dCoords[i+1],dCoords[uiQtyCoords+i+1],dCoords[2*uiQtyCoords+i]);//2 + points->InsertPoint(j++,dCoords[i],dCoords[uiQtyCoords+i+1],dCoords[2*uiQtyCoords+i]);//3 + points->InsertPoint(j++,dCoords[i],dCoords[uiQtyCoords+i],dCoords[2*uiQtyCoords+i+1]);//4 + points->InsertPoint(j++,dCoords[i+1],dCoords[uiQtyCoords+i],dCoords[2*uiQtyCoords+i+1]);//5 + points->InsertPoint(j++,dCoords[i+1],dCoords[uiQtyCoords+i+1],dCoords[2*uiQtyCoords+i+1]);//6 + points->InsertPoint(j++,dCoords[i],dCoords[uiQtyCoords+i+1],dCoords[2*uiQtyCoords+i+1]);//7 + poly->InsertNextCell(4);poly->InsertCellPoint(0+i*4);poly->InsertCellPoint(1+i*4);poly->InsertCellPoint(2+i*4);poly->InsertCellPoint(3+i*4); + poly->InsertNextCell(4);poly->InsertCellPoint(4+i*4);poly->InsertCellPoint(5+i*4);poly->InsertCellPoint(6+i*4);poly->InsertCellPoint(7+i*4); + poly->InsertNextCell(4);poly->InsertCellPoint(0+i*4);poly->InsertCellPoint(1+i*4);poly->InsertCellPoint(5+i*4);poly->InsertCellPoint(4+i*4); + poly->InsertNextCell(4);poly->InsertCellPoint(1+i*4);poly->InsertCellPoint(2+i*4);poly->InsertCellPoint(6+i*4);poly->InsertCellPoint(5+i*4); + poly->InsertNextCell(4);poly->InsertCellPoint(2+i*4);poly->InsertCellPoint(3+i*4);poly->InsertCellPoint(7+i*4);poly->InsertCellPoint(6+i*4); + poly->InsertNextCell(4);poly->InsertCellPoint(3+i*4);poly->InsertCellPoint(0+i*4);poly->InsertCellPoint(4+i*4);poly->InsertCellPoint(7+i*4); + //for (h=j-8;hInsertTuple1(h,h%8); // not in use jet + //fprintf(stderr,"."); + } + profile->SetPoints(points); + profile->SetPolys(poly); + + AddPolyData(profile, dRGB, dOpacity, tf_matrix); + points->Delete(); + poly->Delete(); + profile->Delete(); +} + +void VTKPrimitives::AddClosedPoly(double *dCoords, unsigned int uiQtyCoords, double *dExtrusionVector, double *dRGB, double dOpacity, const double* tf_matrix) +{ //complete + unsigned int i=0; + vtkPoints *points = vtkPoints::New(); + vtkCellArray *poly = vtkCellArray::New(); + vtkPolyData *profile = vtkPolyData::New(); + vtkLinearExtrusionFilter *extrude = vtkLinearExtrusionFilter::New(); + for (i=0; iInsertPoint(i,dCoords[i],dCoords[uiQtyCoords+i],dCoords[2*uiQtyCoords+i]); + poly->InsertNextCell(uiQtyCoords+1); + for (i=0; iInsertCellPoint(i); + poly->InsertCellPoint(0); + profile->SetPoints(points); + profile->SetPolys(poly); + vtkTriangleFilter *tf = vtkTriangleFilter::New(); +#if VTK_MAJOR_VERSION>=6 + tf->SetInputData(profile); +#else + tf->SetInput(profile); +#endif + extrude->SetInputConnection(tf->GetOutputPort()); + extrude->SetExtrusionTypeToVectorExtrusion(); + extrude->SetVector(dExtrusionVector); + extrude->CappingOn(); + + AddPolyData(extrude->GetOutputPort(), dRGB, dOpacity, tf_matrix); + + points->Delete(); + poly->Delete(); + profile->Delete(); + tf->Delete(); + extrude->Delete(); +} + +void VTKPrimitives::AddLinePoly(const double *dCoords, unsigned int uiQtyCoords, unsigned int LineWidth, double *dRGB, double dOpacity, const double* tf_matrix) +{ //complete + unsigned int i=0; + vtkPoints *points = vtkPoints::New(); + vtkCellArray *poly = vtkCellArray::New(); + vtkPolyData *profile = vtkPolyData::New(); + for (i=0; iInsertPoint(i,dCoords[i],dCoords[uiQtyCoords+i],dCoords[2*uiQtyCoords+i]); + for (i=1; iInsertNextCell(2); + poly->InsertCellPoint(i-1); + poly->InsertCellPoint(i); + } + + profile->SetPoints(points); + profile->SetLines(poly); + + vtkActor* actor = AddPolyData(profile, dRGB, dOpacity, tf_matrix); + actor->GetProperty()->SetLineWidth(LineWidth); + + points->Delete(); + poly->Delete(); + profile->Delete(); +} + +void VTKPrimitives::AddTubePoly(const double *dCoords, unsigned int uiQtyCoords, double TubeRadius, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix) +{ //complete + unsigned int i=0; + vtkPoints *points = vtkPoints::New(); + vtkCellArray *poly = vtkCellArray::New(); + vtkPolyData *profile = vtkPolyData::New(); + for (i=0; iInsertPoint(i,dCoords[i],dCoords[uiQtyCoords+i],dCoords[2*uiQtyCoords+i]); + for (i=1; iInsertNextCell(2); + poly->InsertCellPoint(i-1); + poly->InsertCellPoint(i); + } + + profile->SetPoints(points); + profile->SetLines(poly); + + vtkTubeFilter* m_profileTubes = vtkTubeFilter::New(); + m_profileTubes->SetNumberOfSides(iResolution); +#if VTK_MAJOR_VERSION>=6 + m_profileTubes->SetInputData(profile); +#else + m_profileTubes->SetInput(profile); +#endif + m_profileTubes->SetRadius(TubeRadius); + + AddPolyData(m_profileTubes->GetOutputPort(), dRGB, dOpacity, tf_matrix); + + points->Delete(); + poly->Delete(); + profile->Delete(); + m_profileTubes->Delete(); +} + +void VTKPrimitives::AddCylinder2(const double *dAxisStart, const double* dAxisStop, float fRadius, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix) +{ + double direction[3] = {dAxisStop[0]-dAxisStart[0],dAxisStop[1]-dAxisStart[1],dAxisStop[2]-dAxisStart[2]}; + AddCylinder(dAxisStart,direction,fRadius,dRGB,dOpacity,iResolution,tf_matrix); +} + +void VTKPrimitives::AddCylinder(const double *dCenter, const double *dExtrusionVector, float fRadius, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix) +{ + double alpha=0,beta=0; + double length=sqrt( dExtrusionVector[0]*dExtrusionVector[0]+dExtrusionVector[1]*dExtrusionVector[1]+dExtrusionVector[2]*dExtrusionVector[2] ) ; + //if (length==0) { fprintf(stderr," Error Cylinder Extrusion Vector ist Zero.. Abort..."); exit(1); } + vtkCylinderSource *Source = vtkCylinderSource::New(); + vtkTransform *transform = vtkTransform::New(); + vtkTransformPolyDataFilter *transformFilter = vtkTransformPolyDataFilter::New(); + Source->SetResolution(iResolution); + Source->SetRadius(fRadius); + Source->SetHeight(length); + + alpha=VectorAngel(dExtrusionVector[0],sqrt(dExtrusionVector[1]*dExtrusionVector[1]+dExtrusionVector[2]*dExtrusionVector[2]),0,0,1,0); + beta=VectorAngel(0,dExtrusionVector[1],dExtrusionVector[2],0,1,0); + // cout << alpha << " " << beta << endl; //debuging + if (dExtrusionVector[0]>0) alpha=-alpha; + if (dExtrusionVector[2]<0) beta=-beta; + transform->Translate(dExtrusionVector[0]/2+dCenter[0],dExtrusionVector[1]/2+dCenter[1],dExtrusionVector[2]/2+dCenter[2]); + transform->RotateWXYZ(beta,1,0,0); + transform->RotateWXYZ(alpha,0,0,1); + + transform->PostMultiply(); + +#if VTK_MAJOR_VERSION>=6 + transformFilter->SetInputConnection(Source->GetOutputPort()); +#else + transformFilter->SetInput(Source->GetOutput()); +#endif + transformFilter->SetTransform(transform); + + AddPolyData(transformFilter->GetOutputPort(), dRGB, dOpacity, tf_matrix); + + Source->Delete(); + transform->Delete(); + transformFilter->Delete(); +} + +void VTKPrimitives::AddCylindricalShell(const double *dAxisStart, const double* dAxisStop, double r_i, double r_o, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix) +{ + const double dExtrusionVector[3] = {dAxisStop[0]-dAxisStart[0], dAxisStop[1]-dAxisStart[1], dAxisStop[2]-dAxisStart[2]}; + double length = sqrt( dExtrusionVector[0]*dExtrusionVector[0] + dExtrusionVector[1]*dExtrusionVector[1] + dExtrusionVector[2]*dExtrusionVector[2] ) ; + + // create a disk in xy plane + vtkDiskSource *diskSource = vtkDiskSource::New(); + diskSource->SetInnerRadius( r_i ); + diskSource->SetOuterRadius( r_o ); + diskSource->SetCircumferentialResolution(iResolution); + + // extrude in +z + vtkLinearExtrusionFilter *linearExtrusionFilter = vtkLinearExtrusionFilter::New(); +#if VTK_MAJOR_VERSION>=6 + linearExtrusionFilter->SetInputConnection( diskSource->GetOutputPort() ); +#else + linearExtrusionFilter->SetInput( diskSource->GetOutput() ); +#endif + linearExtrusionFilter->SetExtrusionTypeToNormalExtrusion(); + linearExtrusionFilter->SetVector(0,0,length); + + // create transform to correctly orient and move the cylinder shell + vtkTransform *transform = vtkTransform::New(); + transform->PostMultiply(); + double phi = atan2( dExtrusionVector[1], dExtrusionVector[0] ); + double theta = acos( dExtrusionVector[2] / length ); + transform->RotateY( theta / M_PI * 180 ); + transform->RotateZ( phi / M_PI * 180 ); + transform->Translate( dAxisStart ); + if (tf_matrix) + transform->Concatenate( tf_matrix ); + + vtkTransformPolyDataFilter *transformFilter = vtkTransformPolyDataFilter::New(); + transformFilter->SetInputConnection( linearExtrusionFilter->GetOutputPort() ); + transformFilter->SetTransform( transform ); + + vtkPolyDataMapper *mapper = vtkPolyDataMapper::New(); + mapper->SetInputConnection( transformFilter->GetOutputPort() ); + mapper->ScalarVisibilityOff(); + vtkActor *actor = vtkLODActor::New(); + actor->SetMapper( mapper ); + + m_PolyDataCollection->AddInputConnection( transformFilter->GetOutputPort()); + actor->GetProperty()->SetColor(dRGB); + actor->GetProperty()->SetOpacity(dOpacity); + + ActorColl->AddItem(actor); + ren->AddActor(actor); +} + +void VTKPrimitives::AddSphere(const double *dCenter, double fRadius, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix) +{//complete + vtkSphereSource *Source = vtkSphereSource::New(); + double center[3]={dCenter[0],dCenter[1],dCenter[2]}; + Source->SetCenter(center); + Source->SetRadius(fRadius); + Source->SetPhiResolution(iResolution); + Source->SetThetaResolution(iResolution); + + AddPolyData(Source->GetOutputPort(), dRGB, dOpacity, tf_matrix); + + Source->Delete(); +} + +void VTKPrimitives::AddSphericalShell(const double *dCenter, double r_i, double r_o, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix) +{//complete +#if (VTK_MAJOR_VERSION==5 && VTK_MINOR_VERSION>=10) || (VTK_MAJOR_VERSION>=6) + vtkSphereSource *Source_o = vtkSphereSource::New(); + double center[3]={dCenter[0],dCenter[1],dCenter[2]}; + Source_o->SetCenter(center); + Source_o->SetRadius(r_o); + Source_o->SetPhiResolution(iResolution); + Source_o->SetThetaResolution(iResolution); + + vtkSphereSource *Source_i = vtkSphereSource::New(); + Source_i->SetCenter(center); + Source_i->SetRadius(r_i); + Source_i->SetPhiResolution(iResolution); + Source_i->SetThetaResolution(iResolution); + + vtkBooleanOperationPolyDataFilter* boolFilter = vtkBooleanOperationPolyDataFilter::New(); + boolFilter->SetOperationToDifference(); + boolFilter->SetInputConnection(0, Source_o->GetOutputPort()); + boolFilter->SetInputConnection(1, Source_i->GetOutputPort()); + + //todo, we should remove the unnecessary scalar data produced by the filter... + AddPolyData(boolFilter->GetOutputPort(), dRGB, dOpacity, tf_matrix); + + boolFilter->Delete(); + Source_o->Delete(); + Source_i->Delete(); +#else + cerr << "VTKPrimitives::AddSphericalShell: Error, spherical shell not supported by this vkt version, you require vtk 5.10 or higher." << endl; +#endif +} + + +void VTKPrimitives::AddArrow(double *dStart, double *dEnd, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix) +{ + double alpha=0,beta=0; + double dvector[3]={dEnd[0]-dStart[0],dEnd[1]-dStart[1],dEnd[2]-dStart[2]}; + double length=sqrt( dvector[0]*dvector[0]+dvector[1]*dvector[1]+dvector[2]*dvector[2] ) ; + if (length==0) { fprintf(stderr," Error Arrow Length ist Zero.. Abort..."); exit(1); } + vtkArrowSource *Source = vtkArrowSource::New(); + vtkTransform *transform = vtkTransform::New(); + vtkTransformPolyDataFilter *transformFilter = vtkTransformPolyDataFilter::New(); + Source->SetTipResolution(iResolution); + Source->SetShaftResolution(iResolution); + Source->SetTipLength(0.15); + Source->SetTipRadius(0.03); + Source->SetShaftRadius(0.01); + + alpha=VectorAngel(dvector[0],sqrt(dvector[1]*dvector[1]+dvector[2]*dvector[2]),0,0,1,0); + beta=VectorAngel(0,dvector[1],dvector[2],0,1,0); + if (dvector[0]>0) alpha=-alpha; + if (dvector[2]<0) beta=-beta; + transform->RotateWXYZ(beta,1,0,0); + transform->RotateWXYZ(alpha,0,0,1); + transform->RotateWXYZ(90,0,0,1); + + transform->PostMultiply(); + +#if VTK_MAJOR_VERSION>=6 + transformFilter->SetInputConnection(Source->GetOutputPort()); +#else + transformFilter->SetInput(Source->GetOutput()); +#endif + transformFilter->SetTransform(transform); + + AddPolyData(transformFilter->GetOutputPort(), dRGB, dOpacity, tf_matrix); + + Source->Delete(); + transform->Delete(); + transformFilter->Delete(); +} + +void VTKPrimitives::AddLabel(char *cText, double *dCoords, double *dRGB, double dOpacity, double dscale, const double* tf_matrix) +{ + vtkVectorText *text = vtkVectorText::New(); + vtkPolyDataMapper *Mapper = vtkPolyDataMapper::New(); + vtkFollower *Actor = vtkFollower::New(); + text->SetText(cText); + + vtkTransformPolyDataFilter* filter = vtkTransformPolyDataFilter::New(); + vtkTransform* vtrans = vtkTransform::New(); +#if VTK_MAJOR_VERSION>=6 + filter->SetInputConnection(text->GetOutputPort()); +#else + filter->SetInput(text->GetOutput()); +#endif + + if (tf_matrix) + vtrans->SetMatrix(tf_matrix); + filter->SetTransform(vtrans); + + m_PolyDataCollection->AddInputConnection(filter->GetOutputPort()); + Mapper->SetInputConnection(filter->GetOutputPort()); + Actor->SetMapper(Mapper); + Actor->SetScale(dscale); + Actor->SetCamera(ren->GetActiveCamera()); + Actor->GetProperty()->SetColor(dRGB); + Actor->GetProperty()->SetOpacity(dOpacity); + Actor->SetPosition(dCoords); + + ren->AddActor(Actor); + ActorColl->AddItem(Actor); + + Mapper->Delete(); + text->Delete(); + filter->Delete(); + vtrans->Delete(); +} + +void VTKPrimitives::AddRotationalPoly(const double *dCoords, unsigned int uiQtyCoords, const double *fRotAxis, double StartStopAngle[2], double *dRGB, double dOpacity, int iResolution, const double* tf_matrix) +{ + unsigned int i=0; + double start[3]={0,0,0},vector[3]={0,0,0}; + + vtkPoints *points = vtkPoints::New(); + vtkCellArray *poly = vtkCellArray::New(); + vtkPolyData *profile = vtkPolyData::New(); + vtkRotationalExtrusionFilter *extrude = vtkRotationalExtrusionFilter::New(); + vtkTransform *transform = vtkTransform::New(); + vtkTransform *InvTransform = vtkTransform::New(); + vtkTransformPolyDataFilter *transformFilter = vtkTransformPolyDataFilter::New(); + vtkTransformPolyDataFilter *InvTransformFilter = vtkTransformPolyDataFilter::New(); + + vector[0]=fRotAxis[1]-fRotAxis[0]; + vector[1]=fRotAxis[3]-fRotAxis[2]; + vector[2]=fRotAxis[5]-fRotAxis[4]; + double vec_len = sqrt(vector[0]*vector[0]+vector[1]*vector[1]+vector[2]*vector[2]); + double vec_unit[3]={vector[0]/vec_len,vector[1]/vec_len,vector[2]/vec_len}; + start[0]=fRotAxis[0]; + start[1]=fRotAxis[2]; + start[2]=fRotAxis[4]; + + double d = sqrt(vec_unit[1]*vec_unit[1]+vec_unit[2]*vec_unit[2]); + double alpha = atan2(vec_unit[1],vec_unit[2])/acos(-1)*180; + double beta = atan2(-vec_unit[0],d)/acos(-1)*180; + + for (i=0; iInsertPoint(i,dCoords[i],dCoords[uiQtyCoords+i],dCoords[2*uiQtyCoords+i]); + poly->InsertNextCell(uiQtyCoords+1); + for (i=0; iInsertCellPoint(i); + poly->InsertCellPoint(0); + profile->SetPoints(points); + profile->SetPolys(poly); + vtkTriangleFilter *tf = vtkTriangleFilter::New(); +#if VTK_MAJOR_VERSION>=6 + tf->SetInputData(profile); +#else + tf->SetInput(profile); +#endif + + InvTransform->Translate(-start[0],-start[1],-start[2]); + InvTransform->RotateX(alpha); + InvTransform->RotateY(beta); + + InvTransformFilter->SetInputConnection(tf->GetOutputPort()); + InvTransformFilter->SetTransform(InvTransform); + + extrude->SetInputConnection(InvTransformFilter->GetOutputPort()); + extrude->SetResolution(iResolution); + extrude->SetAngle(StartStopAngle[1]-StartStopAngle[0]); + + transform->RotateZ(-StartStopAngle[0]); + + transform->Translate(-start[0],-start[1],-start[2]); + transform->RotateX(alpha); + transform->RotateY(beta); + transform->Inverse(); + + transform->PostMultiply(); + + transformFilter->SetInputConnection(extrude->GetOutputPort()); + transformFilter->SetTransform(transform); + + AddPolyData(transformFilter->GetOutputPort(), dRGB, dOpacity, tf_matrix); + + points->Delete(); + poly->Delete(); + profile->Delete(); + extrude->Delete(); + transform->Delete(); + transformFilter->Delete(); + InvTransform->Delete(); + InvTransformFilter->Delete(); +} + +void VTKPrimitives::AddRotationalSolid(const double *dPoint, double fRadius, const double *fRotAxis, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix) +{ + vtkPoints *points = vtkPoints::New(); + vtkCellArray *poly = vtkCellArray::New(); + vtkPolyData *profile = vtkPolyData::New(); + vtkRotationalExtrusionFilter *extrude = vtkRotationalExtrusionFilter::New(); + vtkTransform *transform = vtkTransform::New(); + vtkTransformPolyDataFilter *transformFilter = vtkTransformPolyDataFilter::New(); + + double vector[3]={0,0,0},start[3]={0,0,0},Footpoint[3]={0,0,0}; + vector[0]=fRotAxis[1]-fRotAxis[0]; + vector[1]=fRotAxis[3]-fRotAxis[2]; + vector[2]=fRotAxis[5]-fRotAxis[4]; + start[0]=fRotAxis[0]; + start[1]=fRotAxis[2]; + start[2]=fRotAxis[4]; + double dSolidRadius=DistancePointLine(dPoint,start,vector,Footpoint); + + poly->InsertNextCell(iResolution+1); + for (int i=0; iInsertPoint(i,dSolidRadius+fRadius*cos(i*2*PI/iResolution),0,fRadius*sin(i*2*PI/iResolution)); + poly->InsertCellPoint(i); + } + poly->InsertCellPoint(0); + profile->SetPoints(points); + profile->SetLines(poly); + +#if VTK_MAJOR_VERSION>=6 + extrude->SetInputData(profile); +#else + extrude->SetInput(profile); +#endif + extrude->SetResolution(iResolution); + extrude->SetAngle(360.0); + + double alpha=VectorAngel(vector[0],sqrt(vector[1]*vector[1]+vector[2]*vector[2]),0,0,1,0); + double beta=VectorAngel(0,vector[1],vector[2],0,1,0); + if (vector[0]>0) alpha=-alpha; + if (vector[2]<0) beta=-beta; + transform->Translate(Footpoint); + transform->RotateWXYZ(beta,1,0,0); + transform->RotateWXYZ(alpha,0,0,1); + transform->RotateWXYZ(-90,1,0,0); + + transform->PostMultiply(); + + transformFilter->SetInputConnection(extrude->GetOutputPort()); + transformFilter->SetTransform(transform); + + AddPolyData(transformFilter->GetOutputPort(), dRGB, dOpacity, tf_matrix); + + points->Delete(); + poly->Delete(); + profile->Delete(); + extrude->Delete(); + transform->Delete(); + transformFilter->Delete(); +} + + +void VTKPrimitives::AddSurface(double *dCoords, unsigned int uiQtyCoords, double *dRGB, double dOpacity, const double* tf_matrix) +{//complete + unsigned int i=0; + vtkPoints *points = vtkPoints::New(); + vtkCellArray *poly = vtkCellArray::New(); + vtkPolyData *profile = vtkPolyData::New(); + for (i=0; iInsertPoint(i,dCoords[3*i],dCoords[3*i+1],dCoords[3*i+2]); + for (i=0; iInsertNextCell(3); + poly->InsertCellPoint(i++); + poly->InsertCellPoint(i++); + poly->InsertCellPoint(i++); + } + profile->SetPoints(points); + profile->SetPolys(poly); + + AddPolyData(profile, dRGB, dOpacity, tf_matrix); + points->Delete(); + poly->Delete(); + profile->Delete(); +} + +void VTKPrimitives::AddSTLObject(const char *Filename, double *dCenter, double *dRGB, double dOpacity, const double* tf_matrix) +{ //complete?? + vtkSTLReader *part = vtkSTLReader::New(); + part->SetFileName(Filename); + vtkPolyDataMapper *partMapper = vtkPolyDataMapper::New(); + + vtkActor* actor = AddPolyData(part->GetOutputPort(), dRGB, dOpacity, tf_matrix); + actor->SetPosition(dCenter); + + part->Delete(); + partMapper->Delete(); +} + +vtkActor* VTKPrimitives::AddPolyData(vtkPolyData* polydata, double *dRGB, double dOpacity, const double* tf_matrix) +{ + vtkTransformPolyDataFilter* filter = vtkTransformPolyDataFilter::New(); + vtkTransform* vtrans = vtkTransform::New(); +#if VTK_MAJOR_VERSION>=6 + filter->SetInputData(polydata); +#else + filter->SetInput(polydata); +#endif + if (tf_matrix) + vtrans->SetMatrix(tf_matrix); + filter->SetTransform(vtrans); + +#if VTK_MAJOR_VERSION>=6 + m_PolyDataCollection->AddInputConnection(filter->GetOutputPort()); +#else + m_PolyDataCollection->AddInput(filter->GetOutput()); +#endif + + vtkPolyDataMapper *Mapper = vtkPolyDataMapper::New(); + Mapper->SetInputConnection(filter->GetOutputPort()); + Mapper->ScalarVisibilityOff(); + vtkLODActor *Actor = vtkLODActor::New(); + Actor->SetMapper(Mapper); + Actor->GetProperty()->RemoveAllTextures(); + Actor->GetProperty()->SetColor(dRGB); + Actor->GetProperty()->SetOpacity(dOpacity); + + ActorColl->AddItem(Actor); + ren->AddActor(Actor); + + filter->Delete(); + vtrans->Delete(); + Mapper->Delete(); + + return Actor; +} + +vtkActor* VTKPrimitives::AddPolyData(vtkAlgorithmOutput* polydata_port, double *dRGB, double dOpacity, const double* tf_matrix) +{ + vtkTransformPolyDataFilter* filter = vtkTransformPolyDataFilter::New(); + vtkTransform* vtrans = vtkTransform::New(); + filter->SetInputConnection(polydata_port); + if (tf_matrix) + vtrans->SetMatrix(tf_matrix); + filter->SetTransform(vtrans); + +#if VTK_MAJOR_VERSION>=6 + m_PolyDataCollection->AddInputConnection(filter->GetOutputPort()); +#else + m_PolyDataCollection->AddInput(filter->GetOutput()); +#endif + + vtkPolyDataMapper *Mapper = vtkPolyDataMapper::New(); + Mapper->SetInputConnection(filter->GetOutputPort()); + Mapper->ScalarVisibilityOff(); + vtkLODActor *Actor = vtkLODActor::New(); + Actor->SetMapper(Mapper); + Actor->GetProperty()->RemoveAllTextures(); + Actor->GetProperty()->SetColor(dRGB); + Actor->GetProperty()->SetOpacity(dOpacity); + + ActorColl->AddItem(Actor); + ren->AddActor(Actor); + + filter->Delete(); + vtrans->Delete(); + Mapper->Delete(); + + return Actor; +} + +void VTKPrimitives::SetOpacity2All(double opacity) +{ + ActorColl->InitTraversal(); + vtkActor* act=NULL; + while ((act=ActorColl->GetNextActor())) + { + act->GetProperty()->SetOpacity(opacity); + } +} + +void VTKPrimitives::WritePolyData2File(const char* filename, double scale) +{ + cout << "VTKPrimitives::WritePolyData2File: Dump to vtk file: " << filename << " -- Using scale: " << scale << endl; + vtkXMLPolyDataWriter* writer = vtkXMLPolyDataWriter::New(); + writer->SetFileName(filename); + + if (scale==1.0) + { +#if VTK_MAJOR_VERSION>=6 + writer->SetInputConnection(m_PolyDataCollection->GetOutputPort()); +#else + writer->SetInput(m_PolyDataCollection->GetOutput()); +#endif + writer->Write(); + } + else + { + vtkTransform *transform = vtkTransform::New(); + vtkTransformPolyDataFilter *transformFilter = vtkTransformPolyDataFilter::New(); + +#if VTK_MAJOR_VERSION>=6 + transformFilter->SetInputConnection(m_PolyDataCollection->GetOutputPort()); +#else + transformFilter->SetInput(m_PolyDataCollection->GetOutput()); +#endif + transform->Scale(scale,scale,scale); + transformFilter->SetTransform(transform); + +#if VTK_MAJOR_VERSION>=6 + writer->SetInputConnection(transformFilter->GetOutputPort()); +#else + writer->SetInput(transformFilter->GetOutput()); +#endif + writer->Write(); + + transform->Delete(); + transformFilter->Delete(); + } + + writer->Delete(); +} + +void VTKPrimitives::WritePolyData2STL(const char* filename, double scale) +{ + cout << "VTKPrimitives::WritePolyData2STL: Dump to stl file: " << filename << " -- Using scale: " << scale << endl; + + vtkTriangleFilter* filter = vtkTriangleFilter::New(); + +#if VTK_MAJOR_VERSION>=6 + filter->SetInputConnection(m_PolyDataCollection->GetOutputPort()); +#else + filter->SetInput(m_PolyDataCollection->GetOutput()); +#endif + vtkSTLWriter* writer = vtkSTLWriter::New(); + writer->SetFileName(filename); + + if (scale==1.0) + { + writer->SetInputConnection(filter->GetOutputPort()); + writer->Write(); + } + else + { + vtkTransform *transform = vtkTransform::New(); + vtkTransformPolyDataFilter *transformFilter = vtkTransformPolyDataFilter::New(); + + transformFilter->SetInputConnection(filter->GetOutputPort()); + transform->Scale(scale,scale,scale); + transformFilter->SetTransform(transform); + +#if VTK_MAJOR_VERSION>=6 + writer->SetInputConnection(transformFilter->GetOutputPort()); +#else + writer->SetInput(transformFilter->GetOutput()); +#endif + writer->Write(); + + transform->Delete(); + transformFilter->Delete(); + } + + writer->Delete(); +} + +void VTKPrimitives::WritePolyData2PLY(const char* filename, double scale) +{ + cout << "VTKPrimitives::WritePolyData2PLY: Dump to ply file: " << filename << " -- Using scale: " << scale << endl; + + vtkTriangleFilter* filter = vtkTriangleFilter::New(); + +#if VTK_MAJOR_VERSION>=6 + filter->SetInputConnection(m_PolyDataCollection->GetOutputPort()); +#else + filter->SetInput(m_PolyDataCollection->GetOutput()); +#endif + + vtkPLYWriter* writer = vtkPLYWriter::New(); + writer->SetFileName(filename); + + if (scale==1.0) + { + writer->SetInputConnection(filter->GetOutputPort()); + writer->Write(); + } + else + { + vtkTransform *transform = vtkTransform::New(); + vtkTransformPolyDataFilter *transformFilter = vtkTransformPolyDataFilter::New(); + + transformFilter->SetInputConnection(filter->GetOutputPort()); + transform->Scale(scale,scale,scale); + transformFilter->SetTransform(transform); + +#if VTK_MAJOR_VERSION>=6 + writer->SetInputConnection(transformFilter->GetOutputPort()); +#else + writer->SetInput(transformFilter->GetOutput()); +#endif + writer->Write(); + + transform->Delete(); + transformFilter->Delete(); + } + + writer->Delete(); +} + + +double VTKPrimitives::VectorAngel(double dV1_1, double dV1_2, double dV1_3, double dV2_1, double dV2_2, double dV2_3) +{ + double angel=0,dV1L,dV2L; + double scalarP; + dV1L=sqrt(dV1_1*dV1_1+dV1_2*dV1_2+dV1_3*dV1_3); + dV2L=sqrt(dV2_1*dV2_1+dV2_2*dV2_2+dV2_3*dV2_3); + scalarP=dV1_1*dV2_1+dV1_2*dV2_2+dV1_3*dV2_3; + if ((dV1L*dV2L)==0) return 0; + angel=scalarP/(dV1L*dV2L); + if (angel>1) angel=0.0; + else if (angel<-1) angel=180.0; + else angel=acos(angel)*180/PI; + return angel; +} + +double VTKPrimitives::DistancePointLine(const double *dpoint, const double *dstart, const double *dvector, double *dFootpoint) +{ + double dpos=0; + dpos= ( (dpoint[0]-dstart[0])*dvector[0]+(dpoint[1]-dstart[1])*dvector[1]+(dpoint[2]-dstart[2])*dvector[2] ) /(dvector[0]*dvector[0]+dvector[1]*dvector[1]+dvector[2]*dvector[2]); + for (int i=0; i<3; i++) dFootpoint[i]=dstart[i]+dpos*dvector[i]; + return sqrt( (dpoint[0]-dFootpoint[0])*(dpoint[0]-dFootpoint[0]) + (dpoint[1]-dFootpoint[1])*(dpoint[1]-dFootpoint[1]) + (dpoint[2]-dFootpoint[2])*(dpoint[2]-dFootpoint[2]) ); +} + +double VTKPrimitives::DistancePointPoint(const double *dpoint1, const double *dpoint2) +{ + return sqrt( (dpoint1[0]-dpoint2[0])*(dpoint1[0]-dpoint2[0]) + (dpoint1[1]-dpoint2[1])*(dpoint1[1]-dpoint2[1]) + (dpoint1[2]-dpoint2[2])*(dpoint1[2]-dpoint2[2]) ); +} + +double* VTKPrimitives::TransformCylindricalCoords(const double* in, double* out, unsigned int nrPoints) +{ + unsigned int i,j,k; + for (unsigned int n=0;n. +*/ + +/*! +\class VTKPrimitives +\author Thorsten Liebig +\version 2 +\date 7.8.2007 +\bug Methode AddRotationalPoly produces false 3D alignment +\todo Methode AddDisc data structure has to be revised +*/ + +#ifndef _VTKPRIMITIVES_H +#define _VTKPRIMITIVES_H + +class vtkRenderer; +class vtkPolyData; +class vtkActorCollection; +class vtkAppendPolyData; +class vtkActor; +class vtkAlgorithmOutput; + +#define PI 3.141592654 + +class VTKPrimitives +{ +public: + /// Constructor needs a vtkRenderer for adding primitives + /*! \param *Renderer necessary for construction is a valid vtkRenderer \sa VTKVisualization */ + VTKPrimitives(vtkRenderer *Renderer); + /// Deconstructor + ~VTKPrimitives(); + /// Add a Cube to scene + /*! \param *dCoords Set points as room diagonal (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax) \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) */ + void AddCube(double *dCoords, double *dRGB, double dOpacity, const double* tf_matrix=0); //complete + void AddCube(const double *dStart, const double *dStop, double *dRGB, double dOpacity, const double* tf_matrix=0); //complete + /// Add a Cube in cylindrical coordinates to scene + /*! \param *dCoords Set points as room diagonal (Rmin,Rmax,Amin,Amax,Zmin,Zmax) \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) */ + void AddCylindricalCube(double *dCoords, double *dRGB, double dOpacity, const double* tf_matrix=0); + void AddCylindricalCube(const double *dStart, const double *dStop, double *dRGB, double dOpacity, const double* tf_matrix=0); + /// Add a Plane to scene + /*! \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) */ + void AddPlane(double *dOrigin, double* dP1, double* dP2, double *dRGB, double dOpacity, const double* tf_matrix=0); //complete + /// Add a discrete object (many cubes) to scene + /*! \param *dCoords Set Points as X1,X2,...,Xn,Y1,Y2,...,Yn,Z1,Z2,...Zn. \param uiQtyCoords Set quantity of Points X,Y,Z. \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) */ + void AddDisc(double *dCoords, unsigned int uiQtyCoords, double *dRGB, double dOpacity, const double* tf_matrix=0); + /// Add a closed polygon to scene + /*! \param *dCoords Set Points as X1,X2,...,Xn,Y1,Y2,...,Yn,Z1,Z2,...Zn for polygon. \param uiQtyCoords Set Quantity of Points X,Y,Z \param dExtrusionVector Give extrusion vector (X,Y,Z) \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness)*/ + void AddClosedPoly(double *dCoords, unsigned int uiQtyCoords, double *dExtrusionVector, double *dRGB, double dOpacity, const double* tf_matrix=0);//complete + /// Add a linear polygon to scene + /*! \param *dCoords Set Points as X1,X2,...,Xn,Y1,Y2,...,Yn,Z1,Z2,...Zn for polygon. \param uiQtyCoords Set Quantity of Points X,Y,Z \param LineWidth Set line width \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness)*/ + void AddLinePoly(const double *dCoords, unsigned int uiQtyCoords,unsigned int LineWidth, double *dRGB, double dOpacity, const double* tf_matrix=0);//complete + /// Add a linear polygon as tubes to scene + /*! \param *dCoords Set Points as X1,X2,...,Xn,Y1,Y2,...,Yn,Z1,Z2,...Zn for polygon. \param uiQtyCoords Set Quantity of Points X,Y,Z \param TubeRadius Set tube radius \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness)*/ + void AddTubePoly(const double *dCoords, unsigned int uiQtyCoords, double TubeRadius, double *dRGB, double dOpacity, int iResolution=8, const double* tf_matrix=0);//complete + /// Add a cylinder to scene + /*! \param *dCenterAxis Set Base Point in 3D space \param *dExtrusionVector Set height (absolute value) and direction \param fRadius Set Radius \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) \param iResolution Set resolution of discretisation*/ + void AddCylinder(const double *dCenterAxis, const double *dExtrusionVector, float fRadius, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix=0); //complete + /*! \param *dAxisStart Cylinder axis start point \param *dAxisStop Cylinder axis end point \param fRadius Set Radius \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) \param iResolution Set resolution of discretisation*/ + void AddCylinder2(const double *dAxisStart, const double* dAxisStop, float fRadius, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix=0); //complete + /*! \brief Add a cylindrical shell to the scene. \param *dAxisStart Cylinder axis start point \param *dAxisStop Cylinder axis end point \param r_i Set inner radius \param r_o Set outer radius \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) \param iResolution Set resolution of discretisation*/ + void AddCylindricalShell(const double *dAxisStart, const double* dAxisStop, double r_i, double r_o, double *dRGB, double dOpacity, int iResolution, const double *tf_matrix=0); + /// Add a Sphere to scene + /*! \param *dCenter Set Center Point in 3D space \param fRadius Set Radius \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) \param iResolution Set resolution of discretisation*/ + void AddSphere(const double *dCenter, double fRadius, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix=0); //complete + /// Add a Spherical shell to scene + /*! \param *dCenter Set Center Point in 3D space \param r_i Set inner radius \param r_o Set outer radius \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) \param iResolution Set resolution of discretisation*/ + void AddSphericalShell(const double *dCenter, double r_i, double r_o, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix=0); //complete + /// Add an arrow to scene + /*! \param *dStart Set start point \param *dEnd Set end point \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) \param iResolution Set resolution of discretisation*/ + void AddArrow(double *dStart, double *dEnd, double *dRGB, double dOpacity, int iResolution=6, const double* tf_matrix=0); + /// Add a text-label to scene + /*! \param *cText Set text for the label \param *dCoords Set point of label origin \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) \param dscale Scale the size of the label*/ + void AddLabel(char *cText, double *dCoords, double *dRGB, double dOpacity, double dscale=1.0, const double* tf_matrix=0); + /// Add a rotated polygon to scene + /*! \param *dCoords Set Points as X1,X2,...,Xn,Y1,Y2,...,Yn,Z1,Z2,...Zn for polygon. \param uiQtyCoords Set Quantity of Points X,Y,Z \param *fRotAxis Set rotation axis (X1,X2,Y1,Y2,Z1,Z2) \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) \param iResolution Set resolution of discretisation*/ + void AddRotationalPoly(const double *dCoords, unsigned int uiQtyCoords, const double *fRotAxis, double StartStopAngle[2], double *dRGB, double dOpacity, int iResolution, const double* tf_matrix=0);//complete + /// Add a rotated circle (torus) to scene + /*! \param dPoint Set point in 3D space \param fRadius Set radius of the torus \param *fRotAxis Set rotation axis (X1,X2,Y1,Y2,Z1,Z2) \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness) \param iResolution Set resolution of discretisation*/ + void AddRotationalSolid(const double *dPoint, double fRadius, const double *fRotAxis, double *dRGB, double dOpacity, int iResolution, const double* tf_matrix=0); //complete + /// Add a surface (triangles) to scene + /*! \param *dCoords Set Points as X1,X2,...,Xn,Y1,Y2,...,Yn,Z1,Z2,...Zn for triangles of surface. \param uiQtyCoords Set Quantity of Points X,Y,Z \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness)*/ + void AddSurface(double *dCoords, unsigned int uiQtyCoords, double *dRGB, double dOpacity, const double* tf_matrix=0);//complete + /// Add a STL-object to scene + /*! \param *Filename Set filename of STL object \param *dCenter Set point of origin for STL object \param *dRGB Set RGB Colors (range 0 to 1 for red, green, blue) \param dOpacity Set opacity (0 complete transparency to 1 complete opaqueness)*/ + void AddSTLObject(const char *Filename, double *dCenter, double *dRGB, double dOpacity, const double* tf_matrix=0);//complete + + //! Add the given polydata to the scene + vtkActor* AddPolyData(vtkAlgorithmOutput* polydata_port, double *dRGB, double dOpacity, const double* tf_matrix=0); + //! Add the given polydata to the scene + vtkActor* AddPolyData(vtkPolyData* polydata, double *dRGB, double dOpacity, const double* tf_matrix=0); + + void SetOpacity2All(double opacity); + + //! Write the collected poly-data into a vtk xml file (should be a *.vtp) + void WritePolyData2File(const char* filename, double scale=1.0); + + //! Write the collected poly-data into a stl file (should be a *.stl) + void WritePolyData2STL(const char* filename, double scale=1.0); + + //! Write the collected poly-data into a ply file (should be a *.ply) + void WritePolyData2PLY(const char* filename, double scale=1.0); + +protected: + /// unusable constructor, only for inheritance + VTKPrimitives(); + /// vtkRenderer, has to be set by constructor + vtkRenderer *ren; + /// Collection of all Actors generated in this class so far + vtkActorCollection *ActorColl; + /// Calculate angle between 2 vectors + double VectorAngel(double dV1_1, double dV1_2, double dV1_3, double dV2_1, double dV2_2, double dV2_3); + /// Calculate distance between a point and an axis + /*! \param *dpoint Set point \param *dstart Set footpoint of axis \param *dvector Set direction of axis \param *dFootpoint Returns the point on axis, that is nearest to the input point \return Methode returns distance */ + double DistancePointLine(const double *dpoint, const double *dstart, const double *dvector, double *dFootpoint); + /// Calculate distance between one point and another + /*! \param *dpoint1 Set first point \param *dpoint2 Set second point \return Methode returns distance */ + double DistancePointPoint(const double *dpoint1, const double *dpoint2); + + //! A Collection of all incoming poly-data + vtkAppendPolyData* m_PolyDataCollection; + + double m_ArcDelta; + + //! This internal methode will transform cylindrical coords into cartesian coords used by vtk. + double* TransformCylindricalCoords(const double* in, double* out, unsigned int nrPoints=1); +}; + +#endif diff --git a/QCSXCAD/cmake/Modules/FindTinyXML.cmake b/QCSXCAD/cmake/Modules/FindTinyXML.cmake new file mode 100644 index 0000000..aabb323 --- /dev/null +++ b/QCSXCAD/cmake/Modules/FindTinyXML.cmake @@ -0,0 +1,74 @@ +################################################################################################## +# +# CMake script for finding TinyXML. +# +# Input variables: +# +# - TinyXML_ROOT_DIR (optional): When specified, header files and libraries will be searched for in +# ${TinyXML_ROOT_DIR}/include +# ${TinyXML_ROOT_DIR}/libs +# respectively, and the default CMake search order will be ignored. When unspecified, the default +# CMake search order is used. +# This variable can be specified either as a CMake or environment variable. If both are set, +# preference is given to the CMake variable. +# Use this variable for finding packages installed in a nonstandard location, or for enforcing +# that one of multiple package installations is picked up. +# +# +# Cache variables (not intended to be used in CMakeLists.txt files) +# +# - TinyXML_INCLUDE_DIR: Absolute path to package headers. +# - TinyXML_LIBRARY: Absolute path to library. +# +# +# Output variables: +# +# - TinyXML_FOUND: Boolean that indicates if the package was found +# - TinyXML_INCLUDE_DIRS: Paths to the necessary header files +# - TinyXML_LIBRARIES: Package libraries +# +# +# Example usage: +# +# find_package(TinyXML) +# if(NOT TinyXML_FOUND) +# # Error handling +# endif() +# ... +# include_directories(${TinyXML_INCLUDE_DIRS} ...) +# ... +# target_link_libraries(my_target ${TinyXML_LIBRARIES}) +# +################################################################################################## + +# Get package location hint from environment variable (if any) +if(NOT TinyXML_ROOT_DIR AND DEFINED ENV{TinyXML_ROOT_DIR}) + set(TinyXML_ROOT_DIR "$ENV{TinyXML_ROOT_DIR}" CACHE PATH + "TinyXML base directory location (optional, used for nonstandard installation paths)") +endif() + +# Search path for nonstandard package locations +if(TinyXML_ROOT_DIR) + set(TinyXML_INCLUDE_PATH PATHS "${TinyXML_ROOT_DIR}/include" NO_DEFAULT_PATH) + set(TinyXML_LIBRARY_PATH PATHS "${TinyXML_ROOT_DIR}/lib" NO_DEFAULT_PATH) +endif() + +# Find headers and libraries +find_path(TinyXML_INCLUDE_DIR NAMES tinyxml.h PATH_SUFFIXES "tinyxml" ${TinyXML_INCLUDE_PATH}) +find_library(TinyXML_LIBRARY NAMES tinyxml PATH_SUFFIXES "tinyxml" ${TinyXML_LIBRARY_PATH}) + +mark_as_advanced(TinyXML_INCLUDE_DIR + TinyXML_LIBRARY) + +# Output variables generation +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(TinyXML DEFAULT_MSG TinyXML_LIBRARY + TinyXML_INCLUDE_DIR) + +set(TinyXML_FOUND ${TINYXML_FOUND}) # Enforce case-correctness: Set appropriately cased variable... +unset(TINYXML_FOUND) # ...and unset uppercase variable generated by find_package_handle_standard_args + +if(TinyXML_FOUND) + set(TinyXML_INCLUDE_DIRS ${TinyXML_INCLUDE_DIR}) + set(TinyXML_LIBRARIES ${TinyXML_LIBRARY}) +endif() diff --git a/QCSXCAD/export_pov.cpp b/QCSXCAD/export_pov.cpp new file mode 100644 index 0000000..07f6fb5 --- /dev/null +++ b/QCSXCAD/export_pov.cpp @@ -0,0 +1,267 @@ +/* +* Copyright (C) 2010 Sebastian Held (sebastian.held@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 . +*/ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "CSPrimBox.h" +#include "CSPrimCylinder.h" +#include "CSPrimPolygon.h" +#include "CSPrimCurve.h" +#include "CSPrimWire.h" + +#include "QVTKStructure.h" +#include "QCSXCAD.h" +#include "export_pov.h" + +export_pov::export_pov( QCSXCAD *CSX ) : m_CSX(CSX) +{ + m_epsilon = 1; // FIXME this should be small compared to any other linear dimension of any object in the scene + +} + +void export_pov::save( QString filename ) +{ + QFile file( filename ); + if (!file.open( QFile::WriteOnly )) { + QMessageBox::warning( m_CSX, QObject::tr("save failed"), QObject::tr("Cannot save to the file %1").arg(filename), QMessageBox::Ok ); + return; + } + QTextStream stream(&file); + stream.setCodec( "UTF-8" ); + + stream << "// povray-file exported by QCSXCAD" << endl; + stream << "// render with:" << endl; + stream << "// povray -W640 -H480 +A " << QFileInfo(filename).fileName() << endl; + stream << endl; + stream << "#declare TRANSPARENT = off; // if on, also use the \"+ua\" command line flag" << endl; + stream << endl; + stream << "#include \"colors.inc\"" << endl; + stream << "#include \"metals.inc\"" << endl; + stream << "#include \"textures.inc\"" << endl; + stream << "#include \"transforms.inc\"" << endl; + stream << "background { color rgb<1.000000,1.000000,1.000000> #if(TRANSPARENT) transmit 1.0 #end }" << endl; + + // export material + std::vector properties = m_CSX->GetPropertyByType( CSProperties::MATERIAL ); + export_properties( stream, properties, "pigment { color rgbt <0.000, 0.533, 0.800,0.0> } finish { diffuse 0.6 }" ); + + // export metal + properties = m_CSX->GetPropertyByType( CSProperties::METAL ); + export_properties( stream, properties, "texture { Copper_Metal }" ); + + // create camera + stream << get_camera() << endl; + + // create light + stream << get_light() << endl; + + stream.flush(); + file.close(); +} + +void export_pov::export_properties( QTextStream &stream, std::vector properties, QString default_obj_modifier ) +{ + foreach( CSProperties* prop, properties ) + { + int size = prop->GetQtyPrimitives(); + for( int i=0; iGetPrimitive(i); + if (prim->GetType() == CSPrimitives::BOX) + { + CSPrimBox *box = prim->ToBox(); + double start[] = {box->GetCoord(0),box->GetCoord(2),box->GetCoord(4)}; + double stop[] = {box->GetCoord(1),box->GetCoord(3),box->GetCoord(5)}; + export_box( stream, start, stop, default_obj_modifier ); + } + else if (prim->GetType() == CSPrimitives::POLYGON) + { + CSPrimPolygon *polygon = prim->ToPolygon(); + size_t count = -1; + double *array = 0; + array = polygon->GetAllCoords( count, array ); + int normDir = polygon->GetNormDir(); + double elevation = polygon->GetElevation(); + export_polygon( stream, count, array, elevation, normDir, default_obj_modifier ); + } + else if (prim->GetType() == CSPrimitives::CYLINDER) + { + CSPrimCylinder *primitive = prim->ToCylinder(); + double start[] = {primitive->GetCoord(0),primitive->GetCoord(2),primitive->GetCoord(4)}; + double stop[] = {primitive->GetCoord(1),primitive->GetCoord(3),primitive->GetCoord(5)}; + double radius = primitive->GetRadius(); + export_cylinder( stream, start, stop, radius, default_obj_modifier ); + } + else if (prim->GetType() == CSPrimitives::WIRE) + { + CSPrimWire *primitive = prim->ToWire(); + double radius = primitive->GetWireRadius(); + size_t count = primitive->GetNumberOfPoints(); + double *array = new double[count*3]; + for (unsigned int i=0; iGetPoint(i,array+i*3, CARTESIAN); + export_wire( stream, count, array, radius, default_obj_modifier ); + delete[] array; + } + else if (prim->GetType() == CSPrimitives::CURVE) + { + CSPrimCurve *primitive = prim->ToCurve(); + double radius = m_epsilon; + size_t count = primitive->GetNumberOfPoints(); + double *array = new double[count*3]; + for (unsigned int i=0; iGetPoint(i,array+i*3, CARTESIAN); + export_wire( stream, count, array, radius, default_obj_modifier ); + delete[] array; + } + } + } +} + +void export_pov::export_box( QTextStream &stream, double start[3], double stop[3], QString object_modifier ) +{ + for (int i=0; i<3; i++) + if (start[i] == stop[i]) { + // 2D box + // povray supports 2D polygons, but has no priority concept, therefore we use the box primitive + start[i] -= m_epsilon; + stop[i] += m_epsilon; + } + QString box = "box { %1, %2 %3 }"; + box = box.arg(pov_vect(start),pov_vect(stop),object_modifier); + stream << box << endl; +} + +void export_pov::export_polygon( QTextStream &stream, size_t count, double *array, double elevation, int normDir, QString object_modifier ) +{ + UNUSED(normDir); + Q_ASSERT((count%2)==0); + + count = count / 2; // now count is the number of 2D-vectors + if (count < 2) + return; + + elevation = -elevation; + //NormDir = [CSX_polygon.NormDir.ATTRIBUTE.X CSX_polygon.NormDir.ATTRIBUTE.Y CSX_polygon.NormDir.ATTRIBUTE.Z]; + QString str = "prism { linear_spline linear_sweep %1, %2, %3"; + str = str.arg(elevation - m_epsilon).arg(elevation + m_epsilon).arg(count+1); + for (unsigned int a=0; a }"; + + stream << str << endl; +} + +void export_pov::export_cylinder( QTextStream &stream, double start[3], double stop[3], double radius, QString object_modifier ) +{ + QString str = "cylinder { %1, %2, %3 %4 }"; + str = str.arg(pov_vect(start)).arg(pov_vect(stop)).arg(radius).arg(object_modifier); + stream << str << endl; +} + +void export_pov::export_wire( QTextStream &stream, size_t count, double *array, double radius, QString object_modifier ) +{ + QString str = "sphere_sweep { linear_spline, " + QString::number(count); + for (unsigned int a=0; aStructureVTK->GetVTKWidget()))->GetRenderWindow()->GetRenderers(); + vtkRenderer *r = collection->GetFirstRenderer(); + if (!r) + return QString(); + vtkCamera *c = r->GetActiveCamera(); + if (!c) + return QString(); + + double *pos = c->GetPosition(); +// cout << "Camera position: " << pos[0] << ", " << pos[1] << ", " << pos[2] << endl; + double *focalpos = c->GetFocalPoint(); +// cout << "Camera focal point: " << focalpos[0] << ", " << focalpos[1] << ", " << focalpos[2] << endl; +// double distance = c->GetDistance(); +// cout << "Camera distance (position to focal point): " << distance << endl; +// double roll = c->GetRoll(); +// cout << "Camera roll angle (about direction of projection): " << roll << "°" << endl; + double angle = c->GetViewAngle(); +// cout << "Camera view angle: " << angle << "°" << endl; + double *up = c->GetViewUp(); +// cout << "Camera up vector: " << up[0] << ", " << up[1] << ", " << up[2] << endl; + + QString camera_str; + camera_str = "camera { perspective location %1 look_at %2 sky %3 right -1.33*x angle %4 }"; + camera_str = camera_str.arg(pov_vect(pos),pov_vect(focalpos),pov_vect(up)).arg(angle); + + return camera_str; +} + +QString export_pov::get_light() +{ + vtkRendererCollection* collection = ((QVTKWidget*)(m_CSX->StructureVTK->GetVTKWidget()))->GetRenderWindow()->GetRenderers(); + vtkRenderer *r = collection->GetFirstRenderer(); + if (!r) + return QString(); + vtkCamera *c = r->GetActiveCamera(); + if (!c) + return QString(); + + double *pos = c->GetPosition(); +// double *focalpos = c->GetFocalPoint(); +// double distance = c->GetDistance(); +// double roll = c->GetRoll(); +// double angle = c->GetViewAngle(); +// double *up = c->GetViewUp(); + + QString light_str; + light_str = "light_source { %1, rgb <1,1,1> }"; + light_str = light_str.arg(pov_vect(pos)); + + return light_str; +} + +QString export_pov::pov_vect( double *v ) +{ + QString v_str = "<%1,%2,%3>"; + v_str = v_str.arg(v[0]).arg(v[1]).arg(v[2]); + return v_str; +} +QString export_pov::pov_vect2( double *v ) +{ + QString v_str = "<%1,%2>"; + v_str = v_str.arg(v[0]).arg(v[1]); + return v_str; +} diff --git a/QCSXCAD/export_pov.h b/QCSXCAD/export_pov.h new file mode 100644 index 0000000..a59917f --- /dev/null +++ b/QCSXCAD/export_pov.h @@ -0,0 +1,49 @@ +/* +* Copyright (C) 2010 Sebastian Held (sebastian.held@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 . +*/ + +#ifndef EXPORT_POV_H +#define EXPORT_POV_H + +#include +#include + +class QCSXCAD; +class CSProperties; + +class export_pov +{ +public: + export_pov( QCSXCAD * ); + void save( QString filename ); + +protected: + void export_properties( QTextStream &stream, std::vector properties, QString default_obj_modifier = QString() ); + void export_box( QTextStream &stream, double start[3], double stop[3], QString obj_modifier = QString() ); + void export_polygon( QTextStream &stream, size_t count, double *array, double elevation, int normDir, QString obj_modifier = QString() ); + void export_cylinder( QTextStream &stream, double start[3], double stop[3], double radius, QString object_modifier = QString() ); + void export_wire( QTextStream &stream, size_t count, double *array, double radius, QString object_modifier ); + QString get_camera(); + QString get_light(); + QString pov_vect( double *v ); + QString pov_vect2( double *v ); + +protected: + QCSXCAD *m_CSX; + double m_epsilon; //!< this should be very small compared to every object inside m_CSX; used to make 2D boxes -> 3D +}; + +#endif // EXPORT_POV_H diff --git a/QCSXCAD/export_x3d.cpp b/QCSXCAD/export_x3d.cpp new file mode 100644 index 0000000..347463d --- /dev/null +++ b/QCSXCAD/export_x3d.cpp @@ -0,0 +1,201 @@ +/* +* Copyright (C) 2010 Sebastian Held (sebastian.held@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 . +*/ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include "CSPrimBox.h" +#include "CSPrimPolygon.h" + +#include "QVTKStructure.h" +#include "QCSXCAD.h" +#include "export_x3d.h" + +export_X3D::export_X3D( QCSXCAD *CSX ) : m_CSX(CSX) +{ +} + +void export_X3D::save( QString filename ) +{ + QDomImplementation impl; + QDomDocument doc( impl.createDocumentType ( "X3D", "ISO//Web3D//DTD X3D 3.2//EN", "http://www.web3d.org/specifications/x3d-3.2.dtd" ) ); + doc.appendChild( doc.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"" )); // FIXME this is not a processing instruction! + QDomElement X3D = doc.createElement( "X3D" ); + X3D.setAttribute( "version", "3.2" ); + X3D.setAttribute( "profile", "Immersive" ); + doc.appendChild( X3D ); + QDomElement head = doc.createElement( "head" ); + X3D.appendChild( head ); + QDomElement meta = doc.createElement( "meta" ); + meta.setAttribute( "name", "description" ); + meta.setAttribute( "content", "X3D model exported by QCSXCAD" ); + head.appendChild( meta ); + QDomElement Scene = doc.createElement( "Scene" ); + X3D.appendChild( Scene ); + + QDomElement NavigationInfo = doc.createElement( "NavigationInfo" ); + NavigationInfo.setAttribute( "headlight", "true" ); +// NavigationInfo.setAttribute( "avatarSize", "0.25 1.6 0.75" ); + NavigationInfo.setAttribute( "type", "EXAMINE" ); + Scene.appendChild( NavigationInfo ); + + std::vector properties = m_CSX->GetPropertyByType( CSProperties::MATERIAL ); + export_properties( Scene, properties ); + + properties = m_CSX->GetPropertyByType( CSProperties::METAL ); + QDomElement Material = doc.createElement( "Material" ); + Material.setAttribute( "diffuseColor", "0.0 1.0 0.0" ); + export_properties( Scene, properties, Material ); + + // create camera + vtkRendererCollection* collection = ((QVTKWidget*)(m_CSX->StructureVTK->GetVTKWidget()))->GetRenderWindow()->GetRenderers(); + vtkRenderer *r = collection->GetFirstRenderer(); + if (!r) + return; + vtkCamera *c = r->GetActiveCamera(); + if (!c) + return; + + QDomElement Viewpoint = doc.createElement( "Viewpoint" ); + double *pos = c->GetPosition(); + Viewpoint.setAttribute( "position", QString::number(pos[0]) + " " + QString::number(pos[1]) + " " + QString::number(pos[2]) ); +// double *focalpos = c->GetFocalPoint(); +// Viewpoint.setAttribute( "centerOfRotation", QString::number(focalpos[0]) + " " + QString::number(focalpos[1]) + " " + QString::number(focalpos[2]) ); + double angle = c->GetViewAngle(); + Viewpoint.setAttribute( "fieldOfView", QString::number(angle/180.0*M_PI) ); + double *WXYZ = c->GetOrientationWXYZ(); + Viewpoint.setAttribute( "orientation", QString::number(WXYZ[1]) + " " + QString::number(WXYZ[2]) + " " + QString::number(WXYZ[3]) + " " + QString::number((360.0-WXYZ[0])/180.0*M_PI) ); // WXYZ[0] is wrong VTK-BUG!? + Scene.appendChild( Viewpoint ); + +// cout << doc.toString(4).toStdString() << endl; + + QFile file( filename ); + if (!file.open( QFile::WriteOnly )) { + QMessageBox::warning( m_CSX, QObject::tr("save failed"), QObject::tr("Cannot save to the file %1").arg(filename), QMessageBox::Ok ); + return; + } + QTextStream stream(&file); + stream.setCodec( "UTF-8" ); + doc.save( stream, 4, QDomNode::EncodingFromTextStream ); +} + +void export_X3D::export_properties( QDomElement Scene, std::vector properties, QDomElement Material ) +{ + foreach( CSProperties* prop, properties ) + { + int size = prop->GetQtyPrimitives(); + for( int i=0; iGetPrimitive(i); + if (prim->GetType() == CSPrimitives::BOX) + { + CSPrimBox *box = prim->ToBox(); + double start[] = {box->GetCoord(0),box->GetCoord(2),box->GetCoord(4)}; + double stop[] = {box->GetCoord(1),box->GetCoord(3),box->GetCoord(5)}; + export_box( Scene, start, stop, Material.cloneNode().toElement() ); + } + else if (prim->GetType() == CSPrimitives::POLYGON) + { + CSPrimPolygon *polygon = prim->ToPolygon(); + size_t count = -1; + double *array = 0; + array = polygon->GetAllCoords( count, array ); + int normDir = polygon->GetNormDir(); + double elevation = polygon->GetElevation(); + export_polygon( Scene, count, array, elevation, normDir, Material.cloneNode().toElement() ); + } + } + } +} + +void export_X3D::export_box( QDomElement &elem, double start[3], double stop[3], QDomElement Material ) +{ + double center[3], size[3]; + for (int i=0; i<3; i++) + { + center[i] = (stop[i]+start[i])/2.0;// * GetGrid()->GetDeltaUnit(); + size[i] = fabs(stop[i]-start[i]);// * GetGrid()->GetDeltaUnit(); + } + + QDomDocument doc = elem.ownerDocument(); + QDomElement Transform = doc.createElement( "Transform" ); + Transform.setAttribute( "translation", QString::number(center[0]) + " " + QString::number(center[1]) + " " + QString::number(center[2]) ); + QDomElement Shape = doc.createElement( "Shape" ); + Transform.appendChild( Shape ); + QDomElement Box = doc.createElement( "Box" ); + Box.setAttribute( "size", QString::number(size[0]) + " " + QString::number(size[1]) + " " + QString::number(size[2]) ); + Shape.appendChild( Box ); + QDomElement Appearance = doc.createElement( "Appearance" ); + Shape.appendChild( Appearance ); + if (Material.isNull()) + { + Material = doc.createElement( "Material" ); + Material.setAttribute( "diffuseColor", "1.0 0.0 0.0" ); + } + Appearance.appendChild( Material ); + + elem.appendChild( Transform ); +} + +void export_X3D::export_polygon( QDomElement &elem, size_t count, double *array, double elevation, int normDir, QDomElement Material ) +{ + if (count < 2) + return; + + // VRML: cross section in xz-plane + QString crossSection; + crossSection = QString::number( array[0] ) + " " + QString::number( array[1] ); + for (size_t i=2; i. +*/ + +#ifndef EXPORT_X3D_H +#define EXPORT_X3D_H + +#include +#include + +class QCSXCAD; +class CSProperties; + +class export_X3D +{ +public: + export_X3D( QCSXCAD * ); + void save( QString filename ); + +protected: + void export_properties( QDomElement Scene, std::vector properties, QDomElement Material = QDomElement() ); + void export_box( QDomElement &elem, double start[3], double stop[3], QDomElement Material = QDomElement() ); + void export_polygon( QDomElement &elem, size_t count, double *array, double elevation, int normDir, QDomElement Material = QDomElement() ); + +protected: + QCSXCAD *m_CSX; +}; + +#endif // EXPORT_X3D_H diff --git a/QCSXCAD/images/Arrows/Arrows.odg b/QCSXCAD/images/Arrows/Arrows.odg new file mode 100644 index 0000000..b5210d9 Binary files /dev/null and b/QCSXCAD/images/Arrows/Arrows.odg differ diff --git a/QCSXCAD/images/Arrows/ArrowsXY.png b/QCSXCAD/images/Arrows/ArrowsXY.png new file mode 100644 index 0000000..dba241e Binary files /dev/null and b/QCSXCAD/images/Arrows/ArrowsXY.png differ diff --git a/QCSXCAD/images/Arrows/ArrowsXZ.odg b/QCSXCAD/images/Arrows/ArrowsXZ.odg new file mode 100644 index 0000000..de87dba Binary files /dev/null and b/QCSXCAD/images/Arrows/ArrowsXZ.odg differ diff --git a/QCSXCAD/images/Arrows/ArrowsXZ.png b/QCSXCAD/images/Arrows/ArrowsXZ.png new file mode 100644 index 0000000..439c52e Binary files /dev/null and b/QCSXCAD/images/Arrows/ArrowsXZ.png differ diff --git a/QCSXCAD/images/Arrows/ArrowsYZ.odg b/QCSXCAD/images/Arrows/ArrowsYZ.odg new file mode 100644 index 0000000..80084b2 Binary files /dev/null and b/QCSXCAD/images/Arrows/ArrowsYZ.odg differ diff --git a/QCSXCAD/images/Arrows/ArrowsYZ.png b/QCSXCAD/images/Arrows/ArrowsYZ.png new file mode 100644 index 0000000..c7285e6 Binary files /dev/null and b/QCSXCAD/images/Arrows/ArrowsYZ.png differ diff --git a/QCSXCAD/images/ArrowsXY.png b/QCSXCAD/images/ArrowsXY.png new file mode 100644 index 0000000..dba241e Binary files /dev/null and b/QCSXCAD/images/ArrowsXY.png differ diff --git a/QCSXCAD/images/ArrowsXZ.png b/QCSXCAD/images/ArrowsXZ.png new file mode 100644 index 0000000..439c52e Binary files /dev/null and b/QCSXCAD/images/ArrowsXZ.png differ diff --git a/QCSXCAD/images/ArrowsYZ.png b/QCSXCAD/images/ArrowsYZ.png new file mode 100644 index 0000000..c7285e6 Binary files /dev/null and b/QCSXCAD/images/ArrowsYZ.png differ diff --git a/QCSXCAD/images/CVS/Entries b/QCSXCAD/images/CVS/Entries new file mode 100644 index 0000000..3593808 --- /dev/null +++ b/QCSXCAD/images/CVS/Entries @@ -0,0 +1,40 @@ +/GeoEdit.png/1.1/Mon Oct 20 07:11:47 2003/-kb/ +/ParaSetup.png/1.1/Mon Oct 20 07:11:13 2003/-kb/ +/Thumbs.db/1.2/Tue Jun 27 14:51:16 2006/-kb/ +/accept.png/1.1/Mon Aug 29 14:17:00 2005/-kb/ +/bulb.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/bulb_off.png/1.1/Wed Oct 11 20:48:27 2006/-kb/ +/cancel.png/1.1/Mon Oct 20 07:16:21 2003/-kb/ +/close.png/1.1/Mon Oct 20 07:16:25 2003/-kb/ +/configure.png/1.1/Mon Oct 10 19:03:03 2005/-kb/ +/down.png/1.1/Mon Oct 10 19:03:03 2005/-kb/ +/edit.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/edit_add.png/1.1/Mon Oct 20 07:16:24 2003/-kb/ +/edit_remove.png/1.1/Mon Oct 20 07:16:25 2003/-kb/ +/editcopy.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/exit.png/1.1/Mon Oct 20 07:16:26 2003/-kb/ +/failed.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/filenew.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/fileopen.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/filesave.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/filesaveas.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/folder.png/1.1/Fri Apr 4 12:47:44 2003/-kb/ +/funct.png/1.1/Mon Oct 20 07:16:30 2003/-kb/ +/hourglass.png/1.1/Wed Sep 28 17:56:00 2005/-kb/ +/icon.gif/1.1/Sun Aug 28 21:13:00 2005/-kb/ +/launch.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/qt-logo.png/1.1/Wed Dec 14 17:02:26 2005/-kb/ +/reload.png/1.1/Mon Dec 16 23:41:14 2002/-kb/ +/result_small.png/1.1/Mon Oct 20 07:16:29 2003/-kb/ +/results.png/1.1/Mon Oct 20 07:11:58 2003/-kb/ +/setup.png/1.1/Sun Aug 14 17:45:15 2005/-kb/ +/simulation.png/1.1/Fri Jan 6 12:43:58 2006/-kb/ +/simulation_icon.png/1.1/Fri Jan 6 14:24:45 2006/-kb/ +/simulation_small.png/1.1/Thu Jun 29 20:43:26 2006/-kb/ +/simulation_tr.png/1.1/Fri Jan 6 14:23:52 2006/-kb/ +/up.png/1.1/Mon Oct 10 19:03:03 2005/-kb/ +/viewmag+.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/viewmag-.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/viewmagfit.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ +/window_icon2.png/1.1/Mon Aug 29 14:17:00 2005/-kb/ +/work.png/1.1/Mon Oct 20 07:14:09 2003/-kb/ diff --git a/QCSXCAD/images/CVS/Repository b/QCSXCAD/images/CVS/Repository new file mode 100644 index 0000000..d336c21 --- /dev/null +++ b/QCSXCAD/images/CVS/Repository @@ -0,0 +1 @@ +StaticSimulator/images diff --git a/QCSXCAD/images/CVS/Root b/QCSXCAD/images/CVS/Root new file mode 100644 index 0000000..800d2fc --- /dev/null +++ b/QCSXCAD/images/CVS/Root @@ -0,0 +1 @@ +:extssh:coft@atex.ate.uni-duisburg.de:/srv/CVS diff --git a/QCSXCAD/images/GeoEdit.png b/QCSXCAD/images/GeoEdit.png new file mode 100644 index 0000000..2b4ed78 Binary files /dev/null and b/QCSXCAD/images/GeoEdit.png differ diff --git a/QCSXCAD/images/ParaSetup.png b/QCSXCAD/images/ParaSetup.png new file mode 100644 index 0000000..c49947f Binary files /dev/null and b/QCSXCAD/images/ParaSetup.png differ diff --git a/QCSXCAD/images/QCSXCAD_Icon.png b/QCSXCAD/images/QCSXCAD_Icon.png new file mode 100644 index 0000000..a1530be Binary files /dev/null and b/QCSXCAD/images/QCSXCAD_Icon.png differ diff --git a/QCSXCAD/images/accept.png b/QCSXCAD/images/accept.png new file mode 100644 index 0000000..a24d605 Binary files /dev/null and b/QCSXCAD/images/accept.png differ diff --git a/QCSXCAD/images/bulb.png b/QCSXCAD/images/bulb.png new file mode 100644 index 0000000..8d72794 Binary files /dev/null and b/QCSXCAD/images/bulb.png differ diff --git a/QCSXCAD/images/bulb_off.png b/QCSXCAD/images/bulb_off.png new file mode 100644 index 0000000..8407b89 Binary files /dev/null and b/QCSXCAD/images/bulb_off.png differ diff --git a/QCSXCAD/images/cancel.png b/QCSXCAD/images/cancel.png new file mode 100644 index 0000000..57fdcb9 Binary files /dev/null and b/QCSXCAD/images/cancel.png differ diff --git a/QCSXCAD/images/close.png b/QCSXCAD/images/close.png new file mode 100644 index 0000000..07e8886 Binary files /dev/null and b/QCSXCAD/images/close.png differ diff --git a/QCSXCAD/images/configure.png b/QCSXCAD/images/configure.png new file mode 100644 index 0000000..33ad550 Binary files /dev/null and b/QCSXCAD/images/configure.png differ diff --git a/QCSXCAD/images/down.png b/QCSXCAD/images/down.png new file mode 100644 index 0000000..9fd08a2 Binary files /dev/null and b/QCSXCAD/images/down.png differ diff --git a/QCSXCAD/images/edit.png b/QCSXCAD/images/edit.png new file mode 100644 index 0000000..1d69145 Binary files /dev/null and b/QCSXCAD/images/edit.png differ diff --git a/QCSXCAD/images/edit_add.png b/QCSXCAD/images/edit_add.png new file mode 100644 index 0000000..072ac68 Binary files /dev/null and b/QCSXCAD/images/edit_add.png differ diff --git a/QCSXCAD/images/edit_remove.png b/QCSXCAD/images/edit_remove.png new file mode 100644 index 0000000..78cb1de Binary files /dev/null and b/QCSXCAD/images/edit_remove.png differ diff --git a/QCSXCAD/images/editcopy.png b/QCSXCAD/images/editcopy.png new file mode 100644 index 0000000..cfa9cb4 Binary files /dev/null and b/QCSXCAD/images/editcopy.png differ diff --git a/QCSXCAD/images/exit.png b/QCSXCAD/images/exit.png new file mode 100644 index 0000000..cade942 Binary files /dev/null and b/QCSXCAD/images/exit.png differ diff --git a/QCSXCAD/images/failed.png b/QCSXCAD/images/failed.png new file mode 100644 index 0000000..1cabc6e Binary files /dev/null and b/QCSXCAD/images/failed.png differ diff --git a/QCSXCAD/images/filenew.png b/QCSXCAD/images/filenew.png new file mode 100644 index 0000000..8a303b7 Binary files /dev/null and b/QCSXCAD/images/filenew.png differ diff --git a/QCSXCAD/images/fileopen.png b/QCSXCAD/images/fileopen.png new file mode 100644 index 0000000..503a004 Binary files /dev/null and b/QCSXCAD/images/fileopen.png differ diff --git a/QCSXCAD/images/filesave.png b/QCSXCAD/images/filesave.png new file mode 100644 index 0000000..dd00abd Binary files /dev/null and b/QCSXCAD/images/filesave.png differ diff --git a/QCSXCAD/images/filesaveas.png b/QCSXCAD/images/filesaveas.png new file mode 100644 index 0000000..61a080e Binary files /dev/null and b/QCSXCAD/images/filesaveas.png differ diff --git a/QCSXCAD/images/folder.png b/QCSXCAD/images/folder.png new file mode 100644 index 0000000..b5e286a Binary files /dev/null and b/QCSXCAD/images/folder.png differ diff --git a/QCSXCAD/images/funct.png b/QCSXCAD/images/funct.png new file mode 100644 index 0000000..4171db5 Binary files /dev/null and b/QCSXCAD/images/funct.png differ diff --git a/QCSXCAD/images/hourglass.png b/QCSXCAD/images/hourglass.png new file mode 100644 index 0000000..c3ffd08 Binary files /dev/null and b/QCSXCAD/images/hourglass.png differ diff --git a/QCSXCAD/images/icon.gif b/QCSXCAD/images/icon.gif new file mode 100644 index 0000000..35e9499 Binary files /dev/null and b/QCSXCAD/images/icon.gif differ diff --git a/QCSXCAD/images/launch.png b/QCSXCAD/images/launch.png new file mode 100644 index 0000000..5f61bea Binary files /dev/null and b/QCSXCAD/images/launch.png differ diff --git a/QCSXCAD/images/launch2.png b/QCSXCAD/images/launch2.png new file mode 100644 index 0000000..50d8029 Binary files /dev/null and b/QCSXCAD/images/launch2.png differ diff --git a/QCSXCAD/images/launch3.png b/QCSXCAD/images/launch3.png new file mode 100644 index 0000000..cad0e5e Binary files /dev/null and b/QCSXCAD/images/launch3.png differ diff --git a/QCSXCAD/images/opening.png b/QCSXCAD/images/opening.png new file mode 100644 index 0000000..9539266 Binary files /dev/null and b/QCSXCAD/images/opening.png differ diff --git a/QCSXCAD/images/qt-logo.png b/QCSXCAD/images/qt-logo.png new file mode 100644 index 0000000..a8b452e Binary files /dev/null and b/QCSXCAD/images/qt-logo.png differ diff --git a/QCSXCAD/images/reload.png b/QCSXCAD/images/reload.png new file mode 100644 index 0000000..9cec493 Binary files /dev/null and b/QCSXCAD/images/reload.png differ diff --git a/QCSXCAD/images/result_small.png b/QCSXCAD/images/result_small.png new file mode 100644 index 0000000..00dc24a Binary files /dev/null and b/QCSXCAD/images/result_small.png differ diff --git a/QCSXCAD/images/results.png b/QCSXCAD/images/results.png new file mode 100644 index 0000000..6f11252 Binary files /dev/null and b/QCSXCAD/images/results.png differ diff --git a/QCSXCAD/images/setup.png b/QCSXCAD/images/setup.png new file mode 100644 index 0000000..874c686 Binary files /dev/null and b/QCSXCAD/images/setup.png differ diff --git a/QCSXCAD/images/simulation.png b/QCSXCAD/images/simulation.png new file mode 100644 index 0000000..9983830 Binary files /dev/null and b/QCSXCAD/images/simulation.png differ diff --git a/QCSXCAD/images/simulation_icon.png b/QCSXCAD/images/simulation_icon.png new file mode 100644 index 0000000..8f249f3 Binary files /dev/null and b/QCSXCAD/images/simulation_icon.png differ diff --git a/QCSXCAD/images/simulation_small.png b/QCSXCAD/images/simulation_small.png new file mode 100644 index 0000000..801fa6a Binary files /dev/null and b/QCSXCAD/images/simulation_small.png differ diff --git a/QCSXCAD/images/simulation_tr.png b/QCSXCAD/images/simulation_tr.png new file mode 100644 index 0000000..1552c45 Binary files /dev/null and b/QCSXCAD/images/simulation_tr.png differ diff --git a/QCSXCAD/images/up.png b/QCSXCAD/images/up.png new file mode 100644 index 0000000..6fe4ead Binary files /dev/null and b/QCSXCAD/images/up.png differ diff --git a/QCSXCAD/images/viewmag+.png b/QCSXCAD/images/viewmag+.png new file mode 100644 index 0000000..15b2fa1 Binary files /dev/null and b/QCSXCAD/images/viewmag+.png differ diff --git a/QCSXCAD/images/viewmag-.png b/QCSXCAD/images/viewmag-.png new file mode 100644 index 0000000..18002f9 Binary files /dev/null and b/QCSXCAD/images/viewmag-.png differ diff --git a/QCSXCAD/images/viewmagfit.png b/QCSXCAD/images/viewmagfit.png new file mode 100644 index 0000000..2ef0fd5 Binary files /dev/null and b/QCSXCAD/images/viewmagfit.png differ diff --git a/QCSXCAD/images/vtk-logo.png b/QCSXCAD/images/vtk-logo.png new file mode 100644 index 0000000..4129025 Binary files /dev/null and b/QCSXCAD/images/vtk-logo.png differ diff --git a/QCSXCAD/images/window_icon2.png b/QCSXCAD/images/window_icon2.png new file mode 100644 index 0000000..a24d605 Binary files /dev/null and b/QCSXCAD/images/window_icon2.png differ diff --git a/QCSXCAD/images/work.png b/QCSXCAD/images/work.png new file mode 100644 index 0000000..e0dadb1 Binary files /dev/null and b/QCSXCAD/images/work.png differ diff --git a/QCSXCAD/linux/QCSXCAD.dsc b/QCSXCAD/linux/QCSXCAD.dsc new file mode 100644 index 0000000..49f13a5 --- /dev/null +++ b/QCSXCAD/linux/QCSXCAD.dsc @@ -0,0 +1,9 @@ +Format: 1.0 +Source: qcsxcad +Version: 0.3.0-1 +Binary: qcsxcad, qcsxcad-dev +Maintainer: Thorsten Liebig , Sebastian Held +Homepage: http://www.openems.de +Architecture: any +Build-Depends: debhelper (>=7.0.50~), libqt4-dev, qt4-qmake, libtinyxml-dev, libvtk5-qt4-dev, csxcad-dev +DEBTRANSFORM-TAR: QCSXCAD-0.3.0.tar.bz2 diff --git a/QCSXCAD/linux/QCSXCAD.spec b/QCSXCAD/linux/QCSXCAD.spec new file mode 100644 index 0000000..05579ca --- /dev/null +++ b/QCSXCAD/linux/QCSXCAD.spec @@ -0,0 +1,115 @@ +# +# spec file for package [spectemplate] +# +# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + +# norootforbuild + +Name: QCSXCAD +Version: 0.3.0 +Release: 1 +Summary: Qt bindings for CSXCAD +Group: Development/Languages/C and C++ +License: LGPLv3 +URL: http://www.openems.de +Source0: %{name}-%{version}.tar.bz2 +Patch0: fedora17.diff +# BuildArch: noarch +BuildRoot: %_tmppath/%name-%version-build + +BuildRequires: libqt4-devel gcc-c++ tinyxml-devel vtk-devel vtk-qt CSXCAD-devel +#Requires: + + +# determine qt4 qmake executable +%if 0%{?fedora} + %global qmake qmake-qt4 +%else + %global qmake qmake +%endif + + + +%description +Qt bindings for CSXCAD. + +%package -n lib%{name}0 +Summary: Shared Library for %{name} +Group: Development/Languages/C and C++ + +%description -n lib%{name}0 +The lib%{name}0 package contains the shared library. + +%package devel +Summary: Development files for %{name} +Group: Development/Languages/C and C++ +Requires: %{name} = %{version}-%{release} +Requires: lib%{name}0 = %{version}-%{release} + +%description devel +The %{name}-devel package contains libraries and header files for +developing applications that use %{name}. + + +%prep +%setup -q +%if 0%{?fedora} >= 17 +%patch0 -p1 +%endif + +%build +%qmake QMAKE_CFLAGS="%optflags" QMAKE_CXXFLAGS="%optflags" LIB_SUFFIX="$(echo %_lib | cut -b4-)" +make %{?_smp_mflags} + + +%install +make INSTALL_ROOT=%{buildroot} install +find %{buildroot} -name '*.la' -exec rm -f {} ';' + + +%clean +rm -rf %{buildroot} + + +%post -n lib%{name}0 -p /sbin/ldconfig + +%postun -n lib%{name}0 -p /sbin/ldconfig + + +%files +%defattr(-,root,root) +%doc COPYING + + +%files -n lib%{name}0 +%defattr(-,root,root) +%{_libdir}/*.so.* + + +%files devel +%defattr(-,root,root) +%{_includedir}/* +%{_libdir}/*.so + + +%changelog +* Sun Jun 17 2012 Sebastian Held - 0.3.0-1 +- new upstream version +* Thu Dec 29 2011 Sebastian Held - 0.1.3-3 +- new upstream version +* Wed Dec 28 2011 Sebastian Held - 0.1.3-2 +- Fedora 16 build support +* Sun Dec 04 2011 Sebastian Held - 0.1.3-1 +- initial version diff --git a/QCSXCAD/linux/debian.changelog b/QCSXCAD/linux/debian.changelog new file mode 100644 index 0000000..aa7f02a --- /dev/null +++ b/QCSXCAD/linux/debian.changelog @@ -0,0 +1,9 @@ +qcsxcad (0.3.0-1) stable; urgency=low + * New upstream version + -- Sebastian Held Sun, 17 Jun 2012 21:51:14 +0200 +qcsxcad (0.1.3-2) stable; urgency=low + * New upstream version + -- Sebastian Held Thu, 29 Dec 2011 18:01:00 +0100 +qcsxcad (0.1.3-1) stable; urgency=low + * Initial Release + -- Sebastian Held Sun, 4 Dec 2011 19:03:00 +0100 diff --git a/QCSXCAD/linux/debian.control b/QCSXCAD/linux/debian.control new file mode 100644 index 0000000..20286da --- /dev/null +++ b/QCSXCAD/linux/debian.control @@ -0,0 +1,17 @@ +Source: qcsxcad +Section: contrib/libdevel +Priority: optional +Maintainer: Sebastian Held +Build-Depends: debhelper (>=7.0.50~), libqt4-dev, qt4-qmake, libtinyxml-dev, libvtk5-qt4-dev, csxcad-dev + +Package: qcsxcad +Architecture: any +Depends: ${shlibs:Depends} +Description: Qt bindings for CSXCAD + Qt bindings for CSXCAD + +Package: qcsxcad-dev +Architecture: any +Depends: ${shlibs:Depends} qcsxcad (= ${binary:Version}) +Description: Development files for qcsxcad + The qcsxcad-dev package contains libraries and header files for developing applications that use qcsxcad. diff --git a/QCSXCAD/linux/debian.rules b/QCSXCAD/linux/debian.rules new file mode 100644 index 0000000..874a39c --- /dev/null +++ b/QCSXCAD/linux/debian.rules @@ -0,0 +1,7 @@ +#!/usr/bin/make -f + +export DH_VERBOSE=1 +export DH_OPTIONS=-v + +%: + dh $@ diff --git a/QCSXCAD/linux/fedora17.diff b/QCSXCAD/linux/fedora17.diff new file mode 100644 index 0000000..33c78b4 --- /dev/null +++ b/QCSXCAD/linux/fedora17.diff @@ -0,0 +1,13 @@ +diff --git a/QCSXCAD.pro b/QCSXCAD.pro +index 7cbf438..7d9e75c 100644 +--- a/QCSXCAD.pro ++++ b/QCSXCAD.pro +@@ -79,7 +79,7 @@ unix { + /usr/include/vtk-5.10 \ + /usr/include/vtk + INCLUDEPATH += /usr/include/CSXCAD +- LIBS += -lvtkCommon \ ++ LIBS += -L/usr/lib/vtk -L/usr/lib64/vtk -lvtkCommon \ + -lvtkDICOMParser \ + -lvtkFiltering \ + -lvtkGenericFiltering \ diff --git a/QCSXCAD/resources.qrc b/QCSXCAD/resources.qrc new file mode 100644 index 0000000..3a223d0 --- /dev/null +++ b/QCSXCAD/resources.qrc @@ -0,0 +1,49 @@ + + + + images/QCSXCAD_Icon.png + images/accept.png + images/failed.png + images/hourglass.png + images/qt-logo.png + images/vtk-logo.png + images/simulation_tr.png + images/simulation_small.png + images/simulation_icon.png + images/filesave.png + images/filesaveas.png + images/fileopen.png + images/filenew.png + images/exit.png + images/results.png + images/work.png + images/setup.png + images/GeoEdit.png + images/ParaSetup.png + images/launch.png + images/launch2.png + images/launch3.png + images/result_small.png + images/configure.png + images/down.png + images/up.png + images/funct.png + images/edit_remove.png + images/edit_add.png + images/edit.png + images/reload.png + images/cancel.png + images/close.png + images/viewmagfit.png + images/viewmag-.png + images/viewmag+.png + images/bulb.png + images/bulb_off.png + images/editcopy.png + images/folder.png + images/ArrowsXY.png + images/ArrowsXZ.png + images/ArrowsYZ.png + images/opening.png + + diff --git a/QCSXCAD/vtkInteractorStyleRubberBand2DPlane.cpp b/QCSXCAD/vtkInteractorStyleRubberBand2DPlane.cpp new file mode 100644 index 0000000..1bd9bdf --- /dev/null +++ b/QCSXCAD/vtkInteractorStyleRubberBand2DPlane.cpp @@ -0,0 +1,73 @@ +/* +* Copyright (C) 2010-2013 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 . +*/ + +#include "vtkInteractorStyleRubberBand2DPlane.h" + +#include "vtkCamera.h" +#include "vtkCommand.h" +#include "vtkObjectFactory.h" +#include "vtkRenderer.h" +#include "vtkRenderWindow.h" +#include "vtkRenderWindowInteractor.h" + +vtkStandardNewMacro(vtkInteractorStyleRubberBand2DPlane); + +vtkInteractorStyleRubberBand2DPlane::vtkInteractorStyleRubberBand2DPlane() : vtkInteractorStyleRubberBand2D() +{ +} + +void vtkInteractorStyleRubberBand2DPlane::OnMouseMove() +{ + if (this->Interaction == PANNING) + { + vtkRenderWindowInteractor* rwi = this->GetInteractor(); + int lastPt[] = {0, 0}; + rwi->GetLastEventPosition(lastPt); + int curPt[] = {0, 0}; + rwi->GetEventPosition(curPt); + + vtkCamera* camera = this->CurrentRenderer->GetActiveCamera(); + double lastScale = 2.0 * camera->GetParallelScale() / this->CurrentRenderer->GetSize()[1]; + double lastFocalPt[] = {0, 0, 0}; + camera->GetFocalPoint(lastFocalPt); + double lastPos[] = {0, 0, 0}; + camera->GetPosition(lastPos); + + double dop[3]; + camera->GetDirectionOfProjection(dop); + + int n_dir=-1; + for (int n=0;n<3;++n) + if ((dop[n]!=0) && (dop[(n+1)%2]==0) && (dop[(n+2)%3]==0)) + n_dir = n; + if (n_dir<0) + { + cerr << __func__ << ": Error, no view in x-, y- or z-direction, skipping panning!"; + return; + } + + double delta[] = {0, 0, 0}; + delta[(n_dir+1)%3] = -lastScale*(curPt[0] - lastPt[0]); + delta[(n_dir+2)%3] = -lastScale*(curPt[1] - lastPt[1]); + camera->SetFocalPoint(lastFocalPt[0] + delta[0], lastFocalPt[1] + delta[1], lastFocalPt[2] + delta[2]); + camera->SetPosition(lastPos[0] + delta[0], lastPos[1] + delta[1], lastPos[2] + delta[2]); + this->InvokeEvent(vtkCommand::InteractionEvent); + rwi->Render(); + } + else + vtkInteractorStyleRubberBand2D::OnMouseMove(); +} diff --git a/QCSXCAD/vtkInteractorStyleRubberBand2DPlane.h b/QCSXCAD/vtkInteractorStyleRubberBand2DPlane.h new file mode 100644 index 0000000..62725b9 --- /dev/null +++ b/QCSXCAD/vtkInteractorStyleRubberBand2DPlane.h @@ -0,0 +1,35 @@ +/* +* Copyright (C) 2010-2013 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 . +*/ + +#ifndef VTKINTERACTORSTYLERUBBERBAND2DPLANE_H +#define VTKINTERACTORSTYLERUBBERBAND2DPLANE_H + +#include "vtkInteractorStyleRubberBand2D.h" + +class vtkInteractorStyleRubberBand2DPlane : public vtkInteractorStyleRubberBand2D +{ +public: + static vtkInteractorStyleRubberBand2DPlane *New(); + vtkTypeMacro(vtkInteractorStyleRubberBand2DPlane, vtkInteractorStyle); + + virtual void OnMouseMove(); + +protected: + vtkInteractorStyleRubberBand2DPlane(); +}; + +#endif // VTKINTERACTORSTYLERUBBERBAND2DPLANE_H diff --git a/brew/README.md b/brew/README.md new file mode 100644 index 0000000..2d85f66 --- /dev/null +++ b/brew/README.md @@ -0,0 +1,35 @@ +openEMS Homebrew +================ + +This is a [homebrew](http://brew.sh) formula to install [openEMS](http://openEMS.de) and all dependencies. + +How to install openEMS: +----------------------- + +You can install openEMS using this URL: +```bash + brew install --HEAD https://raw.github.com/thliebig/openEMS-Project/master/brew/openEMS.rb +``` + +Then create a folder and symbolic link in your home folder with these commands + +``` +mkdir ~/opt +ln -s /usr/local/Cellar/openEMS/HEAD ~/opt/openEMS +``` + +Install Octave if it isn't already installed + +``` +brew install octave +``` + +Start Octave from the command line and add the openEMS paths + +``` +addpath('~/opt/openEMS/share/openEMS/matlab'); +addpath('~/opt/openEMS/share/CSXCAD/matlab'); +savepath() +``` + +Verify your installation by completing the First Steps section of the Tutorials. http://openems.de/index.php/Tutorial:_First_Steps diff --git a/brew/openEMS.rb b/brew/openEMS.rb new file mode 100644 index 0000000..6ab3ebe --- /dev/null +++ b/brew/openEMS.rb @@ -0,0 +1,26 @@ +require "formula" + +class Openems < Formula + homepage "http://openems.de" + + head do + url "https://github.com/thliebig/openEMS-Project.git" + end + + depends_on "cmake" => :build + depends_on "flex" + depends_on "bison" + depends_on "qt" + depends_on "tinyxml" + depends_on "vtk" => ["with-qt", "c++11"] + depends_on "cgal" => "c++11" + depends_on "boost" => "c++11" + + def install + system "cmake", ".", *std_cmake_args + system "make" + # install is handled by ExternalProject_Add + end + +end + diff --git a/hyp2mat/.gitignore b/hyp2mat/.gitignore new file mode 100644 index 0000000..05ed96b --- /dev/null +++ b/hyp2mat/.gitignore @@ -0,0 +1,11 @@ +private/ +autom4te.cache/ +Makefile +config.log +config.status +libtool +config/* +Makefile.in +m4/ +configure +aclocal.m4 diff --git a/hyp2mat/AUTHORS b/hyp2mat/AUTHORS new file mode 100644 index 0000000..b976301 --- /dev/null +++ b/hyp2mat/AUTHORS @@ -0,0 +1,2 @@ +Koen De Vleeschauwer, kdv@kdvelectronics.eu, http://www.kdvelectronics.eu +Thorsten Liebig, thorsten.liebig@uni-due.de, http:://www.openems.de, for the openEMS examples. diff --git a/hyp2mat/COPYING b/hyp2mat/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/hyp2mat/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/hyp2mat/ChangeLog b/hyp2mat/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/hyp2mat/INSTALL b/hyp2mat/INSTALL new file mode 100644 index 0000000..33ea92c --- /dev/null +++ b/hyp2mat/INSTALL @@ -0,0 +1,55 @@ +This is a utility which converts HyperLynx files to CSXCAD for electromagnetic simulation. + +Tested on Linux ubuntu, MacOSX and Windows/MingW. + +Dependencies: requires libhpdf, libpng, zlib. + +Default is installing the hyp2mat executable only. +If you wish to install not only the executable, but also the hyp2mat library, includes and package information, add the "--enable-library" flag, e.g. "configure --enable-library" + +Default is building the static libhyp2mat.a library only. +If you wish to build not only the static library, but also the shared libhyp2mat.so library, add the "--enable-shared" flag, e.g. "configure --enable-library --enable-shared" + +The following packages are necessary for development: g++, libtool, make, bison, flex, gengetopt, help2man, groff, ps2pdf. + +On Linux ubuntu, with libhpdf installed in /usr/lib: + sh ./bootstrap.sh + ./configure + make + make install + +On MacOSX, with libhpdf installed in /opt/local using MacPorts: + sh ./bootstrap.sh + CPPFLAGS=-I/opt/local/include LDFLAGS=-L/opt/local/lib ./configure + make + make install + +On Windows: + + Install MinGW (http://www.mingw.org) + Compile zlib, libpng and libharu (libhpdf): + + zlib-1.2.8: + INCLUDE_PATH=/usr/include LIBRARY_PATH=/usr/lib BINARY_PATH=/usr/bin make -f win32/Makefile.gcc install + + libpng-1.5.17: + CPPFLAGS=-I/usr/include LDFLAGS=-L/usr/lib/ ./configure --prefix=/usr + make + make install + + libharu-2.2.1: + Download libharu-2.2.1-png15.patch from http://sisyphus.ru/en/srpm/Sisyphus/libharu/patches/0 + Patch libharu, configure and install: + patch -p0 < libharu-2.2.1-png15.patch + ./configure --prefix=/usr + make + make install + + Compile hyp2mat as a static binary: + + hyp2mat: + CPPFLAGS=-I/usr/include LDFLAGS="-static -static-libgcc -static-libstdc++ -L/usr/lib" ./configure + make + make install + + diff --git a/hyp2mat/Makefile.am b/hyp2mat/Makefile.am new file mode 100644 index 0000000..b157b32 --- /dev/null +++ b/hyp2mat/Makefile.am @@ -0,0 +1,34 @@ +# used by automake +ACLOCAL_AMFLAGS=-I m4 +SUBDIRS=lib src doc matlab eagle + +README: README.md + tr -d '#[]' < $< > $@ + +EXTRA_DIST=README.md + +# create a git archive without generated files +tarball: + git archive --format=tar --prefix=hyp2mat-@PACKAGE_VERSION@/ HEAD | bzip2 > hyp2mat-@PACKAGE_VERSION@.tar.bz2 + +# create a tarball with all generated files inside +tarball-dist: all + $(MAKE) -C doc + git archive --format=tar --prefix=hyp2mat-@PACKAGE_VERSION@/ HEAD > hyp2mat-@PACKAGE_VERSION@-dist.tar + echo configure > .tar-files + echo doc/hyp2mat.pdf >> .tar-files + echo doc/hyp2mat.1 >> .tar-files + echo lib/parse.cc >> .tar-files + echo lib/parse.h >> .tar-files + echo lib/scan.cc >> .tar-files + echo src/cmdline.c >> .tar-files + echo src/cmdline.h >> .tar-files + echo aclocal.m4 >> .tar-files + echo libtool >> .tar-files + find . -name '*.in' >> .tar-files + find . -path './config/*' -or -path './m4/*' >> .tar-files + tar --append -f hyp2mat-@PACKAGE_VERSION@-dist.tar --dereference --transform 's,^,hyp2mat-@PACKAGE_VERSION@/,' --files-from .tar-files + bzip2 -f hyp2mat-@PACKAGE_VERSION@-dist.tar + rm .tar-files + +.PHONY: tarball tarball-dist diff --git a/hyp2mat/NEWS b/hyp2mat/NEWS new file mode 100644 index 0000000..5411240 --- /dev/null +++ b/hyp2mat/NEWS @@ -0,0 +1,22 @@ +27 Mar 2013: 0.0.5 "c++" release for OpenEMS v0.0.30 + - Joins adjacent and overlapping copper + - pdf output added + +29 July 2013: 0.0.6 release for OpenEMS v0.0.31 +13 September 2013: 0.0.7 release + - bug fixes. + - attempt at PLANE type polygons and PLANE layers. + These are polygons and layers which are flooded with copper, + where the copper automatically keeps a preset clearance between nets. + +1 March 2014: + - allow for lossy copper and lossy dielectric + +21 February 2015: + - adapt for bison 3 + - add board outline if board outline is not defined + - allow blind and buried vias + +29 April 2015: + - add option for 3d metal + - fix stack height diff --git a/hyp2mat/README b/hyp2mat/README new file mode 100644 index 0000000..3f03a92 --- /dev/null +++ b/hyp2mat/README @@ -0,0 +1,16 @@ + hyp2mat + +hyp2mat is a utility which converts HyperLynx files to matlab for electromagnetic simulation, or to PDF for printing. +hyp2mat is distributed with openEMS (http://www.openems.de), a free open-source electromagnetic field solver. + + Installation + +hyp2mat can be installed from pre-compiled binaries, or compiled from source: + +* Windows binaries ( http://www.kdvelectronics.eu/hyp2mat/hyp2mat-win32-current.zip ) +* Linux packages ( https://build.opensuse.org/package/show?package=hyp2mat&project=home%3Asibbi77 ) +* To install from source see the file INSTALL for compilation instructions + + Tutorial + +How to simulate a printed circuit board in openEMS using HyperLynx files ( http://openems.de/index.php/Tutorial:_Importing_with_hyp2mat ) diff --git a/hyp2mat/README.md b/hyp2mat/README.md new file mode 100644 index 0000000..196ac6a --- /dev/null +++ b/hyp2mat/README.md @@ -0,0 +1,16 @@ +# hyp2mat + +hyp2mat is a utility which converts HyperLynx files to matlab for electromagnetic simulation, or to PDF for printing. +hyp2mat is distributed with [openEMS] (http://www.openems.de), a free open-source electromagnetic field solver. + +## Installation + +hyp2mat can be installed from pre-compiled binaries, or compiled from source: + +* [Windows binaries] ( http://www.kdvelectronics.eu/hyp2mat/hyp2mat-win32-current.zip ) +* [Linux packages] ( https://build.opensuse.org/package/show?package=hyp2mat&project=home%3Asibbi77 ) +* To install from source see the file INSTALL for compilation instructions + +## Tutorial + +How to [simulate a printed circuit board in openEMS using HyperLynx files] ( http://openems.de/index.php/Tutorial:_Importing_with_hyp2mat ) diff --git a/hyp2mat/THANKS b/hyp2mat/THANKS new file mode 100644 index 0000000..b1df414 --- /dev/null +++ b/hyp2mat/THANKS @@ -0,0 +1,7 @@ +Inmaculada Pindado. + +Thorsten Liebig and Sebastian Held from OpenEMS. + +Ulf Niessmann for suggesting ClipperLib. + +Todd Elliott. diff --git a/hyp2mat/bootstrap.sh b/hyp2mat/bootstrap.sh new file mode 100755 index 0000000..660af14 --- /dev/null +++ b/hyp2mat/bootstrap.sh @@ -0,0 +1,3 @@ +#!/bin/sh +mkdir m4 2>/dev/null +autoreconf -i diff --git a/hyp2mat/configure.ac b/hyp2mat/configure.ac new file mode 100644 index 0000000..a02cf1a --- /dev/null +++ b/hyp2mat/configure.ac @@ -0,0 +1,48 @@ +# Process this file with autoconf to produce a configure script. +AC_INIT([hyp2mat], [0.0.15]) +AC_CONFIG_AUX_DIR([config]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_SRCDIR([src/hyp2mat.cc]) +AC_CONFIG_HEADER([src/config.h]) +AC_CONFIG_FILES([Makefile src/Makefile lib/Makefile lib/hyp2mat.pc doc/Makefile matlab/Makefile eagle/Makefile]) +AM_INIT_AUTOMAKE + +# optionally install libraries and headers +AC_ARG_ENABLE([library], +AC_HELP_STRING([--enable-library], [install hyp2mat library and includes]), +[case "${enableval}" in + yes) install_library=true ;; + no) install_library=false ;; + *) AC_MSG_ERROR([bad value ${enableval} for --enable-library]) ;; +esac], [install_library=false]) +AM_CONDITIONAL([INSTALL_LIBRARY], [test x$install_library = xtrue]) + +# For building documentation +# +AC_PATH_PROG(GENGETOPT, gengetopt) +AM_CONDITIONAL(NO_GENGETOPT, test -z "$ac_cv_path_GENGETOPT" ) +AC_PATH_PROG(HELP2MAN, help2man) +AM_CONDITIONAL(NO_HELP2MAN, test -z "$ac_cv_path_HELP2MAN" ) +AC_PATH_PROG(GROFF, groff) +AM_CONDITIONAL(NO_GROFF, test -z "$ac_cv_path_GROFF" ) +AC_PATH_PROG(PS2PDF, ps2pdf) +AM_CONDITIONAL(NO_PS2PDF, test -z "$ac_cv_path_PS2PDF" ) + +AC_LANG([C++]) +AC_PROG_CXX +AC_PROG_CC +AM_PROG_LEX +AC_PROG_YACC +AC_PROG_LIBTOOL +AC_DISABLE_SHARED + +# libhpdf is used for pdf output +# libhpdf needs -lhpdf -lpng -lz -lm +AC_CHECK_HEADER([hpdf.h], [],[AC_MSG_ERROR([hpdf.h include file not found])]) +AC_CHECK_LIB([m], [sqrt]) +AC_CHECK_LIB([z], [deflate], [], [AC_ERROR([libz library not found])]) +AC_CHECK_LIB([png], [png_read_info]) +AC_CHECK_LIB([hpdf], [HPDF_New], [], [AC_ERROR([libhpdf library not found])]) + +AC_OUTPUT +# not truncated diff --git a/hyp2mat/doc/.gitignore b/hyp2mat/doc/.gitignore new file mode 100644 index 0000000..a42dc1e --- /dev/null +++ b/hyp2mat/doc/.gitignore @@ -0,0 +1,2 @@ +hyp2mat.1 +hyp2mat.pdf diff --git a/hyp2mat/doc/Makefile.am b/hyp2mat/doc/Makefile.am new file mode 100644 index 0000000..e423936 --- /dev/null +++ b/hyp2mat/doc/Makefile.am @@ -0,0 +1,44 @@ +# used by automake + +# +# man page and friends +# + +dist_man_MANS=hyp2mat.1 +dist_DATA=hyp2mat.pdf +distdir=$(pkgdatadir) + +PROGNAME = $(top_builddir)/src/hyp2mat$(EXEEXT) + +# create man page from --help output + +if NO_HELP2MAN +hyp2mat.1: hyp2mat.h2m $(top_srcdir)/src/cmdline.ggo + touch $@ +else +hyp2mat.1: hyp2mat.h2m $(top_srcdir)/src/cmdline.ggo + -$(HELP2MAN) --output=$@ --no-info --include=$< $(PROGNAME) +endif + +# +# pdf man page, mainly for Windows users +# + +if NO_GROFF +hyp2mat.pdf: hyp2mat.1 + touch $@ +else +if NO_PS2PDF +hyp2mat.pdf: hyp2mat.1 + touch $@ +else +hyp2mat.pdf: hyp2mat.1 + -$(GROFF) -Tps -man hyp2mat.1 | $(PS2PDF) - hyp2mat.pdf +endif +endif + +EXTRA_DIST=hyp2mat.h2m hyp2mat.pdf + +CLEANFILES=hyp2mat.1 hyp2mat.pdf + +#not truncated diff --git a/hyp2mat/doc/hyp2mat.h2m b/hyp2mat/doc/hyp2mat.h2m new file mode 100644 index 0000000..b8ddeef --- /dev/null +++ b/hyp2mat/doc/hyp2mat.h2m @@ -0,0 +1,144 @@ +[NAME] +hyp2mat \- convert hyperlynx files to octave/matlab scripts for electromagnetic simulation. + +/scripts./ +.SH OPTIONS + +/Print board summary/ + +Hyperlynx input files conventionally end in +.BR .hyp +\&. + +.I hyp2mat +reads input from file +.IB infile . +If no input file is specified input is read from standard in. + +If no output file is specified output is to standard out. + +If a syntax error occurs during conversion, error recovery is attempted. +.I hyp2mat +exits with zero status if conversion was succesful and non-zero if not. + +The +.BR --verbose +option can be used to list board dimensions. + +If only a small region of the board needs to be simulated the +.BR --xmin +.BR --xmax +.BR --ymin +.BR --ymax +.BR --zmin +and +.BR --zmax +options can be used to crop the board to a smaller region. + +If not all layers of the board need to be simulated, the +.BR --layers +option may be used to specify layers of interest. + +If not all nets of the board need to be simulated, the +.BR --nets +option may be used to specify nets of interest. +The option +.BR --net=? +lists all available nets. + +Circles and arcs are approximated by polygons. By default a circle is approximated by an octagon. If higher accuracy is needed, set +.BR --arc-precision +to the desired precision. This will increase the number of line segments used to draw circular, oval and oblong pads, amongst others. + +To simulate a lossy dielectric, copy AddHyperLynxDielectric.m to your project directory and customize. + +The +.BR --flood +option floods layers with copper. +The flooded copper respects trace-to-plane clearances. +Copper net name is identical to layer name. + +Typical use of +.I hyp2mat +is with simulation packages such as OpenEMS. + +[EXAMPLES] +Convert pcb.hyp to pdf: +.nf +hyp2mat -o pcb.pdf pcb.hyp +.ni + +Examine original Hyperlynx file: +.nf +hyp2mat -o pcb.pdf --raw pcb.hyp +.ni + +Draw arcs with an accuracy of 10 mil or better: +.nf +hyp2mat -o pcb.pdf --arc-precision 0.000254 pcb.hyp +.ni + +[NOTES] +Board outlines and copper polygons should not be self-intersecting. + +Common causes of syntax errors are unquoted strings, and unassigned component values. + +.SS Unquoted strings +.IP "Error:" +.I syntax error, unexpected STRING at 'Logo' + +.IP "Source:" +.nf +(? REF=My Logo BOT1 L=Bottom_Layer) +.fi + +.IP Cause: +An unquoted string contains a space (' '). + +.IP Solution: +Edit the .hyp file and put the string between double quotes: +.nf +(? REF="My Logo BOT1" L=Bottom_Layer) +.fi + +.SS Unassigned component values +.IP "Error:" +.I syntax error, unexpected L, expecting FLOAT or STRING at 'L' + +.IP "Source:" +.nf +(R REF="R1" VAL= L="Top") +.fi + +.IP Cause: +Component has not been assigned a value (VAL=). + +.IP Solution: +Edit the .hyp file and assign a value to resistor R1: +.nf +(R REF="R1" VAL=0 L="Top") +.fi +or assign the resistor a value in the schematics editor and re-export to HyperLynx. + +[FILES] +.B /usr/share/hyp2mat/matlab/ +.br +.ns +Supporting matlab routines for OpenEMS. + +.B /usr/share/hyp2mat/eagle/ +.br +.ns +Examples and tutorial. + +[AUTHOR] +.nf +Koen De Vleeschauwer, http://www.kdvelectronics.eu +.ni + +[SEE ALSO] +.IR octave (1) +.br +.IR "OpenEMS" , +a free and open-source electromagnetic field solver using the FDTD method. + diff --git a/hyp2mat/eagle/Makefile.am b/hyp2mat/eagle/Makefile.am new file mode 100644 index 0000000..e375f6d --- /dev/null +++ b/hyp2mat/eagle/Makefile.am @@ -0,0 +1,40 @@ +eagledir = $(pkgdatadir)/eagle +dist_eagle_DATA = README_eagle.txt + +hairpinfilterdir = $(eagledir)/hairpinfilter +dist_hairpinfilter_DATA = \ + hairpinfilter/hairpinfilter_board.png \ + hairpinfilter/hairpinfilter.HYP \ + hairpinfilter/README.txt \ + hairpinfilter/hairpinfilter.pdf \ + hairpinfilter/hairpinfilter.sch \ + hairpinfilter/demo_hairpin.m \ + hairpinfilter/hairpinfilter.brd \ + hairpinfilter/hairpinfilter_simulation.png + + +tutorialdir = $(eagledir)/tutorial +dist_tutorial_DATA = \ + tutorial/msl.brd \ + tutorial/GetUnits.m \ + tutorial/msl.lbr \ + tutorial/README.txt \ + tutorial/msl.patch \ + tutorial/msl.pdf \ + tutorial/msl.sch \ + tutorial/sparam.png \ + tutorial/msl.HYP \ + tutorial/GetEpsilon.m \ + tutorial/tutorial_hyp2mat.m + +notchfilterdir = $(eagledir)/notchfilter +dist_notchfilter_DATA = \ + notchfilter/demo_notch.m \ + notchfilter/notchfilter.pdf \ + notchfilter/notchfilter.sch \ + notchfilter/README.txt \ + notchfilter/notchfilter_simulation.png \ + notchfilter/notchfilter_board.png \ + notchfilter/notchfilter.brd \ + notchfilter/notchfilter.HYP + diff --git a/hyp2mat/eagle/README_eagle.txt b/hyp2mat/eagle/README_eagle.txt new file mode 100644 index 0000000..b6f9e43 --- /dev/null +++ b/hyp2mat/eagle/README_eagle.txt @@ -0,0 +1,10 @@ +The eagle subdirectory contains two sample boards, created with Cadsoft Eagle. + +The boards were exported from Eagle to HyperLynx format using hyperlynx.ulp, a script in Eagle User Language. + +The hyperlynx.ulp script used can be downloaded from http://www.cadsoftusa.com/downloads/ulps?language=en + +To export a bord in hyperlynx format, in Eagle first run "ratsnest" then "run hyperlynx". + +koen +14.11.12 diff --git a/hyp2mat/eagle/hairpinfilter/README.txt b/hyp2mat/eagle/hairpinfilter/README.txt new file mode 100644 index 0000000..93b00aa --- /dev/null +++ b/hyp2mat/eagle/hairpinfilter/README.txt @@ -0,0 +1,26 @@ +This directory is a demo of a hairpin filter. +It contains the following files: + +demo_hairpin.m matlab simulation script +hairpinfilter.sch CADsoft Eagle schematic +hairpinfilter.brd CADsoft Eagle board +hairpinfilter.HYP board exported to hyperlynx +hairpinfilter_board.png screenshot of board after import in CSXCAD +hairpinfilter_simulation.png openEMS simulation output +README.txt this file + +To run the demo, first install and configure matlab or octave, CSXCAD, openEMS and hyp2mat. +Copy the demo files to a directory where you have read and write access. +Start up matlab or octave from that directory, and type 'demo_hairpin'. +When the AppCSXCAD window appears, exit AppCSXCAD. +After a few minutes simulation output should appear. + +On Linux: + +cd +mkdir demo +cp /usr/share/hyp2mat/eagle/hairpinfilter/* demo/ +cd demo +octave +demo_hairpin + diff --git a/hyp2mat/eagle/hairpinfilter/demo_hairpin.m b/hyp2mat/eagle/hairpinfilter/demo_hairpin.m new file mode 100644 index 0000000..ebe4bd8 --- /dev/null +++ b/hyp2mat/eagle/hairpinfilter/demo_hairpin.m @@ -0,0 +1,109 @@ +% demo for hyp2mat - simulation of a hairpin filter. +% +% run from openems matlab command prompt +% See hyp2mat(1) - convert hyperlynx files to matlab scripts. + +% (C) 2011,2012 Thorsten Liebig +% Copyright 2012 Koen De Vleeschauwer. +% +% This file is part of hyp2mat. +% +% 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 . + +close all +clear +clc + +% initialize +physical_constants; +unit = 1; % this pcb has units in meters. +fc= 1.1e9; % center frequency +f0= 1.0e9; % estimated 20db frequency +substrate_epr = 4.8; +resolution = c0 / (f0+fc) / sqrt(substrate_epr) / unit / 25; +hypfilename = 'hairpinfilter.HYP'; + +AirBox = c0/(f0+fc)/unit/25; + +% set up FTDT +FDTD = InitFDTD(); +FDTD = SetGaussExcite( FDTD, f0, fc ); +BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +% create 3d model +CSX = InitCSX(); +disp([ 'loading ' hypfilename ]); +CSX = ImportHyperLynx(CSX, hypfilename); + +mesh = DetectEdges(CSX); + +% get the coordinates of the ports. +% 'TP1.TP' is pin 'TP' of test point 'TP1'. (See schematic) +[port1_material, port1_start, port1_stop] = GetHyperLynxPort(CSX, 'TP1.TP'); +[port2_material, port2_start, port2_stop] = GetHyperLynxPort(CSX, 'TP5.TP'); + +port1_stop(3)=mesh.z(1); % port goes all the way to the ground plane +[CSX, port{1}] = AddLumpedPort( CSX, 999, 1, 50 , port1_start, port1_stop, [0 0 -1], true); + +port2_stop(3)=mesh.z(1); % port goes all the way to the ground plane +[CSX, port{2}] = AddLumpedPort( CSX, 999, 2, 50, port2_start, port2_stop, [0 0 -1]); + +% re-run DetectEdges to add the lumped ports to the mesh +mesh = DetectEdges(CSX); + +% add air-box around the imported structure +mesh.x = [min(mesh.x)-AirBox max(mesh.x)+AirBox mesh.x]; +mesh.y = [min(mesh.y)-AirBox max(mesh.y)+AirBox mesh.y]; +mesh.z = [min(mesh.z)-AirBox max(mesh.z)+2*AirBox mesh.z]; + +mesh = SmoothMesh(mesh, resolution); + +% add 8 additional cells for the pml +mesh = AddPML(mesh, 8); + +CSX = DefineRectGrid(CSX, unit, mesh); + +% write/show/run the openEMS compatible xml-file + +Sim_Path = 'tmp'; +Sim_CSX = 'msl.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +disp([ 'Estimated simulation runtime: 25000 timesteps' ]); % inform user this may take a while... +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +RunOpenEMS( Sim_Path, Sim_CSX ); + +%% post-processing +close all +f = linspace( 1e6, 2e9, 1601 ); +port = calcPort( port, Sim_Path, f, 'RefImpedance', 50); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; + +plot(f/1e9,20*log10(abs(s11)),'k-','LineWidth',2); +hold on; +grid on; +plot(f/1e9,20*log10(abs(s21)),'r--','LineWidth',2); +legend('S_{11}','S_{21}'); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (GHz) \rightarrow','FontSize',12); +ylim([-60 2]); +print ('hairpinfilter_simulation.png', '-dpng'); + +% not truncated diff --git a/hyp2mat/eagle/hairpinfilter/hairpinfilter.brd b/hyp2mat/eagle/hairpinfilter/hairpinfilter.brd new file mode 100644 index 0000000..ff18c65 --- /dev/null +++ b/hyp2mat/eagle/hairpinfilter/hairpinfilter.brd @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hairpin filter +(c) 2012 Koen De Vleeschauwer. Licensed under GPL. +See "Recipes for printed hairpin filters", by Paul Wade, W1GHZ + + + + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + + + + + + + + + + + +<b>EAGLE Design Rules</b> +<p> +Die Standard-Design-Rules sind so gewählt, dass sie für +die meisten Anwendungen passen. Sollte ihre Platine +besondere Anforderungen haben, treffen Sie die erforderlichen +Einstellungen hier und speichern die Design Rules unter +einem neuen Namen ab. +<b>EAGLE Design Rules</b> +<p> +The default Design Rules have been set to cover +a wide range of applications. Your particular design +may have different requirements, so please make the +necessary adjustments and save your customized +design rules under a new name. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hyp2mat/eagle/hairpinfilter/hairpinfilter.pdf b/hyp2mat/eagle/hairpinfilter/hairpinfilter.pdf new file mode 100644 index 0000000..1a9cb82 Binary files /dev/null and b/hyp2mat/eagle/hairpinfilter/hairpinfilter.pdf differ diff --git a/hyp2mat/eagle/hairpinfilter/hairpinfilter.sch b/hyp2mat/eagle/hairpinfilter/hairpinfilter.sch new file mode 100644 index 0000000..e502312 Binary files /dev/null and b/hyp2mat/eagle/hairpinfilter/hairpinfilter.sch differ diff --git a/hyp2mat/eagle/hairpinfilter/hairpinfilter_board.png b/hyp2mat/eagle/hairpinfilter/hairpinfilter_board.png new file mode 100644 index 0000000..a8070bc Binary files /dev/null and b/hyp2mat/eagle/hairpinfilter/hairpinfilter_board.png differ diff --git a/hyp2mat/eagle/hairpinfilter/hairpinfilter_simulation.png b/hyp2mat/eagle/hairpinfilter/hairpinfilter_simulation.png new file mode 100644 index 0000000..3d08885 Binary files /dev/null and b/hyp2mat/eagle/hairpinfilter/hairpinfilter_simulation.png differ diff --git a/hyp2mat/eagle/notchfilter/README.txt b/hyp2mat/eagle/notchfilter/README.txt new file mode 100644 index 0000000..9c5fcbe --- /dev/null +++ b/hyp2mat/eagle/notchfilter/README.txt @@ -0,0 +1,26 @@ +This directory is a demo of a notch filter. +It contains the following files: + +demo_notch.m matlab simulation script +notchfilter.sch CADsoft Eagle schematic +notchfilter.brd CADsoft Eagle board +notchfilter.HYP board exported to hyperlynx +notchfilter_board.png screenshot of board after import in CSXCAD +notchfilter_simulation.png openEMS simulation output +README.txt this file + +To run the demo, first install and configure matlab or octave, CSXCAD, openEMS and hyp2mat. +Copy the demo files to a directory where you have read and write access. +Start up matlab or octave from that directory, and type 'demo_notch'. +When the AppCSXCAD window appears, exit AppCSXCAD. +After a few minutes simulation output should appear. + +On Linux: + +cd +mkdir demo +cp /usr/share/hyp2mat/eagle/notchfilter/* demo/ +cd demo +octave +demo_notch + diff --git a/hyp2mat/eagle/notchfilter/demo_notch.m b/hyp2mat/eagle/notchfilter/demo_notch.m new file mode 100644 index 0000000..fa9cdaf --- /dev/null +++ b/hyp2mat/eagle/notchfilter/demo_notch.m @@ -0,0 +1,109 @@ +% demo for hyp2mat - simulation of a notch filter. +% +% run from openems matlab command prompt +% See hyp2mat(1) - convert hyperlynx files to matlab scripts. + +% (C) 2011,2012 Thorsten Liebig +% Copyright 2012 Koen De Vleeschauwer. +% +% This file is part of hyp2mat. +% +% 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 . + +close all +clear +clc + +% initialize +physical_constants; +unit = 1; % this pcb has units in meter. +f_max = 7e9; +substrate_epr = 4.8; +resolution = c0 / f_max / sqrt(substrate_epr) / unit / 25; +hypfilename = 'notchfilter.HYP'; + +AirBox = c0/f_max/unit/4; + +% set up FTDT +FDTD = InitFDTD(); +FDTD = SetGaussExcite( FDTD, f_max/2, f_max/2 ); +BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +% create 3d model +CSX = InitCSX(); +disp([ 'loading ' hypfilename ]); +CSX = ImportHyperLynx(CSX, hypfilename); + +mesh = DetectEdges(CSX); + +% get the coordinates of the ports. +% 'TP1.TP' is pin 'TP' of test point 'TP1'. (See schematic) +[port1_material, port1_start, port1_stop] = GetHyperLynxPort(CSX, 'TP1.TP'); +[port2_material, port2_start, port2_stop] = GetHyperLynxPort(CSX, 'TP3.TP'); + +port1_stop(3)=mesh.z(1); % port goes all the way to the ground plane +[CSX, port{1}] = AddLumpedPort( CSX, 999, 1, 50 , port1_start, port1_stop, [0 0 -1], true); + +port2_stop(3)=mesh.z(1); % port goes all the way to the ground plane +[CSX, port{2}] = AddLumpedPort( CSX, 999, 2, 50, port2_start, port2_stop, [0 0 -1]); + +% re-run DetectEdges to add include the lumped ports in the mesh. +mesh = DetectEdges(CSX); + +% add air-box around the imported structure +mesh.x = [min(mesh.x)-AirBox max(mesh.x)+AirBox mesh.x]; +mesh.y = [min(mesh.y)-AirBox max(mesh.y)+AirBox mesh.y]; +mesh.z = [min(mesh.z)-AirBox max(mesh.z)+2*AirBox mesh.z]; + +mesh = SmoothMesh(mesh, resolution); + +% add 8 additional cells for the pml +mesh = AddPML(mesh, 8); + +CSX = DefineRectGrid(CSX, unit, mesh); + +% write/show/run the openEMS compatible xml-file + +Sim_Path = 'tmp'; +Sim_CSX = 'msl.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +disp([ 'Estimated simulation runtime: 2500 timesteps' ]); % inform user this may take a while... + +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +RunOpenEMS( Sim_Path, Sim_CSX ); + +%% post-processing +close all +f = linspace( 1e6, f_max, 1601 ); +port = calcPort( port, Sim_Path, f, 'RefImpedance', 50); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; + +plot(f/1e9,20*log10(abs(s11)),'k-','LineWidth',2); +hold on; +grid on; +plot(f/1e9,20*log10(abs(s21)),'r--','LineWidth',2); +legend('S_{11}','S_{21}'); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (GHz) \rightarrow','FontSize',12); +ylim([-40 2]); +print ('notchfilter_simulation.png', '-dpng'); + +% not truncated diff --git a/hyp2mat/eagle/notchfilter/notchfilter.brd b/hyp2mat/eagle/notchfilter/notchfilter.brd new file mode 100644 index 0000000..3f20e9e Binary files /dev/null and b/hyp2mat/eagle/notchfilter/notchfilter.brd differ diff --git a/hyp2mat/eagle/notchfilter/notchfilter.pdf b/hyp2mat/eagle/notchfilter/notchfilter.pdf new file mode 100644 index 0000000..a39d114 Binary files /dev/null and b/hyp2mat/eagle/notchfilter/notchfilter.pdf differ diff --git a/hyp2mat/eagle/notchfilter/notchfilter.sch b/hyp2mat/eagle/notchfilter/notchfilter.sch new file mode 100644 index 0000000..746fd2d Binary files /dev/null and b/hyp2mat/eagle/notchfilter/notchfilter.sch differ diff --git a/hyp2mat/eagle/notchfilter/notchfilter_board.png b/hyp2mat/eagle/notchfilter/notchfilter_board.png new file mode 100644 index 0000000..4f73ef5 Binary files /dev/null and b/hyp2mat/eagle/notchfilter/notchfilter_board.png differ diff --git a/hyp2mat/eagle/notchfilter/notchfilter_simulation.png b/hyp2mat/eagle/notchfilter/notchfilter_simulation.png new file mode 100644 index 0000000..f100deb Binary files /dev/null and b/hyp2mat/eagle/notchfilter/notchfilter_simulation.png differ diff --git a/hyp2mat/eagle/tutorial/GetEpsilon.m b/hyp2mat/eagle/tutorial/GetEpsilon.m new file mode 100644 index 0000000..4ad7fb9 --- /dev/null +++ b/hyp2mat/eagle/tutorial/GetEpsilon.m @@ -0,0 +1,59 @@ +% epsilon = GetEpsilon(CSX) +% +% Obtain dielectric constant of CSX model +% +% See hyp2mat(1) - convert hyperlynx files to matlab scripts. + +% Copyright 2012 Koen De Vleeschauwer. +% +% This file is part of hyp2mat. +% +% 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 . + + +function epsilon = GetEpsilon(CSX) + + if (~isstruct(CSX)) + error ('CSX struct expected'); + end + + if (~isfield(CSX, 'RectilinearGrid')) + error('CSX does not have a rectilinear grid'); + end + + % + % Iterate over CSX and return maximum epsilon. + % Maximum epsilon determines smallest resolution. + % + epsilon = 1; + if (~isfield(CSX, 'Properties')) + error ('CSX struct expected'); + end + if (isstruct(CSX.Properties)) + prop_fn = fieldnames(CSX.Properties); + for p = 1:length(prop_fn) + property = CSX.Properties.(prop_fn{p}); + for m = 1:length(property) + material=property{m}; + if (isfield(material, 'Property') && isfield(material.Property, 'ATTRIBUTE') && isfield(material.Property.ATTRIBUTE, 'Epsilon')) + if (material.Property.ATTRIBUTE.Epsilon > epsilon) + epsilon = material.Property.ATTRIBUTE.Epsilon; + end + end + end + end + end + +end +%not truncated diff --git a/hyp2mat/eagle/tutorial/GetUnits.m b/hyp2mat/eagle/tutorial/GetUnits.m new file mode 100644 index 0000000..02f0160 --- /dev/null +++ b/hyp2mat/eagle/tutorial/GetUnits.m @@ -0,0 +1,38 @@ +% units = GetUnits(CSX) +% +% returns CSX rectangular grid units. +% +% See hyp2mat(1) - convert hyperlynx files to matlab scripts. + +% Copyright 2012 Koen De Vleeschauwer. +% +% This file is part of hyp2mat. +% +% 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 . + + +function units = GetUnits(CSX) + + if (~isstruct(CSX)) + error ('CSX struct expected'); + end + + if (~isfield(CSX, 'RectilinearGrid')) + error('CSX does not have a rectilinear grid'); + end + + units = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit; + +end +%not truncated diff --git a/hyp2mat/eagle/tutorial/README.txt b/hyp2mat/eagle/tutorial/README.txt new file mode 100644 index 0000000..a4b8a4c --- /dev/null +++ b/hyp2mat/eagle/tutorial/README.txt @@ -0,0 +1,10 @@ +Tutorial for hyp2mat. + +To run the demo, first install and configure matlab or octave, CSXCAD, openEMS and hyp2mat. +Copy the tutorial files to a directory where you have read and write access. +Start up matlab or octave from that directory, and type 'tutorial_hyp2mat'. +When the AppCSXCAD window appears, exit AppCSXCAD. +After a few minutes simulation output should appear. + +Further documentation is at http://www.openems.de, under "Tutorial: Importing with hyp2mat" + diff --git a/hyp2mat/eagle/tutorial/msl.brd b/hyp2mat/eagle/tutorial/msl.brd new file mode 100644 index 0000000..a173021 --- /dev/null +++ b/hyp2mat/eagle/tutorial/msl.brd @@ -0,0 +1,329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>Ceramic Chip Capacitor KEMET 0204 reflow solder</b><p> +Metric Code Size 1005 + + + + +>NAME +>VALUE + + + + + + + + + + + + + + + +<b>EAGLE Design Rules</b> +<p> +Die Standard-Design-Rules sind so gewählt, dass sie für +die meisten Anwendungen passen. Sollte ihre Platine +besondere Anforderungen haben, treffen Sie die erforderlichen +Einstellungen hier und speichern die Design Rules unter +einem neuen Namen ab. +<b>EAGLE Design Rules</b> +<p> +The default Design Rules have been set to cover +a wide range of applications. Your particular design +may have different requirements, so please make the +necessary adjustments and save your customized +design rules under a new name. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hyp2mat/eagle/tutorial/msl.lbr b/hyp2mat/eagle/tutorial/msl.lbr new file mode 100644 index 0000000..ee32673 --- /dev/null +++ b/hyp2mat/eagle/tutorial/msl.lbr @@ -0,0 +1,3070 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>Ceramic Chip Capacitor KEMET 0204 reflow solder</b><p> +Metric Code Size 1005 + + + + +>NAME +>VALUE + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b><p> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 2.4 x 4.4 mm + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 2.5 x 5 mm + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 3 x 5 mm + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 4 x 5 mm + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 5 x 5 mm + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 6 x 5 mm + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm + 5 mm, outline 2.4 x 7 mm + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 + 5 mm, outline 2.5 x 7.5 mm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 + 5 mm, outline 3.5 x 7.5 mm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 + 5 mm, outline 4.5 x 7.5 mm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 + 5 mm, outline 5.5 x 7.5 mm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 2.4 x 4.4 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 2.5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 4.5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 3 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 5.5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 7.5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +Horizontal, grid 5 mm, outline 7.5 x 7.5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>CAPACITOR</b><p> +grid 7.5 mm, outline 3.2 x 10.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 7.5 mm, outline 4.2 x 10.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 7.5 mm, outline 5.2 x 10.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 10.2 mm, outline 4.3 x 13.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 10.2 mm, outline 5.4 x 13.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 10.2 mm, outline 6.4 x 13.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 10.2 mm + 15.2 mm, outline 6.2 x 18.4 mm + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 15 mm, outline 5.4 x 18.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 15 mm, outline 6.4 x 18.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 15 mm, outline 7.2 x 18.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 15 mm, outline 8.4 x 18.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 15 mm, outline 9.1 x 18.2 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 22.5 mm, outline 6.2 x 26.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 22.5 mm, outline 7.4 x 26.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 22.5 mm, outline 8.7 x 26.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 22.5 mm, outline 10.8 x 26.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 22.5 mm, outline 11.3 x 26.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 9.3 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 11.3 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 13.4 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 20.5 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 32.5 mm, outline 13.7 x 37.4 mm + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 32.5 mm, outline 16.2 x 37.4 mm + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 32.5 mm, outline 18.2 x 37.4 mm + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 37.5 mm, outline 19.2 x 41.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 37.5 mm, outline 20.3 x 41.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 3.5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 37.5 mm, outline 15.5 x 41.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 7.5 mm, outline 6.3 x 10.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 15.4 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 17.3 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>Ceramic Chip Capacitor KEMET 0603 reflow solder</b><p> +Metric Code Size 1608 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 0805 reflow solder</b><p> +Metric Code Size 2012 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 1206 reflow solder</b><p> +Metric Code Size 3216 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 1210 reflow solder</b><p> +Metric Code Size 3225 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 1812 reflow solder</b><p> +Metric Code Size 4532 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 1825 reflow solder</b><p> +Metric Code Size 4564 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 2220 reflow solder</b><p>Metric Code Size 5650 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 2225 reflow solder</b><p>Metric Code Size 5664 + + + + +>NAME +>VALUE + + + + +<b> </b><p> +Source: http://www.vishay.com/docs/10129/hpc0201a.pdf + + +>NAME +>VALUE + + + +Source: http://www.avxcorp.com/docs/catalogs/cx5r.pdf + + +>NAME +>VALUE + + + + + + +<b>CAPACITOR</b><p> +Source: AVX .. aphvc.pdf + + + + +>NAME +>VALUE + + + + +<b>CAPACITOR</b><p> +Source: AVX .. aphvc.pdf + + + + +>NAME +>VALUE + + + + +<b>TEST PAD</b> + + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + + + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + + + + + +>VALUE + + + + + +>NAME +>VALUE + + + + + + + + + + +>NAME +>TP_SIGNAL_NAME + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<B>CAPACITOR</B>, European symbol + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>Test pad</b> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hyp2mat/eagle/tutorial/msl.patch b/hyp2mat/eagle/tutorial/msl.patch new file mode 100644 index 0000000..21d3fde --- /dev/null +++ b/hyp2mat/eagle/tutorial/msl.patch @@ -0,0 +1,24 @@ +*** msl.HYP.ORIG 2012-12-03 18:47:03.567775824 +0100 +--- msl.HYP 2012-12-03 18:50:55.191769514 +0100 +*************** +*** 28,36 **** + * Thickness of Copper and Dielectric Layer Data + * + {STACKUP +! (SIGNAL T=0.00070 P=0.00070 L=Top) +! (DIELECTRIC T=0.05970 C=4.80000 L=DL01) +! (SIGNAL T=0.00070 P=0.00070 L=Bottom) + } + * Total Board Thickness 0.0625 inch + +--- 28,37 ---- + * Thickness of Copper and Dielectric Layer Data + * + {STACKUP +! (SIGNAL T=0.00140 P=0.00140 L=Top) +! (DIELECTRIC T=0.01259 C=4.80000 L=DL01) +! (SIGNAL T=0.00140 P=0.00140 L=Bottom) +! (DIELECTRIC T=0.05970 C=4.80000 L=DL02) + } + * Total Board Thickness 0.0625 inch + diff --git a/hyp2mat/eagle/tutorial/msl.pdf b/hyp2mat/eagle/tutorial/msl.pdf new file mode 100644 index 0000000..feecf61 --- /dev/null +++ b/hyp2mat/eagle/tutorial/msl.pdf @@ -0,0 +1,138 @@ +%PDF-1.3 +%·¾­ª +1 0 obj +<< +/Type /Catalog +/Pages 2 0 R +>> +endobj +2 0 obj +<< +/Type /Pages +/Kids [ 5 0 R 8 0 R 11 0 R ] +/Count 3 +>> +endobj +3 0 obj +<< +/Producer (Haru Free PDF Library 2.2.1) +/Creator (hyp2mat) +>> +endobj +4 0 obj +<< +/Type /Font +/BaseFont /Helvetica +/Subtype /Type1 +/Encoding /StandardEncoding +>> +endobj +5 0 obj +<< +/Type /Page +/MediaBox [ 0 0 76.69292 86.69292 ] +/Contents 6 0 R +/Resources << +/ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +/Font << +/F1 4 0 R +>> +>> +/Parent 2 0 R +>> +endobj +6 0 obj +<< +/Length 7 0 R +/Filter [ /FlateDecode ] +>> +stream +xœu“ËNÄ0 E÷ùŠ,acâ8vâ-Ø3ýÞêh ñû$i’ª­úÐõ©®í©Îþ™›´èìðjn“Eõêíðl®îNǯÓÏÇï˵>Íý`œ-×ÓãE|¿‹Ì–c©ò=šŠ–U£y7ã@­’ó«t]€ÒÝCR¤`… 9äXf̬Š> +>> +/Parent 2 0 R +>> +endobj +9 0 obj +<< +/Length 10 0 R +/Filter [ /FlateDecode ] +>> +stream +xœmÝ +Â0 …ïó¹Ô›˜þ¥ëí@½×>‚Ì!øú6è:£¥œ|IÏ0~àt1hsm†"¢$›,æÚiž§ñˆùç Œzn׿x?u^–ùQ«r¨h[U1@w`JÈää÷¨ë¨»¥&çQ5lBÔŒ…UQ–ö«BS'ã-ºD‰C0ÅÑ[bgŠ† Å&ªÝú±¢º|ØnCÞ +endstream +endobj +10 0 obj +166 +endobj +11 0 obj +<< +/Type /Page +/MediaBox [ 0 0 76.69292 86.69292 ] +/Contents 12 0 R +/Resources << +/ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] +/Font << +/F1 4 0 R +>> +>> +/Parent 2 0 R +>> +endobj +12 0 obj +<< +/Length 13 0 R +/Filter [ /FlateDecode ] +>> +stream +xœu’ÁN! †ï} +Žz©´¥@¯&ê]y³³FãÅ×·˜†ÍÌHÚþ…ŸÃ/Ü=R Ú îxP2fcãÐ^á¦}}߆ö bèãùéü¼õâ¼öÌçºÎFp†wxˆ’CDû_½éœ{o©h‰Š1ßÉ&~ÂÊ*¦ZɼWg$bGŒc*|a‹vË + +«Ug‰0IfÞg«6RV¿ó[î2k·lñÖßDY=»r<ت&Eå¢ùˆ w“vËVw%ªûlÒ:+¦rÄÆëOÚ-›ŸvþÔÖB‚¨ +endstream +endobj +13 0 obj +220 +endobj +xref +0 14 +0000000000 65535 f +0000000015 00000 n +0000000064 00000 n +0000000136 00000 n +0000000216 00000 n +0000000314 00000 n +0000000500 00000 n +0000000865 00000 n +0000000884 00000 n +0000001070 00000 n +0000001316 00000 n +0000001336 00000 n +0000001524 00000 n +0000001825 00000 n +trailer +<< +/Root 1 0 R +/Info 3 0 R +/Size 14 +>> +startxref +1845 +%%EOF diff --git a/hyp2mat/eagle/tutorial/msl.sch b/hyp2mat/eagle/tutorial/msl.sch new file mode 100644 index 0000000..6492dfd --- /dev/null +++ b/hyp2mat/eagle/tutorial/msl.sch @@ -0,0 +1,3138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<b>TEST PAD</b> + + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + + + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + + +>NAME +>VALUE +>TP_SIGNAL_NAME + + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>TEST PAD</b> + +>NAME +>VALUE +>TP_SIGNAL_NAME + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b><p> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b> + + + + + + + + +>NAME +>VALUE + + + + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 2.4 x 4.4 mm + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 2.5 x 5 mm + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 3 x 5 mm + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 4 x 5 mm + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 5 x 5 mm + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm, outline 6 x 5 mm + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 mm + 5 mm, outline 2.4 x 7 mm + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 + 5 mm, outline 2.5 x 7.5 mm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 + 5 mm, outline 3.5 x 7.5 mm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 + 5 mm, outline 4.5 x 7.5 mm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 2.5 + 5 mm, outline 5.5 x 7.5 mm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 2.4 x 4.4 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 2.5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 4.5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 3 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 5.5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 7.5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +Horizontal, grid 5 mm, outline 7.5 x 7.5 mm + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + + + +<b>CAPACITOR</b><p> +grid 7.5 mm, outline 3.2 x 10.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 7.5 mm, outline 4.2 x 10.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 7.5 mm, outline 5.2 x 10.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 10.2 mm, outline 4.3 x 13.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 10.2 mm, outline 5.4 x 13.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 10.2 mm, outline 6.4 x 13.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 10.2 mm + 15.2 mm, outline 6.2 x 18.4 mm + + + + + + + + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 15 mm, outline 5.4 x 18.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 15 mm, outline 6.4 x 18.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 15 mm, outline 7.2 x 18.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 15 mm, outline 8.4 x 18.3 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 15 mm, outline 9.1 x 18.2 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 22.5 mm, outline 6.2 x 26.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 22.5 mm, outline 7.4 x 26.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 22.5 mm, outline 8.7 x 26.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 22.5 mm, outline 10.8 x 26.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 22.5 mm, outline 11.3 x 26.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 9.3 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 11.3 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 13.4 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 20.5 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 32.5 mm, outline 13.7 x 37.4 mm + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 32.5 mm, outline 16.2 x 37.4 mm + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 32.5 mm, outline 18.2 x 37.4 mm + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 37.5 mm, outline 19.2 x 41.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 37.5 mm, outline 20.3 x 41.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 5 mm, outline 3.5 x 7.5 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 37.5 mm, outline 15.5 x 41.8 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 7.5 mm, outline 6.3 x 10.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 15.4 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>CAPACITOR</b><p> +grid 27.5 mm, outline 17.3 x 31.6 mm + + + + + + + + + + + + + + + + +>NAME +>VALUE + + +<b>Ceramic Chip Capacitor KEMET 0204 reflow solder</b><p> +Metric Code Size 1005 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 0603 reflow solder</b><p> +Metric Code Size 1608 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 0805 reflow solder</b><p> +Metric Code Size 2012 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 1206 reflow solder</b><p> +Metric Code Size 3216 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 1210 reflow solder</b><p> +Metric Code Size 3225 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 1812 reflow solder</b><p> +Metric Code Size 4532 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 1825 reflow solder</b><p> +Metric Code Size 4564 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 2220 reflow solder</b><p>Metric Code Size 5650 + + + + +>NAME +>VALUE + + + + +<b>Ceramic Chip Capacitor KEMET 2225 reflow solder</b><p>Metric Code Size 5664 + + + + +>NAME +>VALUE + + + + +<b> </b><p> +Source: http://www.vishay.com/docs/10129/hpc0201a.pdf + + +>NAME +>VALUE + + + +Source: http://www.avxcorp.com/docs/catalogs/cx5r.pdf + + +>NAME +>VALUE + + + + + + +<b>CAPACITOR</b><p> +Source: AVX .. aphvc.pdf + + + + +>NAME +>VALUE + + + + +<b>CAPACITOR</b><p> +Source: AVX .. aphvc.pdf + + + + +>NAME +>VALUE + + + + + + + + + +>VALUE + + + + + + + +>NAME +>TP_SIGNAL_NAME + + + + + +>NAME +>VALUE + + + + + + + + +<b>SUPPLY SYMBOL</b> + + + + + + + + + + + + +<b>Test pad</b> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +<B>CAPACITOR</B>, European symbol + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hyp2mat/eagle/tutorial/sparam.png b/hyp2mat/eagle/tutorial/sparam.png new file mode 100644 index 0000000..b9dec1b Binary files /dev/null and b/hyp2mat/eagle/tutorial/sparam.png differ diff --git a/hyp2mat/eagle/tutorial/tutorial_hyp2mat.m b/hyp2mat/eagle/tutorial/tutorial_hyp2mat.m new file mode 100644 index 0000000..d0bd068 --- /dev/null +++ b/hyp2mat/eagle/tutorial/tutorial_hyp2mat.m @@ -0,0 +1,124 @@ +% tutorial for hyp2mat - capacitor in a microstrip. +% +% run from openems matlab command prompt +% See hyp2mat(1) - convert hyperlynx files to matlab scripts. + +% (C) 2011,2012 Thorsten Liebig +% Copyright 2012 Koen De Vleeschauwer. +% +% This file is part of hyp2mat. +% +% 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 . + +close all +clear +clc + +% initialize +physical_constants; +f_max = 10e9; + +% Importing printed circuit board +CSX = InitCSX(); +CSX = ImportHyperLynx(CSX, 'msl.HYP'); + +% Adding a component +[pad1_material, pad1_start, pad1_stop] = GetHyperLynxPort(CSX, 'C1.1'); +[pad2_material, pad2_start, pad2_stop] = GetHyperLynxPort(CSX, 'C1.2'); + +c1_height = pad1_stop - pad1_start; +c1_start = [(pad1_start(1)+pad1_stop(1))/2, pad1_start(2), pad1_start(3)]; +c1_stop = [(pad2_start(1)+pad2_stop(1))/2, pad2_stop(2), pad2_stop(3)+c1_height]; + +CSX = AddLumpedElement( CSX, 'Capacitor', 0, 'Caps', 1, 'C', 100e-9); +CSX = AddBox( CSX, 'Capacitor', 0, c1_start, c1_stop ); + +% Adding excitation and load +[port1_material, port1_start, port1_stop] = GetHyperLynxPort(CSX, 'TP1.TP'); +[gnd1_material, gnd1_start, gnd1_stop] = GetHyperLynxPort(CSX, 'TP3.TP'); +[port2_material, port2_start, port2_stop] = GetHyperLynxPort(CSX, 'TP2.TP'); +[gnd2_material, gnd2_start, gnd2_stop] = GetHyperLynxPort(CSX, 'TP4.TP'); + +[CSX, port{1}] = AddLumpedPort( CSX, 999, 1, 50, gnd1_start, port1_stop, [0 0 -1], true); +[CSX, port{2}] = AddLumpedPort( CSX, 999, 2, 50, gnd2_start, port2_stop, [0 0 -1]); + +% Setting up a mesh +unit = GetUnits(CSX); +substrate_epr = GetEpsilon(CSX); +resolution = c0 / f_max / sqrt(substrate_epr) / unit / 25; +AirBox = c0 / f_max / unit / 25; + +z_top = port1_start(3); +z_bottom = gnd1_start(3); +z_middle = (z_top+z_bottom)/2; + +mesh.x = []; +mesh.y = []; +mesh.z = [ z_middle ]; + +mesh = DetectEdges(CSX, mesh); + +mesh.x = [min(mesh.x)-AirBox max(mesh.x)+AirBox mesh.x]; +mesh.y = [min(mesh.y)-AirBox max(mesh.y)+AirBox mesh.y]; +mesh.z = [min(mesh.z)-AirBox max(mesh.z)+2*AirBox mesh.z]; + +%mesh = SmoothMesh(mesh, resolution); +mesh = SmoothMesh(mesh, resolution, 'algorithm', [ 1 ]); + +% Setting boundary conditions + +FDTD = InitFDTD(); +FDTD = SetGaussExcite(FDTD, f_max/2, f_max/2); + +BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; +FDTD = SetBoundaryCond(FDTD, BC ); + +mesh = AddPML(mesh, 8); + +CSX = DefineRectGrid(CSX, unit, mesh); + +% Simulation + +Sim_Path = 'tmp'; +Sim_CSX = 'msl.xml'; + +[status, message, messageid] = rmdir(Sim_Path, 's'); % clear previous directory +[status, message, messageid] = mkdir(Sim_Path ); % create empty simulation folder + +disp([ 'Estimated simulation runtime: 6500 timesteps' ]); % inform user this may take a while... + +WriteOpenEMS([Sim_Path '/' Sim_CSX], FDTD, CSX); +CSXGeomPlot([Sim_Path '/' Sim_CSX]); +RunOpenEMS(Sim_Path, Sim_CSX); + +% Calculating the s-parameters + +close all +f = linspace( 1e6, f_max, 1601 ); +port = calcPort( port, Sim_Path, f, 'RefImpedance', 50); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; + +semilogx(f/1e9,20*log10(abs(s11)),'k-','LineWidth',2); +hold on; +grid on; +semilogx(f/1e9,20*log10(abs(s21)),'r--','LineWidth',2); +legend('S_{11}','S_{21}'); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (GHz) \rightarrow','FontSize',12); +ylim([-80 10]); +print('sparam.png', '-dpng'); + +% not truncated diff --git a/hyp2mat/lib/.gitignore b/hyp2mat/lib/.gitignore new file mode 100644 index 0000000..17fd190 --- /dev/null +++ b/hyp2mat/lib/.gitignore @@ -0,0 +1,11 @@ +*.lo +*.o +.deps/ +.libs/ +config.h +config.h.in~ +hyp2mat.pc +libhyp2mat.la +parse.cc +parse.h +scan.cc diff --git a/hyp2mat/lib/Makefile.am b/hyp2mat/lib/Makefile.am new file mode 100644 index 0000000..5e1000d --- /dev/null +++ b/hyp2mat/lib/Makefile.am @@ -0,0 +1,69 @@ +# used by automake + +# +# hyp2mat library +# + +# if you wish to install libraries, headers, and package information +if INSTALL_LIBRARY +include_HEADERS=hyp2mat.h +lib_LTLIBRARIES=libhyp2mat.la +pkgconfig_DATA=hyp2mat.pc +else +# if you do not wish to install libraries, headers, and package information +noinst_HEADERS=hyp2mat.h +noinst_LTLIBRARIES=libhyp2mat.la +noinst_DATA=hyp2mat.pc +endif + +pkgconfigdir=$(datarootdir)/pkgconfig + +libhyp2mat_la_SOURCES=\ + clipper.cpp \ + clipper.hpp \ + copper.cc \ + crop.h \ + crop.cc \ + csxcad.cc \ + csxcad.h \ + draw.cc \ + exec_board.cc \ + exec_devices.cc \ + exec_end.cc \ + exec_net.cc \ + exec_netclass.cc \ + exec_padstack.cc \ + exec_polygon.cc \ + exec_stackup.cc \ + exec_supplies.cc \ + hyp2mat.h \ + hyperlynx.cc \ + hyperlynx.h \ + hypfile.cc \ + hypfile.h \ + misc.cc \ + palette.cc \ + palette.h \ + parse_param.h \ + parser.h \ + parse.yy \ + polygon.h \ + polygon.cc \ + pcb.cc \ + pdf.cc \ + pdf.h \ + scan.ll + +EXTRA_DIST=clipper.txt parse.h + +BUILT_SOURCES=parse.cc parse.h scan.cc + +scan.cc: scan.ll parse.h + ${LEX} -o $*.cc $< + +parse.h parse.cc: parse.yy + ${YACC} --output=$*.cc --defines=$*.h $< + +CLEANFILES=parse.cc parse.h scan.cc + +#not truncated diff --git a/hyp2mat/lib/clipper.cpp b/hyp2mat/lib/clipper.cpp new file mode 100644 index 0000000..02a7b70 --- /dev/null +++ b/hyp2mat/lib/clipper.cpp @@ -0,0 +1,3700 @@ +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 5.1.6 * +* Date : 23 May 2013 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2013 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Attributions: * +* The code in this library is an extension of Bala Vatti's clipping algorithm: * +* "A generic solution to polygon clipping" * +* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * +* http://portal.acm.org/citation.cfm?id=129906 * +* * +* Computer graphics and geometric modeling: implementation and algorithms * +* By Max K. Agoston * +* Springer; 1 edition (January 4, 2005) * +* http://books.google.com/books?q=vatti+clipping+agoston * +* * +* See also: * +* "Polygon Offsetting by Computing Winding Numbers" * +* Paper no. DETC2005-85513 pp. 565-575 * +* ASME 2005 International Design Engineering Technical Conferences * +* and Computers and Information in Engineering Conference (IDETC/CIE2005) * +* September 24-28, 2005 , Long Beach, California, USA * +* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * +* * +*******************************************************************************/ + +/******************************************************************************* +* * +* This is a translation of the Delphi Clipper library and the naming style * +* used has retained a Delphi flavour. * +* * +*******************************************************************************/ + +#include "clipper.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace ClipperLib { + +static long64 const loRange = 0x3FFFFFFF; +static long64 const hiRange = 0x3FFFFFFFFFFFFFFFLL; +static double const pi = 3.141592653589793238; +enum Direction { dRightToLeft, dLeftToRight }; + +#define HORIZONTAL (-1.0E+40) +#define TOLERANCE (1.0e-20) +#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE)) +#define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b)) + +const char coords_range_error[] = "Coordinate exceeds range bounds."; + +inline long64 Abs(long64 val) +{ + return val < 0 ? -val : val; +} + +//------------------------------------------------------------------------------ +// PolyTree methods ... +//------------------------------------------------------------------------------ + +void PolyTree::Clear() +{ + for (PolyNodes::size_type i = 0; i < AllNodes.size(); ++i) + delete AllNodes[i]; + AllNodes.resize(0); + Childs.resize(0); +} +//------------------------------------------------------------------------------ + +PolyNode* PolyTree::GetFirst() const +{ + if (!Childs.empty()) + return Childs[0]; + else + return 0; +} +//------------------------------------------------------------------------------ + +int PolyTree::Total() const +{ + return AllNodes.size(); +} + +//------------------------------------------------------------------------------ +// PolyNode methods ... +//------------------------------------------------------------------------------ + +PolyNode::PolyNode(): Childs(), Parent(0), Index(0) +{ +} +//------------------------------------------------------------------------------ + +int PolyNode::ChildCount() const +{ + return Childs.size(); +} +//------------------------------------------------------------------------------ + +void PolyNode::AddChild(PolyNode& child) +{ + unsigned cnt = Childs.size(); + Childs.push_back(&child); + child.Parent = this; + child.Index = cnt; +} +//------------------------------------------------------------------------------ + +PolyNode* PolyNode::GetNext() const +{ + if (!Childs.empty()) + return Childs[0]; + else + return GetNextSiblingUp(); +} +//------------------------------------------------------------------------------ + +PolyNode* PolyNode::GetNextSiblingUp() const +{ + if (!Parent) //protects against PolyTree.GetNextSiblingUp() + return 0; + else if (Index == Parent->Childs.size() - 1) + return Parent->GetNextSiblingUp(); + else + return Parent->Childs[Index + 1]; +} +//------------------------------------------------------------------------------ + +bool PolyNode::IsHole() const +{ + bool result = true; + PolyNode* node = Parent; + while (node) + { + result = !result; + node = node->Parent; + } + return result; +} + +//------------------------------------------------------------------------------ +// Int128 class (enables safe math on signed 64bit integers) +// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1 +// Int128 val2((long64)9223372036854775807); +// Int128 val3 = val1 * val2; +// val3.AsString => "85070591730234615847396907784232501249" (8.5e+37) +//------------------------------------------------------------------------------ + +class Int128 +{ + public: + + ulong64 lo; + long64 hi; + + Int128(long64 _lo = 0) + { + lo = (ulong64)_lo; + if (_lo < 0) hi = -1; else hi = 0; + } + + + Int128(const Int128 &val): lo(val.lo), hi(val.hi){} + + Int128(const long64& _hi, const ulong64& _lo): lo(_lo), hi(_hi){} + + long64 operator = (const long64 &val) + { + lo = (ulong64)val; + if (val < 0) hi = -1; else hi = 0; + return val; + } + + bool operator == (const Int128 &val) const + {return (hi == val.hi && lo == val.lo);} + + bool operator != (const Int128 &val) const + { return !(*this == val);} + + bool operator > (const Int128 &val) const + { + if (hi != val.hi) + return hi > val.hi; + else + return lo > val.lo; + } + + bool operator < (const Int128 &val) const + { + if (hi != val.hi) + return hi < val.hi; + else + return lo < val.lo; + } + + bool operator >= (const Int128 &val) const + { return !(*this < val);} + + bool operator <= (const Int128 &val) const + { return !(*this > val);} + + Int128& operator += (const Int128 &rhs) + { + hi += rhs.hi; + lo += rhs.lo; + if (lo < rhs.lo) hi++; + return *this; + } + + Int128 operator + (const Int128 &rhs) const + { + Int128 result(*this); + result+= rhs; + return result; + } + + Int128& operator -= (const Int128 &rhs) + { + *this += -rhs; + return *this; + } + + Int128 operator - (const Int128 &rhs) const + { + Int128 result(*this); + result -= rhs; + return result; + } + + Int128 operator-() const //unary negation + { + if (lo == 0) + return Int128(-hi,0); + else + return Int128(~hi,~lo +1); + } + + Int128 operator/ (const Int128 &rhs) const + { + if (rhs.lo == 0 && rhs.hi == 0) + throw "Int128 operator/: divide by zero"; + + bool negate = (rhs.hi < 0) != (hi < 0); + Int128 dividend = *this; + Int128 divisor = rhs; + if (dividend.hi < 0) dividend = -dividend; + if (divisor.hi < 0) divisor = -divisor; + + if (divisor < dividend) + { + Int128 result = Int128(0); + Int128 cntr = Int128(1); + while (divisor.hi >= 0 && !(divisor > dividend)) + { + divisor.hi <<= 1; + if ((long64)divisor.lo < 0) divisor.hi++; + divisor.lo <<= 1; + + cntr.hi <<= 1; + if ((long64)cntr.lo < 0) cntr.hi++; + cntr.lo <<= 1; + } + divisor.lo >>= 1; + if ((divisor.hi & 1) == 1) + divisor.lo |= 0x8000000000000000LL; + divisor.hi = (ulong64)divisor.hi >> 1; + + cntr.lo >>= 1; + if ((cntr.hi & 1) == 1) + cntr.lo |= 0x8000000000000000LL; + cntr.hi >>= 1; + + while (cntr.hi != 0 || cntr.lo != 0) + { + if (!(dividend < divisor)) + { + dividend -= divisor; + result.hi |= cntr.hi; + result.lo |= cntr.lo; + } + divisor.lo >>= 1; + if ((divisor.hi & 1) == 1) + divisor.lo |= 0x8000000000000000LL; + divisor.hi >>= 1; + + cntr.lo >>= 1; + if ((cntr.hi & 1) == 1) + cntr.lo |= 0x8000000000000000LL; + cntr.hi >>= 1; + } + if (negate) result = -result; + return result; + } + else if (rhs.hi == this->hi && rhs.lo == this->lo) + return Int128(1); + else + return Int128(0); + } + + double AsDouble() const + { + const double shift64 = 18446744073709551616.0; //2^64 + if (hi < 0) + { + if (lo == 0) return (double)hi * shift64; + else return -(double)(~lo + ~hi * shift64); + } + else + return (double)(lo + hi * shift64); + } +}; + +Int128 Int128Mul (long64 lhs, long64 rhs) +{ + bool negate = (lhs < 0) != (rhs < 0); + + if (lhs < 0) lhs = -lhs; + ulong64 int1Hi = ulong64(lhs) >> 32; + ulong64 int1Lo = ulong64(lhs & 0xFFFFFFFF); + + if (rhs < 0) rhs = -rhs; + ulong64 int2Hi = ulong64(rhs) >> 32; + ulong64 int2Lo = ulong64(rhs & 0xFFFFFFFF); + + //nb: see comments in clipper.pas + ulong64 a = int1Hi * int2Hi; + ulong64 b = int1Lo * int2Lo; + ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi; + + Int128 tmp; + tmp.hi = long64(a + (c >> 32)); + tmp.lo = long64(c << 32); + tmp.lo += long64(b); + if (tmp.lo < b) tmp.hi++; + if (negate) tmp = -tmp; + return tmp; +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +bool FullRangeNeeded(const Polygon &pts) +{ + bool result = false; + for (Polygon::size_type i = 0; i < pts.size(); ++i) + { + if (Abs(pts[i].X) > hiRange || Abs(pts[i].Y) > hiRange) + throw coords_range_error; + else if (Abs(pts[i].X) > loRange || Abs(pts[i].Y) > loRange) + result = true; + } + return result; +} +//------------------------------------------------------------------------------ + +bool Orientation(const Polygon &poly) +{ + return Area(poly) >= 0; +} +//------------------------------------------------------------------------------ + +inline bool PointsEqual( const IntPoint &pt1, const IntPoint &pt2) +{ + return ( pt1.X == pt2.X && pt1.Y == pt2.Y ); +} +//------------------------------------------------------------------------------ + +double Area(const Polygon &poly) +{ + int highI = (int)poly.size() -1; + if (highI < 2) return 0; + + if (FullRangeNeeded(poly)) { + Int128 a; + a = Int128Mul(poly[highI].X + poly[0].X, poly[0].Y - poly[highI].Y); + for (int i = 1; i <= highI; ++i) + a += Int128Mul(poly[i - 1].X + poly[i].X, poly[i].Y - poly[i -1].Y); + return a.AsDouble() / 2; + } + else + { + double a; + a = ((double)poly[highI].X + poly[0].X) * ((double)poly[0].Y - poly[highI].Y); + for (int i = 1; i <= highI; ++i) + a += ((double)poly[i - 1].X + poly[i].X) * ((double)poly[i].Y - poly[i - 1].Y); + return a / 2; + } +} +//------------------------------------------------------------------------------ + +double Area(const OutRec &outRec, bool UseFullInt64Range) +{ + OutPt *op = outRec.pts; + if (!op) return 0; + if (UseFullInt64Range) { + Int128 a(0); + do { + a += Int128Mul(op->pt.X + op->prev->pt.X, op->prev->pt.Y - op->pt.Y); + op = op->next; + } while (op != outRec.pts); + return a.AsDouble() / 2; + } + else + { + double a = 0; + do { + a = a + (op->pt.X + op->prev->pt.X) * (op->prev->pt.Y - op->pt.Y); + op = op->next; + } while (op != outRec.pts); + return a / 2; + } +} +//------------------------------------------------------------------------------ + +bool PointIsVertex(const IntPoint &pt, OutPt *pp) +{ + OutPt *pp2 = pp; + do + { + if (PointsEqual(pp2->pt, pt)) return true; + pp2 = pp2->next; + } + while (pp2 != pp); + return false; +} +//------------------------------------------------------------------------------ + +bool PointOnLineSegment(const IntPoint pt, + const IntPoint linePt1, const IntPoint linePt2, bool UseFullInt64Range) +{ + if (UseFullInt64Range) + return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) || + ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) || + (((pt.X > linePt1.X) == (pt.X < linePt2.X)) && + ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) && + ((Int128Mul((pt.X - linePt1.X), (linePt2.Y - linePt1.Y)) == + Int128Mul((linePt2.X - linePt1.X), (pt.Y - linePt1.Y))))); + else + return ((pt.X == linePt1.X) && (pt.Y == linePt1.Y)) || + ((pt.X == linePt2.X) && (pt.Y == linePt2.Y)) || + (((pt.X > linePt1.X) == (pt.X < linePt2.X)) && + ((pt.Y > linePt1.Y) == (pt.Y < linePt2.Y)) && + ((pt.X - linePt1.X) * (linePt2.Y - linePt1.Y) == + (linePt2.X - linePt1.X) * (pt.Y - linePt1.Y))); +} +//------------------------------------------------------------------------------ + +bool PointOnPolygon(const IntPoint pt, OutPt *pp, bool UseFullInt64Range) +{ + OutPt *pp2 = pp; + while (true) + { + if (PointOnLineSegment(pt, pp2->pt, pp2->next->pt, UseFullInt64Range)) + return true; + pp2 = pp2->next; + if (pp2 == pp) break; + } + return false; +} +//------------------------------------------------------------------------------ + +bool PointInPolygon(const IntPoint &pt, OutPt *pp, bool UseFullInt64Range) +{ + OutPt *pp2 = pp; + bool result = false; + if (UseFullInt64Range) { + do + { + if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) || + ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) && + Int128(pt.X - pp2->pt.X) < + Int128Mul(pp2->prev->pt.X - pp2->pt.X, pt.Y - pp2->pt.Y) / + Int128(pp2->prev->pt.Y - pp2->pt.Y)) + result = !result; + pp2 = pp2->next; + } + while (pp2 != pp); + } + else + { + do + { + if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) || + ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) && + (pt.X < (pp2->prev->pt.X - pp2->pt.X) * (pt.Y - pp2->pt.Y) / + (pp2->prev->pt.Y - pp2->pt.Y) + pp2->pt.X )) result = !result; + pp2 = pp2->next; + } + while (pp2 != pp); + } + return result; +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range) +{ + if (UseFullInt64Range) + return Int128Mul(e1.deltaY, e2.deltaX) == Int128Mul(e1.deltaX, e2.deltaY); + else return e1.deltaY * e2.deltaX == e1.deltaX * e2.deltaY; +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, + const IntPoint pt3, bool UseFullInt64Range) +{ + if (UseFullInt64Range) + return Int128Mul(pt1.Y-pt2.Y, pt2.X-pt3.X) == Int128Mul(pt1.X-pt2.X, pt2.Y-pt3.Y); + else return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y); +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, + const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range) +{ + if (UseFullInt64Range) + return Int128Mul(pt1.Y-pt2.Y, pt3.X-pt4.X) == Int128Mul(pt1.X-pt2.X, pt3.Y-pt4.Y); + else return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y); +} +//------------------------------------------------------------------------------ + +double GetDx(const IntPoint pt1, const IntPoint pt2) +{ + return (pt1.Y == pt2.Y) ? + HORIZONTAL : (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y); +} +//--------------------------------------------------------------------------- + +void SetDx(TEdge &e) +{ + e.deltaX = (e.xtop - e.xbot); + e.deltaY = (e.ytop - e.ybot); + + if (e.deltaY == 0) e.dx = HORIZONTAL; + else e.dx = (double)(e.deltaX) / e.deltaY; +} +//--------------------------------------------------------------------------- + +void SwapSides(TEdge &edge1, TEdge &edge2) +{ + EdgeSide side = edge1.side; + edge1.side = edge2.side; + edge2.side = side; +} +//------------------------------------------------------------------------------ + +void SwapPolyIndexes(TEdge &edge1, TEdge &edge2) +{ + int outIdx = edge1.outIdx; + edge1.outIdx = edge2.outIdx; + edge2.outIdx = outIdx; +} +//------------------------------------------------------------------------------ + +inline long64 Round(double val) +{ + return (val < 0) ? static_cast(val - 0.5) : static_cast(val + 0.5); +} +//------------------------------------------------------------------------------ + +long64 TopX(TEdge &edge, const long64 currentY) +{ + return ( currentY == edge.ytop ) ? + edge.xtop : edge.xbot + Round(edge.dx *(currentY - edge.ybot)); +} +//------------------------------------------------------------------------------ + +bool IntersectPoint(TEdge &edge1, TEdge &edge2, + IntPoint &ip, bool UseFullInt64Range) +{ + double b1, b2; + if (SlopesEqual(edge1, edge2, UseFullInt64Range)) + { + if (edge2.ybot > edge1.ybot) ip.Y = edge2.ybot; + else ip.Y = edge1.ybot; + return false; + } + else if (NEAR_ZERO(edge1.dx)) + { + ip.X = edge1.xbot; + if (NEAR_EQUAL(edge2.dx, HORIZONTAL)) + ip.Y = edge2.ybot; + else + { + b2 = edge2.ybot - (edge2.xbot / edge2.dx); + ip.Y = Round(ip.X / edge2.dx + b2); + } + } + else if (NEAR_ZERO(edge2.dx)) + { + ip.X = edge2.xbot; + if (NEAR_EQUAL(edge1.dx, HORIZONTAL)) + ip.Y = edge1.ybot; + else + { + b1 = edge1.ybot - (edge1.xbot / edge1.dx); + ip.Y = Round(ip.X / edge1.dx + b1); + } + } + else + { + b1 = edge1.xbot - edge1.ybot * edge1.dx; + b2 = edge2.xbot - edge2.ybot * edge2.dx; + double q = (b2-b1) / (edge1.dx - edge2.dx); + ip.Y = Round(q); + if (std::fabs(edge1.dx) < std::fabs(edge2.dx)) + ip.X = Round(edge1.dx * q + b1); + else + ip.X = Round(edge2.dx * q + b2); + } + + if (ip.Y < edge1.ytop || ip.Y < edge2.ytop) + { + if (edge1.ytop > edge2.ytop) + { + ip.X = edge1.xtop; + ip.Y = edge1.ytop; + return TopX(edge2, edge1.ytop) < edge1.xtop; + } + else + { + ip.X = edge2.xtop; + ip.Y = edge2.ytop; + return TopX(edge1, edge2.ytop) > edge2.xtop; + } + } + else + return true; +} +//------------------------------------------------------------------------------ + +void ReversePolyPtLinks(OutPt *pp) +{ + if (!pp) return; + OutPt *pp1, *pp2; + pp1 = pp; + do { + pp2 = pp1->next; + pp1->next = pp1->prev; + pp1->prev = pp2; + pp1 = pp2; + } while( pp1 != pp ); +} +//------------------------------------------------------------------------------ + +void DisposeOutPts(OutPt*& pp) +{ + if (pp == 0) return; + pp->prev->next = 0; + while( pp ) + { + OutPt *tmpPp = pp; + pp = pp->next; + delete tmpPp; + } +} +//------------------------------------------------------------------------------ + +void InitEdge(TEdge *e, TEdge *eNext, + TEdge *ePrev, const IntPoint &pt, PolyType polyType) +{ + std::memset(e, 0, sizeof(TEdge)); + e->next = eNext; + e->prev = ePrev; + e->xcurr = pt.X; + e->ycurr = pt.Y; + if (e->ycurr >= e->next->ycurr) + { + e->xbot = e->xcurr; + e->ybot = e->ycurr; + e->xtop = e->next->xcurr; + e->ytop = e->next->ycurr; + e->windDelta = 1; + } else + { + e->xtop = e->xcurr; + e->ytop = e->ycurr; + e->xbot = e->next->xcurr; + e->ybot = e->next->ycurr; + e->windDelta = -1; + } + SetDx(*e); + e->polyType = polyType; + e->outIdx = -1; +} +//------------------------------------------------------------------------------ + +inline void SwapX(TEdge &e) +{ + //swap horizontal edges' top and bottom x's so they follow the natural + //progression of the bounds - ie so their xbots will align with the + //adjoining lower edge. [Helpful in the ProcessHorizontal() method.] + e.xcurr = e.xtop; + e.xtop = e.xbot; + e.xbot = e.xcurr; +} +//------------------------------------------------------------------------------ + +void SwapPoints(IntPoint &pt1, IntPoint &pt2) +{ + IntPoint tmp = pt1; + pt1 = pt2; + pt2 = tmp; +} +//------------------------------------------------------------------------------ + +bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a, + IntPoint pt2b, IntPoint &pt1, IntPoint &pt2) +{ + //precondition: segments are colinear. + if (Abs(pt1a.X - pt1b.X) > Abs(pt1a.Y - pt1b.Y)) + { + if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b); + if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b); + if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a; + if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b; + return pt1.X < pt2.X; + } else + { + if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b); + if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b); + if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a; + if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b; + return pt1.Y > pt2.Y; + } +} +//------------------------------------------------------------------------------ + +bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2) +{ + OutPt *p = btmPt1->prev; + while (PointsEqual(p->pt, btmPt1->pt) && (p != btmPt1)) p = p->prev; + double dx1p = std::fabs(GetDx(btmPt1->pt, p->pt)); + p = btmPt1->next; + while (PointsEqual(p->pt, btmPt1->pt) && (p != btmPt1)) p = p->next; + double dx1n = std::fabs(GetDx(btmPt1->pt, p->pt)); + + p = btmPt2->prev; + while (PointsEqual(p->pt, btmPt2->pt) && (p != btmPt2)) p = p->prev; + double dx2p = std::fabs(GetDx(btmPt2->pt, p->pt)); + p = btmPt2->next; + while (PointsEqual(p->pt, btmPt2->pt) && (p != btmPt2)) p = p->next; + double dx2n = std::fabs(GetDx(btmPt2->pt, p->pt)); + return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); +} +//------------------------------------------------------------------------------ + +OutPt* GetBottomPt(OutPt *pp) +{ + OutPt* dups = 0; + OutPt* p = pp->next; + while (p != pp) + { + if (p->pt.Y > pp->pt.Y) + { + pp = p; + dups = 0; + } + else if (p->pt.Y == pp->pt.Y && p->pt.X <= pp->pt.X) + { + if (p->pt.X < pp->pt.X) + { + dups = 0; + pp = p; + } else + { + if (p->next != pp && p->prev != pp) dups = p; + } + } + p = p->next; + } + if (dups) + { + //there appears to be at least 2 vertices at bottomPt so ... + while (dups != p) + { + if (!FirstIsBottomPt(p, dups)) pp = dups; + dups = dups->next; + while (!PointsEqual(dups->pt, pp->pt)) dups = dups->next; + } + } + return pp; +} +//------------------------------------------------------------------------------ + +bool FindSegment(OutPt* &pp, bool UseFullInt64Range, + IntPoint &pt1, IntPoint &pt2) +{ + //outPt1 & outPt2 => the overlap segment (if the function returns true) + if (!pp) return false; + OutPt* pp2 = pp; + IntPoint pt1a = pt1, pt2a = pt2; + do + { + if (SlopesEqual(pt1a, pt2a, pp->pt, pp->prev->pt, UseFullInt64Range) && + SlopesEqual(pt1a, pt2a, pp->pt, UseFullInt64Range) && + GetOverlapSegment(pt1a, pt2a, pp->pt, pp->prev->pt, pt1, pt2)) + return true; + pp = pp->next; + } + while (pp != pp2); + return false; +} +//------------------------------------------------------------------------------ + +bool Pt3IsBetweenPt1AndPt2(const IntPoint pt1, + const IntPoint pt2, const IntPoint pt3) +{ + if (PointsEqual(pt1, pt3) || PointsEqual(pt2, pt3)) return true; + else if (pt1.X != pt2.X) return (pt1.X < pt3.X) == (pt3.X < pt2.X); + else return (pt1.Y < pt3.Y) == (pt3.Y < pt2.Y); +} +//------------------------------------------------------------------------------ + +OutPt* InsertPolyPtBetween(OutPt* p1, OutPt* p2, const IntPoint pt) +{ + if (p1 == p2) throw "JoinError"; + OutPt* result = new OutPt; + result->pt = pt; + if (p2 == p1->next) + { + p1->next = result; + p2->prev = result; + result->next = p2; + result->prev = p1; + } else + { + p2->next = result; + p1->prev = result; + result->next = p1; + result->prev = p2; + } + return result; +} + +//------------------------------------------------------------------------------ +// ClipperBase class methods ... +//------------------------------------------------------------------------------ + +ClipperBase::ClipperBase() //constructor +{ + m_MinimaList = 0; + m_CurrentLM = 0; + m_UseFullRange = true; +} +//------------------------------------------------------------------------------ + +ClipperBase::~ClipperBase() //destructor +{ + Clear(); +} +//------------------------------------------------------------------------------ + +void RangeTest(const IntPoint& pt, long64& maxrange) +{ + if (Abs(pt.X) > maxrange) + { + if (Abs(pt.X) > hiRange) + throw coords_range_error; + else maxrange = hiRange; + } + if (Abs(pt.Y) > maxrange) + { + if (Abs(pt.Y) > hiRange) + throw coords_range_error; + else maxrange = hiRange; + } +} +//------------------------------------------------------------------------------ + +bool ClipperBase::AddPolygon(const Polygon &pg, PolyType polyType) +{ + int len = (int)pg.size(); + if (len < 3) return false; + + long64 maxVal; + if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange; + RangeTest(pg[0], maxVal); + + Polygon p(len); + p[0] = pg[0]; + int j = 0; + + for (int i = 0; i < len; ++i) + { + RangeTest(pg[i], maxVal); + + if (i == 0 || PointsEqual(p[j], pg[i])) continue; + else if (j > 0 && SlopesEqual(p[j-1], p[j], pg[i], m_UseFullRange)) + { + if (PointsEqual(p[j-1], pg[i])) j--; + } else j++; + p[j] = pg[i]; + } + if (j < 2) return false; + + len = j+1; + while (len > 2) + { + //nb: test for point equality before testing slopes ... + if (PointsEqual(p[j], p[0])) j--; + else if (PointsEqual(p[0], p[1]) || + SlopesEqual(p[j], p[0], p[1], m_UseFullRange)) + p[0] = p[j--]; + else if (SlopesEqual(p[j-1], p[j], p[0], m_UseFullRange)) j--; + else if (SlopesEqual(p[0], p[1], p[2], m_UseFullRange)) + { + for (int i = 2; i <= j; ++i) p[i-1] = p[i]; + j--; + } + else break; + len--; + } + if (len < 3) return false; + + //create a new edge array ... + TEdge *edges = new TEdge [len]; + m_edges.push_back(edges); + + //convert vertices to a double-linked-list of edges and initialize ... + edges[0].xcurr = p[0].X; + edges[0].ycurr = p[0].Y; + InitEdge(&edges[len-1], &edges[0], &edges[len-2], p[len-1], polyType); + for (int i = len-2; i > 0; --i) + InitEdge(&edges[i], &edges[i+1], &edges[i-1], p[i], polyType); + InitEdge(&edges[0], &edges[1], &edges[len-1], p[0], polyType); + + //reset xcurr & ycurr and find 'eHighest' (given the Y axis coordinates + //increase downward so the 'highest' edge will have the smallest ytop) ... + TEdge *e = &edges[0]; + TEdge *eHighest = e; + do + { + e->xcurr = e->xbot; + e->ycurr = e->ybot; + if (e->ytop < eHighest->ytop) eHighest = e; + e = e->next; + } + while ( e != &edges[0]); + + //make sure eHighest is positioned so the following loop works safely ... + if (eHighest->windDelta > 0) eHighest = eHighest->next; + if (NEAR_EQUAL(eHighest->dx, HORIZONTAL)) eHighest = eHighest->next; + + //finally insert each local minima ... + e = eHighest; + do { + e = AddBoundsToLML(e); + } + while( e != eHighest ); + return true; +} +//------------------------------------------------------------------------------ + +void ClipperBase::InsertLocalMinima(LocalMinima *newLm) +{ + if( ! m_MinimaList ) + { + m_MinimaList = newLm; + } + else if( newLm->Y >= m_MinimaList->Y ) + { + newLm->next = m_MinimaList; + m_MinimaList = newLm; + } else + { + LocalMinima* tmpLm = m_MinimaList; + while( tmpLm->next && ( newLm->Y < tmpLm->next->Y ) ) + tmpLm = tmpLm->next; + newLm->next = tmpLm->next; + tmpLm->next = newLm; + } +} +//------------------------------------------------------------------------------ + +TEdge* ClipperBase::AddBoundsToLML(TEdge *e) +{ + //Starting at the top of one bound we progress to the bottom where there's + //a local minima. We then go to the top of the next bound. These two bounds + //form the left and right (or right and left) bounds of the local minima. + e->nextInLML = 0; + e = e->next; + for (;;) + { + if (NEAR_EQUAL(e->dx, HORIZONTAL)) + { + //nb: proceed through horizontals when approaching from their right, + // but break on horizontal minima if approaching from their left. + // This ensures 'local minima' are always on the left of horizontals. + if (e->next->ytop < e->ytop && e->next->xbot > e->prev->xbot) break; + if (e->xtop != e->prev->xbot) SwapX(*e); + e->nextInLML = e->prev; + } + else if (e->ycurr == e->prev->ycurr) break; + else e->nextInLML = e->prev; + e = e->next; + } + + //e and e.prev are now at a local minima ... + LocalMinima* newLm = new LocalMinima; + newLm->next = 0; + newLm->Y = e->prev->ybot; + + if ( NEAR_EQUAL(e->dx, HORIZONTAL) ) //horizontal edges never start a left bound + { + if (e->xbot != e->prev->xbot) SwapX(*e); + newLm->leftBound = e->prev; + newLm->rightBound = e; + } else if (e->dx < e->prev->dx) + { + newLm->leftBound = e->prev; + newLm->rightBound = e; + } else + { + newLm->leftBound = e; + newLm->rightBound = e->prev; + } + newLm->leftBound->side = esLeft; + newLm->rightBound->side = esRight; + InsertLocalMinima( newLm ); + + for (;;) + { + if ( e->next->ytop == e->ytop && !NEAR_EQUAL(e->next->dx, HORIZONTAL) ) break; + e->nextInLML = e->next; + e = e->next; + if ( NEAR_EQUAL(e->dx, HORIZONTAL) && e->xbot != e->prev->xtop) SwapX(*e); + } + return e->next; +} +//------------------------------------------------------------------------------ + +bool ClipperBase::AddPolygons(const Polygons &ppg, PolyType polyType) +{ + bool result = false; + for (Polygons::size_type i = 0; i < ppg.size(); ++i) + if (AddPolygon(ppg[i], polyType)) result = true; + return result; +} +//------------------------------------------------------------------------------ + +void ClipperBase::Clear() +{ + DisposeLocalMinimaList(); + for (EdgeList::size_type i = 0; i < m_edges.size(); ++i) delete [] m_edges[i]; + m_edges.clear(); + m_UseFullRange = false; +} +//------------------------------------------------------------------------------ + +void ClipperBase::Reset() +{ + m_CurrentLM = m_MinimaList; + if( !m_CurrentLM ) return; //ie nothing to process + + //reset all edges ... + LocalMinima* lm = m_MinimaList; + while( lm ) + { + TEdge* e = lm->leftBound; + while( e ) + { + e->xcurr = e->xbot; + e->ycurr = e->ybot; + e->side = esLeft; + e->outIdx = -1; + e = e->nextInLML; + } + e = lm->rightBound; + while( e ) + { + e->xcurr = e->xbot; + e->ycurr = e->ybot; + e->side = esRight; + e->outIdx = -1; + e = e->nextInLML; + } + lm = lm->next; + } +} +//------------------------------------------------------------------------------ + +void ClipperBase::DisposeLocalMinimaList() +{ + while( m_MinimaList ) + { + LocalMinima* tmpLm = m_MinimaList->next; + delete m_MinimaList; + m_MinimaList = tmpLm; + } + m_CurrentLM = 0; +} +//------------------------------------------------------------------------------ + +void ClipperBase::PopLocalMinima() +{ + if( ! m_CurrentLM ) return; + m_CurrentLM = m_CurrentLM->next; +} +//------------------------------------------------------------------------------ + +IntRect ClipperBase::GetBounds() +{ + IntRect result; + LocalMinima* lm = m_MinimaList; + if (!lm) + { + result.left = result.top = result.right = result.bottom = 0; + return result; + } + result.left = lm->leftBound->xbot; + result.top = lm->leftBound->ybot; + result.right = lm->leftBound->xbot; + result.bottom = lm->leftBound->ybot; + while (lm) + { + if (lm->leftBound->ybot > result.bottom) + result.bottom = lm->leftBound->ybot; + TEdge* e = lm->leftBound; + for (;;) { + TEdge* bottomE = e; + while (e->nextInLML) + { + if (e->xbot < result.left) result.left = e->xbot; + if (e->xbot > result.right) result.right = e->xbot; + e = e->nextInLML; + } + if (e->xbot < result.left) result.left = e->xbot; + if (e->xbot > result.right) result.right = e->xbot; + if (e->xtop < result.left) result.left = e->xtop; + if (e->xtop > result.right) result.right = e->xtop; + if (e->ytop < result.top) result.top = e->ytop; + + if (bottomE == lm->leftBound) e = lm->rightBound; + else break; + } + lm = lm->next; + } + return result; +} + + +//------------------------------------------------------------------------------ +// TClipper methods ... +//------------------------------------------------------------------------------ + +Clipper::Clipper() : ClipperBase() //constructor +{ + m_Scanbeam = 0; + m_ActiveEdges = 0; + m_SortedEdges = 0; + m_IntersectNodes = 0; + m_ExecuteLocked = false; + m_UseFullRange = false; + m_ReverseOutput = false; + m_ForceSimple = false; +} +//------------------------------------------------------------------------------ + +Clipper::~Clipper() //destructor +{ + Clear(); + DisposeScanbeamList(); +} +//------------------------------------------------------------------------------ + +void Clipper::Clear() +{ + if (m_edges.empty()) return; //avoids problems with ClipperBase destructor + DisposeAllPolyPts(); + ClipperBase::Clear(); +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeScanbeamList() +{ + while ( m_Scanbeam ) { + Scanbeam* sb2 = m_Scanbeam->next; + delete m_Scanbeam; + m_Scanbeam = sb2; + } +} +//------------------------------------------------------------------------------ + +void Clipper::Reset() +{ + ClipperBase::Reset(); + m_Scanbeam = 0; + m_ActiveEdges = 0; + m_SortedEdges = 0; + DisposeAllPolyPts(); + LocalMinima* lm = m_MinimaList; + while (lm) + { + InsertScanbeam(lm->Y); + lm = lm->next; + } +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, Polygons &solution, + PolyFillType subjFillType, PolyFillType clipFillType) +{ + if( m_ExecuteLocked ) return false; + m_ExecuteLocked = true; + solution.resize(0); + m_SubjFillType = subjFillType; + m_ClipFillType = clipFillType; + m_ClipType = clipType; + m_UsingPolyTree = false; + bool succeeded = ExecuteInternal(); + if (succeeded) BuildResult(solution); + m_ExecuteLocked = false; + return succeeded; +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, PolyTree& polytree, + PolyFillType subjFillType, PolyFillType clipFillType) +{ + if( m_ExecuteLocked ) return false; + m_ExecuteLocked = true; + m_SubjFillType = subjFillType; + m_ClipFillType = clipFillType; + m_ClipType = clipType; + m_UsingPolyTree = true; + bool succeeded = ExecuteInternal(); + if (succeeded) BuildResult2(polytree); + m_ExecuteLocked = false; + return succeeded; +} +//------------------------------------------------------------------------------ + +void Clipper::FixHoleLinkage(OutRec &outrec) +{ + //skip OutRecs that (a) contain outermost polygons or + //(b) already have the correct owner/child linkage ... + if (!outrec.FirstLeft || + (outrec.isHole != outrec.FirstLeft->isHole && + outrec.FirstLeft->pts)) return; + + OutRec* orfl = outrec.FirstLeft; + while (orfl && ((orfl->isHole == outrec.isHole) || !orfl->pts)) + orfl = orfl->FirstLeft; + outrec.FirstLeft = orfl; +} +//------------------------------------------------------------------------------ + +bool Clipper::ExecuteInternal() +{ + bool succeeded; + try { + Reset(); + if (!m_CurrentLM ) return true; + long64 botY = PopScanbeam(); + do { + InsertLocalMinimaIntoAEL(botY); + ClearHorzJoins(); + ProcessHorizontals(); + long64 topY = PopScanbeam(); + succeeded = ProcessIntersections(botY, topY); + if (!succeeded) break; + ProcessEdgesAtTopOfScanbeam(topY); + botY = topY; + } while(m_Scanbeam || m_CurrentLM); + } + catch(...) { + succeeded = false; + } + + if (succeeded) + { + //tidy up output polygons and fix orientations where necessary ... + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec *outRec = m_PolyOuts[i]; + if (!outRec->pts) continue; + FixupOutPolygon(*outRec); + if (!outRec->pts) continue; + + if ((outRec->isHole ^ m_ReverseOutput) == (Area(*outRec, m_UseFullRange) > 0)) + ReversePolyPtLinks(outRec->pts); + } + + if (!m_Joins.empty()) JoinCommonEdges(); + if (m_ForceSimple) DoSimplePolygons(); + } + + ClearJoins(); + ClearHorzJoins(); + return succeeded; +} +//------------------------------------------------------------------------------ + +void Clipper::InsertScanbeam(const long64 Y) +{ + if( !m_Scanbeam ) + { + m_Scanbeam = new Scanbeam; + m_Scanbeam->next = 0; + m_Scanbeam->Y = Y; + } + else if( Y > m_Scanbeam->Y ) + { + Scanbeam* newSb = new Scanbeam; + newSb->Y = Y; + newSb->next = m_Scanbeam; + m_Scanbeam = newSb; + } else + { + Scanbeam* sb2 = m_Scanbeam; + while( sb2->next && ( Y <= sb2->next->Y ) ) sb2 = sb2->next; + if( Y == sb2->Y ) return; //ie ignores duplicates + Scanbeam* newSb = new Scanbeam; + newSb->Y = Y; + newSb->next = sb2->next; + sb2->next = newSb; + } +} +//------------------------------------------------------------------------------ + +long64 Clipper::PopScanbeam() +{ + long64 Y = m_Scanbeam->Y; + Scanbeam* sb2 = m_Scanbeam; + m_Scanbeam = m_Scanbeam->next; + delete sb2; + return Y; +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeAllPolyPts(){ + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + DisposeOutRec(i); + m_PolyOuts.clear(); +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeOutRec(PolyOutList::size_type index) +{ + OutRec *outRec = m_PolyOuts[index]; + if (outRec->pts) DisposeOutPts(outRec->pts); + delete outRec; + m_PolyOuts[index] = 0; +} +//------------------------------------------------------------------------------ + +void Clipper::SetWindingCount(TEdge &edge) +{ + TEdge *e = edge.prevInAEL; + //find the edge of the same polytype that immediately preceeds 'edge' in AEL + while ( e && e->polyType != edge.polyType ) e = e->prevInAEL; + if ( !e ) + { + edge.windCnt = edge.windDelta; + edge.windCnt2 = 0; + e = m_ActiveEdges; //ie get ready to calc windCnt2 + } else if ( IsEvenOddFillType(edge) ) + { + //EvenOdd filling ... + edge.windCnt = 1; + edge.windCnt2 = e->windCnt2; + e = e->nextInAEL; //ie get ready to calc windCnt2 + } else + { + //nonZero, Positive or Negative filling ... + if ( e->windCnt * e->windDelta < 0 ) + { + if (Abs(e->windCnt) > 1) + { + if (e->windDelta * edge.windDelta < 0) edge.windCnt = e->windCnt; + else edge.windCnt = e->windCnt + edge.windDelta; + } else + edge.windCnt = e->windCnt + e->windDelta + edge.windDelta; + } else + { + if ( Abs(e->windCnt) > 1 && e->windDelta * edge.windDelta < 0) + edge.windCnt = e->windCnt; + else if ( e->windCnt + edge.windDelta == 0 ) + edge.windCnt = e->windCnt; + else edge.windCnt = e->windCnt + edge.windDelta; + } + edge.windCnt2 = e->windCnt2; + e = e->nextInAEL; //ie get ready to calc windCnt2 + } + + //update windCnt2 ... + if ( IsEvenOddAltFillType(edge) ) + { + //EvenOdd filling ... + while ( e != &edge ) + { + edge.windCnt2 = (edge.windCnt2 == 0) ? 1 : 0; + e = e->nextInAEL; + } + } else + { + //nonZero, Positive or Negative filling ... + while ( e != &edge ) + { + edge.windCnt2 += e->windDelta; + e = e->nextInAEL; + } + } +} +//------------------------------------------------------------------------------ + +bool Clipper::IsEvenOddFillType(const TEdge& edge) const +{ + if (edge.polyType == ptSubject) + return m_SubjFillType == pftEvenOdd; else + return m_ClipFillType == pftEvenOdd; +} +//------------------------------------------------------------------------------ + +bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const +{ + if (edge.polyType == ptSubject) + return m_ClipFillType == pftEvenOdd; else + return m_SubjFillType == pftEvenOdd; +} +//------------------------------------------------------------------------------ + +bool Clipper::IsContributing(const TEdge& edge) const +{ + PolyFillType pft, pft2; + if (edge.polyType == ptSubject) + { + pft = m_SubjFillType; + pft2 = m_ClipFillType; + } else + { + pft = m_ClipFillType; + pft2 = m_SubjFillType; + } + + switch(pft) + { + case pftEvenOdd: + case pftNonZero: + if (Abs(edge.windCnt) != 1) return false; + break; + case pftPositive: + if (edge.windCnt != 1) return false; + break; + default: //pftNegative + if (edge.windCnt != -1) return false; + } + + switch(m_ClipType) + { + case ctIntersection: + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.windCnt2 != 0); + case pftPositive: + return (edge.windCnt2 > 0); + default: + return (edge.windCnt2 < 0); + } + break; + case ctUnion: + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.windCnt2 == 0); + case pftPositive: + return (edge.windCnt2 <= 0); + default: + return (edge.windCnt2 >= 0); + } + break; + case ctDifference: + if (edge.polyType == ptSubject) + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.windCnt2 == 0); + case pftPositive: + return (edge.windCnt2 <= 0); + default: + return (edge.windCnt2 >= 0); + } + else + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.windCnt2 != 0); + case pftPositive: + return (edge.windCnt2 > 0); + default: + return (edge.windCnt2 < 0); + } + break; + default: + return true; + } +} +//------------------------------------------------------------------------------ + +void Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt) +{ + TEdge *e, *prevE; + if( NEAR_EQUAL(e2->dx, HORIZONTAL) || ( e1->dx > e2->dx ) ) + { + AddOutPt( e1, pt ); + e2->outIdx = e1->outIdx; + e1->side = esLeft; + e2->side = esRight; + e = e1; + if (e->prevInAEL == e2) + prevE = e2->prevInAEL; + else + prevE = e->prevInAEL; + } else + { + AddOutPt( e2, pt ); + e1->outIdx = e2->outIdx; + e1->side = esRight; + e2->side = esLeft; + e = e2; + if (e->prevInAEL == e1) + prevE = e1->prevInAEL; + else + prevE = e->prevInAEL; + } + if (prevE && prevE->outIdx >= 0 && + (TopX(*prevE, pt.Y) == TopX(*e, pt.Y)) && + SlopesEqual(*e, *prevE, m_UseFullRange)) + AddJoin(e, prevE, -1, -1); +} +//------------------------------------------------------------------------------ + +void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt) +{ + AddOutPt( e1, pt ); + if( e1->outIdx == e2->outIdx ) + { + e1->outIdx = -1; + e2->outIdx = -1; + } + else if (e1->outIdx < e2->outIdx) + AppendPolygon(e1, e2); + else + AppendPolygon(e2, e1); +} +//------------------------------------------------------------------------------ + +void Clipper::AddEdgeToSEL(TEdge *edge) +{ + //SEL pointers in PEdge are reused to build a list of horizontal edges. + //However, we don't need to worry about order with horizontal edge processing. + if( !m_SortedEdges ) + { + m_SortedEdges = edge; + edge->prevInSEL = 0; + edge->nextInSEL = 0; + } + else + { + edge->nextInSEL = m_SortedEdges; + edge->prevInSEL = 0; + m_SortedEdges->prevInSEL = edge; + m_SortedEdges = edge; + } +} +//------------------------------------------------------------------------------ + +void Clipper::CopyAELToSEL() +{ + TEdge* e = m_ActiveEdges; + m_SortedEdges = e; + while ( e ) + { + e->prevInSEL = e->prevInAEL; + e->nextInSEL = e->nextInAEL; + e = e->nextInAEL; + } +} +//------------------------------------------------------------------------------ + +void Clipper::AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx, int e2OutIdx) +{ + JoinRec* jr = new JoinRec; + if (e1OutIdx >= 0) + jr->poly1Idx = e1OutIdx; else + jr->poly1Idx = e1->outIdx; + jr->pt1a = IntPoint(e1->xcurr, e1->ycurr); + jr->pt1b = IntPoint(e1->xtop, e1->ytop); + if (e2OutIdx >= 0) + jr->poly2Idx = e2OutIdx; else + jr->poly2Idx = e2->outIdx; + jr->pt2a = IntPoint(e2->xcurr, e2->ycurr); + jr->pt2b = IntPoint(e2->xtop, e2->ytop); + m_Joins.push_back(jr); +} +//------------------------------------------------------------------------------ + +void Clipper::ClearJoins() +{ + for (JoinList::size_type i = 0; i < m_Joins.size(); i++) + delete m_Joins[i]; + m_Joins.resize(0); +} +//------------------------------------------------------------------------------ + +void Clipper::AddHorzJoin(TEdge *e, int idx) +{ + HorzJoinRec* hj = new HorzJoinRec; + hj->edge = e; + hj->savedIdx = idx; + m_HorizJoins.push_back(hj); +} +//------------------------------------------------------------------------------ + +void Clipper::ClearHorzJoins() +{ + for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); i++) + delete m_HorizJoins[i]; + m_HorizJoins.resize(0); +} +//------------------------------------------------------------------------------ + +void Clipper::InsertLocalMinimaIntoAEL(const long64 botY) +{ + while( m_CurrentLM && ( m_CurrentLM->Y == botY ) ) + { + TEdge* lb = m_CurrentLM->leftBound; + TEdge* rb = m_CurrentLM->rightBound; + + InsertEdgeIntoAEL( lb ); + InsertScanbeam( lb->ytop ); + InsertEdgeIntoAEL( rb ); + + if (IsEvenOddFillType(*lb)) + { + lb->windDelta = 1; + rb->windDelta = 1; + } + else + { + rb->windDelta = -lb->windDelta; + } + SetWindingCount( *lb ); + rb->windCnt = lb->windCnt; + rb->windCnt2 = lb->windCnt2; + + if( NEAR_EQUAL(rb->dx, HORIZONTAL) ) + { + //nb: only rightbounds can have a horizontal bottom edge + AddEdgeToSEL( rb ); + InsertScanbeam( rb->nextInLML->ytop ); + } + else + InsertScanbeam( rb->ytop ); + + if( IsContributing(*lb) ) + AddLocalMinPoly( lb, rb, IntPoint(lb->xcurr, m_CurrentLM->Y) ); + + //if any output polygons share an edge, they'll need joining later ... + if (rb->outIdx >= 0 && NEAR_EQUAL(rb->dx, HORIZONTAL)) + { + for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i) + { + IntPoint pt, pt2; //returned by GetOverlapSegment() but unused here. + HorzJoinRec* hj = m_HorizJoins[i]; + //if horizontals rb and hj.edge overlap, flag for joining later ... + if (GetOverlapSegment(IntPoint(hj->edge->xbot, hj->edge->ybot), + IntPoint(hj->edge->xtop, hj->edge->ytop), + IntPoint(rb->xbot, rb->ybot), + IntPoint(rb->xtop, rb->ytop), pt, pt2)) + AddJoin(hj->edge, rb, hj->savedIdx); + } + } + + if( lb->nextInAEL != rb ) + { + if (rb->outIdx >= 0 && rb->prevInAEL->outIdx >= 0 && + SlopesEqual(*rb->prevInAEL, *rb, m_UseFullRange)) + AddJoin(rb, rb->prevInAEL); + + TEdge* e = lb->nextInAEL; + IntPoint pt = IntPoint(lb->xcurr, lb->ycurr); + while( e != rb ) + { + if(!e) throw clipperException("InsertLocalMinimaIntoAEL: missing rightbound!"); + //nb: For calculating winding counts etc, IntersectEdges() assumes + //that param1 will be to the right of param2 ABOVE the intersection ... + IntersectEdges( rb , e , pt , ipNone); //order important here + e = e->nextInAEL; + } + } + PopLocalMinima(); + } +} +//------------------------------------------------------------------------------ + +void Clipper::DeleteFromAEL(TEdge *e) +{ + TEdge* AelPrev = e->prevInAEL; + TEdge* AelNext = e->nextInAEL; + if( !AelPrev && !AelNext && (e != m_ActiveEdges) ) return; //already deleted + if( AelPrev ) AelPrev->nextInAEL = AelNext; + else m_ActiveEdges = AelNext; + if( AelNext ) AelNext->prevInAEL = AelPrev; + e->nextInAEL = 0; + e->prevInAEL = 0; +} +//------------------------------------------------------------------------------ + +void Clipper::DeleteFromSEL(TEdge *e) +{ + TEdge* SelPrev = e->prevInSEL; + TEdge* SelNext = e->nextInSEL; + if( !SelPrev && !SelNext && (e != m_SortedEdges) ) return; //already deleted + if( SelPrev ) SelPrev->nextInSEL = SelNext; + else m_SortedEdges = SelNext; + if( SelNext ) SelNext->prevInSEL = SelPrev; + e->nextInSEL = 0; + e->prevInSEL = 0; +} +//------------------------------------------------------------------------------ + +void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, + const IntPoint &pt, const IntersectProtects protects) +{ + //e1 will be to the left of e2 BELOW the intersection. Therefore e1 is before + //e2 in AEL except when e1 is being inserted at the intersection point ... + bool e1stops = !(ipLeft & protects) && !e1->nextInLML && + e1->xtop == pt.X && e1->ytop == pt.Y; + bool e2stops = !(ipRight & protects) && !e2->nextInLML && + e2->xtop == pt.X && e2->ytop == pt.Y; + bool e1Contributing = ( e1->outIdx >= 0 ); + bool e2contributing = ( e2->outIdx >= 0 ); + + //update winding counts... + //assumes that e1 will be to the right of e2 ABOVE the intersection + if ( e1->polyType == e2->polyType ) + { + if ( IsEvenOddFillType( *e1) ) + { + int oldE1WindCnt = e1->windCnt; + e1->windCnt = e2->windCnt; + e2->windCnt = oldE1WindCnt; + } else + { + if (e1->windCnt + e2->windDelta == 0 ) e1->windCnt = -e1->windCnt; + else e1->windCnt += e2->windDelta; + if ( e2->windCnt - e1->windDelta == 0 ) e2->windCnt = -e2->windCnt; + else e2->windCnt -= e1->windDelta; + } + } else + { + if (!IsEvenOddFillType(*e2)) e1->windCnt2 += e2->windDelta; + else e1->windCnt2 = ( e1->windCnt2 == 0 ) ? 1 : 0; + if (!IsEvenOddFillType(*e1)) e2->windCnt2 -= e1->windDelta; + else e2->windCnt2 = ( e2->windCnt2 == 0 ) ? 1 : 0; + } + + PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2; + if (e1->polyType == ptSubject) + { + e1FillType = m_SubjFillType; + e1FillType2 = m_ClipFillType; + } else + { + e1FillType = m_ClipFillType; + e1FillType2 = m_SubjFillType; + } + if (e2->polyType == ptSubject) + { + e2FillType = m_SubjFillType; + e2FillType2 = m_ClipFillType; + } else + { + e2FillType = m_ClipFillType; + e2FillType2 = m_SubjFillType; + } + + long64 e1Wc, e2Wc; + switch (e1FillType) + { + case pftPositive: e1Wc = e1->windCnt; break; + case pftNegative: e1Wc = -e1->windCnt; break; + default: e1Wc = Abs(e1->windCnt); + } + switch(e2FillType) + { + case pftPositive: e2Wc = e2->windCnt; break; + case pftNegative: e2Wc = -e2->windCnt; break; + default: e2Wc = Abs(e2->windCnt); + } + + if ( e1Contributing && e2contributing ) + { + if ( e1stops || e2stops || + (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || + (e1->polyType != e2->polyType && m_ClipType != ctXor) ) + AddLocalMaxPoly(e1, e2, pt); + else + { + AddOutPt(e1, pt); + AddOutPt(e2, pt); + SwapSides( *e1 , *e2 ); + SwapPolyIndexes( *e1 , *e2 ); + } + } + else if ( e1Contributing ) + { + if (e2Wc == 0 || e2Wc == 1) + { + AddOutPt(e1, pt); + SwapSides(*e1, *e2); + SwapPolyIndexes(*e1, *e2); + } + } + else if ( e2contributing ) + { + if (e1Wc == 0 || e1Wc == 1) + { + AddOutPt(e2, pt); + SwapSides(*e1, *e2); + SwapPolyIndexes(*e1, *e2); + } + } + else if ( (e1Wc == 0 || e1Wc == 1) && + (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops ) + { + //neither edge is currently contributing ... + + long64 e1Wc2, e2Wc2; + switch (e1FillType2) + { + case pftPositive: e1Wc2 = e1->windCnt2; break; + case pftNegative : e1Wc2 = -e1->windCnt2; break; + default: e1Wc2 = Abs(e1->windCnt2); + } + switch (e2FillType2) + { + case pftPositive: e2Wc2 = e2->windCnt2; break; + case pftNegative: e2Wc2 = -e2->windCnt2; break; + default: e2Wc2 = Abs(e2->windCnt2); + } + + if (e1->polyType != e2->polyType) + AddLocalMinPoly(e1, e2, pt); + else if (e1Wc == 1 && e2Wc == 1) + switch( m_ClipType ) { + case ctIntersection: + if (e1Wc2 > 0 && e2Wc2 > 0) + AddLocalMinPoly(e1, e2, pt); + break; + case ctUnion: + if ( e1Wc2 <= 0 && e2Wc2 <= 0 ) + AddLocalMinPoly(e1, e2, pt); + break; + case ctDifference: + if (((e1->polyType == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || + ((e1->polyType == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) + AddLocalMinPoly(e1, e2, pt); + break; + case ctXor: + AddLocalMinPoly(e1, e2, pt); + } + else + SwapSides( *e1, *e2 ); + } + + if( (e1stops != e2stops) && + ( (e1stops && (e1->outIdx >= 0)) || (e2stops && (e2->outIdx >= 0)) ) ) + { + SwapSides( *e1, *e2 ); + SwapPolyIndexes( *e1, *e2 ); + } + + //finally, delete any non-contributing maxima edges ... + if( e1stops ) DeleteFromAEL( e1 ); + if( e2stops ) DeleteFromAEL( e2 ); +} +//------------------------------------------------------------------------------ + +void Clipper::SetHoleState(TEdge *e, OutRec *outrec) +{ + bool isHole = false; + TEdge *e2 = e->prevInAEL; + while (e2) + { + if (e2->outIdx >= 0) + { + isHole = !isHole; + if (! outrec->FirstLeft) + outrec->FirstLeft = m_PolyOuts[e2->outIdx]; + } + e2 = e2->prevInAEL; + } + if (isHole) outrec->isHole = true; +} +//------------------------------------------------------------------------------ + +OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2) +{ + //work out which polygon fragment has the correct hole state ... + if (!outRec1->bottomPt) + outRec1->bottomPt = GetBottomPt(outRec1->pts); + if (!outRec2->bottomPt) + outRec2->bottomPt = GetBottomPt(outRec2->pts); + OutPt *outPt1 = outRec1->bottomPt; + OutPt *outPt2 = outRec2->bottomPt; + if (outPt1->pt.Y > outPt2->pt.Y) return outRec1; + else if (outPt1->pt.Y < outPt2->pt.Y) return outRec2; + else if (outPt1->pt.X < outPt2->pt.X) return outRec1; + else if (outPt1->pt.X > outPt2->pt.X) return outRec2; + else if (outPt1->next == outPt1) return outRec2; + else if (outPt2->next == outPt2) return outRec1; + else if (FirstIsBottomPt(outPt1, outPt2)) return outRec1; + else return outRec2; +} +//------------------------------------------------------------------------------ + +bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2) +{ + do + { + outRec1 = outRec1->FirstLeft; + if (outRec1 == outRec2) return true; + } while (outRec1); + return false; +} +//------------------------------------------------------------------------------ + +OutRec* Clipper::GetOutRec(int idx) +{ + OutRec* outrec = m_PolyOuts[idx]; + while (outrec != m_PolyOuts[outrec->idx]) + outrec = m_PolyOuts[outrec->idx]; + return outrec; +} +//------------------------------------------------------------------------------ + +void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) +{ + //get the start and ends of both output polygons ... + OutRec *outRec1 = m_PolyOuts[e1->outIdx]; + OutRec *outRec2 = m_PolyOuts[e2->outIdx]; + + OutRec *holeStateRec; + if (Param1RightOfParam2(outRec1, outRec2)) + holeStateRec = outRec2; + else if (Param1RightOfParam2(outRec2, outRec1)) + holeStateRec = outRec1; + else + holeStateRec = GetLowermostRec(outRec1, outRec2); + + OutPt* p1_lft = outRec1->pts; + OutPt* p1_rt = p1_lft->prev; + OutPt* p2_lft = outRec2->pts; + OutPt* p2_rt = p2_lft->prev; + + EdgeSide side; + //join e2 poly onto e1 poly and delete pointers to e2 ... + if( e1->side == esLeft ) + { + if( e2->side == esLeft ) + { + //z y x a b c + ReversePolyPtLinks(p2_lft); + p2_lft->next = p1_lft; + p1_lft->prev = p2_lft; + p1_rt->next = p2_rt; + p2_rt->prev = p1_rt; + outRec1->pts = p2_rt; + } else + { + //x y z a b c + p2_rt->next = p1_lft; + p1_lft->prev = p2_rt; + p2_lft->prev = p1_rt; + p1_rt->next = p2_lft; + outRec1->pts = p2_lft; + } + side = esLeft; + } else + { + if( e2->side == esRight ) + { + //a b c z y x + ReversePolyPtLinks(p2_lft); + p1_rt->next = p2_rt; + p2_rt->prev = p1_rt; + p2_lft->next = p1_lft; + p1_lft->prev = p2_lft; + } else + { + //a b c x y z + p1_rt->next = p2_lft; + p2_lft->prev = p1_rt; + p1_lft->prev = p2_rt; + p2_rt->next = p1_lft; + } + side = esRight; + } + + outRec1->bottomPt = 0; + if (holeStateRec == outRec2) + { + if (outRec2->FirstLeft != outRec1) + outRec1->FirstLeft = outRec2->FirstLeft; + outRec1->isHole = outRec2->isHole; + } + outRec2->pts = 0; + outRec2->bottomPt = 0; + + outRec2->FirstLeft = outRec1; + + int OKIdx = e1->outIdx; + int ObsoleteIdx = e2->outIdx; + + e1->outIdx = -1; //nb: safe because we only get here via AddLocalMaxPoly + e2->outIdx = -1; + + TEdge* e = m_ActiveEdges; + while( e ) + { + if( e->outIdx == ObsoleteIdx ) + { + e->outIdx = OKIdx; + e->side = side; + break; + } + e = e->nextInAEL; + } + + outRec2->idx = outRec1->idx; +} +//------------------------------------------------------------------------------ + +OutRec* Clipper::CreateOutRec() +{ + OutRec* result = new OutRec; + result->isHole = false; + result->FirstLeft = 0; + result->pts = 0; + result->bottomPt = 0; + result->polyNode = 0; + m_PolyOuts.push_back(result); + result->idx = (int)m_PolyOuts.size()-1; + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::AddOutPt(TEdge *e, const IntPoint &pt) +{ + bool ToFront = (e->side == esLeft); + if( e->outIdx < 0 ) + { + OutRec *outRec = CreateOutRec(); + e->outIdx = outRec->idx; + OutPt* newOp = new OutPt; + outRec->pts = newOp; + newOp->pt = pt; + newOp->idx = outRec->idx; + newOp->next = newOp; + newOp->prev = newOp; + SetHoleState(e, outRec); + } else + { + OutRec *outRec = m_PolyOuts[e->outIdx]; + OutPt* op = outRec->pts; + if ((ToFront && PointsEqual(pt, op->pt)) || + (!ToFront && PointsEqual(pt, op->prev->pt))) return; + + OutPt* newOp = new OutPt; + newOp->pt = pt; + newOp->idx = outRec->idx; + newOp->next = op; + newOp->prev = op->prev; + newOp->prev->next = newOp; + op->prev = newOp; + if (ToFront) outRec->pts = newOp; + } +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessHorizontals() +{ + TEdge* horzEdge = m_SortedEdges; + while( horzEdge ) + { + DeleteFromSEL( horzEdge ); + ProcessHorizontal( horzEdge ); + horzEdge = m_SortedEdges; + } +} +//------------------------------------------------------------------------------ + +bool Clipper::IsTopHorz(const long64 XPos) +{ + TEdge* e = m_SortedEdges; + while( e ) + { + if( ( XPos >= std::min(e->xcurr, e->xtop) ) && + ( XPos <= std::max(e->xcurr, e->xtop) ) ) return false; + e = e->nextInSEL; + } + return true; +} +//------------------------------------------------------------------------------ + +inline bool IsMinima(TEdge *e) +{ + return e && (e->prev->nextInLML != e) && (e->next->nextInLML != e); +} +//------------------------------------------------------------------------------ + +inline bool IsMaxima(TEdge *e, const long64 Y) +{ + return e && e->ytop == Y && !e->nextInLML; +} +//------------------------------------------------------------------------------ + +inline bool IsIntermediate(TEdge *e, const long64 Y) +{ + return e->ytop == Y && e->nextInLML; +} +//------------------------------------------------------------------------------ + +TEdge *GetMaximaPair(TEdge *e) +{ + if( !IsMaxima(e->next, e->ytop) || e->next->xtop != e->xtop ) + return e->prev; else + return e->next; +} +//------------------------------------------------------------------------------ + +void Clipper::SwapPositionsInAEL(TEdge *edge1, TEdge *edge2) +{ + if( edge1->nextInAEL == edge2 ) + { + TEdge* next = edge2->nextInAEL; + if( next ) next->prevInAEL = edge1; + TEdge* prev = edge1->prevInAEL; + if( prev ) prev->nextInAEL = edge2; + edge2->prevInAEL = prev; + edge2->nextInAEL = edge1; + edge1->prevInAEL = edge2; + edge1->nextInAEL = next; + } + else if( edge2->nextInAEL == edge1 ) + { + TEdge* next = edge1->nextInAEL; + if( next ) next->prevInAEL = edge2; + TEdge* prev = edge2->prevInAEL; + if( prev ) prev->nextInAEL = edge1; + edge1->prevInAEL = prev; + edge1->nextInAEL = edge2; + edge2->prevInAEL = edge1; + edge2->nextInAEL = next; + } + else + { + TEdge* next = edge1->nextInAEL; + TEdge* prev = edge1->prevInAEL; + edge1->nextInAEL = edge2->nextInAEL; + if( edge1->nextInAEL ) edge1->nextInAEL->prevInAEL = edge1; + edge1->prevInAEL = edge2->prevInAEL; + if( edge1->prevInAEL ) edge1->prevInAEL->nextInAEL = edge1; + edge2->nextInAEL = next; + if( edge2->nextInAEL ) edge2->nextInAEL->prevInAEL = edge2; + edge2->prevInAEL = prev; + if( edge2->prevInAEL ) edge2->prevInAEL->nextInAEL = edge2; + } + + if( !edge1->prevInAEL ) m_ActiveEdges = edge1; + else if( !edge2->prevInAEL ) m_ActiveEdges = edge2; +} +//------------------------------------------------------------------------------ + +void Clipper::SwapPositionsInSEL(TEdge *edge1, TEdge *edge2) +{ + if( !( edge1->nextInSEL ) && !( edge1->prevInSEL ) ) return; + if( !( edge2->nextInSEL ) && !( edge2->prevInSEL ) ) return; + + if( edge1->nextInSEL == edge2 ) + { + TEdge* next = edge2->nextInSEL; + if( next ) next->prevInSEL = edge1; + TEdge* prev = edge1->prevInSEL; + if( prev ) prev->nextInSEL = edge2; + edge2->prevInSEL = prev; + edge2->nextInSEL = edge1; + edge1->prevInSEL = edge2; + edge1->nextInSEL = next; + } + else if( edge2->nextInSEL == edge1 ) + { + TEdge* next = edge1->nextInSEL; + if( next ) next->prevInSEL = edge2; + TEdge* prev = edge2->prevInSEL; + if( prev ) prev->nextInSEL = edge1; + edge1->prevInSEL = prev; + edge1->nextInSEL = edge2; + edge2->prevInSEL = edge1; + edge2->nextInSEL = next; + } + else + { + TEdge* next = edge1->nextInSEL; + TEdge* prev = edge1->prevInSEL; + edge1->nextInSEL = edge2->nextInSEL; + if( edge1->nextInSEL ) edge1->nextInSEL->prevInSEL = edge1; + edge1->prevInSEL = edge2->prevInSEL; + if( edge1->prevInSEL ) edge1->prevInSEL->nextInSEL = edge1; + edge2->nextInSEL = next; + if( edge2->nextInSEL ) edge2->nextInSEL->prevInSEL = edge2; + edge2->prevInSEL = prev; + if( edge2->prevInSEL ) edge2->prevInSEL->nextInSEL = edge2; + } + + if( !edge1->prevInSEL ) m_SortedEdges = edge1; + else if( !edge2->prevInSEL ) m_SortedEdges = edge2; +} +//------------------------------------------------------------------------------ + +TEdge* GetNextInAEL(TEdge *e, Direction dir) +{ + return dir == dLeftToRight ? e->nextInAEL : e->prevInAEL; +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessHorizontal(TEdge *horzEdge) +{ + Direction dir; + long64 horzLeft, horzRight; + + if( horzEdge->xcurr < horzEdge->xtop ) + { + horzLeft = horzEdge->xcurr; + horzRight = horzEdge->xtop; + dir = dLeftToRight; + } else + { + horzLeft = horzEdge->xtop; + horzRight = horzEdge->xcurr; + dir = dRightToLeft; + } + + TEdge* eMaxPair; + if( horzEdge->nextInLML ) eMaxPair = 0; + else eMaxPair = GetMaximaPair(horzEdge); + + TEdge* e = GetNextInAEL( horzEdge , dir ); + while( e ) + { + if ( e->xcurr == horzEdge->xtop && !eMaxPair ) + { + if (SlopesEqual(*e, *horzEdge->nextInLML, m_UseFullRange)) + { + //if output polygons share an edge, they'll need joining later ... + if (horzEdge->outIdx >= 0 && e->outIdx >= 0) + AddJoin(horzEdge->nextInLML, e, horzEdge->outIdx); + break; //we've reached the end of the horizontal line + } + else if (e->dx < horzEdge->nextInLML->dx) + //we really have got to the end of the intermediate horz edge so quit. + //nb: More -ve slopes follow more +ve slopes ABOVE the horizontal. + break; + } + + TEdge* eNext = GetNextInAEL( e, dir ); + + if (eMaxPair || + ((dir == dLeftToRight) && (e->xcurr < horzRight)) || + ((dir == dRightToLeft) && (e->xcurr > horzLeft))) + { + //so far we're still in range of the horizontal edge + if( e == eMaxPair ) + { + //horzEdge is evidently a maxima horizontal and we've arrived at its end. + if (dir == dLeftToRight) + IntersectEdges(horzEdge, e, IntPoint(e->xcurr, horzEdge->ycurr), ipNone); + else + IntersectEdges(e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr), ipNone); + if (eMaxPair->outIdx >= 0) throw clipperException("ProcessHorizontal error"); + return; + } + else if( NEAR_EQUAL(e->dx, HORIZONTAL) && !IsMinima(e) && !(e->xcurr > e->xtop) ) + { + //An overlapping horizontal edge. Overlapping horizontal edges are + //processed as if layered with the current horizontal edge (horizEdge) + //being infinitesimally lower that the next (e). Therfore, we + //intersect with e only if e.xcurr is within the bounds of horzEdge ... + if( dir == dLeftToRight ) + IntersectEdges( horzEdge , e, IntPoint(e->xcurr, horzEdge->ycurr), + (IsTopHorz( e->xcurr ))? ipLeft : ipBoth ); + else + IntersectEdges( e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr), + (IsTopHorz( e->xcurr ))? ipRight : ipBoth ); + } + else if( dir == dLeftToRight ) + { + IntersectEdges( horzEdge, e, IntPoint(e->xcurr, horzEdge->ycurr), + (IsTopHorz( e->xcurr ))? ipLeft : ipBoth ); + } + else + { + IntersectEdges( e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr), + (IsTopHorz( e->xcurr ))? ipRight : ipBoth ); + } + SwapPositionsInAEL( horzEdge, e ); + } + else if( (dir == dLeftToRight && e->xcurr >= horzRight) || + (dir == dRightToLeft && e->xcurr <= horzLeft) ) break; + e = eNext; + } //end while + + if( horzEdge->nextInLML ) + { + if( horzEdge->outIdx >= 0 ) + AddOutPt( horzEdge, IntPoint(horzEdge->xtop, horzEdge->ytop)); + UpdateEdgeIntoAEL( horzEdge ); + } + else + { + if ( horzEdge->outIdx >= 0 ) + IntersectEdges( horzEdge, eMaxPair, + IntPoint(horzEdge->xtop, horzEdge->ycurr), ipBoth); + if (eMaxPair->outIdx >= 0) throw clipperException("ProcessHorizontal error"); + DeleteFromAEL(eMaxPair); + DeleteFromAEL(horzEdge); + } +} +//------------------------------------------------------------------------------ + +void Clipper::UpdateEdgeIntoAEL(TEdge *&e) +{ + if( !e->nextInLML ) throw + clipperException("UpdateEdgeIntoAEL: invalid call"); + TEdge* AelPrev = e->prevInAEL; + TEdge* AelNext = e->nextInAEL; + e->nextInLML->outIdx = e->outIdx; + if( AelPrev ) AelPrev->nextInAEL = e->nextInLML; + else m_ActiveEdges = e->nextInLML; + if( AelNext ) AelNext->prevInAEL = e->nextInLML; + e->nextInLML->side = e->side; + e->nextInLML->windDelta = e->windDelta; + e->nextInLML->windCnt = e->windCnt; + e->nextInLML->windCnt2 = e->windCnt2; + e = e->nextInLML; + e->prevInAEL = AelPrev; + e->nextInAEL = AelNext; + if( !NEAR_EQUAL(e->dx, HORIZONTAL) ) InsertScanbeam( e->ytop ); +} +//------------------------------------------------------------------------------ + +bool Clipper::ProcessIntersections(const long64 botY, const long64 topY) +{ + if( !m_ActiveEdges ) return true; + try { + BuildIntersectList(botY, topY); + if (!m_IntersectNodes) return true; + if (!m_IntersectNodes->next || FixupIntersectionOrder()) ProcessIntersectList(); + else return false; + } + catch(...) { + m_SortedEdges = 0; + DisposeIntersectNodes(); + throw clipperException("ProcessIntersections error"); + } + m_SortedEdges = 0; + return true; +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeIntersectNodes() +{ + while ( m_IntersectNodes ) + { + IntersectNode* iNode = m_IntersectNodes->next; + delete m_IntersectNodes; + m_IntersectNodes = iNode; + } +} +//------------------------------------------------------------------------------ + +void Clipper::BuildIntersectList(const long64 botY, const long64 topY) +{ + if ( !m_ActiveEdges ) return; + + //prepare for sorting ... + TEdge* e = m_ActiveEdges; + m_SortedEdges = e; + while( e ) + { + e->prevInSEL = e->prevInAEL; + e->nextInSEL = e->nextInAEL; + e->xcurr = TopX( *e, topY ); + e = e->nextInAEL; + } + + //bubblesort ... + bool isModified; + do + { + isModified = false; + e = m_SortedEdges; + while( e->nextInSEL ) + { + TEdge *eNext = e->nextInSEL; + IntPoint pt; + if(e->xcurr > eNext->xcurr) + { + if (!IntersectPoint(*e, *eNext, pt, m_UseFullRange) && e->xcurr > eNext->xcurr +1) + throw clipperException("Intersection error"); + if (pt.Y > botY) + { + pt.Y = botY; + pt.X = TopX(*e, pt.Y); + } + InsertIntersectNode( e, eNext, pt ); + SwapPositionsInSEL(e, eNext); + isModified = true; + } + else + e = eNext; + } + if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0; + else break; + } + while ( isModified ); + m_SortedEdges = 0; //important +} +//------------------------------------------------------------------------------ + +void Clipper::InsertIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt) +{ + IntersectNode* newNode = new IntersectNode; + newNode->edge1 = e1; + newNode->edge2 = e2; + newNode->pt = pt; + newNode->next = 0; + if( !m_IntersectNodes ) m_IntersectNodes = newNode; + else if(newNode->pt.Y > m_IntersectNodes->pt.Y ) + { + newNode->next = m_IntersectNodes; + m_IntersectNodes = newNode; + } + else + { + IntersectNode* iNode = m_IntersectNodes; + while(iNode->next && newNode->pt.Y <= iNode->next->pt.Y) + iNode = iNode->next; + newNode->next = iNode->next; + iNode->next = newNode; + } +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessIntersectList() +{ + while( m_IntersectNodes ) + { + IntersectNode* iNode = m_IntersectNodes->next; + { + IntersectEdges( m_IntersectNodes->edge1 , + m_IntersectNodes->edge2 , m_IntersectNodes->pt, ipBoth ); + SwapPositionsInAEL( m_IntersectNodes->edge1 , m_IntersectNodes->edge2 ); + } + delete m_IntersectNodes; + m_IntersectNodes = iNode; + } +} +//------------------------------------------------------------------------------ + +void Clipper::DoMaxima(TEdge *e, long64 topY) +{ + TEdge* eMaxPair = GetMaximaPair(e); + long64 X = e->xtop; + TEdge* eNext = e->nextInAEL; + while( eNext != eMaxPair ) + { + if (!eNext) throw clipperException("DoMaxima error"); + IntersectEdges( e, eNext, IntPoint(X, topY), ipBoth ); + SwapPositionsInAEL(e, eNext); + eNext = e->nextInAEL; + } + if( e->outIdx < 0 && eMaxPair->outIdx < 0 ) + { + DeleteFromAEL( e ); + DeleteFromAEL( eMaxPair ); + } + else if( e->outIdx >= 0 && eMaxPair->outIdx >= 0 ) + { + IntersectEdges( e, eMaxPair, IntPoint(X, topY), ipNone ); + } + else throw clipperException("DoMaxima error"); +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessEdgesAtTopOfScanbeam(const long64 topY) +{ + TEdge* e = m_ActiveEdges; + while( e ) + { + //1. process maxima, treating them as if they're 'bent' horizontal edges, + // but exclude maxima with horizontal edges. nb: e can't be a horizontal. + if( IsMaxima(e, topY) && !NEAR_EQUAL(GetMaximaPair(e)->dx, HORIZONTAL) ) + { + //'e' might be removed from AEL, as may any following edges so ... + TEdge* ePrev = e->prevInAEL; + DoMaxima(e, topY); + if( !ePrev ) e = m_ActiveEdges; + else e = ePrev->nextInAEL; + } + else + { + bool intermediateVert = IsIntermediate(e, topY); + //2. promote horizontal edges, otherwise update xcurr and ycurr ... + if (intermediateVert && NEAR_EQUAL(e->nextInLML->dx, HORIZONTAL) ) + { + if (e->outIdx >= 0) + { + AddOutPt(e, IntPoint(e->xtop, e->ytop)); + + for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i) + { + IntPoint pt, pt2; + HorzJoinRec* hj = m_HorizJoins[i]; + if (GetOverlapSegment(IntPoint(hj->edge->xbot, hj->edge->ybot), + IntPoint(hj->edge->xtop, hj->edge->ytop), + IntPoint(e->nextInLML->xbot, e->nextInLML->ybot), + IntPoint(e->nextInLML->xtop, e->nextInLML->ytop), pt, pt2)) + AddJoin(hj->edge, e->nextInLML, hj->savedIdx, e->outIdx); + } + + AddHorzJoin(e->nextInLML, e->outIdx); + } + UpdateEdgeIntoAEL(e); + AddEdgeToSEL(e); + } else + { + e->xcurr = TopX( *e, topY ); + e->ycurr = topY; + + if (m_ForceSimple && e->prevInAEL && + e->prevInAEL->xcurr == e->xcurr && + e->outIdx >= 0 && e->prevInAEL->outIdx >= 0) + { + if (intermediateVert) + AddOutPt(e->prevInAEL, IntPoint(e->xcurr, topY)); + else + AddOutPt(e, IntPoint(e->xcurr, topY)); + } + } + e = e->nextInAEL; + } + } + + //3. Process horizontals at the top of the scanbeam ... + ProcessHorizontals(); + + //4. Promote intermediate vertices ... + e = m_ActiveEdges; + while( e ) + { + if( IsIntermediate( e, topY ) ) + { + if( e->outIdx >= 0 ) AddOutPt(e, IntPoint(e->xtop,e->ytop)); + UpdateEdgeIntoAEL(e); + + //if output polygons share an edge, they'll need joining later ... + TEdge* ePrev = e->prevInAEL; + TEdge* eNext = e->nextInAEL; + if (ePrev && ePrev->xcurr == e->xbot && + ePrev->ycurr == e->ybot && e->outIdx >= 0 && + ePrev->outIdx >= 0 && ePrev->ycurr > ePrev->ytop && + SlopesEqual(*e, *ePrev, m_UseFullRange)) + { + AddOutPt(ePrev, IntPoint(e->xbot, e->ybot)); + AddJoin(e, ePrev); + } + else if (eNext && eNext->xcurr == e->xbot && + eNext->ycurr == e->ybot && e->outIdx >= 0 && + eNext->outIdx >= 0 && eNext->ycurr > eNext->ytop && + SlopesEqual(*e, *eNext, m_UseFullRange)) + { + AddOutPt(eNext, IntPoint(e->xbot, e->ybot)); + AddJoin(e, eNext); + } + } + e = e->nextInAEL; + } +} +//------------------------------------------------------------------------------ + +void Clipper::FixupOutPolygon(OutRec &outrec) +{ + //FixupOutPolygon() - removes duplicate points and simplifies consecutive + //parallel edges by removing the middle vertex. + OutPt *lastOK = 0; + outrec.bottomPt = 0; + OutPt *pp = outrec.pts; + + for (;;) + { + if (pp->prev == pp || pp->prev == pp->next ) + { + DisposeOutPts(pp); + outrec.pts = 0; + return; + } + //test for duplicate points and for same slope (cross-product) ... + if ( PointsEqual(pp->pt, pp->next->pt) || + SlopesEqual(pp->prev->pt, pp->pt, pp->next->pt, m_UseFullRange) ) + { + lastOK = 0; + OutPt *tmp = pp; + pp->prev->next = pp->next; + pp->next->prev = pp->prev; + pp = pp->prev; + delete tmp; + } + else if (pp == lastOK) break; + else + { + if (!lastOK) lastOK = pp; + pp = pp->next; + } + } + outrec.pts = pp; +} +//------------------------------------------------------------------------------ + +void Clipper::BuildResult(Polygons &polys) +{ + polys.reserve(m_PolyOuts.size()); + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + if (m_PolyOuts[i]->pts) + { + Polygon pg; + OutPt* p = m_PolyOuts[i]->pts; + do + { + pg.push_back(p->pt); + p = p->prev; + } while (p != m_PolyOuts[i]->pts); + if (pg.size() > 2) + polys.push_back(pg); + } + } +} +//------------------------------------------------------------------------------ + +int PointCount(OutPt *pts) +{ + if (!pts) return 0; + int result = 0; + OutPt* p = pts; + do + { + result++; + p = p->next; + } + while (p != pts); + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::BuildResult2(PolyTree& polytree) +{ + polytree.Clear(); + polytree.AllNodes.reserve(m_PolyOuts.size()); + //add each output polygon/contour to polytree ... + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) + { + OutRec* outRec = m_PolyOuts[i]; + int cnt = PointCount(outRec->pts); + if (cnt < 3) continue; + FixHoleLinkage(*outRec); + PolyNode* pn = new PolyNode(); + //nb: polytree takes ownership of all the PolyNodes + polytree.AllNodes.push_back(pn); + outRec->polyNode = pn; + pn->Parent = 0; + pn->Index = 0; + pn->Contour.reserve(cnt); + OutPt *op = outRec->pts; + for (int j = 0; j < cnt; j++) + { + pn->Contour.push_back(op->pt); + op = op->prev; + } + } + + //fixup PolyNode links etc ... + polytree.Childs.reserve(m_PolyOuts.size()); + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++) + { + OutRec* outRec = m_PolyOuts[i]; + if (!outRec->polyNode) continue; + if (outRec->FirstLeft) + outRec->FirstLeft->polyNode->AddChild(*outRec->polyNode); + else + polytree.AddChild(*outRec->polyNode); + } +} +//------------------------------------------------------------------------------ + +void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2) +{ + //just swap the contents (because fIntersectNodes is a single-linked-list) + IntersectNode inode = int1; //gets a copy of Int1 + int1.edge1 = int2.edge1; + int1.edge2 = int2.edge2; + int1.pt = int2.pt; + int2.edge1 = inode.edge1; + int2.edge2 = inode.edge2; + int2.pt = inode.pt; +} +//------------------------------------------------------------------------------ + +inline bool EdgesAdjacent(const IntersectNode &inode) +{ + return (inode.edge1->nextInSEL == inode.edge2) || + (inode.edge1->prevInSEL == inode.edge2); +} +//------------------------------------------------------------------------------ + +bool Clipper::FixupIntersectionOrder() +{ + //pre-condition: intersections are sorted bottom-most (then left-most) first. + //Now it's crucial that intersections are made only between adjacent edges, + //so to ensure this the order of intersections may need adjusting ... + IntersectNode *inode = m_IntersectNodes; + CopyAELToSEL(); + while (inode) + { + if (!EdgesAdjacent(*inode)) + { + IntersectNode *nextNode = inode->next; + while (nextNode && !EdgesAdjacent(*nextNode)) + nextNode = nextNode->next; + if (!nextNode) + return false; + SwapIntersectNodes(*inode, *nextNode); + } + SwapPositionsInSEL(inode->edge1, inode->edge2); + inode = inode->next; + } + return true; +} +//------------------------------------------------------------------------------ + +inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2) +{ + if (e2.xcurr == e1.xcurr) + { + if (e2.ytop > e1.ytop) + return e2.xtop < TopX(e1, e2.ytop); + else return e1.xtop > TopX(e2, e1.ytop); + } + else return e2.xcurr < e1.xcurr; +} +//------------------------------------------------------------------------------ + +void Clipper::InsertEdgeIntoAEL(TEdge *edge) +{ + edge->prevInAEL = 0; + edge->nextInAEL = 0; + if( !m_ActiveEdges ) + { + m_ActiveEdges = edge; + } + else if( E2InsertsBeforeE1(*m_ActiveEdges, *edge) ) + { + edge->nextInAEL = m_ActiveEdges; + m_ActiveEdges->prevInAEL = edge; + m_ActiveEdges = edge; + } else + { + TEdge* e = m_ActiveEdges; + while( e->nextInAEL && !E2InsertsBeforeE1(*e->nextInAEL , *edge) ) + e = e->nextInAEL; + edge->nextInAEL = e->nextInAEL; + if( e->nextInAEL ) e->nextInAEL->prevInAEL = edge; + edge->prevInAEL = e; + e->nextInAEL = edge; + } +} +//---------------------------------------------------------------------- + +bool Clipper::JoinPoints(const JoinRec *j, OutPt *&p1, OutPt *&p2) +{ + OutRec *outRec1 = m_PolyOuts[j->poly1Idx]; + OutRec *outRec2 = m_PolyOuts[j->poly2Idx]; + if (!outRec1 || !outRec2) return false; + OutPt *pp1a = outRec1->pts; + OutPt *pp2a = outRec2->pts; + IntPoint pt1 = j->pt2a, pt2 = j->pt2b; + IntPoint pt3 = j->pt1a, pt4 = j->pt1b; + if (!FindSegment(pp1a, m_UseFullRange, pt1, pt2)) return false; + if (outRec1 == outRec2) + { + //we're searching the same polygon for overlapping segments so + //segment 2 mustn't be the same as segment 1 ... + pp2a = pp1a->next; + if (!FindSegment(pp2a, m_UseFullRange, pt3, pt4) || (pp2a == pp1a)) + return false; + } + else if (!FindSegment(pp2a, m_UseFullRange, pt3, pt4)) return false; + + if (!GetOverlapSegment(pt1, pt2, pt3, pt4, pt1, pt2)) return false; + + OutPt *p3, *p4, *prev = pp1a->prev; + //get p1 & p2 polypts - the overlap start & endpoints on poly1 + if (PointsEqual(pp1a->pt, pt1)) p1 = pp1a; + else if (PointsEqual(prev->pt, pt1)) p1 = prev; + else p1 = InsertPolyPtBetween(pp1a, prev, pt1); + + if (PointsEqual(pp1a->pt, pt2)) p2 = pp1a; + else if (PointsEqual(prev->pt, pt2)) p2 = prev; + else if ((p1 == pp1a) || (p1 == prev)) + p2 = InsertPolyPtBetween(pp1a, prev, pt2); + else if (Pt3IsBetweenPt1AndPt2(pp1a->pt, p1->pt, pt2)) + p2 = InsertPolyPtBetween(pp1a, p1, pt2); else + p2 = InsertPolyPtBetween(p1, prev, pt2); + + //get p3 & p4 polypts - the overlap start & endpoints on poly2 + prev = pp2a->prev; + if (PointsEqual(pp2a->pt, pt1)) p3 = pp2a; + else if (PointsEqual(prev->pt, pt1)) p3 = prev; + else p3 = InsertPolyPtBetween(pp2a, prev, pt1); + + if (PointsEqual(pp2a->pt, pt2)) p4 = pp2a; + else if (PointsEqual(prev->pt, pt2)) p4 = prev; + else if ((p3 == pp2a) || (p3 == prev)) + p4 = InsertPolyPtBetween(pp2a, prev, pt2); + else if (Pt3IsBetweenPt1AndPt2(pp2a->pt, p3->pt, pt2)) + p4 = InsertPolyPtBetween(pp2a, p3, pt2); else + p4 = InsertPolyPtBetween(p3, prev, pt2); + + //p1.pt == p3.pt and p2.pt == p4.pt so join p1 to p3 and p2 to p4 ... + if (p1->next == p2 && p3->prev == p4) + { + p1->next = p3; + p3->prev = p1; + p2->prev = p4; + p4->next = p2; + return true; + } + else if (p1->prev == p2 && p3->next == p4) + { + p1->prev = p3; + p3->next = p1; + p2->next = p4; + p4->prev = p2; + return true; + } + else + return false; //an orientation is probably wrong +} +//---------------------------------------------------------------------- + +void Clipper::FixupJoinRecs(JoinRec *j, OutPt *pt, unsigned startIdx) +{ + for (JoinList::size_type k = startIdx; k < m_Joins.size(); k++) + { + JoinRec* j2 = m_Joins[k]; + if (j2->poly1Idx == j->poly1Idx && PointIsVertex(j2->pt1a, pt)) + j2->poly1Idx = j->poly2Idx; + if (j2->poly2Idx == j->poly1Idx && PointIsVertex(j2->pt2a, pt)) + j2->poly2Idx = j->poly2Idx; + } +} +//---------------------------------------------------------------------- + +bool Poly2ContainsPoly1(OutPt* outPt1, OutPt* outPt2, bool UseFullInt64Range) +{ + OutPt* pt = outPt1; + //Because the polygons may be touching, we need to find a vertex that + //isn't touching the other polygon ... + if (PointOnPolygon(pt->pt, outPt2, UseFullInt64Range)) + { + pt = pt->next; + while (pt != outPt1 && PointOnPolygon(pt->pt, outPt2, UseFullInt64Range)) + pt = pt->next; + if (pt == outPt1) return true; + } + return PointInPolygon(pt->pt, outPt2, UseFullInt64Range); +} +//---------------------------------------------------------------------- + +void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) +{ + + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec* outRec = m_PolyOuts[i]; + if (outRec->pts && outRec->FirstLeft == OldOutRec) + { + if (Poly2ContainsPoly1(outRec->pts, NewOutRec->pts, m_UseFullRange)) + outRec->FirstLeft = NewOutRec; + } + } +} +//---------------------------------------------------------------------- + +void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec) +{ + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec* outRec = m_PolyOuts[i]; + if (outRec->FirstLeft == OldOutRec) outRec->FirstLeft = NewOutRec; + } +} +//---------------------------------------------------------------------- + +void Clipper::JoinCommonEdges() +{ + for (JoinList::size_type i = 0; i < m_Joins.size(); i++) + { + JoinRec* j = m_Joins[i]; + + OutRec *outRec1 = GetOutRec(j->poly1Idx); + OutRec *outRec2 = GetOutRec(j->poly2Idx); + + if (!outRec1->pts || !outRec2->pts) continue; + + //get the polygon fragment with the correct hole state (FirstLeft) + //before calling JoinPoints() ... + OutRec *holeStateRec; + if (outRec1 == outRec2) holeStateRec = outRec1; + else if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2; + else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1; + else holeStateRec = GetLowermostRec(outRec1, outRec2); + + OutPt *p1, *p2; + if (!JoinPoints(j, p1, p2)) continue; + + if (outRec1 == outRec2) + { + //instead of joining two polygons, we've just created a new one by + //splitting one polygon into two. + outRec1->pts = p1; + outRec1->bottomPt = 0; + outRec2 = CreateOutRec(); + outRec2->pts = p2; + + if (Poly2ContainsPoly1(outRec2->pts, outRec1->pts, m_UseFullRange)) + { + //outRec2 is contained by outRec1 ... + outRec2->isHole = !outRec1->isHole; + outRec2->FirstLeft = outRec1; + + FixupJoinRecs(j, p2, i+1); + + //fixup FirstLeft pointers that may need reassigning to OutRec1 + if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1); + + FixupOutPolygon(*outRec1); //nb: do this BEFORE testing orientation + FixupOutPolygon(*outRec2); // but AFTER calling FixupJoinRecs() + + + if ((outRec2->isHole ^ m_ReverseOutput) == (Area(*outRec2, m_UseFullRange) > 0)) + ReversePolyPtLinks(outRec2->pts); + + } else if (Poly2ContainsPoly1(outRec1->pts, outRec2->pts, m_UseFullRange)) + { + //outRec1 is contained by outRec2 ... + outRec2->isHole = outRec1->isHole; + outRec1->isHole = !outRec2->isHole; + outRec2->FirstLeft = outRec1->FirstLeft; + outRec1->FirstLeft = outRec2; + + FixupJoinRecs(j, p2, i+1); + + //fixup FirstLeft pointers that may need reassigning to OutRec1 + if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2); + + FixupOutPolygon(*outRec1); //nb: do this BEFORE testing orientation + FixupOutPolygon(*outRec2); // but AFTER calling FixupJoinRecs() + + if ((outRec1->isHole ^ m_ReverseOutput) == (Area(*outRec1, m_UseFullRange) > 0)) + ReversePolyPtLinks(outRec1->pts); + } + else + { + //the 2 polygons are completely separate ... + outRec2->isHole = outRec1->isHole; + outRec2->FirstLeft = outRec1->FirstLeft; + + FixupJoinRecs(j, p2, i+1); + + //fixup FirstLeft pointers that may need reassigning to OutRec2 + if (m_UsingPolyTree) FixupFirstLefts1(outRec1, outRec2); + + FixupOutPolygon(*outRec1); //nb: do this BEFORE testing orientation + FixupOutPolygon(*outRec2); // but AFTER calling FixupJoinRecs() + } + + } else + { + //joined 2 polygons together ... + + //cleanup redundant edges ... + FixupOutPolygon(*outRec1); + + outRec2->pts = 0; + outRec2->bottomPt = 0; + outRec2->idx = outRec1->idx; + + outRec1->isHole = holeStateRec->isHole; + if (holeStateRec == outRec2) + outRec1->FirstLeft = outRec2->FirstLeft; + outRec2->FirstLeft = outRec1; + + //fixup FirstLeft pointers that may need reassigning to OutRec1 + if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1); + } + } +} +//------------------------------------------------------------------------------ + +inline void UpdateOutPtIdxs(OutRec& outrec) +{ + OutPt* op = outrec.pts; + do + { + op->idx = outrec.idx; + op = op->prev; + } + while(op != outrec.pts); +} +//------------------------------------------------------------------------------ + +void Clipper::DoSimplePolygons() +{ + PolyOutList::size_type i = 0; + while (i < m_PolyOuts.size()) + { + OutRec* outrec = m_PolyOuts[i++]; + OutPt* op = outrec->pts; + if (!op) continue; + do //for each Pt in Polygon until duplicate found do ... + { + OutPt* op2 = op->next; + while (op2 != outrec->pts) + { + if (PointsEqual(op->pt, op2->pt) && op2->next != op && op2->prev != op) + { + //split the polygon into two ... + OutPt* op3 = op->prev; + OutPt* op4 = op2->prev; + op->prev = op4; + op4->next = op; + op2->prev = op3; + op3->next = op2; + + outrec->pts = op; + OutRec* outrec2 = CreateOutRec(); + outrec2->pts = op2; + UpdateOutPtIdxs(*outrec2); + if (Poly2ContainsPoly1(outrec2->pts, outrec->pts, m_UseFullRange)) + { + //OutRec2 is contained by OutRec1 ... + outrec2->isHole = !outrec->isHole; + outrec2->FirstLeft = outrec; + } + else + if (Poly2ContainsPoly1(outrec->pts, outrec2->pts, m_UseFullRange)) + { + //OutRec1 is contained by OutRec2 ... + outrec2->isHole = outrec->isHole; + outrec->isHole = !outrec2->isHole; + outrec2->FirstLeft = outrec->FirstLeft; + outrec->FirstLeft = outrec2; + } else + { + //the 2 polygons are separate ... + outrec2->isHole = outrec->isHole; + outrec2->FirstLeft = outrec->FirstLeft; + } + op2 = op; //ie get ready for the next iteration + } + op2 = op2->next; + } + op = op->next; + } + while (op != outrec->pts); + } +} +//------------------------------------------------------------------------------ + +void ReversePolygon(Polygon& p) +{ + std::reverse(p.begin(), p.end()); +} +//------------------------------------------------------------------------------ + +void ReversePolygons(Polygons& p) +{ + for (Polygons::size_type i = 0; i < p.size(); ++i) + ReversePolygon(p[i]); +} + +//------------------------------------------------------------------------------ +// OffsetPolygon functions ... +//------------------------------------------------------------------------------ + +struct DoublePoint +{ + double X; + double Y; + DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} +}; +//------------------------------------------------------------------------------ + +Polygon BuildArc(const IntPoint &pt, + const double a1, const double a2, const double r, double limit) +{ + //see notes in clipper.pas regarding steps + double arcFrac = std::fabs(a2 - a1) / (2 * pi); + int steps = (int)(arcFrac * pi / std::acos(1 - limit / std::fabs(r))); + if (steps < 2) steps = 2; + else if (steps > (int)(222.0 * arcFrac)) steps = (int)(222.0 * arcFrac); + + double x = std::cos(a1); + double y = std::sin(a1); + double c = std::cos((a2 - a1) / steps); + double s = std::sin((a2 - a1) / steps); + Polygon result(steps +1); + for (int i = 0; i <= steps; ++i) + { + result[i].X = pt.X + Round(x * r); + result[i].Y = pt.Y + Round(y * r); + double x2 = x; + x = x * c - s * y; //cross product + y = x2 * s + y * c; //dot product + } + return result; +} +//------------------------------------------------------------------------------ + +DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2) +{ + if(pt2.X == pt1.X && pt2.Y == pt1.Y) + return DoublePoint(0, 0); + + double dx = (double)(pt2.X - pt1.X); + double dy = (double)(pt2.Y - pt1.Y); + double f = 1 *1.0/ std::sqrt( dx*dx + dy*dy ); + dx *= f; + dy *= f; + return DoublePoint(dy, -dx); +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +class OffsetBuilder +{ +private: + const Polygons& m_p; + Polygon* m_curr_poly; + std::vector normals; + double m_delta, m_rmin, m_r; + size_t m_i, m_j, m_k; + static const int buffLength = 128; + +public: + +OffsetBuilder(const Polygons& in_polys, Polygons& out_polys, + bool isPolygon, double delta, JoinType jointype, EndType endtype, double limit): m_p(in_polys) +{ + //precondition: &out_polys != &in_polys + + if (NEAR_ZERO(delta)) {out_polys = in_polys; return;} + m_rmin = 0.5; + m_delta = delta; + if (jointype == jtMiter) + { + if (limit > 2) m_rmin = 2.0 / (limit * limit); + limit = 0.25; //just in case endtype == etRound + } + else + { + if (limit <= 0) limit = 0.25; + else if (limit > std::fabs(delta)) limit = std::fabs(delta); + } + + double deltaSq = delta*delta; + out_polys.clear(); + out_polys.resize(m_p.size()); + for (m_i = 0; m_i < m_p.size(); m_i++) + { + size_t len = m_p[m_i].size(); + + if (len == 0 || (len < 3 && delta <= 0)) + continue; + else if (len == 1) + { + out_polys[m_i] = BuildArc(m_p[m_i][0], 0, 2*pi, delta, limit); + continue; + } + + bool forceClose = PointsEqual(m_p[m_i][0], m_p[m_i][len -1]); + if (forceClose) len--; + + //build normals ... + normals.clear(); + normals.resize(len); + for (m_j = 0; m_j < len -1; ++m_j) + normals[m_j] = GetUnitNormal(m_p[m_i][m_j], m_p[m_i][m_j +1]); + if (isPolygon || forceClose) + normals[len-1] = GetUnitNormal(m_p[m_i][len-1], m_p[m_i][0]); + else //is open polyline + normals[len-1] = normals[len-2]; + + m_curr_poly = &out_polys[m_i]; + m_curr_poly->reserve(len); + + if (isPolygon || forceClose) + { + m_k = len -1; + for (m_j = 0; m_j < len; ++m_j) + OffsetPoint(jointype, limit); + + if (!isPolygon) + { + size_t j = out_polys.size(); + out_polys.resize(j+1); + m_curr_poly = &out_polys[j]; + m_curr_poly->reserve(len); + m_delta = -m_delta; + + m_k = len -1; + for (m_j = 0; m_j < len; ++m_j) + OffsetPoint(jointype, limit); + m_delta = -m_delta; + ReversePolygon(*m_curr_poly); + } + } + else //is open polyline + { + //offset the polyline going forward ... + m_k = 0; + for (m_j = 1; m_j < len -1; ++m_j) + OffsetPoint(jointype, limit); + + //handle the end (butt, round or square) ... + IntPoint pt1; + if (endtype == etButt) + { + m_j = len - 1; + pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta), + Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta)); + AddPoint(pt1); + pt1 = IntPoint(Round(m_p[m_i][m_j].X - normals[m_j].X * m_delta), + Round(m_p[m_i][m_j].Y - normals[m_j].Y * m_delta)); + AddPoint(pt1); + } + else + { + m_j = len - 1; + m_k = len - 2; + normals[m_j].X = -normals[m_j].X; + normals[m_j].Y = -normals[m_j].Y; + if (endtype == etSquare) DoSquare(); + else DoRound(limit); + } + + //re-build Normals ... + for (int j = len - 1; j > 0; --j) + { + normals[j].X = -normals[j - 1].X; + normals[j].Y = -normals[j - 1].Y; + } + normals[0].X = -normals[1].X; + normals[0].Y = -normals[1].Y; + + //offset the polyline going backward ... + m_k = len -1; + for (m_j = m_k - 1; m_j > 0; --m_j) + OffsetPoint(jointype, limit); + + //finally handle the start (butt, round or square) ... + if (endtype == etButt) + { + pt1 = IntPoint(Round(m_p[m_i][0].X - normals[0].X * m_delta), + Round(m_p[m_i][0].Y - normals[0].Y * m_delta)); + AddPoint(pt1); + pt1 = IntPoint(Round(m_p[m_i][0].X + normals[0].X * m_delta), + Round(m_p[m_i][0].Y + normals[0].Y * m_delta)); + AddPoint(pt1); + } else + { + m_k = 1; + if (endtype == etSquare) DoSquare(); + else DoRound(limit); + } + } + } + + //and clean up untidy corners using Clipper ... + Clipper clpr; + clpr.AddPolygons(out_polys, ptSubject); + if (delta > 0) + { + if (!clpr.Execute(ctUnion, out_polys, pftPositive, pftPositive)) + out_polys.clear(); + } + else + { + IntRect r = clpr.GetBounds(); + Polygon outer(4); + outer[0] = IntPoint(r.left - 10, r.bottom + 10); + outer[1] = IntPoint(r.right + 10, r.bottom + 10); + outer[2] = IntPoint(r.right + 10, r.top - 10); + outer[3] = IntPoint(r.left - 10, r.top - 10); + + clpr.AddPolygon(outer, ptSubject); + clpr.ReverseSolution(true); + if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative)) + out_polys.erase(out_polys.begin()); + else + out_polys.clear(); + } +} +//------------------------------------------------------------------------------ + +private: + +void OffsetPoint(JoinType jointype, double limit) +{ + switch (jointype) + { + case jtMiter: + { + m_r = 1 + (normals[m_j].X*normals[m_k].X + + normals[m_j].Y*normals[m_k].Y); + if (m_r >= m_rmin) DoMiter(); else DoSquare(); + break; + } + case jtSquare: DoSquare(); break; + case jtRound: DoRound(limit); break; + } + m_k = m_j; +} +//------------------------------------------------------------------------------ + +void AddPoint(const IntPoint& pt) +{ + if (m_curr_poly->size() == m_curr_poly->capacity()) + m_curr_poly->reserve(m_curr_poly->capacity() + buffLength); + m_curr_poly->push_back(pt); +} +//------------------------------------------------------------------------------ + +void DoSquare() +{ + IntPoint pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta), + Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta)); + IntPoint pt2 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta), + Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta)); + if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0) + { + double a1 = std::atan2(normals[m_k].Y, normals[m_k].X); + double a2 = std::atan2(-normals[m_j].Y, -normals[m_j].X); + a1 = std::fabs(a2 - a1); + if (a1 > pi) a1 = pi * 2 - a1; + double dx = std::tan((pi - a1) / 4) * std::fabs(m_delta); + pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx), (long64)(pt1.Y + normals[m_k].X * dx)); + AddPoint(pt1); + pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx), (long64)(pt2.Y -normals[m_j].X * dx)); + AddPoint(pt2); + } + else + { + AddPoint(pt1); + AddPoint(m_p[m_i][m_j]); + AddPoint(pt2); + } +} +//------------------------------------------------------------------------------ + +void DoMiter() +{ + if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0) + { + double q = m_delta / m_r; + AddPoint(IntPoint(Round(m_p[m_i][m_j].X + (normals[m_k].X + normals[m_j].X) * q), + Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q))); + } + else + { + IntPoint pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta), + Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta)); + IntPoint pt2 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta), + Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta)); + AddPoint(pt1); + AddPoint(m_p[m_i][m_j]); + AddPoint(pt2); + } +} +//------------------------------------------------------------------------------ + +void DoRound(double limit) +{ + IntPoint pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta), + Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta)); + IntPoint pt2 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta), + Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta)); + AddPoint(pt1); + //round off reflex angles (ie > 180 deg) unless almost flat (ie < ~10deg). + if ((normals[m_k].X*normals[m_j].Y - normals[m_j].X*normals[m_k].Y) * m_delta >= 0) + { + if (normals[m_j].X * normals[m_k].X + normals[m_j].Y * normals[m_k].Y < 0.985) + { + double a1 = std::atan2(normals[m_k].Y, normals[m_k].X); + double a2 = std::atan2(normals[m_j].Y, normals[m_j].X); + if (m_delta > 0 && a2 < a1) a2 += pi *2; + else if (m_delta < 0 && a2 > a1) a2 -= pi *2; + Polygon arc = BuildArc(m_p[m_i][m_j], a1, a2, m_delta, limit); + for (Polygon::size_type m = 0; m < arc.size(); m++) + AddPoint(arc[m]); + } + } + else + AddPoint(m_p[m_i][m_j]); + AddPoint(pt2); +} +//-------------------------------------------------------------------------- + +}; //end PolyOffsetBuilder + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +bool UpdateBotPt(const IntPoint &pt, IntPoint &botPt) +{ + if (pt.Y > botPt.Y || (pt.Y == botPt.Y && pt.X < botPt.X)) + { + botPt = pt; + return true; + } + else return false; +} +//-------------------------------------------------------------------------- + +void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys, + double delta, JoinType jointype, double limit, bool autoFix) +{ + if (!autoFix && &in_polys != &out_polys) + { + OffsetBuilder(in_polys, out_polys, true, delta, jointype, etClosed, limit); + return; + } + + Polygons inPolys = Polygons(in_polys); + out_polys.clear(); + + //ChecksInput - fixes polygon orientation if necessary and removes + //duplicate vertices. Can be set false when you're sure that polygon + //orientation is correct and that there are no duplicate vertices. + if (autoFix) + { + size_t polyCount = inPolys.size(), botPoly = 0; + while (botPoly < polyCount && inPolys[botPoly].empty()) botPoly++; + if (botPoly == polyCount) return; + + //botPt: used to find the lowermost (in inverted Y-axis) & leftmost point + //This point (on m_p[botPoly]) must be on an outer polygon ring and if + //its orientation is false (counterclockwise) then assume all polygons + //need reversing ... + IntPoint botPt = inPolys[botPoly][0]; + for (size_t i = botPoly; i < polyCount; ++i) + { + if (inPolys[i].size() < 3) { inPolys[i].clear(); continue; } + if (UpdateBotPt(inPolys[i][0], botPt)) botPoly = i; + Polygon::iterator it = inPolys[i].begin() +1; + while (it != inPolys[i].end()) + { + if (PointsEqual(*it, *(it -1))) + it = inPolys[i].erase(it); + else + { + if (UpdateBotPt(*it, botPt)) botPoly = i; + ++it; + } + } + } + if (!Orientation(inPolys[botPoly])) + ReversePolygons(inPolys); + } + OffsetBuilder(inPolys, out_polys, true, delta, jointype, etClosed, limit); +} +//------------------------------------------------------------------------------ + +void OffsetPolyLines(const Polygons &in_lines, Polygons &out_lines, + double delta, JoinType jointype, EndType endtype, + double limit, bool autoFix) +{ + if (!autoFix && endtype != etClosed && &in_lines != &out_lines) + { + OffsetBuilder(in_lines, out_lines, false, delta, jointype, endtype, limit); + return; + } + + Polygons inLines = Polygons(in_lines); + if (autoFix) + for (size_t i = 0; i < inLines.size(); ++i) + { + if (inLines[i].size() < 2) { inLines[i].clear(); continue; } + Polygon::iterator it = inLines[i].begin() +1; + while (it != inLines[i].end()) + { + if (PointsEqual(*it, *(it -1))) + it = inLines[i].erase(it); + else + ++it; + } + } + + if (endtype == etClosed) + { + size_t sz = inLines.size(); + inLines.resize(sz * 2); + for (size_t i = 0; i < sz; ++i) + { + inLines[sz+i] = inLines[i]; + ReversePolygon(inLines[sz+i]); + } + OffsetBuilder(inLines, out_lines, true, delta, jointype, endtype, limit); + } + else + OffsetBuilder(inLines, out_lines, false, delta, jointype, endtype, limit); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType) +{ + Clipper c; + c.ForceSimple(true); + c.AddPolygon(in_poly, ptSubject); + c.Execute(ctUnion, out_polys, fillType, fillType); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType) +{ + Clipper c; + c.ForceSimple(true); + c.AddPolygons(in_polys, ptSubject); + c.Execute(ctUnion, out_polys, fillType, fillType); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygons(Polygons &polys, PolyFillType fillType) +{ + SimplifyPolygons(polys, polys, fillType); +} +//------------------------------------------------------------------------------ + +inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2) +{ + double dx = ((double)pt1.X - pt2.X); + double dy = ((double)pt1.Y - pt2.Y); + return (dx*dx + dy*dy); +} +//------------------------------------------------------------------------------ + +DoublePoint ClosestPointOnLine(const IntPoint& pt, const IntPoint& linePt1, const IntPoint& linePt2) +{ + double dx = ((double)linePt2.X - linePt1.X); + double dy = ((double)linePt2.Y - linePt1.Y); + if (dx == 0 && dy == 0) + return DoublePoint((double)linePt1.X, (double)linePt1.Y); + double q = ((pt.X-linePt1.X)*dx + (pt.Y-linePt1.Y)*dy) / (dx*dx + dy*dy); + return DoublePoint( + (1-q)*linePt1.X + q*linePt2.X, + (1-q)*linePt1.Y + q*linePt2.Y); +} +//------------------------------------------------------------------------------ + +bool SlopesNearColinear(const IntPoint& pt1, + const IntPoint& pt2, const IntPoint& pt3, double distSqrd) +{ + if (DistanceSqrd(pt1, pt2) > DistanceSqrd(pt1, pt3)) return false; + DoublePoint cpol = ClosestPointOnLine(pt2, pt1, pt3); + double dx = pt2.X - cpol.X; + double dy = pt2.Y - cpol.Y; + return (dx*dx + dy*dy) < distSqrd; +} +//------------------------------------------------------------------------------ + +bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd) +{ + double dx = (double)pt1.X - pt2.X; + double dy = (double)pt1.Y - pt2.Y; + return ((dx * dx) + (dy * dy) <= distSqrd); +} +//------------------------------------------------------------------------------ + +void CleanPolygon(const Polygon& in_poly, Polygon& out_poly, double distance) +{ + //distance = proximity in units/pixels below which vertices + //will be stripped. Default ~= sqrt(2). + int highI = in_poly.size() -1; + double distSqrd = distance * distance; + while (highI > 0 && PointsAreClose(in_poly[highI], in_poly[0], distSqrd)) highI--; + if (highI < 2) { out_poly.clear(); return; } + + if (&in_poly != &out_poly) + out_poly.resize(highI + 1); + + IntPoint pt = in_poly[highI]; + int i = 0, k = 0; + for (;;) + { + while (i < highI && PointsAreClose(pt, in_poly[i+1], distSqrd)) i+=2; + int i2 = i; + while (i < highI && (PointsAreClose(in_poly[i], in_poly[i+1], distSqrd) || + SlopesNearColinear(pt, in_poly[i], in_poly[i+1], distSqrd))) i++; + if (i >= highI) break; + else if (i != i2) continue; + pt = in_poly[i++]; + out_poly[k++] = pt; + } + if (i <= highI) out_poly[k++] = in_poly[i]; + if (k > 2 && SlopesNearColinear(out_poly[k -2], out_poly[k -1], out_poly[0], distSqrd)) k--; + if (k < 3) out_poly.clear(); + else if (k <= highI) out_poly.resize(k); +} +//------------------------------------------------------------------------------ + +void CleanPolygons(const Polygons& in_polys, Polygons& out_polys, double distance) +{ + for (Polygons::size_type i = 0; i < in_polys.size(); ++i) + CleanPolygon(in_polys[i], out_polys[i], distance); +} +//------------------------------------------------------------------------------ + +void AddPolyNodeToPolygons(const PolyNode& polynode, Polygons& polygons) +{ + if (!polynode.Contour.empty()) + polygons.push_back(polynode.Contour); + for (int i = 0; i < polynode.ChildCount(); ++i) + AddPolyNodeToPolygons(*polynode.Childs[i], polygons); +} +//------------------------------------------------------------------------------ + +void PolyTreeToPolygons(const PolyTree& polytree, Polygons& polygons) +{ + polygons.resize(0); + polygons.reserve(polytree.Total()); + AddPolyNodeToPolygons(polytree, polygons); +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, IntPoint& p) +{ + s << p.X << ' ' << p.Y << "\n"; + return s; +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, Polygon &p) +{ + for (Polygon::size_type i = 0; i < p.size(); i++) + s << p[i]; + s << "\n"; + return s; +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, Polygons &p) +{ + for (Polygons::size_type i = 0; i < p.size(); i++) + s << p[i]; + s << "\n"; + return s; +} +//------------------------------------------------------------------------------ + +} //ClipperLib namespace diff --git a/hyp2mat/lib/clipper.hpp b/hyp2mat/lib/clipper.hpp new file mode 100644 index 0000000..4dcfe12 --- /dev/null +++ b/hyp2mat/lib/clipper.hpp @@ -0,0 +1,351 @@ +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 5.1.6 * +* Date : 23 May 2013 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2013 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Attributions: * +* The code in this library is an extension of Bala Vatti's clipping algorithm: * +* "A generic solution to polygon clipping" * +* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * +* http://portal.acm.org/citation.cfm?id=129906 * +* * +* Computer graphics and geometric modeling: implementation and algorithms * +* By Max K. Agoston * +* Springer; 1 edition (January 4, 2005) * +* http://books.google.com/books?q=vatti+clipping+agoston * +* * +* See also: * +* "Polygon Offsetting by Computing Winding Numbers" * +* Paper no. DETC2005-85513 pp. 565-575 * +* ASME 2005 International Design Engineering Technical Conferences * +* and Computers and Information in Engineering Conference (IDETC/CIE2005) * +* September 24-28, 2005 , Long Beach, California, USA * +* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * +* * +*******************************************************************************/ + +#ifndef clipper_hpp +#define clipper_hpp + +#define CLIPPER_VERSION "5.1.6" + +#include +#include +#include +#include +#include + +namespace ClipperLib { + +enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; +enum PolyType { ptSubject, ptClip }; +//By far the most widely used winding rules for polygon filling are +//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) +//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) +//see http://glprogramming.com/red/chapter11.html +enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; + +typedef signed long long long64; +typedef unsigned long long ulong64; + +struct IntPoint { +public: + long64 X; + long64 Y; + IntPoint(long64 x = 0, long64 y = 0): X(x), Y(y) {}; + friend std::ostream& operator <<(std::ostream &s, IntPoint &p); +}; + +typedef std::vector< IntPoint > Polygon; +typedef std::vector< Polygon > Polygons; + + +std::ostream& operator <<(std::ostream &s, Polygon &p); +std::ostream& operator <<(std::ostream &s, Polygons &p); + +class PolyNode; +typedef std::vector< PolyNode* > PolyNodes; + +class PolyNode +{ +public: + PolyNode(); + Polygon Contour; + PolyNodes Childs; + PolyNode* Parent; + PolyNode* GetNext() const; + bool IsHole() const; + int ChildCount() const; +private: + PolyNode* GetNextSiblingUp() const; + unsigned Index; //node index in Parent.Childs + void AddChild(PolyNode& child); + friend class Clipper; //to access Index +}; + +class PolyTree: public PolyNode +{ +public: + ~PolyTree(){Clear();}; + PolyNode* GetFirst() const; + void Clear(); + int Total() const; +private: + PolyNodes AllNodes; + friend class Clipper; //to access AllNodes +}; + +enum JoinType { jtSquare, jtRound, jtMiter }; +enum EndType { etClosed, etButt, etSquare, etRound}; + +bool Orientation(const Polygon &poly); +double Area(const Polygon &poly); + +void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys, + double delta, JoinType jointype = jtSquare, double limit = 0, bool autoFix = true); + +void OffsetPolyLines(const Polygons &in_lines, Polygons &out_lines, + double delta, JoinType jointype = jtSquare, EndType endtype = etSquare, double limit = 0, bool autoFix = true); + +void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType = pftEvenOdd); +void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType = pftEvenOdd); +void SimplifyPolygons(Polygons &polys, PolyFillType fillType = pftEvenOdd); + +void CleanPolygon(const Polygon& in_poly, Polygon& out_poly, double distance = 1.415); +void CleanPolygons(const Polygons& in_polys, Polygons& out_polys, double distance = 1.415); + +void PolyTreeToPolygons(const PolyTree& polytree, Polygons& polygons); + +void ReversePolygon(Polygon& p); +void ReversePolygons(Polygons& p); + +//used internally ... +enum EdgeSide { esLeft = 1, esRight = 2}; +enum IntersectProtects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 }; +//inline IntersectProtects operator|(IntersectProtects a, IntersectProtects b) +//{return static_cast(static_cast(a) | static_cast(b));} + +struct TEdge { + long64 xbot; + long64 ybot; + long64 xcurr; + long64 ycurr; + long64 xtop; + long64 ytop; + double dx; + long64 deltaX; + long64 deltaY; + PolyType polyType; + EdgeSide side; + int windDelta; //1 or -1 depending on winding direction + int windCnt; + int windCnt2; //winding count of the opposite polytype + int outIdx; + TEdge *next; + TEdge *prev; + TEdge *nextInLML; + TEdge *nextInAEL; + TEdge *prevInAEL; + TEdge *nextInSEL; + TEdge *prevInSEL; +}; + +struct IntersectNode { + TEdge *edge1; + TEdge *edge2; + IntPoint pt; + IntersectNode *next; +}; + +struct LocalMinima { + long64 Y; + TEdge *leftBound; + TEdge *rightBound; + LocalMinima *next; +}; + +struct Scanbeam { + long64 Y; + Scanbeam *next; +}; + +struct OutPt; //forward declaration + +struct OutRec { + int idx; + bool isHole; + OutRec *FirstLeft; //see comments in clipper.pas + PolyNode *polyNode; + OutPt *pts; + OutPt *bottomPt; +}; + +struct OutPt { + int idx; + IntPoint pt; + OutPt *next; + OutPt *prev; +}; + +struct JoinRec { + IntPoint pt1a; + IntPoint pt1b; + int poly1Idx; + IntPoint pt2a; + IntPoint pt2b; + int poly2Idx; +}; + +struct HorzJoinRec { + TEdge *edge; + int savedIdx; +}; + +struct IntRect { long64 left; long64 top; long64 right; long64 bottom; }; + +typedef std::vector < OutRec* > PolyOutList; +typedef std::vector < TEdge* > EdgeList; +typedef std::vector < JoinRec* > JoinList; +typedef std::vector < HorzJoinRec* > HorzJoinList; + +//ClipperBase is the ancestor to the Clipper class. It should not be +//instantiated directly. This class simply abstracts the conversion of sets of +//polygon coordinates into edge objects that are stored in a LocalMinima list. +class ClipperBase +{ +public: + ClipperBase(); + virtual ~ClipperBase(); + bool AddPolygon(const Polygon &pg, PolyType polyType); + bool AddPolygons( const Polygons &ppg, PolyType polyType); + virtual void Clear(); + IntRect GetBounds(); +protected: + void DisposeLocalMinimaList(); + TEdge* AddBoundsToLML(TEdge *e); + void PopLocalMinima(); + virtual void Reset(); + void InsertLocalMinima(LocalMinima *newLm); + LocalMinima *m_CurrentLM; + LocalMinima *m_MinimaList; + bool m_UseFullRange; + EdgeList m_edges; +}; + +class Clipper : public virtual ClipperBase +{ +public: + Clipper(); + ~Clipper(); + bool Execute(ClipType clipType, + Polygons &solution, + PolyFillType subjFillType = pftEvenOdd, + PolyFillType clipFillType = pftEvenOdd); + bool Execute(ClipType clipType, + PolyTree &polytree, + PolyFillType subjFillType = pftEvenOdd, + PolyFillType clipFillType = pftEvenOdd); + void Clear(); + bool ReverseSolution() {return m_ReverseOutput;}; + void ReverseSolution(bool value) {m_ReverseOutput = value;}; + bool ForceSimple() {return m_ForceSimple;}; + void ForceSimple(bool value) {m_ForceSimple = value;}; +protected: + void Reset(); + virtual bool ExecuteInternal(); +private: + PolyOutList m_PolyOuts; + JoinList m_Joins; + HorzJoinList m_HorizJoins; + ClipType m_ClipType; + Scanbeam *m_Scanbeam; + TEdge *m_ActiveEdges; + TEdge *m_SortedEdges; + IntersectNode *m_IntersectNodes; + bool m_ExecuteLocked; + PolyFillType m_ClipFillType; + PolyFillType m_SubjFillType; + bool m_ReverseOutput; + bool m_UsingPolyTree; + bool m_ForceSimple; + void DisposeScanbeamList(); + void SetWindingCount(TEdge& edge); + bool IsEvenOddFillType(const TEdge& edge) const; + bool IsEvenOddAltFillType(const TEdge& edge) const; + void InsertScanbeam(const long64 Y); + long64 PopScanbeam(); + void InsertLocalMinimaIntoAEL(const long64 botY); + void InsertEdgeIntoAEL(TEdge *edge); + void AddEdgeToSEL(TEdge *edge); + void CopyAELToSEL(); + void DeleteFromSEL(TEdge *e); + void DeleteFromAEL(TEdge *e); + void UpdateEdgeIntoAEL(TEdge *&e); + void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); + bool IsContributing(const TEdge& edge) const; + bool IsTopHorz(const long64 XPos); + void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); + void DoMaxima(TEdge *e, long64 topY); + void ProcessHorizontals(); + void ProcessHorizontal(TEdge *horzEdge); + void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); + void AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); + OutRec* GetOutRec(int idx); + void AppendPolygon(TEdge *e1, TEdge *e2); + void IntersectEdges(TEdge *e1, TEdge *e2, + const IntPoint &pt, const IntersectProtects protects); + OutRec* CreateOutRec(); + void AddOutPt(TEdge *e, const IntPoint &pt); + void DisposeAllPolyPts(); + void DisposeOutRec(PolyOutList::size_type index); + bool ProcessIntersections(const long64 botY, const long64 topY); + void InsertIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt); + void BuildIntersectList(const long64 botY, const long64 topY); + void ProcessIntersectList(); + void ProcessEdgesAtTopOfScanbeam(const long64 topY); + void BuildResult(Polygons& polys); + void BuildResult2(PolyTree& polytree); + void SetHoleState(TEdge *e, OutRec *outrec); + void DisposeIntersectNodes(); + bool FixupIntersectionOrder(); + void FixupOutPolygon(OutRec &outrec); + bool IsHole(TEdge *e); + void FixHoleLinkage(OutRec &outrec); + void AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx = -1, int e2OutIdx = -1); + void ClearJoins(); + void AddHorzJoin(TEdge *e, int idx); + void ClearHorzJoins(); + bool JoinPoints(const JoinRec *j, OutPt *&p1, OutPt *&p2); + void FixupJoinRecs(JoinRec *j, OutPt *pt, unsigned startIdx); + void JoinCommonEdges(); + void DoSimplePolygons(); + void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec); + void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec); +}; + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +class clipperException : public std::exception +{ + public: + clipperException(const char* description): m_descr(description) {} + virtual ~clipperException() throw() {} + virtual const char* what() const throw() {return m_descr.c_str();} + private: + std::string m_descr; +}; +//------------------------------------------------------------------------------ + +} //ClipperLib namespace + +#endif //clipper_hpp + + diff --git a/hyp2mat/lib/clipper.txt b/hyp2mat/lib/clipper.txt new file mode 100644 index 0000000..51acabf --- /dev/null +++ b/hyp2mat/lib/clipper.txt @@ -0,0 +1,29 @@ +The Clipper code library, the "Software" (that includes Delphi, C++ & C# +source code, accompanying samples and documentation), has been released +under the following license, terms and conditions: + +Boost Software License - Version 1.0 - August 17th, 2003 +http://www.boost.org/LICENSE_1_0.txt + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + diff --git a/hyp2mat/lib/copper.cc b/hyp2mat/lib/copper.cc new file mode 100644 index 0000000..3b5addd --- /dev/null +++ b/hyp2mat/lib/copper.cc @@ -0,0 +1,382 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include "hyperlynx.h" +#include "crop.h" +#include +#include + +using namespace Hyp2Mat; + +/* + * These routines calculate the copper layers. + * The routines operate in one of two modes: raw or normal. + * + * In raw mode, polygons are simply copied from input to output. No processing is done. Raw mode is mainly useful for debugging purposes. + * + * In normal mode, all copper on a single layer is calculated as a set of non-overlapping polygons. + * Two kinds of copper polygons exist: normal and "PLANE". + * + * Normal copper polygons are simply added to the copper of the plane. + * Copper polygons of type "PLANE" have a clearance from other nets. This clearance is the "plane separation". + * Plane separation can be specified for the board, for a layer, for a net or for a polygon. + * + * Copper polygons of type "PLANE" are calculated as follows: + * - all polygons of all other nets on the same layer are computed, and explanded by the plane separation. This produces the mask. + * - The mask is subtracted from the "PLANE" type polygon. + * + * If mask polygon and plane polygon have a different value for plane separation the largest value is used. + * + * Note there is no plane separation between polygons of the same net. + */ + +/* + * copy layer stackup + */ + +void HyperLynx::CopyStackUp(Hyp2Mat::PCB& pcb) +{ + /* iterate over all layers */ + for (HypFile::LayerList::iterator l = hyp_file.stackup.begin(); l != hyp_file.stackup.end(); ++l) { + + /* check if we're interested in this layer. if no layers are specified, copy all layers */ + bool layer_wanted = layers.empty() || (std::find(layers.begin(), layers.end(), l->layer_name) != layers.end()); + + /* copy this layer if needed */ + if (layer_wanted) CopyLayer(pcb, *l); + } + + return; +} + +/* + * copy layer + */ + +void HyperLynx::CopyLayer(Hyp2Mat::PCB& pcb, HypFile::Layer& hyp_layer) +{ + + Hyp2Mat::Layer layer; + layer.layer_name = hyp_layer.layer_name; + layer.material_name = hyp_layer.material_name; + switch (hyp_layer.layer_type) { + case HypFile::LAYER_SIGNAL : layer.layer_type = Hyp2Mat::LAYER_SIGNAL; + break; + case HypFile::LAYER_DIELECTRIC : layer.layer_type = Hyp2Mat::LAYER_DIELECTRIC; + break; + case HypFile::LAYER_PLANE : layer.layer_type = Hyp2Mat::LAYER_PLANE; + break; + default: layer.layer_type = Hyp2Mat::LAYER_SIGNAL; + break; + } + layer.z0 = hyp_layer.z0; + layer.z1 = hyp_layer.z1; + layer.thickness = hyp_layer.thickness; + layer.epsilon_r = hyp_layer.epsilon_r; + layer.loss_tangent = hyp_layer.loss_tangent; + layer.bulk_resistivity = hyp_layer.bulk_resistivity; + layer.resistivity_temp_coeff = hyp_layer.temperature_coefficient; + + /* if the layer is metallic, copy the metal */ + if (layer.layer_type != Hyp2Mat::LAYER_DIELECTRIC) { + + /* Use default plane separation if layer plane separation is not set. layer plane separation is -1.0 if not set */ + layer_plane_separation = hyp_file.board.plane_separation; + + /* board-level override from SetClearance method / --clearance command-line parameter */ + if (HyperLynx::clearance >= 0) layer_plane_separation = HyperLynx::clearance; + + if (hyp_layer.plane_separation >= 0) layer_plane_separation = hyp_layer.plane_separation; + + /* copy layer copper */ + Hyp2Mat::FloatPolygons raw_polygons; + Hyp2Mat::Polygon layer_copper = CopyCopper(layer, raw_polygons); + + if (raw) + layer.metal = raw_polygons; + else + layer.metal = layer_copper.Result(); /* calculate layer copper */ + } + + /* add to stackup */ + pcb.stackup.push_back(layer); + + return; +} + +/* + * copy copper + */ + +Hyp2Mat::Polygon HyperLynx::CopyCopper(Hyp2Mat::Layer layer, Hyp2Mat::FloatPolygons& raw_polygons) +{ + + /* vectors of different polygon types. element [i] belongs to net hyp_file.net[i].net_name */ + std::vector net_pour; /* POLYGON T=POUR and ordinary line and arc segments */ + std::vector net_plane; /* POLYGON T=PLANE */ + std::vector net_copper; /* POLYGON T=COPPER */ + std::vector net_pads; /* pads */ + std::vector net_antipads; /* anti-pads */ + std::vector net_wanted; /* true if net needs to be included in the output */ + + HypFile::NetList::size_type net_size = hyp_file.net.size(); + net_pour.resize(net_size); + net_plane.resize(net_size); + net_copper.resize(net_size); + net_pads.resize(net_size); + net_antipads.resize(net_size); + net_wanted.resize(net_size); + + /* iterate over all nets twice. + The first time we calculate all the copper except "plane" polygons. + The second time we calculate plane polygon pours. Plane polygons have a clearance from copper of other nets */ + + /* Determine which nets we need to include */ + for (int i = 0; i < hyp_file.net.size(); ++i) { + /* check if we're interested in this net. if no nets are specified, copy all nets */ + net_wanted[i] = nets.empty() || (std::find(nets.begin(), nets.end(), hyp_file.net[i].net_name) != nets.end()); + } + + /* calculate all copper. */ + for (int i = 0; i < hyp_file.net.size(); ++i) { + + /* skip unwanted nets */ + if (!net_wanted[i]) continue; + + /* copy anti-metal of this net */ + net_pour[i] = CopyNet(layer, hyp_file.net[i], POLYGON_TYPE_POUR, raw_polygons); + net_copper[i] = CopyNet(layer, hyp_file.net[i], POLYGON_TYPE_COPPER, raw_polygons); + net_plane[i] = CopyNet(layer, hyp_file.net[i], POLYGON_TYPE_PLANE, raw_polygons); + net_pads[i] = CopyNet(layer, hyp_file.net[i], POLYGON_TYPE_PAD, raw_polygons); + net_antipads[i] = CopyNet(layer, hyp_file.net[i], POLYGON_TYPE_ANTIPAD, raw_polygons); + } + + /* + * sum all copper on this layer + */ + + Hyp2Mat::Polygon layer_copper; + + /* add plane and pour polygons */ + for (int i = 0; i < hyp_file.net.size(); ++i) { + + /* skip unwanted nets */ + if (!net_wanted[i]) continue; + + layer_copper.Union(net_pour[i]); + layer_copper.Union(net_plane[i]); + } + + /* subtract antipads from pour and plane polygons. */ + for (int i = 0; i < hyp_file.net.size(); ++i) { + + /* skip unwanted nets */ + if (!net_wanted[i]) continue; + + layer_copper.Difference(net_antipads[i]); + } + + /* add copper and pad polygons */ + for (int i = 0; i < hyp_file.net.size(); ++i) { + + /* skip unwanted nets */ + if (!net_wanted[i]) continue; + + layer_copper.Union(net_copper[i]); + layer_copper.Union(net_pads[i]); + } + + /* + * Crop to board size + */ + + if (!board.IsEmpty()) { + layer_copper.Intersection(board); + layer_copper = CropPolygon(layer_copper, bounds); + } + + return layer_copper; +} + +/* + * copy net + * copy all polygons of a net. + * if anti is true, copy anti-pads + * if plane is true, copy plane polygons (and subtract other_nets) + */ + +Hyp2Mat::Polygon HyperLynx::CopyNet(Hyp2Mat::Layer layer, HypFile::Net& hyp_net, polygon_type_enum poly_type, Hyp2Mat::FloatPolygons& raw_polygons) +{ + Hyp2Mat::Polygon net_copper; + + /* calculate net-specific plane separation */ + net_plane_separation = layer_plane_separation; + if (hyp_net.plane_separation >= 0) net_plane_separation = hyp_net.plane_separation; + + /* iterate over all Hyperlynx polygon id's */ + for (HypFile::PolygonMap::iterator j = hyp_net.metal.begin(); j != hyp_net.metal.end(); ++j) { + + if (j->second.empty()) continue; + + /* polygon layer */ + std::string poly_layer_name = j->second.begin()->layer_name; + + /* this polygon is on our layer if the polygon's layer name is the current layer's name.*/ + if (poly_layer_name != layer.layer_name) continue; + + /* Check polygon is the correct type (pour, plane, copper, pad or antipad) */ + if (j->second.begin()->polygon_type != poly_type) continue; + + /* Join all Hyperlynx polygons/polyvoids with the same id in a single Hyp2Mat polygon */ + Hyp2Mat::Polygon poly_copper = CopyPolygon(j->second, raw_polygons); + net_copper.Union(poly_copper); + } + + return net_copper; +} + +/* + * copy polygon + * polygon is copied twice; once to the list of "raw" polygons for --raw output; + * once added to this layers' copper for normal output. + */ + +Hyp2Mat::Polygon HyperLynx::CopyPolygon(HypFile::PolygonList metal, Hyp2Mat::FloatPolygons& raw_polygons) +{ + Hyp2Mat::Polygon poly; + + if (metal.empty()) return poly; /* ought never to happen */ + + /* Join all Hyperlynx polygons/polyvoids with the same id in a single Hyp2Mat polygon */ + for (HypFile::PolygonList::iterator k = metal.begin(); k != metal.end(); ++k) { + + /* copy vertices */ + Hyp2Mat::FloatPolygon edge; + for (HypFile::PointList::iterator v = k->vertex.begin(); v != k->vertex.end(); ++v) + edge.push_back(Hyp2Mat::FloatPoint(v->x, v->y)); + + /* fix orientation */ + if (IsClockwise(edge) != k->positive) Reverse(edge); + + /* add to raw polygons */ + Hyp2Mat::FloatPoly raw_poly; + raw_poly.poly = edge; + raw_poly.is_hole = !k->positive; + raw_poly.nesting_level = 0; + raw_polygons.push_back(raw_poly); + + /* add to cooked polygons */ + if (k->positive) poly.AddEdge(edge); + else poly.AddHole(edge); + } + + /* take line width of polygon into account */ + double width = metal.begin()->width; + poly.Simplify(); + poly.Offset(width/2); + + if (metal.front().polygon_type == POLYGON_TYPE_PLANE) { + /* calculate polygon-specific plane separation */ + polygon_plane_separation = net_plane_separation; + if (metal.front().plane_separation >= 0) polygon_plane_separation = metal.front().plane_separation; + + /* calculate mask needed to get clearance with other nets */ + Hyp2Mat::Polygon mask; + mask = PlaneSeparation(metal.front().layer_name, metal.front().net_name); + + /* subtract mask from polygon */ + poly.Difference(mask); + } + + return poly; +} + +/* + * Creates the mask by which to trim a plane polygon, taking into account plane separation. + * + * Algorithm: sum all polygons on layer 'layer_name' belonging to nets other than net 'net_name', + * expanded by the biggest polygon_plane separation. + */ + +Hyp2Mat::Polygon HyperLynx::PlaneSeparation(std::string layer_name, std::string net_name) +{ + Hyp2Mat::Polygon mask; + + if (polygon_plane_separation < 0) return mask; // XXX correct? + + /* iterate over all nets */ + for (HypFile::NetList::iterator i = hyp_file.net.begin(); i != hyp_file.net.end(); ++i) { + + /* all nets except net 'net_name' */ + if (i->net_name == net_name) continue; + + /* wanted nets only */ + bool net_wanted = nets.empty() || (std::find(nets.begin(), nets.end(), net_name) != nets.end()); + if (!net_wanted) continue; + + /* iterate over all Hyperlynx polygon id's */ + for (HypFile::PolygonMap::iterator j = i->metal.begin(); j != i->metal.end(); ++j) { + Hyp2Mat::Polygon poly; + + if (j->second.empty()) continue; /* ought never to happen */ + + /* polygons on layer 'layer_name' only */ + if (j->second.begin()->layer_name != layer_name) continue; + + /* iterate over all edges */ + for (HypFile::PolygonList::iterator k = j->second.begin(); k != j->second.end(); ++k) { + + /* iterate over all vertices */ + Hyp2Mat::FloatPolygon edge; + for (HypFile::PointList::iterator v = k->vertex.begin(); v != k->vertex.end(); ++v) + edge.push_back(Hyp2Mat::FloatPoint(v->x, v->y)); + + /* add edge to polygon */ + if (k->positive) poly.AddEdge(edge); + else poly.AddHole(edge); + } + + double width = j->second.begin()->width; + + /* calculate plane separation of the masking polygon */ + double mask_plane_separation; + mask_plane_separation = layer_plane_separation; /* layer */ + if (i->plane_separation >= 0) mask_plane_separation = i->plane_separation; /* net */ + if (j->second.begin()->plane_separation >= 0) mask_plane_separation = j->second.begin()->plane_separation; /* polygon */ + + /* compare plane separation of polygon and masking polygon; choose biggest plane separation. */ + double biggest_plane_separation; + if (polygon_plane_separation > mask_plane_separation) biggest_plane_separation = polygon_plane_separation; + else biggest_plane_separation = mask_plane_separation; + + /* grow masking polygon by plane separation */ + poly.Offset(width/2 + biggest_plane_separation); + + /* add to mask */ + mask.Union(poly); + + } + + } + + return mask; +} + +/* not truncated */ diff --git a/hyp2mat/lib/crop.cc b/hyp2mat/lib/crop.cc new file mode 100644 index 0000000..ebf05c9 --- /dev/null +++ b/hyp2mat/lib/crop.cc @@ -0,0 +1,108 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include "crop.h" + +using namespace Hyp2Mat; + +/* + * Adjust bounds to the size of the board + */ + +Hyp2Mat::Bounds Hyp2Mat::AdjustBounds(Hyp2Mat::PCB& pcb, Hyp2Mat::Bounds bounds) +{ + Bounds new_bounds = bounds; + Bounds size = pcb.GetBounds(); + + if (new_bounds.x_min < size.x_min) new_bounds.x_min = size.x_min; + if (new_bounds.x_max > size.x_max) new_bounds.x_max = size.x_max; + if (new_bounds.y_min < size.y_min) new_bounds.y_min = size.y_min; + if (new_bounds.y_max > size.y_max) new_bounds.y_max = size.y_max; + if (new_bounds.z_min < size.z_min) new_bounds.z_min = size.z_min; + if (new_bounds.z_max > size.z_max) new_bounds.z_max = size.z_max; + + return new_bounds; +} + +/* + * Crop polygon + */ + +Hyp2Mat::Polygon Hyp2Mat::CropPolygon (Hyp2Mat::Polygon poly, Hyp2Mat::Bounds bounds) +{ + Hyp2Mat::Polygon result; + FloatPolygon bounding_poly; + + bounding_poly.push_back(FloatPoint(bounds.x_min, bounds.y_min)); + bounding_poly.push_back(FloatPoint(bounds.x_max, bounds.y_min)); + bounding_poly.push_back(FloatPoint(bounds.x_max, bounds.y_max)); + bounding_poly.push_back(FloatPoint(bounds.x_min, bounds.y_max)); + result.AddEdge(bounding_poly); + + result.Intersection(poly); + + return result; +} + +/* + * Remove all vias which are out of bounds. + * XXX no longer needed? + */ + +void Hyp2Mat::CropVias(Hyp2Mat::PCB& pcb, Hyp2Mat::Bounds bounds) +{ + Hyp2Mat::Via new_via; + Hyp2Mat::ViaList new_vialist; + + for (Hyp2Mat::ViaList::iterator i = pcb.via.begin(); i != pcb.via.end(); ++i) { + if ((i->x > bounds.x_max) || (i->x < bounds.x_min) || (i->y > bounds.y_max) || (i->y < bounds.y_min)) continue; + if ((i->z0 > bounds.z_max) && (i->z1 > bounds.z_max)) continue; + if ((i->z0 < bounds.z_min) && (i->z1 < bounds.z_min)) continue; + new_via = *i; + if (new_via.z1 > bounds.z_max) new_via.z1 = bounds.z_max; + if (new_via.z0 < bounds.z_min) new_via.z0 = bounds.z_min; + new_vialist.push_back(new_via); + } + pcb.via = new_vialist; + return; +} + +/* + * Remove all layers which are out of bounds. + */ + +void Hyp2Mat::CropLayers(Hyp2Mat::PCB& pcb, Hyp2Mat::Bounds& bounds) +{ + Hyp2Mat::Layer new_layer; + Hyp2Mat::LayerList new_stackup; + + for (Hyp2Mat::LayerList::iterator l = pcb.stackup.begin(); l != pcb.stackup.end(); ++l) { + if ((l->z0 > bounds.z_max) && (l->z1 > bounds.z_max)) continue; + if ((l->z0 < bounds.z_min) && (l->z1 < bounds.z_min)) continue; + new_layer = *l; + if (new_layer.z1 > bounds.z_max) new_layer.z1 = bounds.z_max; + if (new_layer.z0 < bounds.z_min) new_layer.z0 = bounds.z_min; + new_stackup.push_back(new_layer); + } + pcb.stackup = new_stackup; + return; +} + +/* not truncated */ diff --git a/hyp2mat/lib/crop.h b/hyp2mat/lib/crop.h new file mode 100644 index 0000000..dd497bc --- /dev/null +++ b/hyp2mat/lib/crop.h @@ -0,0 +1,36 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#ifndef CROP_H +#define CROP_H + +#include "hyp2mat.h" +#include "polygon.h" + +namespace Hyp2Mat { + Hyp2Mat::Bounds AdjustBounds(Hyp2Mat::PCB& pcb, Bounds bounds); + Hyp2Mat::Polygon CropPolygon (Hyp2Mat::Polygon poly, Hyp2Mat::Bounds bounds); + void CropVias(Hyp2Mat::PCB& pcb, Hyp2Mat::Bounds bounds); + void CropLayers(Hyp2Mat::PCB& pcb, Hyp2Mat::Bounds& bounds); + } + +#endif + +/* not truncated */ diff --git a/hyp2mat/lib/csxcad.cc b/hyp2mat/lib/csxcad.cc new file mode 100644 index 0000000..a1ec204 --- /dev/null +++ b/hyp2mat/lib/csxcad.cc @@ -0,0 +1,376 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include + +#include "csxcad.h" + +using namespace Hyp2Mat; + +CSXCAD::CSXCAD() +{ + /* CSXcad priorities */ + + prio_dielectric = 100; // FR4 dielectric + prio_material = 200; // copper + prio_via = 300; // via metal + prio_drill = 400; // hole + + return; +} + +void CSXCAD::export_edge(FloatPolygon& edge) +{ + std::cout << "pgon = [];" << std::endl; + for (FloatPolygon::iterator i = edge.begin(); i != edge.end(); ++i) { + std::cout << "pgon(:, end+1) = [" << i->x << ";" << i->y << "];" << std::endl; + } + return; +} + +/* + * quote a string using matlab conventions. + */ + +std::string CSXCAD::string2matlab(std::string str) +{ + std::ostringstream ostring; + + // escape non-alpha characters, or WriteOpenEMS (in matlab) may crash on characters such as '%' in strings + + ostring << "'"; + for (unsigned int i = 0; i < str.size(); i++) { + if (str[i] == '\'') ostring << '\''; + if (str[i] == '%') ostring << '%'; + ostring << str[i]; + } + ostring << "'"; + + return ostring.str(); +} + +/* true if polygon list contains at least one (positive) polygon */ + +bool CSXCAD::contains_polygon(Hyp2Mat::FloatPolygons& polygons) +{ + bool result = false; + + for (FloatPolygons::iterator i = polygons.begin(); i != polygons.end(); ++i) { + result = !i->is_hole; + if (result) break; + }; + + return result; +} + +/* true if polygon list contains at least one hole */ + +bool CSXCAD::contains_hole(Hyp2Mat::FloatPolygons& polygons) +{ + bool result = false; + + for (FloatPolygons::iterator i = polygons.begin(); i != polygons.end(); ++i) { + result = i->is_hole; + if (result) break; + }; + + return result; +} + + /* + * Export dielectric + * If pcb_outline is true, export exact board shape, including holes. + * If pcb_outline is false, export bounding box. + */ + +void CSXCAD::export_board(Hyp2Mat::PCB& pcb, bool pcb_outline) +{ + /* CSXCAD coordinate grid definition */ + Bounds bounds = pcb.GetBounds(); + + std::cout << "function CSX = pcb(CSX)" << std::endl; + std::cout << "% matlab script created by hyp2mat" << std::endl; + std::cout << "% create minimal mesh" << std::endl; + std::cout << "mesh = {};" << std::endl; + std::cout << "mesh.x = [" << bounds.x_min << " " << bounds.x_max << "];" << std::endl; + std::cout << "mesh.y = [" << bounds.y_min << " " << bounds.y_max << "];" << std::endl; + std::cout << "mesh.z = [" << bounds.z_min << " " << bounds.z_max << "];" << std::endl; + std::cout << "% add mesh" << std::endl; + std::cout << "CSX = DefineRectGrid(CSX, 1, mesh);" << std::endl; + + /* + * Export the board. The board outline is positive; + */ + + /* + * create board material if at least one positive polygon present + * We output one polygon for each dielectric layer, as each layer may have + * a different epsilon_r. + */ + + if (contains_polygon(pcb.board)) { + + for (FloatPolygons::iterator i = pcb.board.begin(); i != pcb.board.end(); ++i) { + /* only output board material, not holes */ + if (i->is_hole) continue; + for (LayerList::reverse_iterator l = pcb.stackup.rbegin(); l != pcb.stackup.rend(); ++l) { + /* only output dielectrics */ + if (l->layer_type != LAYER_DIELECTRIC) continue; + + /* Output command to create material */ + std::cout << "CSX = AddHyperLynxDielectric(CSX, 'Dielectric_" << l->layer_name << "', " << l->epsilon_r << ", " << l->loss_tangent << ");" << std::endl; + + /* output CSXCAD polygon */ + std::cout << "% board outline, layer " << l->layer_name << std::endl; + int priority = prio_dielectric + i->nesting_level; + if (pcb_outline) { + /* Use AddLinPoly */ + export_edge(i->poly); + std::cout << "CSX = AddLinPoly(CSX, 'Dielectric_" << l->layer_name << "', " << priority << ", 2, " << l->z0 << ", pgon, " << l->z1 - l->z0 << ");" << std::endl; + } + else { + /* Use AddBox */ + std::cout << "CSX = AddBox(CSX, 'Dielectric_" << l->layer_name << "', " << priority << ", [ "; + std::cout << bounds.x_min << ", " << bounds.y_min << ", " << l->z0 << "], [ "; + std::cout << bounds.x_max << ", " << bounds.y_max << ", " << l->z1 << "] );" << std::endl; + } + } + } + }; + + + /* + * Export board cutouts + */ + + /* + * create board cutout material if at least one negative polygon present + * For each cutout we create a single polygon which goes through all layers. + */ + + if (pcb_outline && contains_hole(pcb.board)) { + std::cout << "% create board cutout material" << std::endl; + std::cout << "CSX = AddMaterial( CSX, 'Drill');" << std::endl; + std::cout << "CSX = SetMaterialProperty( CSX, 'Drill', 'Epsilon', 1, 'Mue', 1);" << std::endl; + + for (FloatPolygons::iterator i = pcb.board.begin(); i != pcb.board.end(); ++i) { + /* output CSXCAD polygon */ + if (!i->is_hole) continue; + std::cout << "% board cutout" << std::endl; + export_edge(i->poly); + int priority = prio_dielectric + i->nesting_level; + std::cout << "CSX = AddLinPoly(CSX, 'Drill', " << priority << ", 2, " << bounds.z_min << ", pgon, " << bounds.z_max - bounds.z_min << ");" << std::endl; + } + }; + + return; +} + + /* + * Export copper. + * If lossy_copper is true, take copper conductivity into account. + * If lossy_copper is false, assume copper is perfect conductor. + */ + +void CSXCAD::export_layer(Hyp2Mat::PCB& pcb, Hyp2Mat::Layer& layer, bool lossy_copper, bool metal_3d, bool odd) +{ + std::string layer_material = layer.layer_name + "_copper"; + std::string layer_cutout = layer.layer_name + "_cutout"; + + // create layer material if at least one positive polygon present + if (contains_polygon(layer.metal)) { + std::cout << "% create layer " << layer.layer_name << " material" << std::endl; + + double copper_resistivity = 0.0; + if (lossy_copper && (layer.bulk_resistivity > 0)) copper_resistivity = layer.bulk_resistivity; + + if (metal_3d) + std::cout << "CSX = AddHyperLynxMetal3D(CSX, '" << layer_material << "', " << copper_resistivity << ", " << layer.thickness << ");" << std::endl; + else + std::cout << "CSX = AddHyperLynxMetal2D(CSX, '" << layer_material << "', " << copper_resistivity << ", " << layer.thickness << ");" << std::endl; + }; + + // create layer cutout material if at least one hole present + if (contains_hole(layer.metal)) { + std::cout << "% create layer " << layer.layer_name << " cutout" << std::endl; + std::cout << "CSX = AddMaterial( CSX, '" << layer_cutout << "');" << std::endl; + // outer and inner copper layers have different epsilonr + std::cout << "CSX = SetMaterialProperty( CSX, '" << layer_cutout << "', 'Epsilon', " << layer.epsilon_r << ", 'Mue', 1);" << std::endl; + }; + + /* + * Export the layer. + */ + + std::string material; + + for (FloatPolygons::iterator i = layer.metal.begin(); i != layer.metal.end(); ++i) { + /* output CSXCAD polygon */ + if (!i->is_hole) { + std::cout << "% copper" << std::endl; + material = layer_material; + } + else { + std::cout << "% cutout" << std::endl; + material = layer_cutout; + }; + + export_edge(i->poly); + int priority = prio_material + i->nesting_level; + /* Default is exporting copper as a 2D conducting sheet */ + if (metal_3d) { + // We assume alternating layers of substrate and prepreg,and that metal layers are pushed into the prepreg. + // This means that the top metal layer is pointing up, the second metal layer is pointing down, and so on. + double thickness = layer.thickness; + if (odd) thickness = -thickness; + std::cout << "CSX = AddLinPoly(CSX, '" << material << "', " << priority << ", 2, " << layer.z0 << ", pgon, " << thickness << ");" << std::endl; + } + else + std::cout << "CSX = AddPolygon(CSX, '" << material << "', " << priority << ", 2, " << layer.z0 << ", pgon);" << std::endl; + } + + return; +} + +/* + * Export vias + */ + +void CSXCAD::export_vias(Hyp2Mat::PCB& pcb) +{ + if (!pcb.via.empty()) { + /* create via material */ + std::cout << "% via copper" << std::endl; + std::cout << "CSX = AddMetal( CSX, 'via' );" << std::endl; + for (ViaList::iterator i = pcb.via.begin(); i != pcb.via.end(); ++i) { + double z0 = i->z0; + double z1 = i->z1; + std::cout << "CSX = AddCylinder(CSX, 'via', " << prio_via ; + std::cout << ", [ " << i->x << " , " << i->y << " , " << z0; + std::cout << " ], [ " << i->x << " , " << i->y << " , " << z1; + std::cout << " ], " << i->radius << ");" << std::endl; + } + } + return; +} + +/* + * Export devices + */ + +void CSXCAD::export_devices(Hyp2Mat::PCB& pcb) +{ + std::cout << "% devices" << std::endl; + std::cout << "CSX.HyperLynxDevice = {};" << std::endl; + for (DeviceList::iterator i = pcb.device.begin(); i != pcb.device.end(); ++i) { + std::cout << "CSX.HyperLynxDevice{end+1} = struct('name', " << string2matlab(i->name) << ", 'ref', " << string2matlab(i->ref); + + /* output device value if available */ + if (i->value_type == DEVICE_VALUE_FLOAT) + std::cout << ", 'value', " << i->value_float; + else if (i->value_type == DEVICE_VALUE_STRING) + std::cout << ", 'value', " << string2matlab(i->value_string); + + std::cout << ", 'layer_name', " << string2matlab(i->layer_name); + std::cout << ");" << std::endl; + } +} + +/* + * Export port + */ + +void CSXCAD::export_ports(Hyp2Mat::PCB& pcb) +{ + std::cout << "% ports" << std::endl; + std::cout << "CSX.HyperLynxPort = {};" << std::endl; + for (PinList::iterator i = pcb.pin.begin(); i != pcb.pin.end(); ++i) { + /* csxcad requires rectangular ports, axis aligned. Use the bounding box. XXX fixme ? Use largest inscribed rectangle instead */ + double x_max = 0, y_max = 0, x_min = 0, y_min = 0; + bool first = true; + for (FloatPolygon::iterator j = i->metal.begin(); j != i->metal.end(); ++j) { + if ((j->x > x_max) || first) x_max = j->x; + if ((j->y > y_max) || first) y_max = j->y; + if ((j->x < x_min) || first) x_min = j->x; + if ((j->y < y_min) || first) y_min = j->y; + first = false; + } + + /* determine whether port is on top or bottom layer of pcb */ + double dbottom = std::abs(i->z0 - pcb.stackup.back().z0); + double dtop = std::abs(i->z1 - pcb.stackup.front().z1); + bool on_top = dtop <= dbottom; + + std::cout << "CSX.HyperLynxPort{end+1} = struct('ref', " << string2matlab(i->ref); + std::cout << ", 'xc', " << i->x << ", 'yc', " << i->y << ", 'z', " << i->z0; + std::cout << ", 'x1', " << x_min << ", 'y1', " << y_min ; + std::cout << ", 'x2', " << x_max << ", 'y2', " << y_max ; + std::cout << ", 'position', " << (on_top ? "'top'" : "'bottom'"); + std::cout << ", 'layer_name', " << string2matlab(i->layer_name) << ");" << std::endl; + } + return; +} + +/* + * Write pcb to file in CSXCAD format + */ + +void CSXCAD::Write(const std::string& filename, Hyp2Mat::PCB pcb, bool pcb_outline, bool lossy_copper, bool metal_3d) +{ + + /* open file for output */ + + if ((filename != "-") && (freopen(filename.c_str(), "w", stdout) == NULL)) { + std::cerr << "could not open '" << filename << "' for writing"; + return; + } + + /* Export dielectric. If pcb_outline is true, export exact board shape, including holes. + If pcb_outline is false, export bounding box. */ + export_board(pcb, pcb_outline); + + /* Export copper */ + std::cout << "% copper" << std::endl; + bool odd = false; + for (LayerList::iterator l = pcb.stackup.begin(); l != pcb.stackup.end(); ++l) { + if (l->layer_type == LAYER_DIELECTRIC) odd = !odd; + export_layer(pcb, *l, lossy_copper, metal_3d, odd); + } + + /* Export vias */ + export_vias(pcb); + + export_devices(pcb); + + export_ports(pcb); + + std::cout << "%not truncated" << std::endl; + + fclose(stdout); + + return; +} + +/* not truncated */ diff --git a/hyp2mat/lib/csxcad.h b/hyp2mat/lib/csxcad.h new file mode 100644 index 0000000..af7ec5b --- /dev/null +++ b/hyp2mat/lib/csxcad.h @@ -0,0 +1,53 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#ifndef CSXCAD_H +#define CSXCAD_H + +#include "hyp2mat.h" + +class CSXCAD { +public: + CSXCAD(); + void Write(const std::string& filename, Hyp2Mat::PCB pcb, bool pcb_outline, bool lossy_copper, bool metal_3d); /* save in CSXcad format */ + +private: + int prio_dielectric; // FR4 dielectric + int prio_material; // copper + int prio_via; // via metal + int prio_drill; // hole + + double adjust_z(Hyp2Mat::PCB& pcb, double z); + + void export_edge(Hyp2Mat::FloatPolygon& edge); /* output a polygon edge */ + void export_layer(Hyp2Mat::PCB& pcb, Hyp2Mat::Layer& layer, bool lossy_copper, bool metal_3d, bool odd); /* output a copper layer */ + void export_board(Hyp2Mat::PCB& pcb, bool pcb_outline); /* output the dielectric */ + void export_vias(Hyp2Mat::PCB& pcb); + void export_devices(Hyp2Mat::PCB& pcb); + void export_ports(Hyp2Mat::PCB& pcb); + bool contains_polygon(Hyp2Mat::FloatPolygons& polygons); /* true if polygon list contains at least one (positive) polygon */ + bool contains_hole(Hyp2Mat::FloatPolygons& polygons); /* true if polygon list contains at least one hole */ + std::string string2matlab(std::string str); /* quote a string using matlab conventions */ + + }; + +#endif + +/* not truncated */ diff --git a/hyp2mat/lib/draw.cc b/hyp2mat/lib/draw.cc new file mode 100644 index 0000000..0de9634 --- /dev/null +++ b/hyp2mat/lib/draw.cc @@ -0,0 +1,296 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +/* + * Uses the Clipper library from Angus Johnson to do polygon arithmetic + */ + +#include +#include +#include +#include "hypfile.h" + +using namespace std; +using namespace HypFile; + +/* + * Polygon constructor + */ + +Polygon::Polygon() +{ + vertex.clear(); + polygon_type = POLYGON_TYPE_COPPER; + id = -1; + positive = true; /* is a polygon, not a hole */ + width = 0.0; + plane_separation = -1.0; /* negative if not set */ + left_plane_separation = -1.0; /* negative if not set */ + net_name.clear(); + layer_name.clear(); +} + +/* + * Draw an arc from (x1, y1) to (x2, y2) with center (xc, yc) and radius r using a polygonal approximation. + * Arc may be clockwise or counterclockwise. + */ + +Polygon HypFile::Hyp::arc2poly(double x1, double y1, double x2, double y2, double xc, double yc, double r, bool clockwise) +{ + + Polygon arc_segment; + arc_segment.width = 0; + arc_segment.positive = true; + arc_segment.layer_name = ""; + + int poly_points = 0; + + double alpha = atan2(y1-yc, x1-xc); + double beta = atan2(y2-yc, x2-xc); + + + if (clockwise) { + // draw arc clockwise from (x1,y1) to (x2,y2) + if (alpha < beta) + alpha = alpha + 2 * pi; + } + else { + // draw arc counterclockwise from (x1,y1) to (x2,y2) + if (beta < alpha) + beta = beta + 2 * pi; + // draw a circle if starting and end points are the same + if ((x1 == x2) && (y1 == y2)) + beta = alpha + 2 * pi; + } + + // Calculate number of segments needed for a full circle. + int segments = min_circle_segments; + + if (arc_precision > 0) { + // Increase number of segments until difference between circular arc + // and polygonal approximation is less than max_arc_error + + double arc_error; + do { + arc_error = r * (1 - cos(pi/segments)); + if (arc_error > arc_precision) segments += 4; + } + while (arc_error > arc_precision); + + } + else if (arc_precision < 0) + error("error: negative arc precision"); + + // A full circle is drawn using 'segments' segments; a 90 degree arc using segments/4. + poly_points = round(segments*abs(beta-alpha)/(2*pi)); + + // Sanity checks + if (poly_points < 1) poly_points = 1; + + // first point + arc_segment.vertex.push_back(Point(x1, y1)); + + // intermediate points + for (int i = 1; i < poly_points ; i++) { + double angle = alpha + (beta - alpha) * i / poly_points; + double x = xc + r * cos(angle); + double y = yc + r * sin(angle); + arc_segment.vertex.push_back(Point(x, y)); + } + + // last point + arc_segment.vertex.push_back(Point(x2, y2)); + + return arc_segment; +} + +/* + * Draws straight metal trace segment as a polygon. + */ + +Polygon HypFile::Hyp::segment2poly(double x1, double y1, double x2, double y2, double width) +{ +/* + * Note a hyperlynx line segment is drawn, ending in two half-circles: + * ------------------------------- ^ + * / \ | + * | | width + * \ / | + * ------------------------------- V + * + * <----------- length ----------> + */ + + Polygon line_segment; + line_segment.width = 0; + line_segment.positive = true; + line_segment.layer_name = ""; + + /* Sanity check */ + double dx; + double dy; + if (( x1 == x2) && (y2 == y1)) { + dx = width/2; + dy = 0; + } + else { + double length = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); + dx = width / 2 * (y2 - y1) / length; + dy = width / 2 * (x2 - x1) / length; + } + + Polygon arc2 = arc2poly(x2 + dx, y2 - dy, x2 - dx, y2 + dy, x2, y2, width/2, false); + Polygon arc1 = arc2poly(x1 - dx, y1 + dy, x1 + dx, y1 - dy, x1, y1, width/2, false); + + line_segment.vertex = arc2.vertex; + line_segment.vertex.insert(line_segment.vertex.end(), arc1.vertex.begin(), arc1.vertex.end()); + + return line_segment; +} + +/* + * Convert a pad to a polygon + */ + +Polygon HypFile::Hyp::pad2poly(double pad_x, double pad_y, Pad pad) +{ + Polygon pad_poly; + pad_poly.width = 0; + pad_poly.layer_name = pad.layer_name; + pad_poly.positive = true; + if (pad.pad_type == PAD_TYPE_ANTIPAD) pad_poly.polygon_type = POLYGON_TYPE_ANTIPAD; + else pad_poly.polygon_type = POLYGON_TYPE_PAD; + + double sx = pad.pad_sx; + double sy = pad.pad_sy; + double angle = pad.pad_angle; + + if (fmod(angle, 180) == 0) angle = 0; + else if (fmod(angle, 90) == 0) { + double t; + t = sx; + sx = sy; + sy = t; + angle = 0; + } + + /* + * Circular and oval pads + */ + + if (pad.pad_shape == PAD_SHAPE_OVAL) { + /* calculate number of segments needed */ + int segments = min_circle_segments; + if (arc_precision > 0) { + /* Increase number of segments until difference between oval + and polygonal approximation is less than max_arc_error */ + double arc_error_x; + double arc_error_y; + do { + arc_error_x = sx / 2 * (1 - cos(pi/segments)); + arc_error_y = sy / 2 * (1 - cos(pi/segments)); + if ((arc_error_x > arc_precision) || (arc_error_y > arc_precision)) segments += 4; + } + while ((arc_error_x > arc_precision) || (arc_error_y > arc_precision)); + } + /* calculate points */ + for (int i = 0; i < segments; i++) { + double alpha = 2 * pi * i / segments; + double x = sx / 2 / cos(pi / segments) * cos(alpha); + double y = sy / 2 / cos(pi / segments) * sin(alpha); + pad_poly.vertex.push_back(Point(x, y)); + } + } + + /* + * Square and rectangular pads + */ + + else if (pad.pad_shape == PAD_SHAPE_RECTANGULAR) { + pad_poly.vertex.push_back(Point( sx/2, sy/2)); + pad_poly.vertex.push_back(Point( sx/2, -sy/2)); + pad_poly.vertex.push_back(Point(-sx/2, -sy/2)); + pad_poly.vertex.push_back(Point(-sx/2, sy/2)); + } + + /* + * Oblong pads + */ + + else if (pad.pad_shape == PAD_SHAPE_OBLONG) { + if (sx > sy) { + /* horizontal oblong pad */ + double x1 = (sx - sy)/2; + double y1 = -sy/2; + double x2 = x1; + double y2 = -y1; + double xc = (sx - sy)/2; + double yc = 0; + double r = sy/2; + Polygon arc_right = arc2poly(x1, y1, x2, y2, xc, yc, r, false); + Polygon arc_left = arc2poly(-x1, -y1, -x2, -y2, -xc, -yc, r, false); + pad_poly.vertex = arc_right.vertex; + pad_poly.vertex.insert(pad_poly.vertex.end(), arc_left.vertex.begin(), arc_left.vertex.end()); + } + else { + /* vertical oblong pad */ + double x1 = sx/2; + double y1 = (sy - sx)/2; + double x2 = -x1; + double y2 = y1; + double xc = 0; + double yc = (sy-sx)/2; + double r = sx/2; + Polygon arc_top = arc2poly(x1, y1, x2, y2, xc, yc, r, false); + Polygon arc_bottom = arc2poly(-x1, -y1, -x2, -y2, -xc, -yc, r, false); + pad_poly.vertex = arc_top.vertex; + pad_poly.vertex.insert(pad_poly.vertex.end(), arc_bottom.vertex.begin(), arc_bottom.vertex.end()); + } + } + + /* + * Unknown pad shape + */ + + else error("unknown pad shape"); + + /* Rotate polygon over pad rotation angle */ + if (angle != 0) { + double cosa = cos(angle * pi / 180); + double sina = sin(angle * pi / 180); + for (PointList::iterator i = pad_poly.vertex.begin(); i != pad_poly.vertex.end(); ++i) { + double x_rot = cosa * i->x - sina * i->y ; + double y_rot = sina * i->x + cosa * i->y ; + i->x = x_rot; + i->y = y_rot; + } + } + + /* Translate polygon to pad center */ + for (PointList::iterator i = pad_poly.vertex.begin(); i != pad_poly.vertex.end(); ++i) { + i->x += pad_x; + i->y += pad_y; + } + + /* return pad converted to polygon */ + return pad_poly; +} + +/* not truncated */ diff --git a/hyp2mat/lib/exec_board.cc b/hyp2mat/lib/exec_board.cc new file mode 100644 index 0000000..103d586 --- /dev/null +++ b/hyp2mat/lib/exec_board.cc @@ -0,0 +1,251 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include +#include +#include "hypfile.h" + +using namespace std; +using namespace HypFile; + +/* + * Hyperlynx 'BOARD_FILE' section. + * Hyperlynx file header. + */ + +bool HypFile::Hyp::exec_board_file(parse_param& h) +{ + if (trace_hyp) cerr << "board_file" << endl; + + return false; +} + +/* + * Hyperlynx 'VERSION' record. + * Specifies version number. + * Required record; must be first record of the file. + */ + +bool HypFile::Hyp::exec_version(parse_param& h) +{ + if (trace_hyp) cerr << "version: vers = " << h.vers << endl; + + if (h.vers < 2.0) error("warning: version 1.x deprecated"); + + return false; +} + +/* + * Hyperlynx 'DATA_MODE' record. + * Specifies whether data is sufficient for power simulation. + */ + +bool HypFile::Hyp::exec_data_mode(parse_param& h) +{ + if (trace_hyp) cerr << "data_mode: detailed = " << h.detailed << endl; + + return false; +} + +/* + * Hyperlynx 'UNITS' record. + * Specifies measurement system (english/metric) for the rest of the file. + */ + +bool HypFile::Hyp::exec_units(parse_param& h) +{ + if (trace_hyp) cerr << "units: unit_system_english = " << h.unit_system_english << " metal_thickness_weight = " << h.metal_thickness_weight << endl; + // convert everything to meter + + if (h.unit_system_english) { + unit = inches; // lengths in inches. 1 in = 2.54 cm = 0.0254 m + if (h.metal_thickness_weight) + metal_thickness_unit = copper_imperial_weight * unit; // metal thickness in ounces/ft2. 1 oz/ft2 copper = 1.341 mil + else + metal_thickness_unit = unit; // metal thickness in inches + } + else { + unit = 0.01; // lengths in centimeters. 1 cm = 0.01 m + if (h.metal_thickness_weight) + metal_thickness_unit = copper_metric_weight * unit; // metal thickness in grams/cm2. 1 gr/cm2 copper = 0.1116 cm + else + metal_thickness_unit = unit; // metal thickness in centimeters + } + + return false; +} + +/* + * Hyperlynx 'PLANE_SEP' record. + * Defines default trace to plane separation + */ + +bool HypFile::Hyp::exec_plane_sep(parse_param& h) +{ + if (trace_hyp) cerr << "plane_sep: default_plane_separation = " << h.default_plane_separation << endl; + + board.plane_separation = h.default_plane_separation * unit; + + return false; +} + +/* + * Hyperlynx 'PERIMETER_SEGMENT' subrecord of 'BOARD' record. + * Draws linear board outline segment. + */ + +bool HypFile::Hyp::exec_perimeter_segment(parse_param& h) +{ + if (trace_hyp) cerr << "perimeter_segment: x1 = " << h.x1 << " y1 = " << h.y1 << " x2 = " << h.x2 << " y2 = " << h.y2 << endl; + + Polygon poly; + + h.x1 *= unit; + h.y1 *= unit; + h.x2 *= unit; + h.y2 *= unit; + + poly.width = 0; + poly.positive = true; + poly.vertex.push_back(Point(h.x1, h.y1)); + poly.vertex.push_back(Point(h.x2, h.y2)); + + // Add segment to board outline + add_perimeter_polygon(poly); + + return false; +} + +/* + * Hyperlynx 'PERIMETER_ARC' subrecord of 'BOARD' record. + * Draws arc segment of board outline. + */ + +bool HypFile::Hyp::exec_perimeter_arc(parse_param& h) +{ + if (trace_hyp) cerr << "perimeter_arc: x1 = " << h.x1 << " y1 = " << h.y1 << " x2 = " << h.x2 << " y2 = " << h.y2 << " xc = " << h.xc << " yc = " << h.yc << " r = " << h.r << endl; + + Polygon poly; + + h.x1 *= unit; + h.y1 *= unit; + h.x2 *= unit; + h.y2 *= unit; + h.xc *= unit; + h.yc *= unit; + h.r *= unit; + + poly = arc2poly(h.x1, h.y1, h.x2, h.y2, h.xc, h.yc, h.r, false); // 'PERIMETER_ARC' draws arc counterclockwise + + // Add arc to board outline + add_perimeter_polygon(poly); + + return false; +} + +/* + * Hyperlynx 'A' attribute subrecord of 'BOARD' record. + * Defines board attributes as name/value pairs. + */ + +bool HypFile::Hyp::exec_board_attribute(parse_param& h) +{ + if (trace_hyp) cerr << "board_attribute: name = " << h.name << " value = " << h.value << endl; + + Attribute a; + a.name = h.name; + a.value = h.value; + + board.attribute.push_back(a); + + return false; +} + +/* + * Add a polygon to the board outline + */ + +void HypFile::Hyp::add_perimeter_polygon(Polygon new_segment) +{ + // Note first polygon of board perimeter is the board outline, and positive. + // Subsequent polygons are board cutouts, and negative. + + // safety check + if (new_segment.vertex.empty()) + return; + + if (new_segment.vertex.size() == 1) { + error("runt perimeter segment"); + return; + } + + /* add new segment to list of PERIMETER_SEGMENT and PERIMETER_ARC segments */ + board.segments.push_back(new_segment); + + /* re-calculate board edge + * loop over the list of segments, trying to re-construct the + * board edge piece by piece. */ + + board.edge.clear(); + PolygonList segs = board.segments; + Polygon current_edge; + + bool found = false; + do { + found = false; + /* find segment to add to existing edge */ + for (PolygonList::iterator i = segs.begin(); i != segs.end(); ++i) { + + if (current_edge.vertex.empty() || (i->vertex.front() == current_edge.vertex.back())) { + /* first point of segment is last point of current edge: add segment to edge */ + found = true; + current_edge.vertex.insert(current_edge.vertex.end(), i->vertex.begin(), i->vertex.end()); + } + else if (i->vertex.back() == current_edge.vertex.back()) { + /* last point of segment is last point of current edge: add segment to edge back to front */ + found = true; + current_edge.vertex.insert(current_edge.vertex.end(), i->vertex.rbegin(), i->vertex.rend()); + }; + + if (found) { + /* erase added segment from list of unused segments */ + segs.erase(i); + /* check if current edge is closed */ + if (current_edge.vertex.front() == current_edge.vertex.back()) { + /* store old edge, begin new one */ + current_edge.positive = false; + board.edge.push_back(current_edge); + current_edge.vertex.clear(); + } + break; + } + + } + } while (found); + + /* only first polygon of board perimeter is positive, rest are holes. */ + if (!board.edge.empty()) board.edge.front().positive = true; + + return; + +} + +/* not truncated */ diff --git a/hyp2mat/lib/exec_devices.cc b/hyp2mat/lib/exec_devices.cc new file mode 100644 index 0000000..59b7f00 --- /dev/null +++ b/hyp2mat/lib/exec_devices.cc @@ -0,0 +1,89 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include "hypfile.h" + +using namespace std; +using namespace HypFile; + +/* + * Hyperlynx 'DEVICE' record. + * Specifies pcb components: resistors, capacitors, ICs, ... + * Required record. + */ + +bool HypFile::Hyp::exec_devices(parse_param& h) +{ + if (trace_hyp) { + cerr << "device: "; + cerr << "device_type = " << h.device_type; + cerr << " ref = " << h.ref ; + if (h.name_set) cerr << " name = " << h.name; + if (h.value_float_set) cerr << " value_float = " << h.value_float; + if (h.value_string_set) cerr << " value_string = " << h.value_string; + if (h.layer_name_set) cerr << " layer_name = " << h.layer_name; + if (h.package_set) cerr << " package = " << h.package; + cerr << endl; + } + + Device d; + + d.device_type = h.device_type; + + d.ref = h.ref; + + if (h.name_set) + d.name = h.name; + else + d.name = ""; + + if (h.value_float_set) + d.value_float = h.value_float; + else + d.value_float = 0; + + d.value_float_set = h.value_float_set; + + if (h.value_string_set) + d.value_string = h.value_string; + else + d.value_string = ""; + + d.value_string_set = h.value_string_set; + + if (h.layer_name_set) + d.layer_name = h.layer_name; + else { + error ("device layer not set"); + return true; + } + + if (h.package_set) + d.package = h.package; + else + d.package = ""; + + device.push_back(d); + + return false; +} + +/* not truncated */ diff --git a/hyp2mat/lib/exec_end.cc b/hyp2mat/lib/exec_end.cc new file mode 100644 index 0000000..a87ca25 --- /dev/null +++ b/hyp2mat/lib/exec_end.cc @@ -0,0 +1,53 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include "hypfile.h" + +using namespace std; +using namespace HypFile; + +/* + * Hyperlynx 'END' record. + * Marks end of board description. + */ + +bool HypFile::Hyp::exec_end(parse_param& h) +{ + if (trace_hyp) cerr << "end" << endl; + + /* Optionally flood layers with copper */ + flood_layers_with_copper(); + + return false; +} + +/* + * Hyperlynx 'KEY' record. + */ + +bool HypFile::Hyp::exec_key(parse_param& h) +{ + if (trace_hyp) cerr << "key: key = " << h.key << endl; + + return false; +} + +/* not truncated */ diff --git a/hyp2mat/lib/exec_net.cc b/hyp2mat/lib/exec_net.cc new file mode 100644 index 0000000..50000b3 --- /dev/null +++ b/hyp2mat/lib/exec_net.cc @@ -0,0 +1,502 @@ + +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include +#include "hypfile.h" + +using namespace std; +using namespace HypFile; + +/* + * Hyperlynx 'NET' record. + * Specifies a net. + */ + +bool HypFile::Hyp::exec_net(parse_param& h) +{ + if (trace_hyp) cerr << "net: net_name = " << h.net_name << endl; + + Net n; + n.net_name = h.net_name; + n.plane_separation = -1.0; + net.push_back(n); + + return false; +} + +/* + * Hyperlynx 'PS' subrecord of 'NET' record. + * Specifies plane separation of a net. + */ + +bool HypFile::Hyp::exec_net_plane_separation(parse_param& h) +{ + if (trace_hyp) cerr << "net_plane_separation: plane_separation = " << h.plane_separation << endl; + h.plane_separation *= unit; + + net.back().plane_separation = h.plane_separation; + + return false; +} + +/* + * Hyperlynx 'SEG' subrecord of 'NET' record. + * Draws straight metal trace segment. + */ + +bool HypFile::Hyp::exec_seg(parse_param& h) +{ + if (trace_hyp) { + cerr << "seg: x1 = " << h.x1 << " y1 = " << h.y1 << " x2 = " << h.x2 << " y2 = " << h.y2; + cerr << " width = " << h.width << " layer_name = " << h.layer_name; + if (h.plane_separation_set) cerr << " plane_separation = " << h.plane_separation; + if (h.left_plane_separation_set) cerr << " left_plane_separation = " << h.left_plane_separation; + cerr << endl; + } + + Polygon p; + + h.x1 *= unit; + h.y1 *= unit; + h.x2 *= unit; + h.y2 *= unit; + h.width *= unit; + h.plane_separation *= unit; + if (!h.plane_separation_set) h.plane_separation = -1.0; + h.left_plane_separation *= unit; + if (!h.left_plane_separation_set) h.left_plane_separation = -1.0; + + p = segment2poly(h.x1 , h.y1, h.x2, h.y2, h.width); + p.layer_name = h.layer_name; + p.width = 0; + p.positive = true; + p.plane_separation = h.plane_separation; /* distance to other copper; -1 if not set */ + p.left_plane_separation = h.left_plane_separation; + + add_polygon(p); + + return false; +} + +/* + * Hyperlynx 'ARC' subrecord of 'NET' record. + * Draws arc metal trace segment. + */ + +bool HypFile::Hyp::exec_arc(parse_param& h) +{ + if (trace_hyp) { + cerr << "arc: x1 = " << h.x1 << " y1 = " << h.y1 << " x2 = " << h.x2 << " y2 = " << h.y2; + cerr << " xc = " << h.xc << " yc = " << h.yc << " r = " << h.r; + cerr << " width = " << h.width << " layer_name = " << h.layer_name; + if (h.plane_separation_set) cerr << " plane_separation = " << h.plane_separation; + if (h.left_plane_separation_set) cerr << " left_plane_separation = " << h.left_plane_separation; + cerr << endl; + } + + h.x1 *= unit; + h.y1 *= unit; + h.x2 *= unit; + h.y2 *= unit; + h.xc *= unit; + h.yc *= unit; + h.r *= unit; + h.width *= unit; + h.plane_separation *= unit; + if (!h.plane_separation_set) h.plane_separation = -1.0; + h.left_plane_separation *= unit; + if (!h.left_plane_separation_set) h.left_plane_separation = -1.0; + + /* 'ARC' draws arc clockwise */ + Polygon arc = arc2poly(h.x1, h.y1, h.x2, h.y2, h.xc, h.yc, h.r, true); + + /* draw arc segments */ + for (PointList::iterator i = arc.vertex.begin(); (i != arc.vertex.end()) && (i != --arc.vertex.end()); ++i) { + Polygon line_segment; + PointList::iterator j = i + 1; + line_segment = segment2poly(i->x, i->y, j->x, j->y, h.width); + line_segment.positive = true; + line_segment.layer_name = h.layer_name; + line_segment.width = 0; + line_segment.plane_separation = h.plane_separation; + line_segment.left_plane_separation = h.left_plane_separation; + add_polygon(line_segment); + } + + return false; +} + +/* + * Hyperlynx 'VIA' subrecord of 'NET' record. + * Draws via as defined in padstack. + */ + +bool HypFile::Hyp::exec_via(parse_param& h) +{ + if (trace_hyp) { + cerr << "via: x = " << h.x << " y = " << h.y; + if (h.layer1_name_set) cerr << " layer1_name = " << h.layer1_name; + if (h.layer2_name_set) cerr << " layer2_name = " << h.layer2_name; + cerr << " padstack_name = " << h.padstack_name; + cerr << endl; + } + + h.x *= unit; + h.y *= unit; + + /* lookup padstack */ + for (PadstackList::iterator i = padstack.begin(); i != padstack.end(); ++i) + if (i->padstack_name == h.padstack_name) { + + /* set via begin layer */ + if (!h.layer1_name_set) + h.layer1_name = i->pads.front().layer_name; + + /* set via end layer */ + if (!h.layer2_name_set) + h.layer2_name = i->pads.back().layer_name; + + /* add to list of via holes */ + add_via(h.x, h.y, h.layer2_name, h.layer1_name, i->drill_size/2); + + /* loop over padstack and generate pads */ + for (PadList::iterator j = i->pads.begin(); j != i->pads.end(); ++j) + add_pad(h.x, h.y, *j); + + return false; + } + + /* padstack not found */ + + return false; +} + +/* + * Hyperlynx 'VIA' subrecord of 'NET' record. + * Draws deprecated v1.x via. + */ + +bool HypFile::Hyp::exec_via_v1(parse_param& h) +{ + if (trace_hyp) { + cerr << "via: x = " << h.x << " y = " << h.y; + cerr << " drill_size = " << h.drill_size; + if (h.layer1_name_set) cerr << " layer1_name = " << h.layer1_name; + if (h.layer2_name_set) cerr << " layer2_name = " << h.layer2_name; + cerr << " pad1_shape = " << h.pad1_shape << " pad1_sx = " << h.pad1_sx << " pad1_sy = " << h.pad1_sy << " pad1_angle = " << h.pad1_angle; + cerr << " pad2_shape = " << h.pad2_shape << " pad2_sx = " << h.pad2_sx << " pad2_sy = " << h.pad2_sy << " pad2_angle = " << h.pad2_angle; + cerr << endl; + } + + h.drill_size *= unit; + h.x *= unit; + h.y *= unit; + h.pad1_sx *= unit; + h.pad1_sy *= unit; + h.pad2_sx *= unit; + h.pad2_sy *= unit; + + /* add to list of via holes */ + add_via(h.x, h.y, stackup.back().layer_name /* bottom */, stackup.front().layer_name /* top */ , h.drill_size/2); + + /* add top pad */ + Pad pad; + pad.layer_name = stackup.front().layer_name; /* Top layer */ + if (h.pad1_shape == "OVAL") pad.pad_shape = PAD_SHAPE_OVAL; + else if (h.pad1_shape == "RECT") pad.pad_shape = PAD_SHAPE_RECTANGULAR; + else if (h.pad1_shape == "OBLONG") pad.pad_shape = PAD_SHAPE_OBLONG; + else pad.pad_shape = PAD_SHAPE_OVAL; + pad.pad_type = PAD_TYPE_METAL; + pad.pad_sx = h.pad1_sx; + pad.pad_sy = h.pad1_sy; + pad.pad_angle = h.pad1_angle; + pad.thermal_clear_shape = PAD_SHAPE_OVAL; + pad.thermal_clear_sx = 0; + pad.thermal_clear_sy= 0; + pad.thermal_clear_angle= 0; + add_pad(h.x, h.y, pad); + + /* add bottom pad */ + pad.layer_name = stackup.back().layer_name; /* Top layer */ + if (h.pad2_shape == "OVAL") pad.pad_shape = PAD_SHAPE_OVAL; + else if (h.pad2_shape == "RECT") pad.pad_shape = PAD_SHAPE_RECTANGULAR; + else if (h.pad2_shape == "OBLONG") pad.pad_shape = PAD_SHAPE_OBLONG; + else pad.pad_shape = PAD_SHAPE_OVAL; + pad.pad_type = PAD_TYPE_METAL; + pad.pad_sx = h.pad2_sx; + pad.pad_sy = h.pad2_sy; + pad.pad_angle = h.pad2_angle; + add_pad(h.x, h.y, pad); + + return false; +} + +/* + * Hyperlynx 'PIN' subrecord of 'NET' record. + * Draws PIN as defined in padstack. + */ + +bool HypFile::Hyp::exec_pin(parse_param& h) +{ + if (trace_hyp) { + cerr << "pin: x = " << h.x << " y = " << h.y; + cerr << " pin_reference = " << h.pin_reference; + cerr << " padstack_name = " << h.padstack_name; + if (h.pin_function_set) cerr << " pin_function = " << h.pin_function; + cerr << endl; + } + + h.x *= unit; + h.y *= unit; + + /* add to list of pins */ + Pin p; + p.x = h.x; + p.y = h.y; + p.pin_reference = h.pin_reference; + p.padstack_name = h.padstack_name; + p.pin_function = PIN_SIM_BOTH; + if (h.pin_function_set) p.pin_function = h.pin_function; + net.back().pin.push_back(p); + + /* lookup padstack */ + if (h.padstack_name_set) + for (PadstackList::iterator i = padstack.begin(); i != padstack.end(); ++i) + if (i->padstack_name == h.padstack_name) { + /* add to list of via holes */ + add_via(h.x, h.y, stackup.back().layer_name /* bottom */, stackup.front().layer_name /* top */, i->drill_size/2); + + /* loop over padstack and generate pads */ + for (PadList::iterator j = i->pads.begin(); j != i->pads.end(); ++j) + add_pad(h.x, h.y, *j); + return false; + } + + /* padstack not found or not set */ + + return false; +} + +/* + * Hyperlynx 'PAD' subrecord of 'NET' record. + * Draws deprecated v1.x pad. + */ + +bool HypFile::Hyp::exec_pad(parse_param& h) +{ + if (trace_hyp) { + cerr << "pad: x = " << h.x << " y = " << h.y; + if (h.layer_name_set) cerr << " layer_name = " << h.layer_name; + cerr << " pad1_shape = " << h.pad1_shape << " pad1_sx = " << h.pad1_sx << " pad1_sy = " << h.pad1_sy << " pad1_angle = " << h.pad1_angle; + cerr << endl; + } + + h.x *= unit; + h.y *= unit; + h.pad1_sx *= unit; + h.pad1_sy *= unit; + + /* add pad */ + Pad pad; + pad.layer_name = h.layer_name; + if (h.pad1_shape == "OVAL") pad.pad_shape = PAD_SHAPE_OVAL; + else if (h.pad1_shape == "RECT") pad.pad_shape = PAD_SHAPE_RECTANGULAR; + else if (h.pad1_shape == "OBLONG") pad.pad_shape = PAD_SHAPE_OBLONG; + else pad.pad_shape = PAD_SHAPE_OVAL; + pad.pad_type = PAD_TYPE_METAL; + pad.pad_sx = h.pad1_sx; + pad.pad_sy = h.pad1_sy; + pad.pad_angle = h.pad1_angle; + pad.thermal_clear_shape = PAD_SHAPE_OVAL; + pad.thermal_clear_sx = 0; + pad.thermal_clear_sy= 0; + pad.thermal_clear_angle= 0; + add_pad(h.x, h.y, pad); + + return false; +} + +/* + * Hyperlynx 'USEG' subrecord of 'NET' record. + * Designates unrouted metal trace segment + */ + +bool HypFile::Hyp::exec_useg(parse_param& h) +{ + if (trace_hyp) { + cerr << "useg: x1 = " << h.x1 << " y1 = " << h.y1 << " layer1_name = " << h.layer1_name; + cerr << " x2 = " << h.x2 << " y2 = " << h.y2 << " layer2_name = " << h.layer2_name; + if (h.zlayer_name_set) cerr << " zlayer_name = " << h.zlayer_name << " width = " << h.width << " length = " << h.length; + if (h.impedance_set) cerr << " impedance = " << h.impedance << " delay = " << h.delay; + if (h.resistance_set) cerr << " resistance = " << h.resistance; + cerr << endl; + } + + h.x1 *= unit; + h.y1 *= unit; + h.x2 *= unit; + h.y2 *= unit; + h.width *= unit; + h.length *= unit; + if (!h.resistance_set) h.resistance = 0; + + UnroutedSegment u; + u.x1 = h.x1; + u.y1 = h.y1; + u.layer1_name = h.layer1_name; + u.x2 = h.x2; + u.y2 = h.y2; + u.layer2_name = h.layer2_name; + u.zlayer_name = h.zlayer_name; + u.zlayer_name_set = h.zlayer_name_set; + u.width = h.width; + u.impedance = h.impedance; + u.impedance_set = h.impedance_set; + u.delay = h.delay; + u.resistance = h.resistance; + net.back().unrouted_segment.push_back(u); + + return false; +} + +/* + * Hyperlynx 'A' attribute subrecord of 'NET' record. + * Defines net attributes as name/value pairs. + */ + +bool HypFile::Hyp::exec_net_attribute(parse_param& h) +{ + if (trace_hyp) cerr << "net_attribute: name = " << h.name << " value = " << h.value << endl; + + Attribute a; + a.name = h.name; + a.value = h.value; + + net.back().attribute.push_back(a); + + return false; +} + +/* + * Add a polygon to the current net + */ + +void HypFile::Hyp::add_polygon(Polygon poly) +{ + if (poly.vertex.empty()) return; + add_polygon_to_net(net.back(), poly); +} + +/* + * Add polygon poly to net pnet + */ + +void HypFile::Hyp::add_polygon_to_net(Net& pnet, Polygon poly) { + + /* set net name of polygon to net */ + poly.net_name = pnet.net_name; + + /* The polygon id is a positive number if the polygon has been assigned a polygon id. + * If the polygon has not been assigned a polygon id, the id is -1. + * An polygon which has not been assigned a polygon id has a single, outer edge, no holes. + * (the polygon does not have an id a POLYVOID could refer to). + */ + + if (poly.id < 0) { + /* + * If a polygon has id -1, assign the polygon an arbitrary negative id, different from -1. + * Make sure all polygons of the same net do not clash/have different ids. + */ + int new_id = 0; + if (!pnet.metal.empty()) + new_id = pnet.metal.begin()->first - 1; /* new id is one less than the smallest existing id */ + if (new_id >= -1) new_id = -2; /* does not clash with an assigned id (positive) or the default (-1) */ + poly.id = new_id; + } + + /* check if polygons with this id already exist */ + PolygonMap::iterator i = pnet.metal.find(poly.id); + if (i == pnet.metal.end()) { + PolygonList empty_list; + pnet.metal[poly.id] = empty_list; + } + + /* add polygon to net */ + pnet.metal[poly.id].push_back(poly); + + return; +} + +/* + * Add a pad at coordinates (x, y) + */ + +void HypFile::Hyp::add_pad(double pad_x, double pad_y, Pad pad) +{ + /* convert to polygon */ + Polygon pad_poly = pad2poly(pad_x, pad_y, pad); + + /* add pad to copper */ + add_polygon(pad_poly); + + return; +} + +/* + * Add via to list of via holes + */ + +void HypFile::Hyp::add_via(double x, double y, std::string layer0_name, std::string layer1_name, double radius) +{ + if (radius != 0.0) { + + /* lookup drill vertical begin and end */ + double z0 = stackup.back().z0; /* defaults to bottom */ + double z1 = stackup.front().z1; /* defaults to top */ + + for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l) + if (layer0_name == l->layer_name) { + z0 = l->z0; + z1 = l->z1; + } + + for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l) + if (layer1_name == l->layer_name) { + if (l->z1 > z1) z1 = l->z1; + if (l->z0 < z0) z0 = l->z0; + } + + Via v; + v.x = x; + v.y = y; + v.layer0_name = layer0_name; + v.layer1_name = layer1_name; + v.z0 = z0; + v.z1 = z1; + v.radius = radius; + net.back().via.push_back(v); + } + + return; +} + +/* not truncated */ diff --git a/hyp2mat/lib/exec_netclass.cc b/hyp2mat/lib/exec_netclass.cc new file mode 100644 index 0000000..9e592c0 --- /dev/null +++ b/hyp2mat/lib/exec_netclass.cc @@ -0,0 +1,76 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include "hypfile.h" + +using namespace std; +using namespace HypFile; + +/* + * Hyperlynx 'NET_CLASS' record. + * Defines a class of nets. + */ + +bool HypFile::Hyp::exec_net_class(parse_param& h) +{ + if (trace_hyp) cerr << "net_class: net_class_name = " << h.net_class_name << endl; + + NetClass nc; + nc.net_class_name = h.net_class_name; + net_class.push_back(nc); + + return false; +} + +/* + * Hyperlynx 'A' attribute subrecord of 'NET_CLASS' record. + * Defines net class attributes as name/value pairs. + */ + +bool HypFile::Hyp::exec_net_class_attribute(parse_param& h) +{ + if (trace_hyp) cerr << "netclass_attribute: name = " << h.name << " value = " << h.value << endl; + + Attribute a; + a.name = h.name; + a.value = h.value; + + net_class.back().attribute.push_back(a); + + return false; +} + +/* + * Hyperlynx 'N' subrecord of 'NET_CLASS' record. + * Defines membership of a net class. + */ + +bool HypFile::Hyp::exec_net_class_element(parse_param& h) +{ + if (trace_hyp) cerr << "net_class_element: net_name = " << h.net_name << endl; + + if (!net_class.empty()) + net_class.back().net_class_element.push_back(h.net_name); + + return false; +} + +/* not truncated */ diff --git a/hyp2mat/lib/exec_padstack.cc b/hyp2mat/lib/exec_padstack.cc new file mode 100644 index 0000000..0c2435e --- /dev/null +++ b/hyp2mat/lib/exec_padstack.cc @@ -0,0 +1,269 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include "hypfile.h" + +using namespace std; +using namespace HypFile; + +/* + * Hyperlynx 'PADSTACK' record. + * Defines a padstack. + */ + +/* + * Hyperlynx padstack-element subrecord of 'PADSTACK' record. + * Defines an individual pad in a padstack. + */ + +bool HypFile::Hyp::exec_padstack_element(parse_param& h) +{ + if (trace_hyp) { + cerr << "padstack_element:"; + if (h.padstack_name_set) cerr << " padstack_name = " << h.padstack_name; + if (h.drill_size_set) cerr << " drill_size = " << h.drill_size; + cerr << " layer_name = " << h.layer_name; + cerr << " pad_shape = " << h.pad_shape; + cerr << " pad_sx = " << h.pad_sx; + cerr << " pad_sy = " << h.pad_sy; + cerr << " pad_angle = " << h.pad_angle; + if (h.pad_type_set & (h.pad_type == PAD_TYPE_THERMAL_RELIEF)) { + cerr << " thermal_clear_shape = " << h.thermal_clear_shape; + cerr << " thermal_clear_sx = " << h.thermal_clear_sx; + cerr << " thermal_clear_sy = " << h.thermal_clear_sy; + cerr << " thermal_clear_angle = " << h.thermal_clear_angle; + } + if (h.pad_type_set) cerr << " pad_type = " << h.pad_type; + cerr << endl; + } + + h.drill_size *= unit; + h.pad_sx *= unit; + h.pad_sy *= unit; + h.thermal_clear_sx *= unit; + h.thermal_clear_sy *= unit; + + /* new padstack */ + if (h.padstack_name_set) { + Padstack pdstack; + pdstack.padstack_name = h.padstack_name; + if (h.drill_size_set) + pdstack.drill_size = h.drill_size; + else + pdstack.drill_size = 0; + + /* add new padstack to list of padstacks */ + padstack.push_back(pdstack); + } + + /* new pad */ + Pad p; + + p.layer_name = h.layer_name; + + /* pad type */ + if (h.pad_type_set) p.pad_type = h.pad_type; + else if (p.layer_name == "ADEF") p.pad_type = PAD_TYPE_ANTIPAD; + else p.pad_type = PAD_TYPE_METAL; + + if (h.pad_shape == 0) + p.pad_shape = PAD_SHAPE_OVAL; + else if (h.pad_shape == 1) + p.pad_shape = PAD_SHAPE_RECTANGULAR; + else if (h.pad_shape == 2) + p.pad_shape = PAD_SHAPE_OBLONG; + else if (h.pad_shape == -1) + p.pad_shape = PAD_SHAPE_OVAL; /* workaround for Altium bug */ + else { + error("unknown pad shape"); + return true; + } + + p.pad_sx = h.pad_sx; + p.pad_sy = h.pad_sy; + p.pad_angle = h.pad_angle; + + if (p.pad_type == PAD_TYPE_THERMAL_RELIEF) { + if (h.thermal_clear_shape == 0) + p.thermal_clear_shape = PAD_SHAPE_OVAL; + else if (h.thermal_clear_shape == 1) + p.thermal_clear_shape = PAD_SHAPE_RECTANGULAR; + else if (h.thermal_clear_shape == 2) + p.thermal_clear_shape = PAD_SHAPE_OBLONG; + else { + error("unknown thermal clear shape"); + return true; + } + + p.thermal_clear_sx = h.thermal_clear_sx; + p.thermal_clear_sy = h.thermal_clear_sy; + p.thermal_clear_angle = h.thermal_clear_angle; + } + else { + p.thermal_clear_shape = PAD_SHAPE_OVAL; + p.thermal_clear_sx = 0; + p.thermal_clear_sy = 0; + p.thermal_clear_angle = 0; + } + + /* add new pad to list of pads of current padstack */ + padstack.back().pads.push_back(p); + + return false; +} + +/* + * Note: + * MDEF and ADEF layer names have special meaning. + * MDEF specified the default pad for signal or plane layers. + * If a signal or plane layer has no metal pad, and an MDEF default pad is specified, the MDEF pad is applied to the layer. + * ADEF specifies the default anti-pad (non-conducting hole in the copper) for plane layers. + * If a plane layer has no anti-pad, and an ADEF default pad is specified, the ADEF pad is applied to the layer. + */ + +bool HypFile::Hyp::exec_padstack_end(parse_param& h) +{ + if (trace_hyp) { + cerr << "padstack_end:"; + cerr << endl; + }; + + PadList new_pads; + + /* + * Loop through stackup. + * Calculate new padstack, where all MDEF and ADEF pads have been expanded into one or more metal layers. + */ + + for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l) { + /* Loop through pad list */ + bool layer_has_pad = false; + bool layer_has_antipad = false; + for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p) { + if (l->layer_name == p->layer_name) { + new_pads.push_back(*p); + layer_has_pad = layer_has_pad || (p->pad_type == PAD_TYPE_METAL); + layer_has_antipad = layer_has_antipad || (p->pad_type == PAD_TYPE_ANTIPAD); + } + } + + /* If a plane layer has no antipad, add ADEF pad if specified */ + if (!layer_has_antipad && (l->layer_type == LAYER_PLANE)) + for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p) + if (p->layer_name == "ADEF") { + Pad new_pad = *p; + new_pad.layer_name = l->layer_name; /* change ADEF into current layer name */ + new_pads.push_back(new_pad); + } + + /* If a signal or plane layer has no pad, add MDEF pad if specified */ + if (!layer_has_pad && ((l->layer_type == LAYER_SIGNAL) || (l->layer_type == LAYER_PLANE)) ) + for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p) + if (p->layer_name == "MDEF") { + Pad new_pad = *p; + new_pad.layer_name = l->layer_name; /* change MDEF into current layer name */ + new_pads.push_back(new_pad); + layer_has_pad = true; + } + + /* + * Determine begin and end layers of via + */ + + /* via is from top to bottom if at least one pad is metal MDEF */ + bool is_through_hole_via = false; + for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p) + if ((p->layer_name == "MDEF") && (p->pad_type == PAD_TYPE_METAL)) is_through_hole_via = true; + + /* determine via top and bottom layers */ + std::string pad_top_layer; + std::string pad_bottom_layer; + + if (is_through_hole_via) { + pad_top_layer = stackup.front().layer_name; /* via begins at top layer */ + pad_bottom_layer = stackup.back().layer_name; /* via ends at bottom layer */ + } + else { + /* via begins at highest layer with metal pad, and ends at lowest layer with a metal pad */ + bool layer_found = false; + for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l) + for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p) + if ((l->layer_name == p->layer_name) && (p->pad_type == PAD_TYPE_METAL)) { + if (!layer_found) { + pad_top_layer = l->layer_name; + layer_found = true; + } + pad_bottom_layer = l->layer_name; + }; + + if (!layer_found) std::cerr << "warning: padstack without metal:" << h.padstack_name << std::endl; + + } + + /* + * Fill in missing via pads + */ + + // XXX Fixme + // XXX Check if loops need to begin at pad_top_layer / end at pad_bottom_layer + // XXX Check if pad_top_layer / pad_bottom_layer need visibility + // XXX Check if need mechanism to remove pads? + + /* If a signal or plane layer has no pad, and no MDEF pad, copy an existing pad */ + bool is_through_hole_pad = is_through_hole_via && (padstack.back().drill_size > 0); + if (!layer_has_pad && is_through_hole_pad && ((l->layer_type == LAYER_SIGNAL) || (l->layer_type == LAYER_PLANE)) ) { + Pad new_pad; + bool pad_found = false; + for (PadList::iterator p = padstack.back().pads.begin(); p != padstack.back().pads.end(); ++p) { + if (p->pad_type != PAD_TYPE_METAL) continue; + if (!pad_found) { + /* if all padstack pads are equal, create a pad on this layer which is like the others */ + new_pad = *p; + new_pad.layer_name = l->layer_name; + pad_found = true; + } + else if ((p->pad_shape != new_pad.pad_shape) || (p->pad_sx != new_pad.pad_sx) || (p->pad_sy != new_pad.pad_sy) || (p->pad_angle != new_pad.pad_angle)) { + /* if padstack pads are different, create a circular pad with a diameter equal to the smallest pad dimension */ + double radius = new_pad.pad_sx; + if (radius > new_pad.pad_sy) radius = new_pad.pad_sy; + if (radius > p->pad_sx) radius = p->pad_sx; + if (radius > p->pad_sy) radius = p->pad_sy; + new_pad.pad_shape = PAD_SHAPE_OVAL; + new_pad.pad_sx = radius; + new_pad.pad_sy = radius; + new_pad.pad_angle = 0; + } + } + /* add newly created pad to padstack */ + if (pad_found) new_pads.push_back(new_pad); + } + + } + + /* put new padstack in place. */ + + padstack.back().pads = new_pads; + + return false; + +} + +/* not truncated */ diff --git a/hyp2mat/lib/exec_polygon.cc b/hyp2mat/lib/exec_polygon.cc new file mode 100644 index 0000000..88e8be2 --- /dev/null +++ b/hyp2mat/lib/exec_polygon.cc @@ -0,0 +1,275 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include "hypfile.h" + +using namespace std; +using namespace HypFile; + +/* + * Hyperlynx 'POLYGON' subrecord of 'NET' record. + * Draws polygonal metal area. + */ + +bool HypFile::Hyp::exec_polygon_begin(parse_param& h) +{ + if (trace_hyp) { + cerr << "polygon begin:"; + if (h.layer_name_set) cerr << " layer_name = " << h.layer_name; + if (h.width_set) cerr << " width = " << h.width; + if (h.polygon_type_set) { + cerr << " polygon_type = " << h.polygon_type << " "; + switch (h.polygon_type) { + case POLYGON_TYPE_PLANE: cerr << "POLYGON_TYPE_PLANE"; break; + case POLYGON_TYPE_POUR: cerr << "POLYGON_TYPE_POUR"; break; + case POLYGON_TYPE_COPPER: cerr << "POLYGON_TYPE_COPPER"; break; + default: cerr << "Error"; break; + } + } + if (h.id_set) cerr << " id = " << h.id; + cerr << " x = " << h.x << " y = " << h.y << endl; + } + + if (!h.layer_name_set) { + error("expected polygon layer L = "); + return true; + } + + if (!h.width_set) h.width = 0; + + if (!h.polygon_type_set) h.polygon_type = POLYGON_TYPE_PLANE; + + if (!h.id_set) { + error("expected polygon id ID = "); + return true; + } + + h.width *= unit; + h.x *= unit; + h.y *= unit; + + current_polygon.id = h.id; + current_polygon.polygon_type = h.polygon_type; + current_polygon.width = h.width; + current_polygon.positive = true; + current_polygon.layer_name = h.layer_name; + current_polygon.vertex.clear(); + current_polygon.vertex.push_back(Point(h.x, h.y)); + + return false; +} + +bool HypFile::Hyp::exec_polygon_end(parse_param& h) +{ + if (trace_hyp) cerr << "polygon end" << endl; + + add_polygon(current_polygon); + + return false; +} + +/* + * Hyperlynx 'POLYVOID' subrecord of 'NET' record. + * Creates polygonal hole in metal area. + */ + +bool HypFile::Hyp::exec_polyvoid_begin(parse_param& h) +{ + if (trace_hyp) { + cerr << "polyvoid begin:"; + if (h.id_set) cerr << " id = " << h.id; + cerr << " x = " << h.x << " y = " << h.y << endl; + } + + if (!h.id_set) { + error("expected polygon id ID = "); + return true; + } + + h.x *= unit; + h.y *= unit; + + current_polygon.id = h.id; + current_polygon.positive = false; + current_polygon.vertex.clear(); + current_polygon.vertex.push_back(Point(h.x, h.y)); + + /* inherit layer_name and width from parent */ + for (PolygonList::iterator i = net.back().metal[h.id].begin(); i != net.back().metal[h.id].end(); ++i) { + if (i->positive) { + current_polygon.polygon_type = i->polygon_type; + current_polygon.width = i->width; + current_polygon.layer_name = i->layer_name; + return false; + } + } + + /* no positive polygon/polyline found with same id */ + error("polyvoid does not have parent polygon or polyline with same id"); + return true; +} + +bool HypFile::Hyp::exec_polyvoid_end(parse_param& h) +{ + if (trace_hyp) cerr << "polyvoid end" << endl; + + add_polygon(current_polygon); + + return false; +} + +/* + * Hyperlynx 'POLYLINE' subrecord of 'NET' record. + * Draws metal trace. + */ + +bool HypFile::Hyp::exec_polyline_begin(parse_param& h) +{ + if (trace_hyp) { + cerr << "polyline begin:"; + if (h.layer_name_set) cerr << " layer_name = " << h.layer_name; + if (h.width_set) cerr << " width = " << h.width; + if (h.polygon_type_set) { + cerr << " polygon_type = " << h.polygon_type << " "; + switch (h.polygon_type) { + case POLYGON_TYPE_PLANE: cerr << "POLYGON_TYPE_PLANE"; break; + case POLYGON_TYPE_POUR: cerr << "POLYGON_TYPE_POUR"; break; + case POLYGON_TYPE_COPPER: cerr << "POLYGON_TYPE_COPPER"; break; + default: cerr << "Error"; break; + } + } + if (h.id_set) cerr << " id = " << h.id; + cerr << " x = " << h.x << " y = " << h.y << endl; + } + + if (!h.layer_name_set) { + error("expected polygon layer L = "); + return true; + } + + if (!h.width_set) { + error("expected polygon width W = "); + return true; + } + + if (!h.polygon_type_set) h.polygon_type = POLYGON_TYPE_PLANE; + + if (!h.id_set) { + error("expected polygon id ID = "); + return true; + } + + h.width *= unit; + h.x *= unit; + h.y *= unit; + + current_polygon.id = h.id; + current_polygon.polygon_type = h.polygon_type; + current_polygon.width = h.width; + current_polygon.positive = true; + current_polygon.layer_name = h.layer_name; + current_polygon.vertex.clear(); + current_polygon.vertex.push_back(Point(h.x, h.y)); + + return false; +} + +bool HypFile::Hyp::exec_polyline_end(parse_param& h) +{ + if (trace_hyp) cerr << "polyline end" << endl; + + // Draw polyline as sequence of line segments + for (PointList::iterator i = current_polygon.vertex.begin(); (i != current_polygon.vertex.end()) && (i != --current_polygon.vertex.end()); ++i) { + Polygon line_segment; + PointList::iterator j = i + 1; + line_segment = segment2poly(i->x, i->y, j->x, j->y, current_polygon.width); + line_segment.id = current_polygon.id; + line_segment.polygon_type = current_polygon.polygon_type; + line_segment.positive = true; + line_segment.layer_name = current_polygon.layer_name; + line_segment.width = 0; + add_polygon(line_segment); + } + + return false; +} + +/* + * Hyperlynx 'LINE' subrecord of 'NET' record. + * Draws straight metal trace. + */ + +bool HypFile::Hyp::exec_line(parse_param& h) +{ + if (trace_hyp) cerr << "line: x = " << h.x << " y = " << h.y << endl; + + h.x *= unit; + h.y *= unit; + + /* add point to current polygon */ + current_polygon.vertex.push_back(Point(h.x, h.y)); + + return false; +} + +/* + * Hyperlynx 'CURVE' subrecord of 'NET' record. + * Draws curved metal trace. + */ + +bool HypFile::Hyp::exec_curve(parse_param& h) +{ + if (trace_hyp) { + cerr << "curve: x1 = " << h.x1 << " y1 = " << h.y1 << " x2 = " << h.x2 << " y2 = " << h.y2; + cerr << " xc = " << h.xc << " yc = " << h.yc << " r = " << h.r << endl; + } + + h.x1 *= unit; + h.y1 *= unit; + h.x2 *= unit; + h.y2 *= unit; + h.xc *= unit; + h.yc *= unit; + h.r *= unit; + h.width *= unit; + + /* calculate arc */ + /* 'CURVE' draws arc counterclockwise */ + Polygon arc = arc2poly(h.x1, h.y1, h.x2, h.y2, h.xc, h.yc, h.r, false); + + /* calculate distance between polygon end vertex and arc begin and arc end */ + double endvertex_x = current_polygon.vertex.back().x; + double endvertex_y = current_polygon.vertex.back().y; + double dist1 = (endvertex_x - h.x1) * (endvertex_x - h.x1) + (endvertex_y - h.y1) * (endvertex_y - h.y1); + double dist2 = (endvertex_x - h.x2) * (endvertex_x - h.x2) + (endvertex_y - h.y2) * (endvertex_y - h.y2); + + /* add arc to current polygon. begin with point closest to end vertex. */ + if (dist1 <= dist2) + /* add arc from (x1, y1) to (x2, y2) */ + current_polygon.vertex.insert(current_polygon.vertex.end(), arc.vertex.begin(), arc.vertex.end()); + else + /* add arc from (x2, y2) to (x1, y1) */ + current_polygon.vertex.insert(current_polygon.vertex.end(), arc.vertex.rbegin(), arc.vertex.rend()); + + return false; +} + +/* not truncated */ diff --git a/hyp2mat/lib/exec_stackup.cc b/hyp2mat/lib/exec_stackup.cc new file mode 100644 index 0000000..5680cd5 --- /dev/null +++ b/hyp2mat/lib/exec_stackup.cc @@ -0,0 +1,446 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include +#include +#include "hypfile.h" + +using namespace std; +using namespace HypFile; + +/* + * Hyperlynx 'STACKUP' record. + * Defines pcb layers. + */ + +/* + * Hyperlynx 'OPTIONS' subrecord of STACKUP record. + * Defines dielectric constant and loss tangent of metal layers. + */ + +bool HypFile::Hyp::exec_options(parse_param& h) +{ + if (trace_hyp) cerr << "options: use_die_for_metal = " << h.use_die_for_metal << endl; + use_die_for_metal = h.use_die_for_metal; + + return false; +} + +/* + * Hyperlynx 'SIGNAL' subrecord of 'STACKUP' record. + * Defines a pcb signal layer. + */ + +bool HypFile::Hyp::exec_signal(parse_param& h) +{ + if (trace_hyp) + cerr << "signal:"; + trace_layer(h); + + add_metal_layer(h); + + /* + *The difference between signal and plane layers is + * - signal layers are drawn positive, plane layers are drawn negative + * - signal layers need a name + */ + + stackup.back().layer_type = LAYER_SIGNAL; + + if (!h.layer_name_set) + error("missing signal layer name" ); + + calc_layer_position(); + calc_layer_epsilon(); + + return false; +} + +/* + * Hyperlynx 'DIELECTRIC' subrecord of 'STACKUP' record. + * Defines a pcb dielectric layer. + */ + +bool HypFile::Hyp::exec_dielectric(parse_param& h) +{ + if (trace_hyp) + cerr << "dielectric:"; + trace_layer(h); + + add_dielectric_layer(h); + + calc_layer_position(); + calc_layer_epsilon(); + + return false; +} + +/* + * Hyperlynx 'PLANE' subrecord of 'STACKUP' record. + * Defines a pcb power or signal plane. + */ + +bool HypFile::Hyp::exec_plane(parse_param& h) +{ + if (trace_hyp) + cerr << "plane:"; + trace_layer(h); + + add_metal_layer(h); + + stackup.back().layer_type = LAYER_PLANE; + + calc_layer_position(); + calc_layer_epsilon(); + + return false; +} + +/* + * Debug output for layers + */ + +bool HypFile::Hyp::trace_layer(parse_param& h) +{ + if (trace_hyp) { + if (h.thickness_set) cerr << " thickness = " << h.thickness; + if (h.plating_thickness_set) cerr << " plating_thickness = " << h.plating_thickness; + if (h.bulk_resistivity_set) cerr << " bulk_resistivity = " << h.bulk_resistivity; + if (h.temperature_coefficient_set) cerr << " temperature_coefficient = " << h.temperature_coefficient; + if (h.epsilon_r_set) cerr << " epsilon_r = " << h.epsilon_r; + if (h.loss_tangent_set) cerr << " loss_tangent = " << h.loss_tangent; + if (h.conformal_set) cerr << " conformal = " << h.conformal; + if (h.prepreg_set) cerr << " prepreg = " << h.prepreg; + if (h.layer_name_set) cerr << " layer_name = " << h.layer_name; + if (h.material_name_set) cerr << " material_name = " << h.material_name; + if (h.plane_separation_set) cerr << " plane_separation = " << h.plane_separation; + cerr << endl; + } + + return true; +} + +/* + * Add a signal or plane layer. + */ + +bool HypFile::Hyp::add_metal_layer(parse_param& h) +{ + Layer l; + + l.layer_type = LAYER_SIGNAL; + + if (h.thickness_set) + l.thickness = h.thickness * metal_thickness_unit; + else { + error ("thickness missing"); + return true; + } + + if (h.plating_thickness_set) + l.plating_thickness = h.plating_thickness * metal_thickness_unit; + else + l.plating_thickness = 0; + + if (h.bulk_resistivity_set) + l.bulk_resistivity = h.bulk_resistivity; + else + l.bulk_resistivity = copper_bulk_resistivity; + + if (h.temperature_coefficient_set) + l.temperature_coefficient = h.temperature_coefficient; + else + l.temperature_coefficient = copper_temperature_coefficient; + + if (h.conformal_set) { + error("only dielectric layers conformal"); + return true; + } + else + l.conformal = false; + + if (h.epsilon_r_set) + l.epsilon_r = h.epsilon_r; + else + l.epsilon_r = fr4_epsilon_r; + + if (h.loss_tangent_set) + l.loss_tangent = h.loss_tangent; + else + l.loss_tangent = fr4_loss_tangent; + + // use use_die_for_metal ? XXX + + if (h.prepreg_set) { + error("only dielectric layers prepreg"); + return true; + } + else + l.prepreg = false; + + if (h.layer_name_set) + l.layer_name = h.layer_name; + else { + error("missing signal layer name" ); + l.layer_name = ""; // Continue anyhow + } + + if (h.material_name_set) + l.material_name = h.material_name; + else + l.material_name = ""; + + if (h.plane_separation_set) + l.plane_separation = h.plane_separation * unit; + else + l.plane_separation = board.plane_separation; + + // Add layer to stackup + stackup.push_back(l); + + return false; +} + +/* + * add a substrate layer + */ + +bool HypFile::Hyp::add_dielectric_layer(parse_param& h) +{ + + Layer l; + + l.layer_type = LAYER_DIELECTRIC; + + if (h.thickness_set) + l.thickness = h.thickness * unit; + else { + error ("thickness missing"); + return true; + } + + if (h.plating_thickness_set) { + error ("dielectric has no plating thickness"); + return true; + } + else + l.plating_thickness = 0; + + if (h.bulk_resistivity_set) { + error ("dielectric has no bulk resistivity"); + return true; + } + else + l.bulk_resistivity = 0; + + if (h.temperature_coefficient_set) { + error ("dielectric has no bulk resistivity temperature coefficient"); + return true; + } + else + l.temperature_coefficient = 0; + + if (h.conformal_set) + l.conformal = h.conformal; + else + l.conformal = false; + + if (h.epsilon_r_set) + l.epsilon_r = h.epsilon_r; + else if (l.conformal) + l.epsilon_r = conformal_epsilon_r; + else + l.epsilon_r = fr4_epsilon_r; + + if (h.loss_tangent_set) + l.loss_tangent = h.loss_tangent; + else + l.loss_tangent = fr4_loss_tangent; + + if (h.prepreg_set) + l.prepreg = h.prepreg; + else + l.prepreg = true; + + if (h.layer_name_set) + l.layer_name = h.layer_name; + else + l.layer_name = ""; + + if (h.material_name_set) + l.material_name = h.material_name; + else + l.material_name = ""; + + if (h.plane_separation_set) { + error ("dielectric has no plane separation"); + return true; + } + else + l.plane_separation = 0; + + // Add layer to stackup + stackup.push_back(l); + + return false; +} + + /* + * Recalculate vertical position of all layers. + * Layers are ordered top first, bottom last. + * Called when a new layer is added. + */ + +bool HypFile::Hyp::calc_layer_position() +{ + // calculate vertical position, from bottom to top + double z_top = 0; // current vertical position + for (LayerList::reverse_iterator it = stackup.rbegin(); it != stackup.rend(); ++it) { + if (it->layer_type == LAYER_DIELECTRIC) { + /* substrate and prepreg */ + it->z0 = z_top; + it->z1 = z_top + it->thickness; + z_top = it->z1; + } + else { + /* metal layers */ + it->z0 = z_top; + it->z1 = z_top; + } + } + + return true; +} + +bool HypFile::Hyp::calc_layer_epsilon() +{ + + /* no calculation needed if dielectric constant have been specified */ + if (use_die_for_metal) + return true; + + /* calculate dielectric constants */ + for (LayerList::iterator i = stackup.begin(); i != stackup.end(); ++i) { + + /* skip dielectric layers */ + if (i->layer_type == LAYER_DIELECTRIC) + continue; + + /* find first dielectric layer above current metal layer */ + bool upper_layer_found = false; + LayerList::iterator upper_layer; + for (LayerList::iterator j = stackup.begin(); j != i; ++j) + if (j->layer_type == LAYER_DIELECTRIC) { + upper_layer_found = true; + upper_layer = j; + }; + + /* find first dielectric layer below current metal layer */ + bool lower_layer_found = false; + LayerList::iterator lower_layer; + for (LayerList::iterator j = i; j != stackup.end(); ++j) + if (j->layer_type == LAYER_DIELECTRIC) { + lower_layer_found = true; + lower_layer = j; + break; + }; + + if (!upper_layer_found || !lower_layer_found) { + /* assume outer copper layers are in air */ + i->epsilon_r = 1.0; + i->loss_tangent = 0.0; + } + else if (upper_layer->prepreg && !lower_layer->prepreg) { + /* upper layer is prepreg. use values of upper layer */ + i->epsilon_r = upper_layer->epsilon_r; + i->loss_tangent = upper_layer->loss_tangent; + } + else if (!upper_layer->prepreg && lower_layer->prepreg) { + /* lower layer is prepreg. use values of lower layer */ + i->epsilon_r = lower_layer->epsilon_r; + i->loss_tangent = lower_layer->loss_tangent; + } + else { + /* use average of upper and lower layer */ + i->epsilon_r = (upper_layer->epsilon_r + lower_layer->epsilon_r)/2; + i->loss_tangent = (upper_layer->loss_tangent + lower_layer->loss_tangent) /2; + } + } + + return false; +} + +/* + * Flood specified layers with copper + */ + +void HypFile::Hyp::flood_layers_with_copper() +{ + + /* check if we have to flood all plane layers */ + bool flood_plane_layers = std::find(flood_layers.begin(), flood_layers.end(), "plane_layers") != flood_layers.end(); /* look for special value "plane_layers" */ + + for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l) { + + /* metallic layers only */ + if (l->layer_type == LAYER_DIELECTRIC) continue; + + /* check if we have to flood this layer */ + bool flood_this_layer = std::find(flood_layers.begin(), flood_layers.end(), l->layer_name) != flood_layers.end(); + + /* flood with copper if we have to flood this layer, or if this is a plane layer and we have to flood all plane layers */ + if (!(flood_this_layer || (flood_plane_layers && (l->layer_type == LAYER_PLANE)))) continue; + + /* create default copper on plane layer */ + Polygon default_copper; + default_copper.vertex = board.edge.front().vertex; /* polygon is board outline */ + default_copper.polygon_type = POLYGON_TYPE_PLANE; + default_copper.net_name = l->layer_name; /* flood layer VCC with copper belonging to net VCC, layer GND with copper belonging to net GND */ + default_copper.id = -1; + default_copper.positive = true; + default_copper.width = 0.0; + default_copper.plane_separation = -1.0; + default_copper.left_plane_separation = -1.0; + default_copper.layer_name = l->layer_name; + + /* Look up net with same name as layer */ + NetList::iterator n; + for (n = net.begin(); n != net.end(); ++n) + if (n->net_name == l->layer_name) { + add_polygon_to_net(*n, default_copper); + break; + } + + /* Net with same name as layer not found. Create net */ + if (n == net.end()) { + Net plane_net; + plane_net.net_name = l->layer_name; + plane_net.plane_separation = -1.0; + net.push_back(plane_net); + add_polygon_to_net(net.back(), default_copper); + } + + } + + return; +} + +/* not truncated */ diff --git a/hyp2mat/lib/exec_supplies.cc b/hyp2mat/lib/exec_supplies.cc new file mode 100644 index 0000000..d010516 --- /dev/null +++ b/hyp2mat/lib/exec_supplies.cc @@ -0,0 +1,57 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include "hypfile.h" + +using namespace std; +using namespace HypFile; + +/* + * Hyperlynx 'S' subrecord of 'SUPPLIES' record. + * Specifies a power supply net. + */ + +bool HypFile::Hyp::exec_supplies(parse_param& h) +{ + if (trace_hyp) { + cerr << "supplies: name = " << h.name; + cerr << " value_float = " << h.value_float; + cerr << " voltage_specified = " << h.voltage_specified; + cerr << " conversion = " << h.conversion; + cerr << endl; + } + + Supply s; + + s.name = h.name; + + s.value_float = h.value_float; + + s.voltage_specified = h.voltage_specified; + + s.conversion = h.conversion; + + supply.push_back(s); + + return false; +} + +/* not truncated */ diff --git a/hyp2mat/lib/hyp2mat.h b/hyp2mat/lib/hyp2mat.h new file mode 100644 index 0000000..94a095e --- /dev/null +++ b/hyp2mat/lib/hyp2mat.h @@ -0,0 +1,224 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +/* + Class PCB defines a generic pcb board as a stack of dielectric and copper. + The class is intended as the greatest common denominator of formats. + The board outline is defined as a polygon, possibly with polygonal holes. + For each layer, the copper is defined as a list of polygons, each polygon possibly with polygonal holes. + Vias provide connections between the different copper layers. + All dimensions are in meter. + + The following methods are defined: + ReadHyperLynx reads a hyperlynx file. + WritePDF prints a PCB to a pdf file. + WriteCSXCAD converts a PCB to an OpenEMS matlab script. + + */ + + +#ifndef PCB_H +#define PCB_H + +#include +#include + +namespace Hyp2Mat { + + std::string version(); + + /* polygon types */ + + struct FloatPoint { + double x; + double y; + FloatPoint(double x_val = 0, double y_val = 0): x(x_val), y(y_val) {}; + bool operator==(const FloatPoint &right) const { return ((x == right.x) && ( y == right.y)); }; + bool operator!=(const FloatPoint &right) const { return ((x != right.x) || ( y != right.y)); }; + }; + + typedef std::vector FloatPolygon; + + struct FloatPoly { + FloatPolygon poly; + bool is_hole; + int nesting_level; /* hole within polygon within hole within ... */ + }; + + typedef std::vector FloatPolygons; + + /* + * a pin has a reference and an outline + */ + + class Pin { + public: + Pin(); + std::string ref; /* reference, e.g. U1.1 */ + double x; /* pad center coordinates */ + double y; + double z0; /* bottom of copper layer */ + double z1; /* top of copper layer */ + std::string layer_name; + FloatPolygon metal; /* pad outline */ + }; + + typedef std::vector PinList; + + /* + * Layers + */ + + enum layer_enum { LAYER_SIGNAL, LAYER_DIELECTRIC, LAYER_PLANE }; + + class Layer { + public: + std::string layer_name; /* informational only */ + std::string material_name; /* informational only */ + layer_enum layer_type; + FloatPolygons metal; + double thickness; /* layer thickness */ + double z0; /* vertical position of bottom of layer */ + double z1; /* vertical position of top of layer */ + /* dielectric */ + double epsilon_r; + double loss_tangent; + /* copper on signal and plane layers */ + double bulk_resistivity; + double resistivity_temp_coeff; /* temperature coefficient of resistivity */ + }; + + typedef std::vector LayerList; + + /* + * a via is a cylindrical, conductive hole. + */ + + class Via { + public: + double x; + double y; + double z0; /* bottom */ + double z1; /* top */ + double radius; + }; + + typedef std::vector ViaList; + + /* + * Devices + */ + + enum device_value_enum { DEVICE_VALUE_FLOAT, DEVICE_VALUE_STRING, DEVICE_VALUE_NONE }; + + class Device { + public: + Device(); + std::string name; + std::string ref; /* reference, e.g. R1, C2, L3, IC4 */ + device_value_enum value_type; /* whether to use value_float or value_string */ + double value_float; /* in ohms, farad, henry */ + std::string value_string; + std::string layer_name; + }; + + typedef std::vector DeviceList; + + /* board dimensions */ + class Bounds { + public: + Bounds(); + double x_min; + double x_max; + double y_min; + double y_max; + double z_min; + double z_max; + }; + + /* + * class PCB represents a pcb board. + */ + + class PCB { + public: + PCB(); + FloatPolygons board; /* board outline */ + LayerList stackup; + ViaList via; + double via_plating_thickness; + DeviceList device; + PinList pin; + + /* + * ReadHyperLynx loads the Hyperlynx file "filename". + * "layers" is the names of the layers to import. Default is importing all layers. + * "nets" is the names of the nets to import. Default is importing all nets. + */ + + void ReadHyperLynx(std::string filename, std::vector layers = std::vector(), std::vector nets = std::vector()); + void SetEpsilonR(double epsilon_r); /* set dielectric epsilon r. Overrides value in Hyperlynx file. */ + void SetBulkResistance(double bulk_resistivity); /* set dielectric bulk resistance. Overrides value in Hyperlynx file. */ + void SetLossTangent(double loss_tangent); /* set dielectric loss tangent. Overrides value in Hyperlynx file. */ + void SetGrid(double new_grid); /* set resolution of x and y coordinates */ + void SetArcPrecision(double new_arc_precision); /* set maximum difference between perfect circle arc and polygonal approximation */ + void SetClearance(double new_clearance); /* set trace-to-plane clearance */ + Bounds GetBounds(); /* gets board extension in x,y and z */ + void SetBounds(Bounds new_bounds); /* crops board in x,y and z */ + + void PrintSummary(); /* print layer summary */ + + /* + * WritePDF exports to the pdf file "filename". + * "hue", "saturation" and "brightness" are color options with a value between 0.0 and 1.0. + */ + + void WritePDF(std::string filename, double hue = -1, double saturation = -1, double brightness = -1); + + /* + * WriteCSXCAD exports csxcad matlab code to file "filename". + * If "pcb_outline" is true, the detailed pcb shape is exported, including pcb cutouts. + * If "pcb_outline" is false, a simple rectangular bounding box is output." + */ + + void WriteCSXCAD(std::string filename, bool pcb_outline = false, bool lossy_copper = false, bool metal_3d = false); + + unsigned int debug; /* setting debug to 0 switches debugging off */ + std::vector flood_layers; /* names of layers to be flooded with copper */ + bool raw; /* set raw processing */ + private: + void _UserOverrides(); + void _CheckBoardOutline(); + Bounds _bounds; + double _arc_precision; + double _clearance; + double _epsilon_r; + bool _epsilon_r_override; + double _bulk_resistivity; + bool _bulk_resistivity_override; + double _loss_tangent; + bool _loss_tangent_override; + }; + +} + +#endif + +/* not truncated */ diff --git a/hyp2mat/lib/hyp2mat.pc.in b/hyp2mat/lib/hyp2mat.pc.in new file mode 100644 index 0000000..8635861 --- /dev/null +++ b/hyp2mat/lib/hyp2mat.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: hyp2mat +Description: Convert Hyperlynx PCB files to matlab scripts +Requires: +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lhyp2mat +Libs.private: @LIBS@ +Cflags: -I${includedir} diff --git a/hyp2mat/lib/hyperlynx.cc b/hyp2mat/lib/hyperlynx.cc new file mode 100644 index 0000000..adaa043 --- /dev/null +++ b/hyp2mat/lib/hyperlynx.cc @@ -0,0 +1,348 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +/* + * HypFile is concerned with parsing the hyperlynx file, and contains many variables and methods + * which are only of interest during parsing. + * + * Hyp2Mat is interested in presenting an uncluttered interface. + * + * This is where data is passed on from HypFile to Hyp2Mat, from the obscure to the obvious. + */ + +#include +#include + +#include "config.h" +#include "hyperlynx.h" +#include "polygon.h" +#include "crop.h" + +HyperLynx::HyperLynx () +{ + raw = false; + arc_precision = 0; + clearance = 0.0002; +} + + +/* + * Read a pcb in hyperlynx format + */ + +void HyperLynx::Read (std::string filename, Hyp2Mat::PCB& pcb) +{ + /* + * load hyperlynx file in hyp_file + */ + + bool success = LoadHypFile(pcb, filename, arc_precision); + if (!success) throw ("load hyp file error"); + + /* + * Copy hyperlynx file data from hyp_file to pcb + */ + saved_bounds = bounds; + CopyBoard(pcb); /* copy board outline. crop board in x, y axis */ + + CopyStackUp(pcb); /* copy layer stackup */ + bounds = AdjustBounds(pcb, saved_bounds); + CopyVias(pcb); /* copy vias */ + CopyViaPlating(pcb); /* copy via plating thickness */ + CopyDevices(pcb); /* copy device info */ + CopyPins(pcb); /* copy pin references */ + + bounds = AdjustBounds(pcb, saved_bounds); + CropLayers(pcb, bounds); /* crop board in z axis */ + + if (bounds.z_min == bounds.z_max) std::cerr << "warning: zero height board" << std::endl; + + /* + * Check whether to print all net names + */ + + /* if one of the nets is "?", print list of all nets */ + if (std::find(nets.begin(), nets.end(), "?") != nets.end()) + PrintNets(); + + return; +} + +/* + * Load Hyperlynx file in hyp_file + */ + +bool HyperLynx::LoadHypFile(Hyp2Mat::PCB& pcb, std::string filename, double arc_precision) +{ + hyp_file.trace_scanner = (pcb.debug == 4); + hyp_file.trace_parser = (pcb.debug == 3); + hyp_file.trace_hyp = (pcb.debug == 2); + + if (pcb.debug != 0) { + std::cerr << "hyp2mat " << VERSION << " using ClipperLib " << CLIPPER_VERSION << std::endl; + } + + if (arc_precision < 0) { + std::cerr << "arc precision negative" << std::endl; + arc_precision = 0; + } + hyp_file.arc_precision = arc_precision; + + hyp_file.flood_layers = flood_layers; + + bool success = hyp_file.load(filename); + + if (pcb.debug == 1) { + std::cerr << "writing hyp_file dump to hyp_debug.txt" << std::endl; + hyp_file.save ("hyp_debug.txt"); + } + + return success; +} + +/* + * copy board outline into polygon "board" and crop according to "bounds". + */ + +void HyperLynx::CopyBoard(Hyp2Mat::PCB& pcb) +{ + bool outer_edge = true; + + for (HypFile::PolygonList::iterator i = hyp_file.board.edge.begin(); i != hyp_file.board.edge.end(); ++i) { + Hyp2Mat::Polygon poly; + Hyp2Mat::FloatPolygon edge; + for (HypFile::PointList::iterator j = i->vertex.begin(); j != i->vertex.end(); ++j) + edge.push_back(Hyp2Mat::FloatPoint(j->x, j->y)); + poly.AddEdge(edge); + if (outer_edge) + board.Union(poly); + else + board.Difference(poly); + outer_edge = false; + } + + /* + * Cropping - Remove board outside bounds + */ + + pcb.board = board.Result(); /* store intermediate result */ + bounds = AdjustBounds(pcb, bounds); /* tighten bounds around board */ + board = CropPolygon(board, bounds); /* crop board. store board as integer polygon */ + pcb.board = board.Result(); /* board as floating point polygon */ + + return; +} + +/* + * copy vias + */ + +void HyperLynx::CopyVias(Hyp2Mat::PCB& pcb) +{ + for (HypFile::NetList::iterator i = hyp_file.net.begin(); i != hyp_file.net.end(); ++i) { + + /* check if we're interested in this net. if no nets are specified, copy all nets */ + bool net_wanted = nets.empty() || (std::find(nets.begin(), nets.end(), i->net_name) != nets.end()); + if (!net_wanted) continue; + + /* copy vias of current net */ + for (HypFile::ViaList::iterator j = i->via.begin(); j != i->via.end(); ++j) { + Hyp2Mat::Via v; + v.x = j->x; + v.y = j->y; + v.z0 = j->z0; + v.z1 = j->z1; + v.radius = j->radius; + + /* cropping */ + if (!board.IsEmpty() && ((v.x > bounds.x_max) || (v.x < bounds.x_min) || (v.y > bounds.y_max) || (v.y < bounds.y_min))) continue; // Only crop in x and y if board outline is defined + if ((v.z0 > bounds.z_max) && (v.z1 > bounds.z_max)) continue; + if ((v.z0 < bounds.z_min) && (v.z1 < bounds.z_min)) continue; + if (v.z1 > bounds.z_max) v.z1 = bounds.z_max; + if (v.z0 < bounds.z_min) v.z0 = bounds.z_min; + + /* add to list of vias */ + pcb.via.push_back(v); + } + } + + return; +} + +/* + * copy via plating + */ + +void HyperLynx::CopyViaPlating(Hyp2Mat::PCB& pcb) +{ + /* assume via plating thickness is identical to outer plating thickness */ + for (HypFile::LayerList::iterator l = hyp_file.stackup.begin(); l != hyp_file.stackup.end(); ++l) + if (l->layer_type != HypFile::LAYER_DIELECTRIC) { + /* first metal layer */ + pcb.via_plating_thickness = l->plating_thickness; + break; + } + + return; +} + +/* + * copy devices + */ + +void HyperLynx::CopyDevices(Hyp2Mat::PCB& pcb) +{ + for (HypFile::DeviceList::iterator i = hyp_file.device.begin(); i != hyp_file.device.end(); ++i) { + /* set up device */ + Hyp2Mat::Device dev; + dev.ref = i->ref; + dev.name = i->name; + dev.layer_name = i->layer_name; + + if (i->value_float_set) { + dev.value_float = i->value_float; + dev.value_type = Hyp2Mat::DEVICE_VALUE_FLOAT; + } + else if (i->value_string_set) { + dev.value_string = i->value_string; + dev.value_type = Hyp2Mat::DEVICE_VALUE_STRING; + } + else dev.value_type = Hyp2Mat::DEVICE_VALUE_NONE; + + /* add device to board */ + pcb.device.push_back(dev); + } + return; +} + +/* + * copy pins + */ + +void HyperLynx::CopyPins(Hyp2Mat::PCB& pcb) +{ + /* iterate over all pins */ + for (HypFile::NetList::iterator i = hyp_file.net.begin(); i != hyp_file.net.end(); ++i) { + + /* check if we're interested in this net. if no nets are specified, copy all nets */ + bool net_wanted = nets.empty() || (std::find(nets.begin(), nets.end(), i->net_name) != nets.end()); + if (!net_wanted) continue; + + for (HypFile::PinList::iterator j = i->pin.begin(); j != i->pin.end(); ++j) + /* find pin padstack */ + for (HypFile::PadstackList::iterator p = hyp_file.padstack.begin(); p != hyp_file.padstack.end(); ++p) + if (p->padstack_name == j->padstack_name) + /* copy this pin */ + CopyPin(pcb, *j, *p); + } + + return; +} + +/* + * copy a single pin + */ + +void HyperLynx::CopyPin(Hyp2Mat::PCB& pcb, HypFile::Pin& pin, HypFile::Padstack& padstack) +{ + Hyp2Mat::Pin new_pin; + new_pin.x = Hyp2Mat::Polygon::AlignToGrid(pin.x); + new_pin.y = Hyp2Mat::Polygon::AlignToGrid(pin.y); + new_pin.ref = pin.pin_reference; + + HypFile::Pad pad; + + std::string layer_name; + + /* now find pad */ + + /* how many layers does the padstack have? */ + if (padstack.pads.size() == 1) { + /* only a single layer: that's easy */ + pad = padstack.pads.front(); + } + else { + /* determine pin device name */ + size_t found = pin.pin_reference.find('.'); + if ((found == std::string::npos) || (found == 0)) return; /* device not found */ + std::string device_name = pin.pin_reference.substr(0, found); + + /* find device pin belongs to */ + bool device_found = false; + for (Hyp2Mat::DeviceList::iterator i = pcb.device.begin(); i != pcb.device.end(); ++i) + if (device_name == i->ref) { + device_found = true; + layer_name = i->layer_name; /* device layer */ + } + if (!device_found) return; + + /* we now know the device layer. Find this layer in the pin padstack. */ + bool pad_found = false; + for (HypFile::PadList::iterator p = padstack.pads.begin(); p != padstack.pads.end(); ++p) + if (p->layer_name == layer_name) { + pad_found = true; + pad = *p; + } + if (!pad_found) return; + } + + /* find layer vertical position */ + for (Hyp2Mat::LayerList::iterator l = pcb.stackup.begin(); l != pcb.stackup.end(); ++l) + if (pad.layer_name == l->layer_name) { + new_pin.layer_name = l->layer_name; + new_pin.z0 = l->z0; + new_pin.z1 = l->z1; + } + + /* convert pad to polygon, and copy pad shape */ + HypFile::Polygon pad_poly = hyp_file.pad2poly(new_pin.x, new_pin.y, pad); + new_pin.metal.clear(); + for (HypFile::PointList::iterator j = pad_poly.vertex.begin(); j != pad_poly.vertex.end(); ++j) + new_pin.metal.push_back(Hyp2Mat::FloatPoint(Hyp2Mat::Polygon::AlignToGrid(j->x), Hyp2Mat::Polygon::AlignToGrid(j->y))); + + /* add pin to pcb */ + pcb.pin.push_back(new_pin); + + return; +} + +/* + * Print all available nets + */ + +void HyperLynx::PrintNets() +{ + std::vector net_names; + + for (HypFile::NetList::iterator i = hyp_file.net.begin(); i != hyp_file.net.end(); ++i) + net_names.push_back(i->net_name); + + sort(net_names.begin(), net_names.end()); + unique(net_names.begin(), net_names.end()); + + std::cout << "nets:"; + for (std::vector::iterator i = net_names.begin(); i != net_names.end(); ++i) + std::cout << " " << *i; + std::cout << std::endl; + + return; +} + +/* not truncated */ diff --git a/hyp2mat/lib/hyperlynx.h b/hyp2mat/lib/hyperlynx.h new file mode 100644 index 0000000..bfe3033 --- /dev/null +++ b/hyp2mat/lib/hyperlynx.h @@ -0,0 +1,79 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +/* + * loads a Hyperlynx file in a Hyp2Mat class + */ + +#ifndef HYPERLYNX_H +#define HYPERLYNX_H + +#include "hyp2mat.h" +#include "hypfile.h" +#include "polygon.h" + +class HyperLynx { +public: + HyperLynx(); + void Read (std::string filename, Hyp2Mat::PCB& pcb); + + /* parameters */ + std::vector layers; + std::vector nets; + bool raw; + double arc_precision; + double clearance; + std::vector flood_layers; + Hyp2Mat::Bounds bounds; + +private: + HypFile::Hyp hyp_file; + Hyp2Mat::Polygon board; /* polygon of board outline */ + Hyp2Mat::Bounds saved_bounds; /* copy of bounds */ + + double layer_plane_separation; /* plane separation for this layer */ + double net_plane_separation; /* plane separation for this net on this layer */ + double polygon_plane_separation; /* plane separation for this polygon on this net on this layer */ + + bool LoadHypFile(Hyp2Mat::PCB& pcb, std::string filename, double arc_precision); + void CopyBoard(Hyp2Mat::PCB& pcb); /* copy board outline */ + + void CopyStackUp(Hyp2Mat::PCB& pcb); /* copy all layers, both metal and dielectric */ + void CopyLayer(Hyp2Mat::PCB& pcb, HypFile::Layer& hyp_layer); /* copy a single layer */ + Hyp2Mat::Polygon CopyCopper(Hyp2Mat::Layer layer, Hyp2Mat::FloatPolygons& raw_polygons); /* copy all the copper of a layer */ + Hyp2Mat::Polygon CopyNet(Hyp2Mat::Layer layer, HypFile::Net& hyp_net, polygon_type_enum poly_type, Hyp2Mat::FloatPolygons& raw_polygons); /* copy a single net on a layer */ + + Hyp2Mat::Polygon CopyPolygon(HypFile::PolygonList metal, Hyp2Mat::FloatPolygons& raw_polygons); /* copy a single polygon of a net on a layer */ + Hyp2Mat::Polygon PlaneSeparation(std::string layer_name, std::string net_name); + + void CopyVias(Hyp2Mat::PCB& pcb); + void CopyViaPlating(Hyp2Mat::PCB& pcb); + + void CopyDevices(Hyp2Mat::PCB& pcb); + + void CopyPins(Hyp2Mat::PCB& pcb); /* copy all pins to pcb */ + void CopyPin(Hyp2Mat::PCB& pcb, HypFile::Pin& pin, HypFile::Padstack& padstack); /* copy a single pin to pcb */ + + void PrintNets(); + }; + +#endif + +/* not truncated */ diff --git a/hyp2mat/lib/hypfile.cc b/hyp2mat/lib/hypfile.cc new file mode 100644 index 0000000..3535719 --- /dev/null +++ b/hyp2mat/lib/hypfile.cc @@ -0,0 +1,378 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include "hypfile.h" +#include "parser.h" + +using namespace std; +using namespace HypFile; + +HypFile::Hyp::Hyp() + : trace_scanner(false), trace_parser(false), trace_hyp(false) +{ + unit = 1; + metal_thickness_unit = 1; + use_die_for_metal = false; + + min_circle_segments = 8; // 8 seems minimal, 16 seems more than sufficient. + arc_precision = 0; + pi = M_PI; + inches = 0.0254; /* inches to m */ + copper_imperial_weight = 1.341; /* metal thickness in ounces/ft2. 1 oz/ft2 copper = 1.341 mil */ + copper_metric_weight = 0.1116; /* metal thickness in grams/cm2. 1 gr/cm2 copper = 0.1116 cm */ + copper_bulk_resistivity = 1.724e-8; + copper_temperature_coefficient = 0.00393; + fr4_epsilon_r = 4.3; + fr4_loss_tangent = 0.020; + conformal_epsilon_r = 3.3; /* dielectric constant of conformal layer */ + board.plane_separation = -1.0; /* distance between PLANE polygon and copper of different nets; -1 if not set */ + +} + +/* + * parse a Hyperlynx file + */ + +bool HypFile::Hyp::load(const std::string &filename) +{ + if (trace_hyp) cerr << "parsing " << filename << endl; + + /* open input file */ + if (filename != "-") { + yyin = fopen (filename.c_str(),"r"); + if (!yyin) { + cerr << "Can't open input file " << filename << endl; + return false; + } + } + + /* parse input file */ + yy_flex_debug = trace_scanner; + yydebug = trace_parser; + int retval = yyparse(this); + + /* close input file */ + fclose(yyin); + + bool success = retval == 0; + return success; +} + +/* + * Error output + */ + +void HypFile::Hyp::error(const std::string& msg) +{ + cerr << msg << endl; +} + +/* + * Dumps internal structures for debugging. + */ + +bool HypFile::Hyp::save(const std::string& filename) +{ + /* + * Open file for output + */ + + if ((filename != "-") && (freopen(filename.c_str(), "w", stdout) == NULL)) { + std::ostringstream err_msg; + err_msg << "could not open '" << filename << "' for writing"; + error(err_msg.str()); + return true; + } + + /* + * Variables + */ + + cout << "unit = " << unit << endl; + cout << "metal_thickness_unit = " << metal_thickness_unit << endl; + cout << "use_die_for_metal = " << use_die_for_metal << endl; + cout << "min_circle_segments = " << min_circle_segments << endl; + cout << "arc_precision = " << arc_precision << endl; + cout << "pi = " << pi << endl; + cout << "inches = " << inches << endl; + cout << "copper_imperial_weight = " << copper_imperial_weight << endl; + cout << "copper_metric_weight = " << copper_metric_weight << endl; + cout << "copper_bulk_resistivity = " << copper_bulk_resistivity << endl; + cout << "copper_temperature_coefficient = " << copper_temperature_coefficient << endl; + cout << "fr4_epsilon_r = " << fr4_epsilon_r << endl; + cout << "fr4_loss_tangent = " << fr4_loss_tangent << endl; + cout << "conformal_epsilon_r = " << conformal_epsilon_r << endl; + + /* + * Export board + */ + + cout << "board" << endl; + for (PolygonList::iterator i = board.edge.begin(); i != board.edge.end(); ++i) { + cout << " polygon" << endl; + cout << " positive " << i->positive << endl; + for (PointList::iterator j = i->vertex.begin(); j != i->vertex.end(); ++j) { + cout << " x = " << j->x << endl; + cout << " y = " << j->y << endl; + } + } + + cout << " plane_separation = " << board.plane_separation << endl; + cout << " board_attribute" << endl; + for (AttributeList::iterator j = board.attribute.begin(); j != board.attribute.end(); ++j) { + cout << " name = '" << j->name << "'" << endl; + cout << " value = '" << j->value << "'" << endl; + } + + /* + * Export devices + */ + + cout << "device" << endl; + for (DeviceList::iterator dev_it = device.begin(); dev_it != device.end(); ++dev_it) { + cout << " device" << endl; + cout << " device_type = '" << dev_it->device_type << "'" << endl; + cout << " ref = '" << dev_it->ref << "'" << endl; + cout << " name = '" << dev_it->name << "'" << endl; + cout << " value_float = " << dev_it->value_float << endl; + cout << " value_float_set = " << dev_it->value_float_set << endl; + cout << " value_string = '" << dev_it->value_string << "'" << endl; + cout << " value_string_set = " << dev_it->value_string_set << endl; + cout << " layer_name = '" << dev_it->layer_name << "'" << endl; + cout << " package = '" << dev_it->package << "'" << endl; + } + + /* + * Export supplies + */ + + cout << "supplies" << endl; + for (SupplyList::iterator supp_it = supply.begin(); supp_it != supply.end(); ++supp_it) { + cout << " supply" << endl; + cout << " name = '" << supp_it->name << "'" << endl; + cout << " value_float = " << supp_it->value_float << endl; + cout << " voltage_specified = " << supp_it->voltage_specified << endl; + cout << " conversion = " << supp_it->conversion << endl; + } + + /* + * Export stackup + */ + + cout << "layers" << endl; + for (LayerList::iterator it = stackup.begin(); it != stackup.end(); ++it) { + cout << " layer" << endl; + cout << " layer_name = '" << it->layer_name << "'" << endl; + cout << " layer_type = " << it->layer_type << " "; + switch (it->layer_type) { + case LAYER_SIGNAL: cout << "LAYER_SIGNAL"; break; + case LAYER_DIELECTRIC: cout << "LAYER_DIELECTRIC"; break; + case LAYER_PLANE: cout << "LAYER_PLANE"; break; + default: cout << "Error"; break; + } + cout << endl; + + cout << " bulk_resistivity = " << it->bulk_resistivity << endl; + cout << " conformal = " << it->conformal << endl; + cout << " epsilon_r = " << it->epsilon_r << endl; + cout << " layer_name = " << it->layer_name << endl; + cout << " loss_tangent = " << it->loss_tangent << endl; + cout << " material_name = " << it->material_name << endl; + cout << " plane_separation = " << it->plane_separation << endl; + cout << " plating_thickness = " << it->plating_thickness << endl; + cout << " prepreg = " << it->prepreg << endl; + cout << " temperature_coefficient = " << it->temperature_coefficient << endl; + cout << " thickness = " << it->thickness << endl; + cout << " z0 = " << it->z0 << endl; + cout << " z1 = " << it->z1 << endl; + } + + /* + * Padstack + */ + + cout << "padstacks" << endl; + for (PadstackList::iterator it = padstack.begin(); it != padstack.end(); ++it) { + cout << " padstack" << endl; + cout << " padstack_name = '" << it->padstack_name << "'" << endl; + cout << " drill_size = " << it->drill_size << endl; + cout << " pads" << endl; + for (PadList::iterator p = it->pads.begin(); p != it->pads.end(); ++p) { + cout << " pad" << endl; + cout << " layer_name = '" << p->layer_name << "'" << endl; + cout << " pad_type = " << p->pad_type << " "; + switch (p->pad_type) { + case PAD_TYPE_METAL: cout << "PAD_TYPE_METAL"; break; + case PAD_TYPE_ANTIPAD: cout << "PAD_TYPE_ANTIPAD"; break; + case PAD_TYPE_THERMAL_RELIEF: cout << "PAD_TYPE_THERMAL_RELIEF"; break; + default: cout << "Error"; break; + } + cout << endl; + cout << " pad_shape = " << p->pad_shape << " "; + switch (p->pad_shape) { + case PAD_SHAPE_OVAL: cout << "PAD_SHAPE_OVAL"; break; + case PAD_SHAPE_RECTANGULAR: cout << "PAD_SHAPE_RECTANGULAR"; break; + case PAD_SHAPE_OBLONG: cout << "PAD_SHAPE_OBLONG"; break; + default: cout << "Error"; break; + } + cout << endl; + cout << " pad_sx = " << p->pad_sx << endl; + cout << " pad_sy = " << p->pad_sy << endl; + cout << " pad_angle = " << p->pad_angle << endl; + cout << " thermal_clear_shape = " << p->thermal_clear_shape << " "; + switch (p->thermal_clear_shape) { + case PAD_SHAPE_OVAL: cout << "PAD_SHAPE_OVAL"; break; + case PAD_SHAPE_RECTANGULAR: cout << "PAD_SHAPE_RECTANGULAR"; break; + case PAD_SHAPE_OBLONG: cout << "PAD_SHAPE_OBLONG"; break; + default: cout << "Error"; break; + } + cout << endl; + cout << " thermal_clear_sx = " << p->thermal_clear_sx << endl; + cout << " thermal_clear_sy = " << p->thermal_clear_sy << endl; + cout << " thermal_clear_angle = " << p->thermal_clear_angle << endl; + } + } + + /* + * Net + */ + + cout << "net" << endl; + for (NetList::iterator i = net.begin(); i != net.end(); ++i) { + cout << " net" << endl; + cout << " net_name = '" << i->net_name << "'" << endl; + + /* + * Net Polygons + */ + for (PolygonMap::iterator j = i->metal.begin(); j != i->metal.end(); ++j) { + cout << " polygon id " << j->first << endl; + for (PolygonList::iterator k = j->second.begin(); k != j->second.end(); ++k) { + cout << " polygon" << endl; + cout << " positive " << k->positive << endl; + cout << " width " << k->width << endl; + cout << " layer_name " << k->layer_name << endl; + for (PointList::iterator l = k->vertex.begin(); l != k->vertex.end(); ++l) { + cout << " x = " << l->x << endl; + cout << " y = " << l->y << endl; + } + } + } + + /* + * Net Vias + */ + + cout << " vias" << endl; + for (ViaList::iterator j = i->via.begin(); j != i->via.end(); ++j) { + cout << " via" << endl; + cout << " x = " << j->x << endl; + cout << " y = " << j->y << endl; + cout << " layer0_name = " << j->layer0_name << endl; + cout << " layer1_name = " << j->layer1_name << endl; + cout << " radius = " << j->radius << endl; + } + + /* + * Net Pins + */ + + cout << " pins" << endl; + for (PinList::iterator j = i->pin.begin(); j != i->pin.end(); ++j) { + cout << " pin" << endl; + cout << " x = " << j->x << endl; + cout << " y = " << j->y << endl; + cout << " pin_reference = " << j->pin_reference << endl; + cout << " padstack_name = " << j->padstack_name << endl; + cout << " pin_function = " << j->pin_function << " "; + switch (j->pin_function) { + case PIN_SIM_IN: cout << "PIN_SIM_IN"; break; + case PIN_SIM_OUT: cout << "PIN_SIM_OUT"; break; + case PIN_SIM_BOTH: cout << "PIN_SIM_BOTH"; break; + default: cout << "Error"; break; + } + cout << endl; + } + + /* + * Net Unrouted segments + */ + + cout << " unrouted_segments" << endl; + for (UnroutedSegmentList::iterator j = i->unrouted_segment.begin(); j != i->unrouted_segment.end(); ++j) { + cout << " unrouted_segment" << endl; + cout << " x1 = " << j->x1 << endl; + cout << " y1 = " << j->y1 << endl; + cout << " layer1_name = " << j->layer1_name << endl; + cout << " x2 = " << j->x2 << endl; + cout << " y2 = " << j->y2 << endl; + cout << " layer2_name = " << j->layer2_name << endl; + cout << " zlayer_name_set = " << j->zlayer_name_set << endl; + cout << " zlayer_name = " << j->zlayer_name << endl; + cout << " width = " << j->width << endl; + cout << " impedance_set = " << j->impedance_set << endl; + cout << " impedance = " << j->impedance << endl; + cout << " delay = " << j->delay << endl; + cout << " resistance = " << j->resistance << endl; + } + + /* + * Net Attributes + */ + + if (!i->attribute.empty()) cout << " attribute" << endl; + for (AttributeList::iterator j = i->attribute.begin(); j != i->attribute.end(); ++j) { + cout << " name = '" << j->name << "'" << endl; + cout << " value = '" << j->value << "'" << endl; + } + } + + /* + * Net Class + */ + + cout << "net_class" << endl; + for (NetClassList::iterator i = net_class.begin(); i != net_class.end(); ++i) { + cout << " net_class" << endl; + cout << " net_class_name = '" << i->net_class_name << "'" << endl; + cout << " net_class_element" << endl; + for (StringList::iterator j = i->net_class_element.begin(); j != i->net_class_element.end(); ++j) { + cout << " net_name = '" << *j << "'" << endl; + } + if (!i->attribute.empty()) cout << " attribute" << endl; + for (AttributeList::iterator j = i->attribute.begin(); j != i->attribute.end(); ++j) { + cout << " name = '" << j->name << "'" << endl; + cout << " value = '" << j->value << "'" << endl; + } + } + + cout << "end" << endl; + + fclose(stdout); + + return true; +} + +/* not truncated */ diff --git a/hyp2mat/lib/hypfile.h b/hyp2mat/lib/hypfile.h new file mode 100644 index 0000000..2670672 --- /dev/null +++ b/hyp2mat/lib/hypfile.h @@ -0,0 +1,333 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +/* + * Loads a hyperlynx file from disk. + */ + +#ifndef HYPFILE_H +#define HYPFILE_H + +#include +#include +#include +#include "parse_param.h" + +namespace HypFile { + + class Point { + public: + double x; + double y; + Point(double x_val = 0, double y_val = 0): x(x_val), y(y_val) {}; + bool operator==(const Point &right) const { return ((x == right.x) && ( y == right.y)); }; + }; + + typedef std::vector PointList; + + class Polygon { + public: + Polygon(); + PointList vertex; + polygon_type_enum polygon_type; + std::string net_name; + int id; + bool positive; /* false if hole */ + double width; /* edge width of polygon */ + /* if polygon_type == POLYGON_TYPE_PLANE keep plane_separation distance from other nets */ + double plane_separation; /* -1.0 if not set */ + double left_plane_separation; /* -1.0 if not set */ + std::string layer_name; + }; + + typedef std::vector PolygonList; + + struct Via { + double x; + double y; + std::string layer0_name; /* bottom */ + std::string layer1_name; /* top */ + double z0; + double z1; + double radius; + }; + + typedef std::vector ViaList; + + struct Pin { + double x; + double y; + std::string pin_reference; + std::string padstack_name; + pin_function_enum pin_function; + }; + + typedef std::vector PinList; + + struct UnroutedSegment { + double x1; + double y1; + std::string layer1_name; + double x2; + double y2; + std::string layer2_name; + bool zlayer_name_set; + std::string zlayer_name; + double width; + bool impedance_set; + double impedance; + double delay; + double resistance; + }; + + typedef std::vector UnroutedSegmentList; + + enum layer_enum { LAYER_SIGNAL, LAYER_DIELECTRIC, LAYER_PLANE }; + + struct Layer { + layer_enum layer_type; + double bulk_resistivity; + bool conformal; + double epsilon_r; + std::string layer_name; + double loss_tangent; + std::string material_name; + double plane_separation; /* trace to plane separation */ + double plating_thickness; + bool prepreg; + double temperature_coefficient; /* temperature coefficient of resistivity */ + double thickness; /* layer thickness */ + double z0; /* vertical position of bottom of layer */ + double z1; /* vertical position of top of layer */ + }; + + typedef std::vector LayerList; + + struct Device { + std::string device_type; + std::string ref; + std::string name; + double value_float; + bool value_float_set; + std::string value_string; + bool value_string_set; + std::string layer_name; + std::string package; + }; + + typedef std::vector DeviceList; + + struct Supply { + std::string name; + double value_float; + bool voltage_specified; + bool conversion; + }; + + typedef std::vector SupplyList; + + enum pad_shape_enum { PAD_SHAPE_OVAL, PAD_SHAPE_RECTANGULAR, PAD_SHAPE_OBLONG }; + + struct Pad { + std::string layer_name; + pad_type_enum pad_type; + pad_shape_enum pad_shape; + double pad_sx; + double pad_sy; + double pad_angle; + pad_shape_enum thermal_clear_shape; + double thermal_clear_sx; + double thermal_clear_sy; + double thermal_clear_angle; + }; + + typedef std::vector PadList; + + struct Padstack { + std::string padstack_name; + double drill_size; + PadList pads; + }; + + typedef std::vector PadstackList; + + struct Attribute { + std::string name; + std::string value; + }; + + typedef std::vector AttributeList; + + typedef std::vector StringList; + + struct NetClass { + std::string net_class_name; + StringList net_class_element; + AttributeList attribute; + }; + + /* PolygonByID orders polygons according to polygon id. PolygonList is a list of polygons with the same polygon id */ + + typedef std::map PolygonMap; + + struct Net { + std::string net_name; + PolygonMap metal; + double plane_separation; + ViaList via; + UnroutedSegmentList unrouted_segment; + PinList pin; + AttributeList attribute; + }; + + typedef std::vector NetList; + + struct Board { + PolygonList edge; + PolygonList segments; + AttributeList attribute; + double plane_separation; + }; + + typedef std::vector NetClassList; + + class Hyp + { + public: + Hyp(); + bool trace_scanner; // flex scanner debugging + bool trace_parser; // bison parser debugging + bool trace_hyp; // hyperlynx debugging + bool load (const std::string& filename); // load Hyperlynx file + bool save (const std::string& filename); // write to file + + void error(const std::string& m); + + Board board; + LayerList stackup; + DeviceList device; + SupplyList supply; + PadstackList padstack; + NetClassList net_class; + NetList net; + + /* Physical constants */ + double pi; + double inches; /* inches to m */ + double copper_imperial_weight; /* metal thickness in ounces/ft2 */ + double copper_metric_weight; /* metal thickness in grams/cm2 */ + double copper_bulk_resistivity; + double copper_temperature_coefficient; /* temperature coefficient of bulk resistivity */ + double fr4_epsilon_r; /* dielectric constant of substrate */ + double fr4_loss_tangent; /* loss tangent of substrate */ + double conformal_epsilon_r; /* dielectric constant of conformal coating */ + + int min_circle_segments; /* minimum number of polygon segments to draw a full circle; needs to be a multiple of 4 */ + double arc_precision; /* maximum difference between perfect circle arc and polygonal approximation */ + StringList flood_layers; /* layers to be flooded with copper */ + + /* Hyperlynx UNIT and OPTIONS */ + double unit; /* conversion factor: pcb length units to meters */ + double metal_thickness_unit; /* conversion factor: metal thickness to meters */ + bool use_die_for_metal; /* use dielectric constant and loss tangent of dielectric for metal layers */ + + Polygon current_polygon; /* polygon currently being parsed */ + + /* exec_* routines are called by parser to interpret hyperlynx file */ + bool exec_board_file(parse_param& h); + bool exec_version(parse_param& h); + bool exec_data_mode(parse_param& h); + bool exec_units(parse_param& h); + bool exec_plane_sep(parse_param& h); + bool exec_perimeter_segment(parse_param& h); + bool exec_perimeter_arc(parse_param& h); + bool exec_board_attribute(parse_param& h); + + bool exec_options(parse_param& h); + bool exec_signal(parse_param& h); + bool exec_dielectric(parse_param& h); + bool exec_plane(parse_param& h); + bool trace_layer(parse_param& h); + bool add_metal_layer(parse_param& h); + bool add_dielectric_layer(parse_param& h); + bool calc_layer_position(); + bool calc_layer_epsilon(); + + bool exec_devices(parse_param& h); + + bool exec_supplies(parse_param& h); + + bool exec_padstack_element(parse_param& h); + bool exec_padstack_end(parse_param& h); + + bool exec_net(parse_param& h); + bool exec_net_plane_separation(parse_param& h); + bool exec_net_attribute(parse_param& h); + bool exec_seg(parse_param& h); + bool exec_arc(parse_param& h); + bool exec_via(parse_param& h); + bool exec_via_v1(parse_param& h); /* Old style via format */ + bool exec_pin(parse_param& h); + bool exec_pad(parse_param& h); + bool exec_useg(parse_param& h); + + bool exec_polygon_begin(parse_param& h); + bool exec_polygon_end(parse_param& h); + bool exec_polyvoid_begin(parse_param& h); + bool exec_polyvoid_end(parse_param& h); + bool exec_polyline_begin(parse_param& h); + bool exec_polyline_end(parse_param& h); + bool exec_line(parse_param& h); + bool exec_curve(parse_param& h); + + bool exec_net_class(parse_param& h); + bool exec_net_class_element(parse_param& h); + bool exec_net_class_attribute(parse_param& h); + + bool exec_end(parse_param& h); + bool exec_key(parse_param& h); + + /* convert a circular arc to a polygon */ + Polygon arc2poly(double x1, double y1, double x2, double y2, double xc, double yc, double r, bool clockwise); + /* convert a line segment to a polygon */ + Polygon segment2poly(double x1, double y1, double x2, double y2, double width); + /* convert a pad to a polygon */ + Polygon pad2poly(double pad_x, double pad_y, Pad pad); + /* Add a polygon to the board outline */ + void add_perimeter_polygon(Polygon poly); + /* Add a polygon to the current net */ + void add_polygon(Polygon poly); + /* Add a polygon to a current net */ + void add_polygon_to_net(Net& pnet, Polygon poly); + /* Add a pad at coordinates x, y */ + void add_pad(double x, double y, Pad pad); + /* Add a via at coordinates x, y */ + void add_via(double x, double y, std::string layer0_name, std::string layer1_name, double radius); + /* Flood specified layers with copper */ + void flood_layers_with_copper(); + + }; + +} + + +#endif + +/* not truncated */ diff --git a/hyp2mat/lib/misc.cc b/hyp2mat/lib/misc.cc new file mode 100644 index 0000000..d8488ae --- /dev/null +++ b/hyp2mat/lib/misc.cc @@ -0,0 +1,65 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include + +#include "config.h" +#include "hyp2mat.h" + +using namespace Hyp2Mat; + +std::string Hyp2Mat::version() +{ + return VERSION; +} + +Device::Device() +{ + name.clear(); + ref.clear(); + value_type = DEVICE_VALUE_NONE; + value_float = -1; + value_string.clear(); +} + +Pin::Pin() +{ + ref.clear(); + x = 0; + y = 0; + z0 = 0; + z1 = 0; + layer_name.clear(); + metal.clear(); +} + +Bounds::Bounds() +{ + /* bounds default to infinity */ + double dbl_max = std::numeric_limits::max(); + x_min = - dbl_max; + x_max = dbl_max; + y_min = - dbl_max; + y_max = dbl_max; + z_min = - dbl_max; + z_max = dbl_max; +} + +/* not truncated */ diff --git a/hyp2mat/lib/palette.cc b/hyp2mat/lib/palette.cc new file mode 100644 index 0000000..b0405a8 --- /dev/null +++ b/hyp2mat/lib/palette.cc @@ -0,0 +1,120 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +/* + * Generate a palette of colors, given hue, saturation and value (brightness). + * The number of colors needed may be specified, but does not need to be known in advance. + * After Martin Ankerl * "How to Generate Random Colors Programmatically" + */ + +#include +#include "palette.h" + +Palette::Palette() +{ + /* default values */ + palette_hue = 0.69; /* blue */ + palette_saturation = 0.99; + palette_value = 0.99; + step = (sqrt(5) - 1)/2; /* golden ratio conjugate */ +} + +void Palette::SetPalette(double hue, double saturation, double value) +{ + /* set user values */ + if ((0 <= hue) && (hue <= 1)) palette_hue = hue; + if ((0 <= saturation) && (saturation <= 1)) palette_saturation = saturation; + if ((0 <= value) && (value <= 1)) palette_value = value; + return; +} + +void Palette::SetNumberOfColors(unsigned int number_of_colors) +{ + if (number_of_colors > 0) step = 1 / (double) number_of_colors; + else step = (sqrt(5) - 1)/2; /* golden ratio conjugate */; + return; +} + +PaletteColor Palette::Color(int color) +{ + + /* hue, saturation and value (brightness) are double, in range 0..1. (HSV color model) */ + + /* calculate hue of color */ + double integer_part; + double h = modf(palette_hue + color * step, &integer_part); + + /* convert hsv color model to rgb */ + double hi; + double f = modf(h * 6, &hi); + double v = palette_value; + double p = v * (1 - palette_saturation); + double q = v * (1 - f * palette_saturation); + double t = v * (1 - (1 - f) * palette_saturation); + + double red, green, blue; + switch(static_cast(hi + 0.5)) { + case 0: + red = v; + green = t; + blue = p; + break; + case 1: + red = q; + green = v; + blue = p; + break; + case 2: + red = p; + green = v; + blue = t; + break; + case 3: + red = p; + green = q; + blue = v; + break; + case 4: + red = t; + green = p; + blue = v; + break; + case 5: + red = v; + green = p; + blue = q; + break; + default: + red = 0; + green = 0; + blue = 0; + break; + } + + PaletteColor clr; + clr.red = red; + clr.green = green; + clr.blue = blue; + + return clr; + +} + +/* not truncated */ diff --git a/hyp2mat/lib/palette.h b/hyp2mat/lib/palette.h new file mode 100644 index 0000000..146e358 --- /dev/null +++ b/hyp2mat/lib/palette.h @@ -0,0 +1,55 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +/* + * Generate a palette of colors, given hue, saturation and value (brightness). + * The number of colors needed may be specified, but does not need to be known in advance. + * After Martin Ankerl "How to Generate Random Colors Programmatically" + */ + +#ifndef PALETTE_H +#define PALETTE_H + +struct PaletteColor { + double red; + double green; + double blue; + }; + +class Palette { +public: + Palette(); + /* hue, saturation and value (brightness) are double, in range 0..1. (HSV color model) */ + void SetPalette(double hue, double saturation, double value); /* HSV model */ + /* Set the number of colors in the palette. If the number of colors is not known in advance, choose 0 */ + void SetNumberOfColors(unsigned int number_of_colors); + /* Return palette color */ + PaletteColor Color(int color); + +private: + double palette_hue; + double palette_saturation; + double palette_value; + double step; + }; + +#endif + +/* not truncated */ diff --git a/hyp2mat/lib/parse.yy b/hyp2mat/lib/parse.yy new file mode 100644 index 0000000..66aeb99 --- /dev/null +++ b/hyp2mat/lib/parse.yy @@ -0,0 +1,826 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +%code requires { +#include "hypfile.h" +} + +%parse-param {class HypFile::Hyp *hyp } +%error-verbose +%debug +%defines + +%union { + int boolval; + int intval; + double floatval; + char* strval; +} + +%{ +#include +#include +#include +#include +#include +#include +#include "parser.h" + +void yyerror(HypFile::Hyp *, const char *); + +/* YYPRINT and yyprint print values of the tokens when debugging is switched on */ +void yyprint(FILE *, int, YYSTYPE); +#define YYPRINT(file, type, value) yyprint (file, type, value) + +/* clear parse_param struct at beginning of new record */ +void new_record(); + +/* struct to pass to calling class */ +parse_param h; + +%} + +/* + * Hyperlynx keywords + */ + + /* Punctuation: { } ( ) = , */ + + /* Sections */ + +%token BOARD_FILE VERSION DATA_MODE UNITS PLANE_SEP +%token BOARD STACKUP DEVICES SUPPLIES +%token PAD PADSTACK NET NET_CLASS END KEY + + /* Keywords */ + +%token A ARC COPPER CURVE DETAILED DIELECTRIC ENGLISH LENGTH +%token LINE METRIC N OPTIONS PERIMETER_ARC PERIMETER_SEGMENT PIN +%token PLANE POLYGON POLYLINE POLYVOID POUR S SEG SIGNAL +%token SIMPLIFIED SIM_BOTH SIM_IN SIM_OUT USEG VIA WEIGHT + + /* Assignments */ + +%token A1 A2 BR C C_QM CO_QM D ER F ID +%token L L1 L2 LPS LT M NAME +%token P PKG PR_QM PS R REF SX SY S1 S1X S1Y S2 S2X S2Y T TC +%token USE_DIE_FOR_METAL V V_QM VAL W X X1 X2 +%token XC Y Y1 Y2 YC Z ZL ZLEN ZW + + /* Booleans */ + +%token YES NO + +%token BOOL +%token POSINT +%token FLOAT +%token STRING + +%start hyp_file + +%% + +/* + * Note: + * Use left recursion when parsing board perimeter and nets. + * When using left recursion cpu time is linear with board size. + * When using right recursion we run out of memory on large boards. + * (Typical error message: line xxx: memory exhausted at 'yyy' ) + */ + + /* + hyperlynx file sections: + + board_file + version + data_mode* + units + plane_sep* + board* + stackup* + devices + supplies* + padstack* + net + net_class* + end + + * = optional section + + */ + +hyp_file + : hyp_file hyp_section + | hyp_section ; + +hyp_section + : board_file + | version + | data_mode + | units + | plane_sep + | board + | stackup + | devices + | supplies + | padstack + | net + | netclass + | end + | key + | '{' error '}' ; + + /* board_file */ + +board_file + : '{' BOARD_FILE { if (hyp->exec_board_file(h)) YYERROR; } '}' ; + + /* version */ + +version + : '{' VERSION '=' FLOAT { h.vers = yylval.floatval; } '}' { if (hyp->exec_version(h)) YYERROR; } ; + + /* data_mode */ + +data_mode + : '{' DATA_MODE '=' mode '}' { if (hyp->exec_data_mode(h)) YYERROR; }; + +mode + : SIMPLIFIED { h.detailed = false; } + | DETAILED { h.detailed = true; } ; + + /* units */ + +units + : '{' UNITS '=' unit_system metal_thickness_unit '}' { if (hyp->exec_units(h)) YYERROR; } ; + +unit_system + : ENGLISH { h.unit_system_english = true; } + | METRIC { h.unit_system_english = false; }; + +metal_thickness_unit + : WEIGHT { h.metal_thickness_weight = true; } + | LENGTH { h.metal_thickness_weight = false; } ; + + /* plane_sep */ +plane_sep + : '{' PLANE_SEP '=' FLOAT { h.default_plane_separation = yylval.floatval; } '}' { if (hyp->exec_plane_sep(h)) YYERROR; } ; + + /* board */ + +board + : '{' BOARD board_paramlist '}' + | '{' BOARD '}' ; + +board_paramlist + : board_paramlist board_param + | board_param ; + +board_param + : perimeter_segment + | perimeter_arc + | board_attribute + | '(' error ')' ; + +perimeter_segment + : '(' PERIMETER_SEGMENT coord_line ')' { if (hyp->exec_perimeter_segment(h)) YYERROR; } ; + +perimeter_arc + : '(' PERIMETER_ARC coord_arc ')' { if (hyp->exec_perimeter_arc(h)) YYERROR; } ; + +board_attribute + : '(' A N '=' STRING { h.name = yylval.strval; } V '=' STRING { h.value = yylval.strval; } ')' { if (hyp->exec_board_attribute(h)) YYERROR; } ; + + /* stackup */ + +stackup + : '{' STACKUP stackup_paramlist '}' ; + +stackup_paramlist + : stackup_paramlist stackup_param + | stackup_param ; + +stackup_param + : options + | signal + | dielectric + | plane + | '(' error ')' ; + +options + : '(' OPTIONS options_params { if (hyp->exec_options(h)) YYERROR; } ; + +options_params + : USE_DIE_FOR_METAL '=' BOOL { h.use_die_for_metal = yylval.boolval; } ')' + | ')' + ; + +signal + : '(' SIGNAL { new_record(); } signal_paramlist ')' { if (hyp->exec_signal(h)) YYERROR; } ; + +signal_paramlist + : signal_paramlist signal_param + | signal_param ; + +signal_param + : thickness + | plating_thickness + | C '=' FLOAT { h.bulk_resistivity = yylval.floatval; h.bulk_resistivity_set = true; } + | bulk_resistivity + | temperature_coefficient + | epsilon_r + | loss_tangent + | layer_name + | material_name + | plane_separation ; + +dielectric + : '(' DIELECTRIC { new_record(); } dielectric_paramlist ')' { if (hyp->exec_dielectric(h)) YYERROR; } ; + +dielectric_paramlist + : dielectric_paramlist dielectric_param + | dielectric_param ; + +dielectric_param + : thickness + | C '=' FLOAT { h.epsilon_r = yylval.floatval; h.epsilon_r_set = true; } + | epsilon_r + | loss_tangent + | conformal + | prepreg + | layer_name + | material_name + ; + +plane + : '(' PLANE { new_record(); } plane_paramlist ')' { if (hyp->exec_plane(h)) YYERROR; } ; + +plane_paramlist + : plane_paramlist plane_param + | plane_param ; + +plane_param + : thickness + | C '=' FLOAT { h.bulk_resistivity = yylval.floatval; h.bulk_resistivity_set = true; } + | bulk_resistivity + | temperature_coefficient + | epsilon_r + | loss_tangent + | layer_name + | material_name + | plane_separation ; + +thickness + : T '=' FLOAT { h.thickness = yylval.floatval; h.thickness_set = true; } + +plating_thickness + : P '=' FLOAT { h.plating_thickness = yylval.floatval; h.plating_thickness_set = true; } + +bulk_resistivity + : BR '=' FLOAT { h.bulk_resistivity = yylval.floatval; h.bulk_resistivity_set = true; } + +temperature_coefficient + : TC '=' FLOAT { h.temperature_coefficient = yylval.floatval; h.temperature_coefficient_set = true; } + +epsilon_r + : ER '=' FLOAT { h.epsilon_r = yylval.floatval; h.epsilon_r_set = true; } + +loss_tangent + : LT '=' FLOAT { h.loss_tangent = yylval.floatval; h.loss_tangent_set = true; } + +layer_name + : L '=' STRING { h.layer_name = yylval.strval; h.layer_name_set = true; } + +material_name + : M '=' STRING { h.material_name = yylval.strval; h.material_name_set = true; } + +plane_separation + : PS '=' FLOAT { h.plane_separation = yylval.floatval; h.plane_separation_set = true; } + +conformal + : CO_QM '=' BOOL { h.conformal = yylval.boolval; h.conformal_set = true; } + +prepreg + : PR_QM '=' BOOL { h.prepreg = yylval.boolval; h.prepreg_set = true; } + + /* devices */ + +devices + : '{' DEVICES device_list '}' + | '{' DEVICES '}' ; + +device_list + : device_list device + | device ; + +device + : '(' { new_record(); } STRING { h.device_type = yylval.strval; } REF '=' STRING { h.ref = yylval.strval; } device_paramlist ')' { if (hyp->exec_devices(h)) YYERROR; } + | '(' error ')' ; + +device_paramlist + : name device_value + | device_value + ; + +device_value + : value device_layer + | device_layer + ; + +device_layer + : layer_name package + | layer_name + ; + +name + : NAME '=' STRING { h.name = yylval.strval; h.name_set = true; } ; + +value + : value_float + | value_string + ; + +value_float + : VAL '=' FLOAT { h.value_float = yylval.floatval; h.value_float_set = true; } ; + +value_string + : VAL '=' STRING { h.value_string = yylval.strval; h.value_string_set = true; } ; + +package + : PKG '=' STRING { h.package = yylval.strval; h.package_set = true; } ; + + /* supplies */ + +supplies + : '{' SUPPLIES supply_list '}' ; + +supply_list + : supply_list supply + | supply ; + +supply + : '(' S name value_float voltage_spec conversion ')' { if (hyp->exec_supplies(h)) YYERROR; } + | '(' error ')' ; + +voltage_spec + : V_QM '=' BOOL { h.voltage_specified = yylval.boolval; } ; + +conversion + : C_QM '=' BOOL { h.conversion = yylval.boolval; } + + /* padstack */ + +padstack + : '{' PADSTACK { new_record(); } '=' STRING { h.padstack_name = yylval.strval; h.padstack_name_set = true; } drill_size '}' { if (hyp->exec_padstack_end(h)) YYERROR; } ; + +drill_size + : ',' FLOAT { h.drill_size = yylval.floatval; h.drill_size_set = true; } padstack_list + | ',' padstack_list ; + | padstack_list ; + +padstack_list + : padstack_list padstack_def + | padstack_def ; + +padstack_def + : '(' STRING { h.layer_name = yylval.strval; h.layer_name_set = true; } ',' pad_shape pad_coord pad_type { if (hyp->exec_padstack_element(h)) YYERROR; new_record(); } + | '(' error ')' ; + +pad_shape + : FLOAT { h.pad_shape = yylval.floatval; } ',' + | ',' { h.pad_shape = -1; } /* Workaround: Altium sometimes prints an empty pad shape */ + ; + +pad_coord + : FLOAT { h.pad_sx = yylval.floatval; } ',' FLOAT { h.pad_sy = yylval.floatval; } ',' FLOAT { h.pad_angle = yylval.floatval; } + +pad_type + : ')' + | ',' M ')' { h.pad_type = PAD_TYPE_METAL; h.pad_type_set = true; } + | ',' A ')' { h.pad_type = PAD_TYPE_ANTIPAD; h.pad_type_set = true; } + | ',' FLOAT { h.thermal_clear_shape = yylval.floatval; } + ',' FLOAT { h.thermal_clear_sx = yylval.floatval; } + ',' FLOAT { h.thermal_clear_sy = yylval.floatval; } + ',' FLOAT { h.thermal_clear_angle = yylval.floatval; } + ',' T ')' { h.pad_type = PAD_TYPE_THERMAL_RELIEF; h.pad_type_set = true; } + ; + + /* net */ + +net + : '{' NET '=' STRING { h.net_name = yylval.strval; if (hyp->exec_net(h)) YYERROR; } net_def '}' ; + +net_def + : plane_separation { if (hyp->exec_net_plane_separation(h)) YYERROR; } net_subrecord_list + | net_subrecord_list ; + +net_subrecord_list + : net_subrecord_list net_subrecord + | net_subrecord ; + +net_subrecord + : seg + | arc + | via + | pin + | pad + | useg + | polygon + | polyvoid + | polyline + | net_attribute + | '(' error ')' + | '{' error '}' + ; + +seg + : '(' SEG { new_record(); } coord_line width layer_name ps_lps_param { if (hyp->exec_seg(h)) YYERROR; } ; + +arc + : '(' ARC { new_record(); } coord_arc width layer_name ps_lps_param { if (hyp->exec_arc(h)) YYERROR; } ; + +ps_lps_param + : plane_separation lps_param + | lps_param + ; + +lps_param + : left_plane_separation ')' + | ')' + ; + +width + : W '=' FLOAT { h.width = yylval.floatval; h.width_set = true; } ; + +left_plane_separation + : LPS '=' FLOAT { h.left_plane_separation = yylval.floatval; h.left_plane_separation_set = true; } ; + +via + : '(' VIA { new_record(); } coord_point via_new_or_old_style + ; + +via_new_or_old_style + : via_new_style + | via_old_style + ; + +via_new_style + : via_new_style_l1_param { if (hyp->exec_via(h)) YYERROR; } ; + +via_new_style_l1_param + : layer1_name via_new_style_l2_param + | via_new_style_l2_param + ; + +via_new_style_l2_param + : layer2_name via_new_style_padstack_param + | via_new_style_padstack_param + ; + +via_new_style_padstack_param + : padstack_name ')' + ; + +padstack_name + : P '=' STRING { h.padstack_name = yylval.strval; h.padstack_name_set = true; } ; + +layer1_name + : L1 '=' STRING { h.layer1_name = yylval.strval; h.layer1_name_set = true; } ; + +layer2_name + : L2 '=' STRING { h.layer2_name = yylval.strval; h.layer2_name_set = true; } ; + +via_old_style + : D '=' FLOAT { h.drill_size = yylval.floatval; } /* deprecated hyperlynx v1.x VIA format */ + layer1_name + layer2_name + S1 '=' STRING { h.pad1_shape = yylval.strval; } + S1X '=' FLOAT { h.pad1_sx = yylval.floatval; } + S1Y '=' FLOAT { h.pad1_sy = yylval.floatval; } + A1 '=' FLOAT { h.pad1_angle = yylval.floatval; } + S2 '=' STRING { h.pad2_shape = yylval.strval; } + S2X '=' FLOAT { h.pad2_sx = yylval.floatval; } + S2Y '=' FLOAT { h.pad2_sy = yylval.floatval; } + A2 '=' FLOAT { h.pad2_angle = yylval.floatval; } + ')' { if (hyp->exec_via_v1(h)) YYERROR; } ; + ; + +pin + : '(' PIN { new_record(); } coord_point pin_reference pin_param { if (hyp->exec_pin(h)) YYERROR; } ; + +pin_param + : padstack_name pin_function_param + | pin_function_param + ; + +pin_function_param + : pin_function ')' + | ')' + ; + +pin_reference + : R '=' STRING { h.pin_reference = yylval.strval; h.pin_reference_set = true; } ; + +pin_function + : F '=' SIM_OUT { h.pin_function = PIN_SIM_OUT; h.pin_function_set = true; } + | F '=' SIM_IN { h.pin_function = PIN_SIM_IN; h.pin_function_set = true; } + | F '=' SIM_BOTH { h.pin_function = PIN_SIM_BOTH; h.pin_function_set = true; } + ; + +pad + : '(' PAD { new_record(); } /* deprecated hyperlynx v1.x only */ + coord_point + layer_name + S '=' STRING { h.pad1_shape = yylval.strval; } + SX '=' FLOAT { h.pad1_sx = yylval.floatval; } + SY '=' FLOAT { h.pad1_sy = yylval.floatval; } + A '=' FLOAT { h.pad1_angle = yylval.floatval; } + ')' { if (hyp->exec_pad(h)) YYERROR; } ; + ; + +useg + : '(' USEG { new_record(); } coord_point1 layer1_name coord_point2 layer2_name useg_param { if (hyp->exec_useg(h)) YYERROR; } ; + +useg_param + : useg_stackup + | useg_impedance + ; + +useg_stackup + : ZL '=' STRING { h.zlayer_name = yylval.strval; h.zlayer_name_set = true; } + ZW '=' FLOAT { h.width = yylval.floatval; } + ZLEN '=' FLOAT { h.length = yylval.floatval; } + ')' + ; + +useg_impedance + : Z '=' FLOAT { h.impedance = yylval.floatval; h.impedance_set = true; } + D '=' FLOAT { h.delay = yylval.floatval; } + useg_resistance; + +useg_resistance + : R '=' FLOAT { h.resistance = yylval.floatval; h.resistance_set = true;} + ')' + | ')' + ; + +polygon + : '{' POLYGON { new_record(); } polygon_param_list coord_point { if (hyp->exec_polygon_begin(h)) YYERROR; } + lines_and_curves '}' { if (hyp->exec_polygon_end(h)) YYERROR; } ; + +polygon_param_list + : polygon_param_list polygon_param + | polygon_param + ; + +polygon_param + : layer_name + | width + | polygon_type + | polygon_id + ; + +polygon_id + : ID '=' POSINT { h.id = yylval.intval; h.id_set = true; } /* polygon id is a non-negative integer */ + ; + +polygon_type + : T '=' POUR { h.polygon_type = POLYGON_TYPE_POUR; h.polygon_type_set = true; } + | T '=' PLANE { h.polygon_type = POLYGON_TYPE_PLANE; h.polygon_type_set = true; } + | T '=' COPPER { h.polygon_type = POLYGON_TYPE_COPPER; h.polygon_type_set = true; } + ; + +polyvoid + : '{' POLYVOID { new_record(); } polygon_id coord_point { if (hyp->exec_polyvoid_begin(h)) YYERROR; } + lines_and_curves '}' { if (hyp->exec_polyvoid_end(h)) YYERROR; } ; + +polyline + : '{' POLYLINE { new_record(); } polygon_param_list coord_point { if (hyp->exec_polyline_begin(h)) YYERROR; } + lines_and_curves '}' { if (hyp->exec_polyline_end(h)) YYERROR; } ; + +lines_and_curves + : lines_and_curves line_or_curve + | line_or_curve + ; + +line_or_curve + : line + | curve + | '(' error ')' + ; + +line + : '(' LINE { new_record(); } coord_point ')' { if (hyp->exec_line(h)) YYERROR; } ; + +curve + : '(' CURVE { new_record(); } coord_arc ')' { if (hyp->exec_curve(h)) YYERROR; } ; + +net_attribute + : '(' A N '=' STRING { h.name = yylval.strval; } V '=' STRING { h.value = yylval.strval; } ')' { if (hyp->exec_net_attribute(h)) YYERROR; } ; + + /* net class */ + +netclass + : '{' NET_CLASS '=' STRING { h.net_class_name = yylval.strval; if (hyp->exec_net_class(h)) YYERROR; } netclass_subrecords ; + +netclass_subrecords + : netclass_paramlist '}' + | '}' + ; + +netclass_paramlist + : netclass_paramlist netclass_param + | netclass_param + ; + +netclass_param + : netclass_attribute + | net_name + | '(' error ')' + ; + +net_name + : '(' N N '=' STRING { h.net_name = yylval.strval; } ')' { if (hyp->exec_net_class_element(h)) YYERROR; } ; + +netclass_attribute + : '(' A N '=' STRING { h.name = yylval.strval; } V '=' STRING { h.value = yylval.strval; } ')' { if (hyp->exec_net_class_attribute(h)) YYERROR; } ; + + /* end */ + +end + : '{' END '}' { if (hyp->exec_end(h)) YYERROR; } ; + + /* key */ + +key + : '{' KEY '=' STRING { h.key = yylval.strval; } '}' { if (hyp->exec_key(h)) YYERROR; } ; + + /* coordinates */ + +coord_point + : X '=' FLOAT { h.x = yylval.floatval; } Y '=' FLOAT { h.y = yylval.floatval; } ; + +coord_point1 + : X1 '=' FLOAT { h.x1 = yylval.floatval; } Y1 '=' FLOAT { h.y1 = yylval.floatval; } ; + +coord_point2 + : X2 '=' FLOAT { h.x2 = yylval.floatval; } Y2 '=' FLOAT { h.y2 = yylval.floatval; } ; + +coord_line + : coord_point1 coord_point2 ; + +coord_arc + : coord_line XC '=' FLOAT { h.xc = yylval.floatval; } YC '=' FLOAT { h.yc = yylval.floatval; } R '=' FLOAT { h.r = yylval.floatval; } ; + +%% + +/* + * Supporting C routines + */ + +void yyerror(HypFile::Hyp *hyp, const char *msg) +{ + std::ostringstream err_msg; + + err_msg << "line " << yylineno << ": " << msg << " at '" << yytext << "'"; + hyp->error(err_msg.str()); +} + +void yyprint(FILE *file, int type, YYSTYPE value) +{ + if (type == STRING) + fprintf (file, "%s", value.strval); + else if (type == FLOAT) + fprintf (file, "%g", value.floatval); + else if (type == BOOL) + fprintf (file, "%i", value.boolval); + return; +} + +/* + * reset parse_param struct at beginning of record + */ + +void new_record() +{ + h.vers = 0; + h.detailed = false; + h.unit_system_english = false; + h.metal_thickness_weight = false; + h.default_plane_separation = 0; + h.use_die_for_metal = false; + h.bulk_resistivity = 0; + h.conformal = false; + h.epsilon_r = 0; + h.layer_name.clear(); + h.loss_tangent = 0; + h.material_name.clear(); + h.plane_separation = 0; + h.plating_thickness = 0; + h.prepreg = false; + h.temperature_coefficient = 0; + h.thickness = 0; + h.bulk_resistivity_set = false; + h.conformal_set = false; + h.epsilon_r_set = false; + h.layer_name_set = false; + h.loss_tangent_set = false; + h.material_name_set = false; + h.plane_separation_set = false; + h.plating_thickness_set = false; + h.prepreg_set = false; + h.temperature_coefficient_set = false; + h.thickness_set = false; + h.device_type.clear(); + h.ref.clear(); + h.value_float = 0; + h.value_string.clear(); + h.package.clear(); + h.name_set = false; + h.value_float_set = false; + h.value_string_set = false; + h.package_set = false; + h.voltage_specified = false; + h.conversion = false; + h.padstack_name.clear(); + h.drill_size = 0; + h.pad_shape = 0; + h.pad_sx = 0; + h.pad_sy = 0; + h.pad_angle = 0; + h.thermal_clear_shape = 0; + h.thermal_clear_sx = 0; + h.thermal_clear_sy = 0; + h.thermal_clear_angle = 0; + h.pad_type = PAD_TYPE_METAL; + h.padstack_name_set = false; + h.drill_size_set = false; + h.pad_type_set = false; + h.width = 0; + h.left_plane_separation = 0; + h.width_set = false; + h.left_plane_separation_set = false; + h.layer1_name.clear(); + h.layer1_name_set = false; + h.layer2_name.clear(); + h.layer2_name_set = false; + h.pad1_shape.clear(); + h.pad1_sx = 0; + h.pad1_sy = 0; + h.pad1_angle = 0; + h.pad2_shape.clear(); + h.pad2_sx = 0; + h.pad2_sy = 0; + h.pad2_angle = 0; + h.pin_reference.clear(); + h.pin_reference_set = false; + h.pin_function = PIN_SIM_BOTH; + h.pin_function_set = false; + h.zlayer_name.clear(); + h.zlayer_name_set = false; + h.length = 0; + h.impedance = 0; + h.impedance_set = false; + h.delay = 0; + h.resistance = 0; + h.resistance_set = false; + h.id = -1; + h.id_set = false; + h.polygon_type = POLYGON_TYPE_PLANE; + h.polygon_type_set = false; + h.net_class_name.clear(); + h.net_name.clear(); + h.key.clear(); + h.name.clear(); + h.value.clear(); + h.x = 0; + h.y = 0; + h.x1 = 0; + h.y1 = 0; + h.x2 = 0; + h.y2 = 0; + h.xc = 0; + h.yc = 0; + h.r = 0; + + return; +} + +/* not truncated */ diff --git a/hyp2mat/lib/parse_param.h b/hyp2mat/lib/parse_param.h new file mode 100644 index 0000000..47ed1bb --- /dev/null +++ b/hyp2mat/lib/parse_param.h @@ -0,0 +1,172 @@ + +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#ifndef PARSE_PARAM_H +#define PARSE_PARAM_H + +#include + + /* + * Parameters passed on by the parser. + * All variables added here are initialized in new_record(). + */ + + enum pad_type_enum { PAD_TYPE_METAL, PAD_TYPE_ANTIPAD, PAD_TYPE_THERMAL_RELIEF }; + + enum pin_function_enum { PIN_SIM_IN, PIN_SIM_OUT, PIN_SIM_BOTH }; + + enum polygon_type_enum { POLYGON_TYPE_POUR, POLYGON_TYPE_PLANE, POLYGON_TYPE_COPPER, POLYGON_TYPE_PAD, POLYGON_TYPE_ANTIPAD }; + + struct parse_param { + double vers; /* version of the hyp file format */ + bool detailed; /* data detailed enough for power integrity */ + bool unit_system_english; /* english or metric units */ + bool metal_thickness_weight; /* copper by weight or by length */ + double default_plane_separation; /* trace to plane separation */ + + /* stackup record */ + bool use_die_for_metal; /* dielectric constant and loss tangent of dielectric for metal layers */ + double bulk_resistivity; + bool conformal; + double epsilon_r; + std::string layer_name; + double loss_tangent; + std::string material_name; + double plane_separation; + double plating_thickness; + bool prepreg; + double temperature_coefficient; /* temperature coefficient of resistivity */ + double thickness; /* layer thickness */ + + /* stackup record flags */ + bool bulk_resistivity_set; + bool conformal_set; + bool epsilon_r_set; + bool layer_name_set; + bool loss_tangent_set; + bool material_name_set; + bool plane_separation_set; + bool plating_thickness_set; + bool prepreg_set; + bool temperature_coefficient_set; + bool thickness_set; + + /* device record */ + std::string device_type; + std::string ref; + double value_float; + std::string value_string; + std::string package; + + /* device record flags */ + bool name_set; + bool value_float_set; + bool value_string_set; + bool package_set; + + /* supplies record */ + bool voltage_specified; + bool conversion; + + /* padstack record */ + std::string padstack_name; + double drill_size; + double pad_shape; + double pad_sx; + double pad_sy; + double pad_angle; + double thermal_clear_shape; + double thermal_clear_sx; + double thermal_clear_sy; + double thermal_clear_angle; + pad_type_enum pad_type; + + /* padstack record flags */ + bool padstack_name_set; + bool drill_size_set; + bool pad_type_set; + + /* net record */ + double width; + double left_plane_separation; + bool width_set; + bool left_plane_separation_set; + + /* via subrecord of net */ + std::string layer1_name; + bool layer1_name_set; + std::string layer2_name; + bool layer2_name_set; + std::string pad1_shape; + double pad1_sx; + double pad1_sy; + double pad1_angle; + std::string pad2_shape; + double pad2_sx; + double pad2_sy; + double pad2_angle; + + /* pin subrecord of net */ + std::string pin_reference; + bool pin_reference_set; + pin_function_enum pin_function; + bool pin_function_set; + + /* useg subrecord of net */ + std::string zlayer_name; + bool zlayer_name_set; + double length; + double impedance; + bool impedance_set; + double delay; + double resistance; + bool resistance_set; + + /* polygon subrecord of net */ + int id; + bool id_set; + polygon_type_enum polygon_type; + bool polygon_type_set; + + /* net class record */ + std::string net_class_name; + std::string net_name; + + /* key record */ + std::string key; + + /* Attributes */ + std::string name; /* attribute name */ + std::string value; /* attribute value */ + + /* point, line and arc coordinates */ + double x; /* coordinates point */ + double y; /* coordinates point */ + double x1; /* coordinates point 1 */ + double y1; /* coordinates point 1 */ + double x2; /* coordinates point 2 */ + double y2; /* coordinates point 2 */ + double xc; /* coordinates arc */ + double yc; /* coordinates arc */ + double r; /* coordinates arc */ + }; + +#endif diff --git a/hyp2mat/lib/parser.h b/hyp2mat/lib/parser.h new file mode 100644 index 0000000..217ed8c --- /dev/null +++ b/hyp2mat/lib/parser.h @@ -0,0 +1,40 @@ + +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#ifndef PARSER_H +#define PARSER_H + +#include +#include "hypfile.h" + + /* + * hooks in bison (parser) and flex (scanner) code + */ + + extern FILE *yyin; /* file the parser reads from */ + extern int yy_flex_debug ; /* debug scanner if == 1 */ + extern int yydebug ; /* debug parser if == 1 */ + extern int yylineno; + extern char *yytext; + extern int yyparse(HypFile::Hyp *); + extern int yylex(void); + +#endif diff --git a/hyp2mat/lib/pcb.cc b/hyp2mat/lib/pcb.cc new file mode 100644 index 0000000..86bc657 --- /dev/null +++ b/hyp2mat/lib/pcb.cc @@ -0,0 +1,333 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include + +#include "config.h" +#include "hyp2mat.h" + +#include "hyperlynx.h" +#include "pdf.h" +#include "csxcad.h" + +using namespace Hyp2Mat; + +PCB::PCB() +{ + debug = 0; + raw = false; + via_plating_thickness = 0; + _arc_precision = 0; + _clearance = -1.0; + _epsilon_r = -1.0; + _epsilon_r_override = false; + _bulk_resistivity = -1.0; + _bulk_resistivity_override = false; + _loss_tangent = -1.0; + _loss_tangent_override = false; +} + +/* + * Read a pcb in hyperlynx format. + * "filename" is the Hyperlynx file to import. + * "layers" is the names of the layers to import. Default is importing all layers. + * "nets" is the names of the nets to import. Default is importing all nets. + */ + +void PCB::ReadHyperLynx (std::string filename, std::vector layers, std::vector nets) +{ + + /* set accuracy with which circle arcs are converted to polygons */ + Polygon::SetArcPrecision(_arc_precision); + + /* read hyperlynx file */ + HyperLynx hyperlynx; + + hyperlynx.layers = layers; + hyperlynx.nets = nets; + hyperlynx.raw = raw; + hyperlynx.arc_precision = _arc_precision; + hyperlynx.clearance = _clearance; + hyperlynx.flood_layers = flood_layers; + hyperlynx.bounds = _bounds; + + hyperlynx.Read(filename, *this); + + /* Check for empty board outline; add default board outline if outline empty */ + _CheckBoardOutline(); + + /* Epsilon_r, bulk resistivity and loss tangent overrides */ + _UserOverrides(); + + return; +} + +/* + * Write a pcb in pdf format + */ + +void PCB::WritePDF (std::string filename, double hue, double saturation, double brightness) +{ + PDF pdf; + pdf.SetPalette(hue, saturation, brightness); + pdf.Write(filename, *this); +} + +/* + * Write a pcb in csxcad format + */ + +void PCB::WriteCSXCAD (std::string filename, bool pcb_outline, bool lossy_copper, bool metal_3d) +{ + CSXCAD csxcad; + csxcad.Write(filename, *this, pcb_outline, lossy_copper, metal_3d); +} + +/* + * Set dielectric epsilon r. Overrides value in Hyperlynx file. + */ + +void PCB::SetEpsilonR(double new_epsilon_r) +{ + /* save the new value of epsilon r. run before loading hyperlynx file. */ + _epsilon_r = new_epsilon_r; + _epsilon_r_override = true; + + return; +} + +void PCB::SetLossTangent(double new_loss_tangent) +{ + /* save the new value of loss_tangent. run before loading hyperlynx file. */ + _loss_tangent = new_loss_tangent; + _loss_tangent_override = true; + return; +} + +void PCB::SetBulkResistance(double new_bulk_resistivity) +{ + /* save the new value of bulk_resistivity. run before loading hyperlynx file. */ + _bulk_resistivity = new_bulk_resistivity; + _bulk_resistivity_override = true; + return; +} + +/* + * Modify the value of epsilon r. Run after loading hyperlynx file. + */ + +void PCB::_UserOverrides() +{ + + /* set all layers to epsilon_r, except outer copper layers, which we assume are in air (er = 1) */ + + /* iterate over all layers, setting epsilon */ + for (LayerList::iterator i = stackup.begin(); i != stackup.end(); ++i) { + + /* override epsilon and loss tangent of dielectric layers */ + if (_epsilon_r_override && (i->layer_type == LAYER_DIELECTRIC)) i->epsilon_r = _epsilon_r; + if (_loss_tangent_override && (i->layer_type == LAYER_DIELECTRIC)) i->loss_tangent = _loss_tangent; + + /* override resistivity of metal layers */ + if (_bulk_resistivity_override && (i->layer_type != LAYER_DIELECTRIC)) i->bulk_resistivity = _bulk_resistivity; + + /* check for outer copper layer */ + if (i->layer_type == LAYER_DIELECTRIC) + continue; + + /* find dielectric layer above current metal layer */ + bool upper_layer_found = false; + for (LayerList::iterator j = stackup.begin(); j != i; ++j) + if (j->layer_type == LAYER_DIELECTRIC) upper_layer_found = true; + + /* find dielectric layer below current metal layer */ + bool lower_layer_found = false; + for (LayerList::iterator j = i; j != stackup.end(); ++j) + if (j->layer_type == LAYER_DIELECTRIC) lower_layer_found = true; + + /* assume outer copper layers are in air */ + if (!upper_layer_found || !lower_layer_found) { + i->epsilon_r = 1.0; + i->loss_tangent = 0.0; + } + } + return; +} + +/* + * set resolution of x and y coordinates + */ + +void PCB::SetGrid(double new_grid) +{ + if (new_grid > 0.0) Polygon::SetGrid(new_grid); + return; +} + +/* + * set maximum difference between perfect circle arc and polygonal approximation + */ + +void PCB::SetArcPrecision(double new_arc_precision) +{ + if (new_arc_precision >= 0.0) _arc_precision = new_arc_precision; + return; +} + +/* + * set track to plane clearance + */ + +void PCB::SetClearance(double new_clearance) +{ + if (new_clearance >= 0.0) _clearance = new_clearance; + return; +} + +/* + * Calculate the bounding rectangle of a pcb. + */ + +Bounds PCB::GetBounds() { + Bounds bounds; + bounds.x_min = 0; + bounds.x_max = 0; + bounds.y_min = 0; + bounds.y_max = 0; + bounds.z_min = 0; + bounds.z_max = 0; + + /* iterate over layers; find z_max and z_min */ + if (!stackup.empty()) { + bounds.z_min = stackup.back().z0; + bounds.z_max = stackup.front().z1; + for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l) { + if (l->z0 < bounds.z_min) bounds.z_min = l->z0; + if (l->z1 > bounds.z_max) bounds.z_max = l->z1; + } + } + + /* iterate over board edge; find x_min, x_max, y_min, y_max */ + bool first_point = true; + + for (FloatPolygons::iterator i = board.begin(); i != board.end(); ++i) + for (FloatPolygon::iterator j = i->poly.begin(); j != i->poly.end(); ++j) { + if ((j->x > bounds.x_max) || first_point) bounds.x_max = j->x; + if ((j->y > bounds.y_max) || first_point) bounds.y_max = j->y; + if ((j->x < bounds.x_min) || first_point) bounds.x_min = j->x; + if ((j->y < bounds.y_min) || first_point) bounds.y_min = j->y; + first_point = false; + } + + /* iterate over layers */ + for (LayerList::iterator l = stackup.begin(); l != stackup.end(); ++l) + for (FloatPolygons::iterator i = l->metal.begin(); i != l->metal.end(); ++i) + for (FloatPolygon::iterator j = i->poly.begin(); j != i->poly.end(); ++j) { + if ((j->x > bounds.x_max) || first_point) bounds.x_max = j->x; + if ((j->y > bounds.y_max) || first_point) bounds.y_max = j->y; + if ((j->x < bounds.x_min) || first_point) bounds.x_min = j->x; + if ((j->y < bounds.y_min) || first_point) bounds.y_min = j->y; + first_point = false; + } + + /* iterate over vias */ + for (ViaList::iterator i = via.begin(); i != via.end(); ++i) { + if ((i->x + i->radius > bounds.x_max) || first_point) bounds.x_max = i->x + i->radius; + if ((i->y + i->radius > bounds.y_max) || first_point) bounds.y_max = i->y + i->radius; + if ((i->x - i->radius < bounds.x_min) || first_point) bounds.x_min = i->x - i->radius; + if ((i->y - i->radius < bounds.y_min) || first_point) bounds.y_min = i->y - i->radius; + first_point = false; + } + + return bounds; + } + +/* + * Set the bounding rectangle of a pcb. + */ + +void PCB::SetBounds(Bounds new_bounds) +{ + _bounds = new_bounds; +} + +void PCB::_CheckBoardOutline() +{ + if (!board.empty()) return; + + if (debug) std::cerr << "board outline empty" << std::endl; + + Bounds bounds = GetBounds(); + + if ((bounds.x_min != bounds.x_max) && (bounds.y_min != bounds.y_max)) { + + if (debug) std::cerr << "adding default board outline" << std::endl; + + /* add rectangular outline to pcb */ + + Hyp2Mat::FloatPoly outline; + outline.poly.push_back(Hyp2Mat::FloatPoint(bounds.x_min, bounds.y_min)); + outline.poly.push_back(Hyp2Mat::FloatPoint(bounds.x_min, bounds.y_max)); + outline.poly.push_back(Hyp2Mat::FloatPoint(bounds.x_max, bounds.y_max)); + outline.poly.push_back(Hyp2Mat::FloatPoint(bounds.x_max, bounds.y_min)); + outline.is_hole = false; + outline.nesting_level = 0; + + board.push_back(outline); + } +} + +void PCB::PrintSummary() { + Bounds bounds = GetBounds(); + + /* save stream flags and precision */ + std::ios::fmtflags saved_flgs = std::cerr.flags(); + std::streamsize saved_prec = std::cerr.precision(); + std::cerr.flags(std::ios::fixed); + std::cerr.precision(2); + + double m_to_mm = 1000; + std::cerr << "board size:" << std::endl; + std::cerr << " x = " << std::setw(8) << bounds.x_min*m_to_mm << " : " << std::setw(8) << bounds.x_max*m_to_mm << " mm" << std::endl; + std::cerr << " y = " << std::setw(8) << bounds.y_min*m_to_mm << " : " << std::setw(8) << bounds.y_max*m_to_mm << " mm" << std::endl; + std::cerr << " z = " << std::setw(8) << bounds.z_min*m_to_mm << " : " << std::setw(8) << bounds.z_max*m_to_mm << " mm" << std::endl; + + std::cerr << "layers:" << std::endl; + if (stackup.empty()) std::cerr << "(none)"; + for (LayerList::iterator it = stackup.begin(); it != stackup.end(); ++it) { + std::cerr << " "; + switch (it->layer_type) { + case LAYER_SIGNAL: std::cerr << "signal " << std::setw(8) << it->thickness * 1E6 << " um" ; break; + case LAYER_DIELECTRIC: std::cerr << "dielectric " << std::setw(8) << it->thickness * 1E3 << " mm" ; break; + case LAYER_PLANE: std::cerr << "plane " << std::setw(8) << it->thickness * 1E6 << " um" ; break; + default: std::cerr << "*** " << std::setw(8) << it->thickness * 1E3 << " mm" ; break; + } + std::cerr << " eps_r " << it->epsilon_r << " '" << it->layer_name << "'" << std::endl; + } + + /* reset flags and precision */ + std::cerr.flags(saved_flgs); + std::cerr.precision(saved_prec); + + return; +} + +/* not truncated */ diff --git a/hyp2mat/lib/pdf.cc b/hyp2mat/lib/pdf.cc new file mode 100644 index 0000000..a233f29 --- /dev/null +++ b/hyp2mat/lib/pdf.cc @@ -0,0 +1,292 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +/* + * Uses libharu by Takeshi Kanno to generate pdf documents. + */ + +#include +#include +#include +#include "pdf.h" +#include + +using namespace Hyp2Mat; + +PDF::PDF() +{ + text_height = 10; /* caption size in points */ + margin = text_height; /* page margin */ + m_to_points = 1 / (2.54 / 100 / 72); /* convert m to points (1/72 of an inch) */ + x_max = x_min = y_max = y_min = 0; +} + +/* + * PDF error handler + */ + +void error_handler (HPDF_STATUS error_no, HPDF_STATUS detail_no, void *user_data) +{ + printf ("ERROR: error_no=%04X, detail_no=%d\n", (unsigned int) error_no, (int) detail_no); + throw std::exception (); /* throw exception on error */ +} + +/* + * set page size to size of pcb board + */ + +void PDF::set_page_size(HPDF_Page page) +{ + double width = x_max - x_min + 2 * margin; + double height = y_max - y_min + 2 * margin + text_height; /* add margin for caption */ + + if (width < 3) width = 3; + if (height < 3) height = 3; + + HPDF_Page_SetWidth(page, width); + HPDF_Page_SetHeight(page, height); +} + +/* + * Generate color palette given hue, saturation and value (brightness). + * After Martin Ankerl * "How to Generate Random Colors Programmatically" + */ + +void PDF::set_color(HPDF_Page page, int color_idx) +{ + PaletteColor rgb = Color(color_idx); + + HPDF_Page_SetRGBStroke(page, rgb.red, rgb.green, rgb.blue); + HPDF_Page_SetRGBFill(page, rgb.red, rgb.green, rgb.blue); +} + +/* + * Set stroke and fill color to black + */ + +void PDF::set_color_black(HPDF_Page page) +{ + HPDF_Page_SetRGBStroke(page, 0, 0, 0); + HPDF_Page_SetRGBFill(page, 0, 0, 0); +} + +/* + * fill all polygons + */ + +void PDF::page_fill(HPDF_Page page) +{ + if (HPDF_Page_GetGMode(page) == HPDF_GMODE_PATH_OBJECT) HPDF_Page_Fill (page); + return; +} + +/* + * draw all polygon outlines + */ + +void PDF::page_stroke(HPDF_Page page) +{ + if (HPDF_Page_GetGMode(page) == HPDF_GMODE_PATH_OBJECT) HPDF_Page_Stroke (page); + return; +} + +/* + * Write layer name on top of page + */ + +void PDF::draw_caption(HPDF_Page page, HPDF_Font font, std::string txt) +{ + HPDF_Page_SetFontAndSize(page, font, text_height); + HPDF_Page_BeginText(page); + HPDF_Page_MoveTextPos(page, margin, y_max - y_min + margin + text_height); /* page top left */ + HPDF_Page_ShowText(page, txt.c_str()); + HPDF_Page_EndText(page); +} + +/* + * Export copper polygon as pdf + */ + +void PDF::draw(HPDF_Page page, FloatPolygon& poly) +{ + double old_px, old_py; + + /* pdf requires outer edge of polygon to be clockwise; holes to be counterclockwise */ + + bool firstpoint = true; + for (FloatPolygon::iterator i = poly.begin(); i != poly.end(); ++i) { + + double px = i->x * m_to_points - x_min + margin; + double py = i->y * m_to_points - y_min + margin; + if (firstpoint) { + HPDF_Page_MoveTo(page, px, py); + firstpoint = false; + } + else { + if ((px != old_px) || (py != old_py)) + HPDF_Page_LineTo(page, px, py); + } + old_px = px; old_py = py; + } + HPDF_Page_ClosePath (page); + return; +} + +/* + * Export all polygons of a copper layer as pdf. May contain holes. + */ + +void PDF::draw(HPDF_Page page, FloatPolygons& polygons) +{ + for (FloatPolygons::iterator i = polygons.begin(); i != polygons.end(); ++i) + draw(page, i->poly); +} + +/* + * Draws a via as a circle. + */ + +void PDF::draw(HPDF_Page page, Hyp2Mat::Via& via) +{ + double x = via.x * m_to_points - x_min + margin; + double y = via.y * m_to_points - y_min + margin; + double r = via.radius * m_to_points; + HPDF_Page_Circle(page, x, y, r); +} + +void PDF::draw_composite_view(HPDF_Doc pdf, HPDF_Font font, Hyp2Mat::PCB& pcb) +{ + /* new page */ + HPDF_Page page = HPDF_AddPage(pdf); + set_page_size(page); + HPDF_Page_SetLineWidth(page, 0); + draw_caption(page, font, "Composite"); + + /* draw board */ + set_color_black(page); + draw(page, pcb.board); + page_stroke (page); + + /* draw layers */ + int current_color = 0; + for (LayerList::reverse_iterator l = pcb.stackup.rbegin(); l != pcb.stackup.rend(); ++l) { + if (l->layer_type == LAYER_DIELECTRIC) continue; + set_color(page, current_color++); + draw(page, l->metal); + page_stroke (page); + } + + /* draw vias */ + set_color_black(page); + for (ViaList::iterator i = pcb.via.begin(); i != pcb.via.end(); ++i) + PDF::draw(page, *i); + page_fill (page); + + return; +} + +void PDF::draw_layer_view(HPDF_Doc pdf, HPDF_Font font, Hyp2Mat::PCB& pcb) +{ + + int current_color = 0; + for (LayerList::reverse_iterator l = pcb.stackup.rbegin(); l != pcb.stackup.rend(); ++l) { + if (l->layer_type == LAYER_DIELECTRIC) continue; + + HPDF_Page page = HPDF_AddPage(pdf); + set_page_size(page); + HPDF_Page_SetLineWidth(page, 0); + + /* draw caption */ + draw_caption(page, font, l->layer_name); + + /* draw board */ + set_color_black(page); + draw(page, pcb.board); + page_stroke (page); + + /* draw layer */ + set_color(page, current_color++); + draw(page, l->metal); + page_fill (page); + + /* draw vias */ + set_color_black(page); + for (ViaList::iterator i = pcb.via.begin(); i != pcb.via.end(); ++i) { + /* blind vias: only draw via if via goes through current layer */ + if ((i->z0 <= l->z0) && (i->z1 >= l->z1)) { + draw(page, *i); + } + } + page_fill (page); + } +} + +/* + * Save current board as pdf. + * First page is the composite view of all signal layers, + * subsequent pages are one layer each. + */ + +void PDF::Write(const std::string& filename, Hyp2Mat::PCB& pcb) +{ + /* choose a color palette. Change HSV values to what suits your taste */ + int number_of_colors = 0; + for (LayerList::reverse_iterator l = pcb.stackup.rbegin(); l != pcb.stackup.rend(); ++l) + if (l->layer_type != LAYER_DIELECTRIC) number_of_colors++; /* count layers to determine number of colors needed */ + + SetNumberOfColors(number_of_colors); + + HPDF_Doc pdf = HPDF_New (error_handler, NULL); /* set error-handler */ + if (!pdf) { + std::cerr << "cannot create pdf object" << std::endl; + return; + } + + try { + /* get pcb size */ + Bounds bounds = pcb.GetBounds(); + x_max = bounds.x_max * m_to_points; + y_max = bounds.y_max * m_to_points; + x_min = bounds.x_min * m_to_points; + y_min = bounds.y_min * m_to_points; + + /* Document settings */ + HPDF_Font font = HPDF_GetFont(pdf, "Helvetica", NULL); + HPDF_SetInfoAttr(pdf, HPDF_INFO_CREATOR, "hyp2mat"); + HPDF_SetCompressionMode (pdf, HPDF_COMP_ALL); + + /* Draw composite page */ + draw_composite_view(pdf, font, pcb); + + /* Draw individual layers' pages */ + draw_layer_view(pdf, font, pcb); + + HPDF_SaveToFile (pdf, filename.c_str()); + } + catch (...) { + HPDF_Free (pdf); + return; + } + + HPDF_Free (pdf); + + return; +} +/* not truncated */ diff --git a/hyp2mat/lib/pdf.h b/hyp2mat/lib/pdf.h new file mode 100644 index 0000000..98d654e --- /dev/null +++ b/hyp2mat/lib/pdf.h @@ -0,0 +1,59 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#ifndef PDF_H +#define PDF_H + +#include +#include + +#include "palette.h" +#include "hyp2mat.h" + +class PDF: public Palette { +public: + PDF(); + void Write(const std::string& filename, Hyp2Mat::PCB& pcb); + +private: + Palette palette; + double x_max; /* board dimensions */ + double y_max; + double x_min; + double y_min; + double text_height; /* in points */ + double margin; /* in points */ + double m_to_points; /* convert meter to points */ + void set_page_size(HPDF_Page page); + void set_color(HPDF_Page page, int color_idx); + void set_color_black(HPDF_Page page); + void draw_composite_view(HPDF_Doc pdf, HPDF_Font font, Hyp2Mat::PCB& pcb); + void draw_layer_view(HPDF_Doc pdf, HPDF_Font font, Hyp2Mat::PCB& pcb); + void draw_caption(HPDF_Page page, HPDF_Font font, std::string txt); + void draw(HPDF_Page page, Hyp2Mat::FloatPolygons& polygons); /* output a polygon */ + void draw(HPDF_Page page, Hyp2Mat::FloatPolygon& polygon); /* output a polygon edge */ + void draw(HPDF_Page page, Hyp2Mat::Via& via); /* output a via */ + void page_fill(HPDF_Page page); /* fill */ + void page_stroke(HPDF_Page page); /* draw lines */ + }; + +#endif + +/* not truncated */ diff --git a/hyp2mat/lib/polygon.cc b/hyp2mat/lib/polygon.cc new file mode 100644 index 0000000..5d3d9d1 --- /dev/null +++ b/hyp2mat/lib/polygon.cc @@ -0,0 +1,335 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include +#include + +#include "polygon.h" + +using namespace Hyp2Mat; + +double Polygon::_grid = 10E-6; /* 10 micron */ +double Polygon::_arc_precision = 0.0; + +Polygon::Polygon() +{ + _filltype = ClipperLib::pftNonZero; // Use edge orientation to determine whether or not polygon edge is a hole. +} + +void Polygon::SetGrid(double new_grid) +{ + _grid = new_grid; +} + +void Polygon::SetArcPrecision(double new_arc_precision) +{ + _arc_precision = new_arc_precision; +} + +/* + * Align coordinates to grid + */ + +double Polygon::AlignToGrid(double x) +{ + return floor(x / _grid + 0.5) * _grid; +} + +/* + * Return true if polygon is empty + */ + +bool Polygon::IsEmpty() +{ + return _subject.empty(); +} + +/* + * Add an outer edge to the polygon + */ + +void Polygon::AddEdge(FloatPolygon edge) +{ + _AddEdge(edge, true); +} + +/* + * Add an inner edge to the polygon + */ + +void Polygon::AddHole(FloatPolygon hole) +{ + _AddEdge(hole, false); +} + +/* + * Add an edge - positive or negative - to the polygon + */ + +void Polygon::_AddEdge(FloatPolygon edge, bool orientation) +{ + + /* trivial case */ + if (edge.empty()) return; + + /* convert edge to Clipper polygon */ + ClipperLib::Polygon poly = _convert(edge); + + /* orient edge clockwise */ + if (!Orientation(poly) == orientation) ClipperLib::ReversePolygon(poly); + + /* Add to polygon */ + _subject.push_back(poly); + + return; +} + +/* + * convert from Hyp2Mat floating point point to Clipper long64 point + */ + +ClipperLib::IntPoint Polygon::_convert(FloatPoint p) +{ + return ClipperLib::IntPoint(floor(p.x / _grid + 0.5), floor(p.y / _grid + 0.5)); +} + +/* + * convert from Hyp2Mat floating point polygon to Clipper long64 polygon + */ + +ClipperLib::Polygon Polygon::_convert(FloatPolygon edge) +{ + ClipperLib::Polygon poly; + for (FloatPolygon::iterator i = edge.begin(); i != edge.end(); ++i) + poly.push_back(_convert(*i)); + + /* remove repeated vertices */ + poly = _unique(poly); + + return poly; +} + +/* + * Remove repeated vertices from a polygon + */ + +ClipperLib::Polygon Polygon::_unique(ClipperLib::Polygon p) +{ + ClipperLib::Polygon q = p; + q.clear(); + + if (p.empty()) return q; + + /* initial condition: add first vertex */ + q.push_back(p.front()); + + /* create list of non-repeating vertices */ + for (ClipperLib::Polygon::iterator i = p.begin(); i != p.end(); ++i) + if ((i->X != q.back().X) || (i->Y != q.back().Y)) q.push_back(*i); + + /* Remove last vertex if first and last vertex same */ + while ((q.size() > 1) && ((q.front().X == q.back().X) && (q.front().Y == q.back().Y))) + q.pop_back(); + + return q; +} + +/* + * Expand the polygon by a distance + */ + +void Polygon::Offset(double delta) +{ + ClipperLib::Polygons result; + double d = delta / _grid; + double limit = _arc_precision / _grid; + + if (delta == 0.0) return; + + if (_arc_precision == 0) + /* square corners */ + OffsetPolygons(_subject, result, d, ClipperLib::jtSquare); + else + /* round corners */ + OffsetPolygons(_subject, result, d, ClipperLib::jtRound, limit); + + _subject = result; + + return; +} + +/* + * Remove self-intersections + */ + +void Polygon::Simplify() +{ + ClipperLib::Polygons result; + ClipperLib::SimplifyPolygons(_subject, result, _filltype); + _subject = result; + +} + +/* + * Basic polygon operations + */ + +void Polygon::Intersection(Polygon clip) +{ + _Execute(ClipperLib::ctIntersection, clip); +} + +void Polygon::Union(Polygon clip) +{ + _Execute(ClipperLib::ctUnion, clip); +} + +void Polygon::Difference(Polygon clip) +{ + _Execute(ClipperLib::ctDifference, clip); +} + +void Polygon::Xor(Polygon clip) +{ + _Execute(ClipperLib::ctXor, clip); +} + +void Polygon::_Execute(ClipperLib::ClipType op, Polygon clip) +{ + ClipperLib::Polygons result; + ClipperLib::Clipper clipper; + + clipper.AddPolygons(_subject, ClipperLib::ptSubject); + clipper.AddPolygons(clip._subject, ClipperLib::ptClip); + + clipper.Execute(op, result, _filltype, _filltype); + _subject = result; + + return; +} + +/* + * Convert from Clipper long64 polygon to Hyp2Mat floating point polygon + */ + +FloatPolygons Polygon::Result() +{ + ClipperLib::Clipper clipper; + ClipperLib::PolyTree polytree; + + /* convert to PolyTree */ + clipper.AddPolygons(_subject, ClipperLib::ptSubject); + clipper.Execute(ClipperLib::ctUnion, polytree, _filltype, _filltype); + + /* recursively descend polytree, converting nodes */ + FloatPolygons result; + for (int i = 0; i < polytree.ChildCount(); ++i) + _AddToPolygonList(*polytree.Childs[i], result, 0); + + return result; +} + +void Polygon::_AddToPolygonList(ClipperLib::PolyNode& polynode, FloatPolygons& polygons, int level) +{ + FloatPoly outer_edge; + + outer_edge.poly = _convert(polynode.Contour); + outer_edge.is_hole = !ClipperLib::Orientation(polynode.Contour); + outer_edge.nesting_level = level; + /* make outer edges of polygon clockwise; holes counterclockwise. XXX is this superfluous? */ + if (outer_edge.is_hole == IsClockwise(outer_edge.poly)) Reverse(outer_edge.poly); + + polygons.push_back(outer_edge); + + for (int i = 0; i < polynode.ChildCount(); ++i) { + FloatPoly inner_edge; + inner_edge.poly = _convert(polynode.Childs[i]->Contour); + inner_edge.is_hole = !ClipperLib::Orientation(polynode.Childs[i]->Contour); + inner_edge.nesting_level = level + 1; + /* make outer edges of polygon clockwise; holes counterclockwise. XXX is this superfluous? */ + if (inner_edge.is_hole == IsClockwise(inner_edge.poly)) Reverse(inner_edge.poly); + polygons.push_back(inner_edge); + } + + /* Add outer polygons nested within holes */ + for (int i = 0; i < polynode.ChildCount(); ++i) + for (int j = 0; j < polynode.Childs[i]->ChildCount(); ++j) + _AddToPolygonList(*polynode.Childs[i]->Childs[j], polygons, level + 2); + + return; +} + + /* + * Convert edge back from ClipperLib to Hyp2Mat + */ + +FloatPolygon Polygon::_convert (ClipperLib::Polygon clip_poly) +{ + FloatPolygon edge; + + for (ClipperLib::Polygon::iterator i = clip_poly.begin(); i != clip_poly.end(); ++i) + edge.push_back(_convert(*i)); + + return edge; +} + + /* + * Convert point back from ClipperLib to Hyp2Mat + */ + +FloatPoint Polygon::_convert (ClipperLib::IntPoint p) +{ + return FloatPoint(p.X * _grid, p.Y * _grid); +} + +/* + * Calculate if a polygon is clockwise or not. + */ + +bool Hyp2Mat::IsClockwise(FloatPolygon& poly) { + + /* calculate area of polygon */ + double area = 0; + for (FloatPolygon::iterator i = poly.begin(); i != poly.end(); ++i) { + /* i points to current element; j points to next element */ + FloatPolygon::iterator j = i; + ++j; + /* polygon is closed */ + if (j == poly.end()) j = poly.begin(); + area += i->x * j->y - j->x * i->y; + } + + /* positive area is clockwise. Arbitrarily choose clockwise if area 0 */ + return area >= 0; + +} + +/* + * Reverse order of vertices. + */ + +void Hyp2Mat::Reverse(FloatPolygon& poly) +{ + std::reverse(poly.begin(), poly.end()); +} + + +/* not truncated */ diff --git a/hyp2mat/lib/polygon.h b/hyp2mat/lib/polygon.h new file mode 100644 index 0000000..3df23ef --- /dev/null +++ b/hyp2mat/lib/polygon.h @@ -0,0 +1,74 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#ifndef POLYGON_H +#define POLYGON_H + +#include "clipper.hpp" +#include "hyp2mat.h" + +namespace Hyp2Mat { + + bool IsClockwise (FloatPolygon& poly); + void Reverse (FloatPolygon& poly); + + class Polygon { + public: + Polygon(); + static void SetGrid(double new_grid); + static double AlignToGrid(double x); + static void SetArcPrecision(double new_arc_precision); + void AddEdge(FloatPolygon edge); + void AddHole(FloatPolygon hole); + void Offset(double delta); + void Simplify(); + void Intersection(Polygon clip); + void Union(Polygon clip); + void Difference(Polygon clip); + void Xor(Polygon clip); + bool IsEmpty(); + FloatPolygons Result(); + private: + /* convert Hyp2Mat to Clipper */ + void _AddEdge(FloatPolygon edge, bool orientation); + ClipperLib::IntPoint _convert(FloatPoint p); + ClipperLib::Polygon _convert(FloatPolygon edge); + ClipperLib::Polygon _unique(ClipperLib::Polygon p); + + /* Clipper polygon operations */ + void _Execute(ClipperLib::ClipType op, Polygon clip); + ClipperLib::PolyFillType _filltype; + + /* convert Clipper to Hyp2Mat */ + void _AddToPolygonList(ClipperLib::PolyNode& polynode, FloatPolygons& polygons, int level); + FloatPolygon _convert (ClipperLib::Polygon clip_poly); + FloatPoint _convert (ClipperLib::IntPoint p); + + /* data */ + ClipperLib::Polygons _subject; + static double _grid; /* resolution of x and y coordinates, identical for all polygons. */ + static double _arc_precision; /* maximum difference between perfect circle arc and polygonal approximation */ + }; + +}; + +#endif + +/* not truncated */ diff --git a/hyp2mat/lib/scan.ll b/hyp2mat/lib/scan.ll new file mode 100644 index 0000000..3e07902 --- /dev/null +++ b/hyp2mat/lib/scan.ll @@ -0,0 +1,371 @@ + +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +%option noyywrap nodefault yylineno debug + +%{ +#include +#include "parse.h" +#include "parser.h" + +/* copy a string between quotes */ +char *strunquote(const char *); + +/* remember hyperlynx file section we're in */ +int section = -1; + +%} + + /* + * The scanner knows five states: INITIAL, STATE_STRING, STATE_POSINT, STATE_FLOAT and STATE_COMMENT + * + * In state INITIAL the scanner recognizes: + * - punctuation (such as {}()=, ) + * - keywords (such as VERSION, BOARD, NET), + * - strings (both between double quotes " and unquoted), + * - and floating point numbers (with optional suffix, eg. 10 uF), + * + * In STATE_STRING the scanner recognizes punctuation and strings only. + * This avoids unquoted strings being interpreted as numbers, or keywords. + * + * In STATE_POSINT the scanner recognizes a positive integer. + * + * In STATE_FLOAT the scanner recognizes a floating point number (without suffix). + * + * In STATE_COMMENT the scanner discards all text up to the next + * right brace } , and then continues in state INITIAL. + * + */ + +%x STATE_STRING STATE_POSINT STATE_FLOAT STATE_COMMENT STATE_COMMENT_EOL + + /* whitespace: space, tab, vertical tab, form feed */ +WS [ \t\v\f] + + /* accept windows and unix newlines */ +NEWLINE [\r\n]+ + + /* + * lines with an asterisk in the first column are comments + */ +COMMENT ^\*[^\n\r]*[\n\r]+ + + /* Left-hand side of an assignment: check whether next token is equals sign */ +LHS [ \t\v\f]*"=" + + /* + * Positive integer + */ + +POSINT [0-9]+ + + /* + * Floating point numbers + */ + + /* ordinary floating point numbers */ +SIMPLE_FLOAT [-+]?([0-9]+"."[0-9]*|"."?[0-9]+)([Ee][-+]?[0-9]+)? + + /* floating point numbers with suffix, e,g. pF, nH */ +FLOAT_SUFFIX [A-Za-z]*{WS}+ +FLOAT_YOTTA {SIMPLE_FLOAT}{WS}*"Y"{FLOAT_SUFFIX} +FLOAT_ZETA {SIMPLE_FLOAT}{WS}*"Z"{FLOAT_SUFFIX} +FLOAT_EXA {SIMPLE_FLOAT}{WS}*"E"{FLOAT_SUFFIX} +FLOAT_PETA {SIMPLE_FLOAT}{WS}*"P"{FLOAT_SUFFIX} +FLOAT_TERA {SIMPLE_FLOAT}{WS}*"T"{FLOAT_SUFFIX} +FLOAT_GIGA {SIMPLE_FLOAT}{WS}*"G"{FLOAT_SUFFIX} +FLOAT_MEGA {SIMPLE_FLOAT}{WS}*"M"{FLOAT_SUFFIX} +FLOAT_KILO {SIMPLE_FLOAT}{WS}*[Kk]{FLOAT_SUFFIX} +FLOAT_MILLI {SIMPLE_FLOAT}{WS}*"m"{FLOAT_SUFFIX} +FLOAT_MICRO {SIMPLE_FLOAT}{WS}*[uU]{FLOAT_SUFFIX} +FLOAT_NANO {SIMPLE_FLOAT}{WS}*[nN]{FLOAT_SUFFIX} +FLOAT_PICO {SIMPLE_FLOAT}{WS}*[pP]{FLOAT_SUFFIX} +FLOAT_FEMTO {SIMPLE_FLOAT}{WS}*[fF]{FLOAT_SUFFIX} +FLOAT_ATTO {SIMPLE_FLOAT}{WS}*"a"{FLOAT_SUFFIX} +FLOAT_ZEPTO {SIMPLE_FLOAT}{WS}*"z"{FLOAT_SUFFIX} +FLOAT_YOCTO {SIMPLE_FLOAT}{WS}*"y"{FLOAT_SUFFIX} + + /* + * Strings + */ + + /* an unquoted string */ +STRING [^ \t\v\f\r\n\{\}\(\)=\"]+ + + /* a string enclosed in double quotes " */ +QUOTED_STRING \"([^\"\n]|\"\")*\" + +%% + + /* When in STATE_COMMENT skip all comment until next right brace */ +{ +[^\}]* { BEGIN INITIAL; /* skip all comment until next right brace */ } +} + + /* When in STATE_COMMENT_EOL skip all comment until end-of-line */ +{ +[^\r\n]*{NEWLINE}+ { BEGIN INITIAL; /* skip all comment until next end-of-line */ } +} + + + /* skip comments and whitespace */ +<*>{ + + {COMMENT} { /* skip comments */ } + + {WS}+ { /* skip whitespace */ } + + {NEWLINE}+ { /* skip newlines */ } + +} + + /* + * Hyperlynx keywords + */ + + /* Sections */ + +"BOARD_FILE" {section = BOARD_FILE; return BOARD_FILE;} +"VERSION" {section = VERSION; return VERSION;} +"DATA_MODE" {section = DATA_MODE; return DATA_MODE;} +"UNITS" {section = UNITS; return UNITS;} +"PLANE_SEP" {section = PLANE_SEP; return PLANE_SEP;} +"BOARD" {section = BOARD; BEGIN STATE_COMMENT_EOL; return BOARD;} +"STACKUP" {section = STACKUP; BEGIN STATE_COMMENT_EOL; return STACKUP;} +"DEVICES" {section = DEVICES; BEGIN STATE_COMMENT_EOL; return DEVICES;} +"SUPPLIES" {section = SUPPLIES; BEGIN STATE_COMMENT_EOL; return SUPPLIES;} +"PADSTACK" {section = PADSTACK; BEGIN STATE_STRING; return PADSTACK;} +"NET" {section = NET; BEGIN STATE_STRING; return NET;} +"NET_CLASS" {section = NET_CLASS; return NET_CLASS;} +"END" {section = END; return END;} +"KEY" {section = KEY; return KEY;} + + /* Keywords */ + +"A" {return A;} +"ARC" {return ARC;} +"COPPER" {return COPPER;} +"CURVE" {return CURVE;} +"DETAILED" {if (section == DATA_MODE) BEGIN STATE_COMMENT; return DETAILED;} +"DIELECTRIC" {return DIELECTRIC;} +"ENGLISH" {return ENGLISH;} +"LENGTH" {if (section == UNITS) BEGIN STATE_COMMENT; return LENGTH;} +"LINE" {return LINE;} +"METRIC" {return METRIC;} +"M" {return M;} +"N" {return N;} +"OPTIONS" {return OPTIONS;} +"PAD" {return PAD;} +"PERIMETER_ARC" {return PERIMETER_ARC;} +"PERIMETER_SEGMENT" {return PERIMETER_SEGMENT;} +"PIN" {return PIN;} +"PLANE" {return PLANE;} +"POLYGON" {return POLYGON;} +"POLYLINE" {return POLYLINE;} +"POLYVOID" {return POLYVOID;} +"POUR" {return POUR;} +"S" {return S;} +"T" {return T;} +"SEG" {return SEG;} +"SIGNAL" {return SIGNAL;} +"SIMPLIFIED" {if (section == DATA_MODE) BEGIN STATE_COMMENT; return SIMPLIFIED; } +"SIM_BOTH" {return SIM_BOTH;} +"SIM_IN" {return SIM_IN;} +"SIM_OUT" {return SIM_OUT;} +"USEG" {return USEG;} +"VIA" {return VIA;} +"WEIGHT" {if (section == UNITS) BEGIN STATE_COMMENT; return WEIGHT;} + + /* Assignments */ + +"A"/{LHS} {return A;} +"A1"/{LHS} {return A1;} +"A2"/{LHS} {return A2;} +"BR"/{LHS} {return BR;} +"C"/{LHS} {return C;} +"C?"/{LHS} {return C_QM;} +"CO?"/{LHS} {return CO_QM;} +"D"/{LHS} {return D;} +"ER"/{LHS} {return ER;} +"F"/{LHS} {return F;} +"ID"/{LHS} {BEGIN STATE_POSINT; return ID;} +"L"/{LHS} {BEGIN STATE_STRING; return L;} +"L1"/{LHS} {BEGIN STATE_STRING; return L1;} +"L2"/{LHS} {BEGIN STATE_STRING; return L2;} +"LPS"/{LHS} {return LPS;} +"LT"/{LHS} {return LT;} +"M"/{LHS} {BEGIN STATE_STRING; return M;} +"N"/{LHS} {BEGIN STATE_STRING; return N;} +"NAME"/{LHS} {BEGIN STATE_STRING; return NAME;} + /* P is used as "plating thickness" in "stackup/signal" and as "padstack" in "net/via" */ +"P"/{LHS} {if (section == NET) BEGIN STATE_STRING; return P;} +"PKG"/{LHS} {BEGIN STATE_STRING; return PKG;} +"PR?"/{LHS} {return PR_QM;} +"PS"/{LHS} {return PS;} +"R"/{LHS} {return R;} +"REF"/{LHS} {BEGIN STATE_STRING; return REF;} +"S"/{LHS} {BEGIN STATE_STRING; return S;} +"SX"/{LHS} {return SX;} +"SY"/{LHS} {return SY;} +"S1"/{LHS} {BEGIN STATE_STRING; return S1;} +"S1X"/{LHS} {return S1X;} +"S1Y"/{LHS} {return S1Y;} +"S2"/{LHS} {BEGIN STATE_STRING; return S2;} +"S2X"/{LHS} {return S2X;} +"S2Y"/{LHS} {return S2Y;} +"T"/{LHS} {return T;} +"TC"/{LHS} {return TC;} +"USE_DIE_FOR_METAL"/{LHS} {return USE_DIE_FOR_METAL;} +"V"/{LHS} {BEGIN STATE_STRING; return V;} +"V?"/{LHS} {return V_QM;} +"VAL"/{LHS} {return VAL;} +"W"/{LHS} {return W;} +"X"/{LHS} {return X;} +"X1"/{LHS} {return X1;} +"X2"/{LHS} {return X2;} +"XC"/{LHS} {return XC;} +"Y"/{LHS} {return Y;} +"Y1"/{LHS} {return Y1;} +"Y2"/{LHS} {return Y2;} +"YC"/{LHS} {return YC;} +"Z"/{LHS} {return Z;} +"ZL"/{LHS} {return ZL;} +"ZLEN"/{LHS} {return ZLEN;} +"ZW"/{LHS} {return ZW;} + + /* Booleans */ + +"YES"|"yes" {yylval.boolval = 1; return BOOL; } +"NO"|"no" {yylval.boolval = 0; return BOOL; } + + /* Floats */ + + /* ordinary floating point numbers */ +{SIMPLE_FLOAT} {yylval.floatval = strtod(yytext, NULL); return FLOAT;} + + /* floating point numbers with suffix, e,g. pF, nH */ +{FLOAT_YOTTA} {yylval.floatval = strtod(yytext, NULL) * 1e24; return FLOAT;} +{FLOAT_ZETA} {yylval.floatval = strtod(yytext, NULL) * 1e21; return FLOAT;} +{FLOAT_EXA} {yylval.floatval = strtod(yytext, NULL) * 1e18; return FLOAT;} +{FLOAT_PETA} {yylval.floatval = strtod(yytext, NULL) * 1e15; return FLOAT;} +{FLOAT_TERA} {yylval.floatval = strtod(yytext, NULL) * 1e12; return FLOAT;} +{FLOAT_GIGA} {yylval.floatval = strtod(yytext, NULL) * 1e9; return FLOAT;} +{FLOAT_MEGA} {yylval.floatval = strtod(yytext, NULL) * 1e6; return FLOAT;} +{FLOAT_KILO} {yylval.floatval = strtod(yytext, NULL) * 1e3; return FLOAT;} +{FLOAT_MILLI} {yylval.floatval = strtod(yytext, NULL) * 1e-3; return FLOAT;} +{FLOAT_MICRO} {yylval.floatval = strtod(yytext, NULL) * 1e-6; return FLOAT;} +{FLOAT_NANO} {yylval.floatval = strtod(yytext, NULL) * 1e-9; return FLOAT;} +{FLOAT_PICO} {yylval.floatval = strtod(yytext, NULL) * 1e-12; return FLOAT;} +{FLOAT_FEMTO} {yylval.floatval = strtod(yytext, NULL) * 1e-15; return FLOAT;} +{FLOAT_ATTO} {yylval.floatval = strtod(yytext, NULL) * 1e-18; return FLOAT;} +{FLOAT_ZEPTO} {yylval.floatval = strtod(yytext, NULL) * 1e-21; return FLOAT;} +{FLOAT_YOCTO} {yylval.floatval = strtod(yytext, NULL) * 1e-24; return FLOAT;} + + /* floating point numbers in VERSION and PLANE_SEP have no suffix and are followed by optional comments */ +{ +{SIMPLE_FLOAT} {yylval.floatval = strtod(yytext, NULL); BEGIN STATE_COMMENT; return FLOAT;} +} + + /* A positive integer is used only in polygon/polyline/polyvoid "ID = posint" */ +{ +{POSINT} { BEGIN INITIAL; yylval.intval = atoi(yytext); return POSINT; } +} + + + /* + * This is a workaround for syntactically incorrect .hyp files. + * We accept the following constructs as representing an empty string: + * NAME= L1=somelayer + * NAME= ) + * NAME= } + */ +{ +([A-Z][A-Z1-2_]*{WS}*"="|")"|"}") { yyless(0); BEGIN INITIAL; yylval.strval = strdup(""); return STRING; } /* emit empty string and reprocess */ +} + +<*>{ + + "{" {return '{';} + + "}" {BEGIN STATE_COMMENT_EOL; return '}';} + + "(" {if (section == PADSTACK) BEGIN STATE_STRING; return '(';} + + /* allow for comment after the closing bracket ) */ + ")" {BEGIN STATE_COMMENT_EOL; return ')';} + + "," {return ',';} + + "=" {if ((section == VERSION) || (section == PLANE_SEP)) BEGIN STATE_FLOAT; return '=';} + + /* string */ + {STRING} { + /* + * Commas are not allowed in strings in the padstack section + * unless the string is enclosed in double quotes ("). + */ + + if ((section == PADSTACK) && strchr(yytext, ',')) + REJECT + else + { + BEGIN INITIAL; + yylval.strval = strdup(yytext); + return STRING; + } + } + + /* string in double quotes */ + {QUOTED_STRING} {BEGIN INITIAL; yylval.strval = strunquote(yytext); return STRING;} + + <> {yyterminate();} + + /* have bison catch all unrecognized characters with parse errors */ + . {return yytext[0];} + +} + +%% + + /* + * copy a quoted string. + * e.g. "data 0" -> data 0 + * a double quote inside the string can be escaped by writing two consecutive double quotes + * e.g. "net ""hi""" -> net "hi" + */ + + char *strunquote(const char *src) + { + char* dst; + size_t len = strlen(src) + 1; + dst = (char *)malloc(len); + if (dst != NULL) + { + char* p = (char *)src + 1; /* first char after initial quote */ + char* q = dst; + do + if (*p == '"') p++; + while ((*q++ = *p++) != '\0'); + } + return dst; + } + + /* not truncated */ diff --git a/hyp2mat/makewin32 b/hyp2mat/makewin32 new file mode 100755 index 0000000..2b659b6 --- /dev/null +++ b/hyp2mat/makewin32 @@ -0,0 +1,23 @@ +#!/bin/sh -x +# +# Script to build win32 binary - run in MinGW. +# Requires libhpdf. +# +HYPDIR=~/hyp2mat +BUILDDIR=~/build-w32 +INSTDIR=~/install-w32 +rm -rf $BUILDDIR $INSTDIR +mkdir $BUILDDIR +cd $BUILDDIR +CPPFLAGS=-I/usr/include LDFLAGS="-static -static-libgcc -static-libstdc++ -L/usr/lib" $HYPDIR/configure --prefix=$INSTDIR +make install +cp $HYPDIR/COPYING $INSTDIR/share/hyp2mat +cp $INSTDIR/bin/hyp2mat $INSTDIR/share/hyp2mat +# posix pthreads dll (win-builds.org) +if [ -f /opt/windows_32/bin/libwinpthread-1.dll ] +then + cp /opt/windows_32/bin/libwinpthread-1.dll $INSTDIR/share/hyp2mat +fi +cd $INSTDIR/share/ +zip -9 -r $BUILDDIR/hyp2mat-win32-current.zip ./hyp2mat +#not truncated diff --git a/hyp2mat/matlab/AddHyperLynxComponent.m b/hyp2mat/matlab/AddHyperLynxComponent.m new file mode 100644 index 0000000..385d964 --- /dev/null +++ b/hyp2mat/matlab/AddHyperLynxComponent.m @@ -0,0 +1,99 @@ +function CSX = AddHyperLynxComponent(CSX, name, prio, port1, port2, varargin) +% function CSX = AddHyperLynxComponent(CSX, name, prio, port1, port2, varargin) +% +% Add a resistor, capacitor or inductance to a CSX model imported from HyperLynx. +% Component layout is limited to x or y direction, and top or bottom layers of pcb. +% +% arguments: +% name: component name. +% prio: component priority. +% port1: component pad name. +% port2: component pad name. +% +% optional arguments: +% 'R', 'C', 'L': definition of the lumped element properties +% +% examples: +% 50R resistor between pads R1.1 and R1.2 with 1pF parasitic capacitance: +% CSX = AddHyperLynxComponent( CSX, 'R1', 'R1.1', 'R1.2', 'R', 50, 'C', 1e-12 ); +% +% See also GetHyperLynxPort, AddLumpedElement +% + +% Copyright 2012 Koen De Vleeschauwer. +% +% This file is part of hyp2mat. +% +% 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 . + +% Check CSX contains HyperLynx port list. + + if (~isfield(CSX, 'HyperLynxPort')) + error('CSX not created by ImportHyperLynx()'); + end + +% Get pad coordinates pad_start and pad_stop. pad position is either 'top' or 'bottom'. + +[position1, pad1_start, pad1_stop] = GetHyperLynxPort(CSX, port1); +[position2, pad2_start, pad2_stop] = GetHyperLynxPort(CSX, port2); + +% Determine component orientation +pad1c=(pad1_start+pad1_stop)/2; +pad2c=(pad2_start+pad2_stop)/2; +v=pad2c-pad1c; +theta=atan2(v(2), v(1)); % theta between -pi and pi. +delta=pi/12; % allow 15 degree play +vertical=abs((abs(theta) - pi/2)) < delta % true if component has vertical orientation +horizontal=(abs(theta) < delta) || ((pi - abs(theta)) < delta) % true if component has horizontal orientation + +% layout component +if (vertical) + % layout component in y-direction + comp_height = abs(pad1_stop(2) - pad1_start(2)); + comp_start = [pad1_start(1), (pad1_start(2)+pad1_stop(2))/2, pad1_start(3)]; + comp_stop = [pad2_stop(1), (pad2_start(2)+pad2_stop(2))/2, pad2_stop(3)]; + direction = 1; +elseif (horizontal) + % layout component in x-direction + comp_height = abs(pad1_stop(1) - pad1_start(1)); + comp_start = [(pad1_start(1)+pad1_stop(1))/2, pad1_start(2), pad1_start(3)]; + comp_stop = [(pad2_start(1)+pad2_stop(1))/2, pad2_stop(2), pad2_stop(3)]; + direction = 0; +else + % arbitrary angles not implemented yet + error ('component orientation has to be 0 or 90 degrees'); +end + +% Component position has to be 'top' or 'bottom'. +% Check both pads are on the same side of the board +if (~strcmp(position1, position2)) + error('component pads not on same side of board'); +end + +if (strcmp(position1, 'top')) + % component mounted on top of board + comp_stop = comp_stop + [ 0, 0, comp_height]; +elseif (strcmp(position1, 'bottom')) + comp_stop = comp_stop - [ 0, 0, comp_height]; +else + error('component pads not on top or bottom side of board'); +end + +% Add component material to CSX model +CSX = AddLumpedElement( CSX, name, direction, 'Caps', 1, varargin{:}); + +% Add component to CSX model +CSX = AddBox( CSX, name, prio, comp_start, comp_stop ); + +% not truncated diff --git a/hyp2mat/matlab/AddHyperLynxDielectric.m b/hyp2mat/matlab/AddHyperLynxDielectric.m new file mode 100644 index 0000000..c4553b0 --- /dev/null +++ b/hyp2mat/matlab/AddHyperLynxDielectric.m @@ -0,0 +1,44 @@ +function CSX = AddHyperLynxDielectric(CSX, name, epsilon, loss_tangent) +% function CSX = AddHyperLynxDielectric(CSX, name, epsilon, loss_tangent) +% +% Add a dielectric to a CSX model imported from HyperLynx. +% +% arguments: +% name: material name. +% epsilon: relative electric permittivity +% loss_tangent: loss tangent +% +% See also AddMaterial, AddDebyeMaterial, AddLorentzMaterial +% + +% Copyright 2014 Koen De Vleeschauwer. +% +% This file is part of hyp2mat. +% +% 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 . + +% Copy this script to your project directory to customize. +% For a discussion of the parameters, see http://openems.de/index.php/Dispersive_Material_Property + +% Default substrate is a lossless dielectric. +CSX = AddMaterial( CSX, name); +CSX = SetMaterialProperty( CSX, name, 'Epsilon', epsilon, 'Mue', 1 ); +%CSX = SetMaterialProperty( CSX, name, 'Kappa', kappa); % optional conductivity + +% Drude material +%CSX = AddLorentzMaterial(CSX, name); +%CSX = SetMaterialProperty(CSX, name, 'Epsilon', epsilon, 'Kappa', kappa); +%CSX = SetMaterialProperty(CSX, name, 'EpsilonPlasmaFrequency', 5e9, 'EpsilonRelaxTime', 5e-9); + +% not truncated diff --git a/hyp2mat/matlab/AddHyperLynxMetal2D.m b/hyp2mat/matlab/AddHyperLynxMetal2D.m new file mode 100644 index 0000000..d0d908a --- /dev/null +++ b/hyp2mat/matlab/AddHyperLynxMetal2D.m @@ -0,0 +1,40 @@ +function CSX = AddHyperLynxMetal2D(CSX, name, resistivity, thickness) +% function CSX = AddHyperLynxMetal2D(CSX, name, resistivity, thickness) +% +% Add a metal as a 2D conducting sheet to a CSX model imported from HyperLynx. +% +% arguments: +% name: material name. +% resistivity: metal resistivity +% thickness: thickness of the metal layer, in m. +% +% See also AddMaterial, AddDebyeMaterial, AddLorentzMaterial +% + +% Copyright 2014 Koen De Vleeschauwer. +% +% This file is part of hyp2mat. +% +% 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 . + +% Copy this script to your project directory to customize. + +if (resistivity > 0.0) + conductivity = 1.0 / resistivity; + CSX = AddConductingSheet(CSX, name, conductivity, thickness); % lossy conductor +else + CSX = AddMetal(CSX, name); % perfect conductor +end + +% not truncated diff --git a/hyp2mat/matlab/AddHyperLynxMetal3D.m b/hyp2mat/matlab/AddHyperLynxMetal3D.m new file mode 100644 index 0000000..00c95b4 --- /dev/null +++ b/hyp2mat/matlab/AddHyperLynxMetal3D.m @@ -0,0 +1,43 @@ +function CSX = AddHyperLynxMetal3D(CSX, name, resistivity, thickness) +% function CSX = AddHyperLynxMetal3D(CSX, name, resistivity, thickness) +% +% Add a metal as a 3D object to a CSX model imported from HyperLynx. +% +% arguments: +% name: material name. +% resistivity: metal resistivity +% thickness: thickness of the metal layer, in m. +% +% See also AddMaterial, AddDebyeMaterial, AddLorentzMaterial +% + +% Copyright 2014 Koen De Vleeschauwer. +% +% This file is part of hyp2mat. +% +% 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 . + +% Copy this script to your project directory to customize. + +disp('Using 3D metal: slow convergence.'); + +if (resistivity > 0.0) + conductivity = 1.0 / resistivity; + CSX = AddMaterial( CSX, name); + CSX = SetMaterialProperty( CSX, name, 'Kappa', conductivity); % lossy conductor +else + CSX = AddMetal(CSX, name); % perfect conductor +end + +% not truncated diff --git a/hyp2mat/matlab/Contents.m b/hyp2mat/matlab/Contents.m new file mode 100644 index 0000000..40048a6 --- /dev/null +++ b/hyp2mat/matlab/Contents.m @@ -0,0 +1,10 @@ +% Imports Hyperlynx Signal-Integrity Transfer Format files into CSXCAD/openEMS. +% +% ImportHyperLynx.m Import Hyperlynx file into CSX model. +% GetHyperLynxPort.m Obtain coordinates of HyperLynx pin or pad. +% AddHyperLynxComponent.m Add a resistor, capacitor or inductance to a CSX model imported from HyperLynx. +% AddHyperLynxDielectric.m Add a dielectric to a CSX model imported from HyperLynx. +% AddHyperLynxMetal2D.m Add a metal as a 2D conducting sheet to a CSX model imported from HyperLynx. +% AddHyperLynxMetal3D.m Add a metal as a 3D object to a CSX model imported from HyperLynx. +% + diff --git a/hyp2mat/matlab/GetHyperLynxPort.m b/hyp2mat/matlab/GetHyperLynxPort.m new file mode 100644 index 0000000..2e62cf0 --- /dev/null +++ b/hyp2mat/matlab/GetHyperLynxPort.m @@ -0,0 +1,84 @@ +% [side, start, stop, centre ] = GetHyperLynxPort(CSX, port_ref) +% Obtain coordinates of HyperLynx pin or pad. +% +% CSX: CSX-object created by ImportHyperLynx() +% port_ref: port reference from HyperLynx file. +% If an invalid port reference is given, all valid port references are printed. +% +% side: board side, 'top', 'bottom' or ''. +% start: 3D port start coordinates +% stop: 3D port stop coordinates +% centre: 3D port centre coordinates + +% Example: +% place an excitation at pin 1 of component 'CON1': +% CSX = AddMaterial(CSX, 'PEC'); +% [port_material, port_start, port_stop] = GetHyperLynxPort(CSX, 'CON1.1'); +% [CSX,portstruct] = AddMSLPort( CSX, 999, 1, 'PEC', port_start, port_stop, 0, [0 0 -1], 'ExcitePort', 'excite'); +% +% See hyp2mat(1) - convert hyperlynx files to matlab scripts. + +% Copyright 2012 Koen De Vleeschauwer. +% +% This file is part of hyp2mat. +% +% 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 . + +function [side, start, stop, centre] = GetHyperLynxPort(CSX, port_ref) + + % the openEMS AddMSLPort, AddCurvePort functions require a port to be + % a rectangular prism with sides parallel to the axis, + % which is what this function returns. + + % Check CSX contains HyperLynx port list. + if (~isfield(CSX, 'HyperLynxPort')) + error('CSX not created by ImportHyperLynx()'); + end + + % find port + port_found = 0; + for i = 1:length(CSX.HyperLynxPort) + if (~port_found && strcmp(port_ref, CSX.HyperLynxPort{i}.ref)) + port_found = 1; + port = CSX.HyperLynxPort{i}; + port_index = i; + end + end + + % exit if port not found + if (~port_found) + % display valid port names + portnames = {}; + for i = 1:length(CSX.HyperLynxPort) + portnames(end+1) = CSX.HyperLynxPort{i}.ref; + end + portnames = sort(portnames); + fprintf('Valid ports:'); + for i = 1:length(portnames) + fprintf(' %s', portnames{i}); + end + fprintf('\n'); + % exit with error message + error(['port not found: ' port_ref ]); + end + + % return values + side = port.position; + start = [ port.x1 port.y1 port.z ]; + stop = [ port.x2 port.y2 port.z ]; + centre = [ port.xc port.yc port.z ]; + +end + +% not truncated diff --git a/hyp2mat/matlab/ImportHyperLynx.m b/hyp2mat/matlab/ImportHyperLynx.m new file mode 100644 index 0000000..305a199 --- /dev/null +++ b/hyp2mat/matlab/ImportHyperLynx.m @@ -0,0 +1,196 @@ +% CSX = ImportHyperLynx(CSX, filename, varargin) +% load Hyperlynx file 'filename' into CSX . +% +% Other optional arguments: +% epsilonr float. Set dielectric epsilon r. Overrides value in Hyperlynx file. +% net string. Import net. Repeat to import several nets. Default is importing all nets. +% layer string. Import layer. Repeat to import several layers. Default is importing all layers. +% epsilonr float. Set dielectric epsilon r. +% xmin float. Crop pcb. Set lower bound of x coordinate. +% xmax float. Crop pcb. Set higher bound of x coordinate. +% ymin float. Crop pcb. Set lower bound of y coordinate. +% ymax float. Crop pcb. Set higher bound of y coordinate. +% zmin float. Crop pcb. Set lower bound of z coordinate. +% zmax float. Crop pcb. Set higher bound of z coordinate. +% grid float. Set output grid size. (default = 10e-6 = 1 um) +% arc-precision float. Set maximum difference between perfect arc and polygonal approximation. +% clearance float. Set trace-to-plane clearance. (default = 0.0002) +% flood string. Flood layer with copper. Repeat to flood several layers. The value "plane_layers" floods all plane layers. +% pcb-outline none. Detailed board outline. +% lossy-copper none. Model copper as lossy. Default is modeling copper as a perfect conductor. +% metal-3d none. Model copper as a 3D object. Default is modeling copper as a 2D sheet. +% version none. Print hyp2mat version number. +% +% ImportHyperLynx needs read and write access to the current directory. +% +% Examples: +% CSX = ImportHyperLynx(CSX, 'board.hyp' ) +% will import the complete Hyperlynx file 'board.hyp' into the struct CSX. +% +% CSX = ImportHyperLynx(CSX, 'board.hyp', 'net', 'CLK_P' ) +% will import only the CLK_P net from the Hyperlynx file 'board.hyp' into the struct CSX. +% +% CSX = ImportHyperLynx(CSX, 'board.hyp', 'net', '?' ) +% lists all available nets. +% +% CSX = ImportHyperLynx(CSX, 'board.hyp', 'net', 'GND', 'net', 'CLK_P', 'net', 'CLK_N' ) +% will import only the GND, CLK_P and CLK_N nets. +% +% CSX = ImportHyperLynx(CSX, 'board.hyp', 'xmin', 0.02, 'xmax', 0.03, 'ymin', 0.04, 'ymax', 0.05 ) +% Imports all nets, and crops the board to the region 2 cm < x < 3 cm, 4 cm < y < 5 cm. +% +% See hyp2mat(1) - convert hyperlynx files to matlab scripts. + +% Copyright 2012 Koen De Vleeschauwer. +% +% This file is part of hyp2mat. +% +% 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 . + +function CSX = ImportHyperLynx(CSX, filename, varargin) + + % determine nets to import + if (nargin < 2) + error('Wrong number of arguments'); + end + + if (~isstruct(CSX)) + error ('expecting CSX struct as first argument'); + end + + if (~ischar(filename)) + error ('expecting filename string as second argument'); + end + + % build command line + cmdargs = ''; + + % parse optional arguments + if (nargin < 3) + varargin = {}; + end + + vn = 1; + while (vn <= numel(varargin)) + if (strcmpi(varargin{vn}, 'net')) + vn = vn + 1; + cmdargs = [ cmdargs ' --net ''' varargin{vn} '''' ]; + end + if (strcmpi(varargin{vn}, 'layer')) + vn = vn + 1; + cmdargs = [ cmdargs ' --layer ''' varargin{vn} '''' ]; + end + if (strcmpi(varargin{vn}, 'xmin')) + vn = vn + 1; + cmdargs = [ cmdargs ' --xmin ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'xmax')) + vn = vn + 1; + cmdargs = [ cmdargs ' --xmax ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'ymin')) + vn = vn + 1; + cmdargs = [ cmdargs ' --ymin ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'ymax')) + vn = vn + 1; + cmdargs = [ cmdargs ' --ymax ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'zmin')) + vn = vn + 1; + cmdargs = [ cmdargs ' --zmin ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'zmax')) + vn = vn + 1; + cmdargs = [ cmdargs ' --zmax ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'grid')) + vn = vn + 1; + cmdargs = [ cmdargs ' --grid ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'arc-precision')) + vn = vn + 1; + cmdargs = [ cmdargs ' --arc-precision ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'clearance')) + vn = vn + 1; + cmdargs = [ cmdargs ' --clearance ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'flood')) + vn = vn + 1; + cmdargs = [ cmdargs ' --flood ''' varargin{vn} '''' ]; + end + if (strcmpi(varargin{vn}, 'epsilonr')) + vn = vn + 1; + cmdargs = [ cmdargs ' --epsilonr ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'bulk-resistivity')) + vn = vn + 1; + cmdargs = [ cmdargs ' --bulk-resistivity ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'loss-tangent')) + vn = vn + 1; + cmdargs = [ cmdargs ' --loss-tangent ' num2str(varargin{vn}) ]; + end + if (strcmpi(varargin{vn}, 'pcb-outline')) + cmdargs = [ cmdargs ' --pcb-outline ' ]; + end + if (strcmpi(varargin{vn}, 'lossy-copper')) + cmdargs = [ cmdargs ' --lossy-copper ' ]; + end + if (strcmpi(varargin{vn}, 'metal-3d')) + cmdargs = [ cmdargs ' --metal-3d ' ]; + end + if (strcmpi(varargin{vn}, 'version')) + cmdargs = [ cmdargs ' --version ' ]; + end + vn = vn + 1; + end + + % conversion + m_filename = mfilename('fullpath'); + dir = fileparts( m_filename ); + if isunix + hyp2mat_binary = searchBinary('hyp2mat', ... + {[dir filesep '..' filesep 'src' filesep], ... % try development path + [dir filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}); % try default install path + cmd = [ 'export LD_LIBRARY_PATH=; ' hyp2mat_binary ' --verbose --output-format csxcad --output pcb.m ' cmdargs ' ''' filename '''' ]; + elseif ispc + hyp2mat_binary = searchBinary('hyp2mat.exe', {[dir filesep '..' filesep]}); + cmd = [ '"' hyp2mat_binary '" --verbose --output-format csxcad --output pcb.m ' cmdargs ' "' filename '"' ]; + else + error('hyp2mat:ImportHyperLynx','unknown/unsupported operating system...'); + end + + % convert .hyp to .m + disp (['command: ' cmd ]); + if isOctave() + fflush(stdout); + else + drawnow('update'); + end + + status = system(cmd); % security implications? + if (status == 0) + % run generated pcb.m + CSX = pcb(CSX); + delete 'pcb.m'; + else + error([ 'error executing ' cmd ]); + end + +end + +% not truncated + diff --git a/hyp2mat/matlab/Makefile.am b/hyp2mat/matlab/Makefile.am new file mode 100644 index 0000000..77cd707 --- /dev/null +++ b/hyp2mat/matlab/Makefile.am @@ -0,0 +1,2 @@ +matlabdir = $(pkgdatadir)/matlab +dist_matlab_DATA = Contents.m GetHyperLynxPort.m ImportHyperLynx.m AddHyperLynxComponent.m AddHyperLynxDielectric.m AddHyperLynxMetal2D.m AddHyperLynxMetal3D.m diff --git a/hyp2mat/src/.gitignore b/hyp2mat/src/.gitignore new file mode 100644 index 0000000..bf5c0e2 --- /dev/null +++ b/hyp2mat/src/.gitignore @@ -0,0 +1,13 @@ +*.lo +*.o +.deps/ +.libs/ +cmdline.c +cmdline.h +config.h +config.h.in~ +hyp2mat +hyp2mat.exe +hyp2mat.pc +libhyp2mat.la +stamp-h1 diff --git a/hyp2mat/src/Makefile.am b/hyp2mat/src/Makefile.am new file mode 100644 index 0000000..3a64431 --- /dev/null +++ b/hyp2mat/src/Makefile.am @@ -0,0 +1,23 @@ +# used by automake + +# +# hyp2mat command line program +# + +bin_PROGRAMS=hyp2mat + +hyp2mat_SOURCES=hyp2mat.cc cmdline.ggo cmdline.c cmdline.h +hyp2mat_LDADD=$(top_builddir)/lib/libhyp2mat.la +AM_CPPFLAGS= -I$(top_srcdir)/lib + +# command line option parsing using gengetopt. +# create cmdline.c and cmdline.h from cmdline.ggo + +cmdline.c cmdline.h: cmdline.ggo + $(GENGETOPT) < $^ + +BUILT_SOURCES=cmdline.c cmdline.h + +CLEANFILES=cmdline.c cmdline.h + +#not truncated diff --git a/hyp2mat/src/cmdline.ggo b/hyp2mat/src/cmdline.ggo new file mode 100644 index 0000000..85f4c18 --- /dev/null +++ b/hyp2mat/src/cmdline.ggo @@ -0,0 +1,43 @@ +# +# Hyp2mat command line options. Use gengetopt to generate the C sources. +# + +args "--unamed-opts" +usage " [-h] [ -o outfile ] [ -f pdf|csxcad ] [-n net]... [OPTIONS]... [-v] [infile]" + +description "Converts Hyperlynx Signal-Integrity Transfer Format files to Octave/matlab scripts." + +option "output" o "Output file." string typestr="filename" default="-" optional +option "output-format" f "Output file format." enum values="csxcad", "pdf" default="pdf" optional +section "Processing options" +option "net" n "Import net. Repeat to import several nets. Default is importing all nets." string optional multiple +option "layer" l "Import layer. Repeat to import several layers. Default is importing all layers." string optional multiple +option "xmin" x "Crop pcb. Set lower bound of x coordinate." double optional +option "xmax" X "Crop pcb. Set upper bound of x coordinate." double optional +option "ymin" y "Crop pcb. Set lower bound of y coordinate." double optional +option "ymax" Y "Crop pcb. Set upper bound of y coordinate." double optional +option "zmin" z "Crop pcb. Set lower bound of z coordinate." double optional +option "zmax" Z "Crop pcb. Set upper bound of z coordinate." double optional +option "grid" - "Set output grid size." double default="10e-6" optional +option "arc-precision" - "Set maximum difference between perfect arc and polygonal approximation." default="0" double optional +option "clearance" - "Set default trace-to-plane clearance." default="0.0002" double optional +option "flood" - "Flood layer with copper. Repeat to flood several layers. The value \"plane_layers\" floods all plane layers." string optional multiple +section "Physical properties" +option "epsilonr" - "Set epsilon r of dielectric." double optional +option "loss-tangent" - "Set loss tangent of dielectric." double optional +option "bulk-resistivity" - "Set bulk resistivity of copper (in Ohm meter)." double optional +section "CSXCAD output options" +option "pcb-outline" - "Detailed board outline." flag off +option "lossy-copper" - "Model copper as lossy. Default is modeling copper as perfect conductor." flag off +option "metal-3d" - "Model copper layers as 3D. Default is modeling metal as 2D sheet." flag off +section "PDF output options" +option "hue" - "Set PDF color hue. Range 0.0 to 1.0" double default="0.0" optional +option "saturation" - "Set PDF color saturation. Range 0.0 to 1.0" double default="0.6" optional +option "brightness" - "Set PDF color brightness. Range 0.0 to 1.0" double default="0.9" optional +section "Debugging options" +option "raw" r "Raw output. Do not join adjacent or overlapping copper." flag off +option "debug" d "Increase debugging level. Repeat for more detailed debugging." optional multiple +option "verbose" v "Print board summary." no + +text "\nAll lengths are in meters." +# not truncated diff --git a/hyp2mat/src/hyp2mat.cc b/hyp2mat/src/hyp2mat.cc new file mode 100644 index 0000000..7c40161 --- /dev/null +++ b/hyp2mat/src/hyp2mat.cc @@ -0,0 +1,160 @@ +/* + * hyp2mat - convert hyperlynx files to matlab scripts + * Copyright 2012 Koen De Vleeschauwer. + * + * This file is part of hyp2mat. + * + * 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 . + */ + +#include +#include +#include + +#include "hyp2mat.h" +#include "cmdline.h" + +using namespace Hyp2Mat; + +int main(int argc, char **argv) +{ + try { + PCB pcb; + + /* + * parse command line + */ + + gengetopt_args_info args_info; + + if (cmdline_parser (argc, argv, &args_info) != 0) + exit(1); + + /* set layers to import */ + std::vector layers; + if (args_info.layer_given && args_info.layer_arg) + for (unsigned int i = 0; i < args_info.layer_given; ++i) + layers.push_back(args_info.layer_arg[i]); + + /* set nets to import */ + std::vector nets; + if (args_info.net_given && args_info.net_arg) + for (unsigned int i = 0; i < args_info.net_given; ++i) + nets.push_back(args_info.net_arg[i]); + + /* set input filename */ + std::string input_file = "-"; + + if (args_info.inputs_num == 1) + input_file = args_info.inputs[0]; + + if (args_info.inputs_num > 1) { + std::cerr << "more than one input file given" << std::endl; + exit(1); + } + + /* output file */ + std::string output_file = args_info.output_arg; + + /* + * Process hyperlynx file + */ + + /* set debug level */ + pcb.debug = args_info.debug_given; + + /* set raw processing */ + pcb.raw = args_info.raw_flag; + + /* optionally set grid */ + if (args_info.grid_given) + pcb.SetGrid(args_info.grid_arg); + + /* optionally set arc precision */ + if (args_info.arc_precision_given) + pcb.SetArcPrecision(args_info.arc_precision_arg); + + /* set trace-to-plane clearance */ + pcb.SetClearance(args_info.clearance_arg); + + /* set layer flooding */ + std::vector flood; + if (args_info.flood_given && args_info.flood_arg) + for (unsigned int i = 0; i < args_info.flood_given; ++i) + flood.push_back(args_info.flood_arg[i]); + pcb.flood_layers = flood; + + /* optionally crop */ + Bounds bounds; + if (args_info.xmin_given) bounds.x_min = args_info.xmin_arg; + if (args_info.xmax_given) bounds.x_max = args_info.xmax_arg; + if (args_info.ymin_given) bounds.y_min = args_info.ymin_arg; + if (args_info.ymax_given) bounds.y_max = args_info.ymax_arg; + if (args_info.zmin_given) bounds.z_min = args_info.zmin_arg; + if (args_info.zmax_given) bounds.z_max = args_info.zmax_arg; + if (args_info.xmin_given || args_info.xmax_given || + args_info.ymin_given || args_info.ymax_given || + args_info.zmin_given || args_info.zmax_given ) + pcb.SetBounds(bounds); + + /* optionally set epsilon */ + if (args_info.epsilonr_given) + pcb.SetEpsilonR(args_info.epsilonr_arg); + + /* optionally set bulk resistivity */ + if (args_info.bulk_resistivity_given) + pcb.SetBulkResistance(args_info.bulk_resistivity_arg); + + /* optionally set loss tangent */ + if (args_info.loss_tangent_given) + pcb.SetLossTangent(args_info.loss_tangent_arg); + + /* load hyperlynx file */ + pcb.ReadHyperLynx(input_file, layers, nets); + + /* optionally print layer summary */ + if (args_info.verbose_given) + pcb.PrintSummary(); + + /* + * write output + */ + + switch(args_info.output_format_arg) { + /* Export Portable Document Format (pdf) */ + case output_format_arg_pdf: + if (!args_info.output_given) + std::cerr << "pdf output file missing " << std::endl; + else + pcb.WritePDF(output_file, args_info.hue_arg, args_info.saturation_arg, args_info.brightness_arg); + break; + /* Export Continuous Structure XML (openEMS) */ + case output_format_arg_csxcad: + pcb.WriteCSXCAD(output_file, args_info.pcb_outline_flag, args_info.lossy_copper_flag, args_info.metal_3d_flag); + break; + default: + std::cerr << "unknown output format " << args_info.output_format_arg << std::endl; + break; + } + + /* exit */ + exit(0); + + } + catch(...) { + exit(1); + } + +} +/* not truncated */ diff --git a/openEMS/Analyse/PlotVoltage.m b/openEMS/Analyse/PlotVoltage.m new file mode 100644 index 0000000..19989c1 --- /dev/null +++ b/openEMS/Analyse/PlotVoltage.m @@ -0,0 +1,70 @@ +%close all; +clear all; +clc + +fmax = 50e6; + +figure(1); +tmpu = load('../tmp/u1'); +tmpi = load('../tmp/i1'); + +t = tmpu(:,1); +u = tmpu(:,2); + +subplot(2,2,1); +title('u_1 TD'); +plot(t,u); +xlabel('t \rightarrow'); +ylabel('ut_1 \rightarrow'); +grid on; + +dt=t(2)-t(1); +u= [u ; zeros(5000,1)]; +L=numel(u); +t = (1:L)*dt; + +f = (0:L-1)/L/dt; +fu = fft(u)/L; +subplot(2,2,2); +title('u_1 FD'); +plot(f(1:L/2),abs(fu(1:L/2))); +xlabel('f \rightarrow'); +ylabel('|uf_1| \rightarrow'); +grid on; + + +t = tmpi(:,1); +i = tmpi(:,2); + +subplot(2,2,3); +title('i_1 TD'); +plot(t,i); +xlabel('t \rightarrow'); +ylabel('it_1 \rightarrow'); +grid on; + +dt=t(2)-t(1); +i = [i; zeros(5000,1)]; +L=numel(i); +t = (1:L)*dt; +f = (0:L-1)/L/dt; + +fi = fft(i)/L; +subplot(2,2,4); +title('i_1 FD'); +plot(f(1:L/2),abs(fi(1:L/2))); +xlabel('f \rightarrow'); +ylabel('|if_1| \rightarrow'); +grid on; + +figure(2); +subplot(2,1,1); +plot(f,real(fu./fi)); +xlim([0 fmax]); +grid on; +subplot(2,1,2); +plot(f,imag(fu./fi)); +xlim([0 fmax]); +grid on; + + diff --git a/openEMS/CMakeLists.txt b/openEMS/CMakeLists.txt new file mode 100644 index 0000000..898f280 --- /dev/null +++ b/openEMS/CMakeLists.txt @@ -0,0 +1,209 @@ + +# define build type +IF( DEFINED CMAKE_BUILD_TYPE ) + SET( CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Set to either \"Release\" or \"Debug\"" ) +ELSE() + SET( CMAKE_BUILD_TYPE Release CACHE STRING "Set to either \"Release\" or \"Debug\"" ) +ENDIF() + +PROJECT(openEMS CXX C) +cmake_minimum_required(VERSION 2.8) + +# default +set(LIB_VERSION_MAJOR 0) +set(LIB_VERSION_MINOR 0) +set(LIB_VERSION_PATCH 35) +set(LIB_VERSION_STRING ${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}) + +set(VERSION "v${LIB_VERSION_STRING}") + +IF(EXISTS ${PROJECT_SOURCE_DIR}/localConfig.cmake) + include(${PROJECT_SOURCE_DIR}/localConfig.cmake) +ENDIF() + +set(VERSION "v0.0.35") + +# add git revision +IF(EXISTS ${PROJECT_SOURCE_DIR}/.git ) + FIND_PACKAGE(Git) + # Get the latest abbreviated commit hash of the working branch + execute_process( + COMMAND ${GIT_EXECUTABLE} describe --tags + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + OUTPUT_VARIABLE GITREV + ) + set(VERSION ${GITREV}) + string(STRIP ${VERSION} VERSION) + message(STATUS "Found Git repository, ${PROJECT_NAME} version tag: ${VERSION}") +ENDIF() + +ADD_DEFINITIONS(-DGIT_VERSION=\"${VERSION}\") + +# +# Set up RPATH for the project +# +option(ENABLE_RPATH "Enable rpath support on Linux and Mac" ON) +if(NOT CMAKE_INSTALL_RPATH) + # the RPATH to be used when installing, but only if it's not a system directory + LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" isSystemDir) + IF("${isSystemDir}" STREQUAL "-1") + SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") + ENDIF("${isSystemDir}" STREQUAL "-1") +endif() +if(APPLE AND NOT CMAKE_INSTALL_NAME_DIR) + set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}") +endif() +if(UNIX AND ENABLE_RPATH) + set(CMAKE_SKIP_BUILD_RPATH FALSE) + set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) +endif() + + +if (WITH_MPI) + ADD_DEFINITIONS(-DMPI_SUPPORT) + # Require MPI for this project: + find_package(MPI REQUIRED) + INCLUDE_DIRECTORIES( ${MPI_INCLUDE_PATH} ) + + message(STATUS "Found MPI. INCLUDE " ${MPI_INCLUDE_PATH}) +endif() + +# Set locations of extra CMake modules +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${openEMS_SOURCE_DIR}/cmake/Modules/") + +# fparser +# $ cmake -D FPARSER_ROOT_DIR=~/opt/openEMS . +# SET(FPARSER_ROOT_DIR ~/opt/openEMS) +find_library(fparser_LIBRARIES + NAMES fparser + HINTS ${FPARSER_ROOT_DIR}/lib${LIB_SUFFIX} + NO_CMAKE_FIND_ROOT_PATH +) +message(STATUS "fparser: ${fparser_LIBRARIES}" ) +#TODO test if fparser was found +INCLUDE_DIRECTORIES( ${FPARSER_ROOT_DIR}/include ) + +# CSXCAD +# $ cmake -D CSXCAD_ROOT_DIR=~/opt/openEMS . +# SET(CSXCAD_ROOT_DIR ~/opt/openEMS) +find_library(CSXCAD_LIBRARIES + NAMES CSXCAD + HINTS ${CSXCAD_ROOT_DIR}/lib${LIB_SUFFIX} + NO_CMAKE_FIND_ROOT_PATH +) +message(STATUS "CSXCAD_LIBRARIES: ${CSXCAD_LIBRARIES}" ) +#TODO test if CSXCADs was found +find_path(CSXCAD_INCLUDE_DIR + NAMES ContinuousStructure.h + HINTS ${CSXCAD_ROOT_DIR}/include + PATH_SUFFIXES "CSXCAD" ${CSXCAD_INCLUDE_DIR} + NO_CMAKE_FIND_ROOT_PATH +) +message(STATUS "CSXCAD_INCLUDE_DIR: ${CSXCAD_INCLUDE_DIR}" ) +INCLUDE_DIRECTORIES( ${CSXCAD_INCLUDE_DIR} ) + +# TinyXML module from https://github.com/ros/cmake_modules +find_package(TinyXML REQUIRED) +ADD_DEFINITIONS( -DTIXML_USE_STL ) + +# hdf5 +find_package(HDF5 1.8 COMPONENTS C HL REQUIRED) +INCLUDE_DIRECTORIES (${HDF5_INCLUDE_DIRS}) +link_directories(${HDF5_LIBRARIES}) + +# boost +find_package(Boost 1.46 COMPONENTS + thread + system + date_time + serialization + chrono +) + +# 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() + +message(STATUS "Found package VTK. Using version " ${VTK_VERSION}) +if("${VTK_MAJOR_VERSION}" GREATER 5) + set( vtk_LIBS ${VTK_LIBRARIES} ) +else() + set( vtk_LIBS + vtkCommon + vtkIO + ) +endif() +message(STATUS "vtk libraries " ${vtk_LIBS}) + +include(${VTK_USE_FILE}) +INCLUDE_DIRECTORIES (${VTK_INCLUDE_DIR}) + +#set(CMAKE_CXX_FLAGS "-msse -march=native") + +# independent tool +ADD_SUBDIRECTORY( nf2ff ) + +set(SOURCES + openems.cpp +) + +set(PUB_HEADERS openems.h) + +# libs +ADD_SUBDIRECTORY( tools ) +ADD_SUBDIRECTORY( FDTD ) +ADD_SUBDIRECTORY( FDTD/extensions ) +ADD_SUBDIRECTORY( Common ) + +INCLUDE_DIRECTORIES( ${openEMS_SOURCE_DIR} ) #find tools + +message(STATUS "Sources:" ${SOURCES}) + +if (${MPI_CXX_FOUND}) + set(CMAKE_CXX_COMPILE_FLAGS ${CMAKE_CXX_COMPILE_FLAGS} ${MPI_COMPILE_FLAGS}) + set(CMAKE_CXX_LINK_FLAGS ${CMAKE_CXX_LINK_FLAGS} ${MPI_LINK_FLAGS}) + SET(CMAKE_CXX_COMPILER ${MPI_CXX_COMPILER}) +endif() + +add_library( openEMS SHARED ${SOURCES}) +set_target_properties(openEMS PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_MAJOR}) +TARGET_LINK_LIBRARIES( openEMS + ${CSXCAD_LIBRARIES} + ${fparser_LIBRARIES} + tinyxml + ${HDF5_LIBRARIES} + ${HDF5_HL_LIBRARIES} + ${Boost_LIBRARIES} + ${vtk_LIBS} + ${MPI_LIBRARIES} +) + +# main program +ADD_EXECUTABLE( openEMS_bin main.cpp ) +SET_TARGET_PROPERTIES(openEMS_bin PROPERTIES OUTPUT_NAME openEMS) +TARGET_LINK_LIBRARIES(openEMS_bin openEMS) + +INSTALL(TARGETS openEMS DESTINATION lib${LIB_SUFFIX}) +INSTALL(TARGETS openEMS_bin DESTINATION bin ) + +if (UNIX) + INSTALL( FILES openEMS.sh + DESTINATION bin + PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE) + if (WITH_MPI) + INSTALL( FILES openEMS_MPI.sh + DESTINATION bin + PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ OWNER_EXECUTE GROUP_EXECUTE WORLD_EXECUTE) + endif() +endif () +INSTALL(FILES ${PUB_HEADERS} DESTINATION include/openEMS) +INSTALL( DIRECTORY matlab DESTINATION share/openEMS ) +# TODO mpi, tarball, debug, release diff --git a/openEMS/COPYING b/openEMS/COPYING new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/openEMS/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/openEMS/Common/CMakeLists.txt b/openEMS/Common/CMakeLists.txt new file mode 100644 index 0000000..004b35e --- /dev/null +++ b/openEMS/Common/CMakeLists.txt @@ -0,0 +1,23 @@ + +#INCLUDE_DIRECTORIES( ${openEMS_SOURCE_DIR} ) + +set(SOURCES + ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/engine_interface_base.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_base.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processcurrent.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processfieldprobe.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processfields.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processfields_fd.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processfields_sar.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processfields_td.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processing.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processintegral.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processmodematch.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/processvoltage.cpp + PARENT_SCOPE +) + +# Common lib +#add_library( Common STATIC ${SOURCES} ) + diff --git a/openEMS/Common/engine_interface_base.cpp b/openEMS/Common/engine_interface_base.cpp new file mode 100644 index 0000000..4db393c --- /dev/null +++ b/openEMS/Common/engine_interface_base.cpp @@ -0,0 +1,39 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "engine_interface_base.h" +#include "string" + +Engine_Interface_Base::Engine_Interface_Base(Operator_Base* base_op) +{ + m_Op_Base = base_op; + m_InterpolType = NO_INTERPOLATION; +} + +std::string Engine_Interface_Base::GetInterpolationNameByType(InterpolationType mode) +{ + switch (mode) + { + case NO_INTERPOLATION: + return std::string("None"); + case NODE_INTERPOLATE: + return std::string("Node"); + case CELL_INTERPOLATE: + return std::string("Cell"); + } + return std::string(); +} diff --git a/openEMS/Common/engine_interface_base.h b/openEMS/Common/engine_interface_base.h new file mode 100644 index 0000000..6ce466b --- /dev/null +++ b/openEMS/Common/engine_interface_base.h @@ -0,0 +1,88 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef ENGINE_INTERFACE_BASE_H +#define ENGINE_INTERFACE_BASE_H + +#include "tools/global.h" + +class Operator_Base; + +//! This is the abstact base for all Engine Interface classes. +/*! + This is the abstact base for all Engine Interface classes. It will provide unified access to the field information of the corresponding engine. + All processing methods should only access this base class. +*/ +class Engine_Interface_Base +{ +public: + enum InterpolationType { NO_INTERPOLATION, NODE_INTERPOLATE, CELL_INTERPOLATE }; + + virtual ~Engine_Interface_Base() {;} //!< provide a virtual destructor to correctly delete derived objects + + //! Set the operator used for this engine interface. + virtual void SetOperator(Operator_Base* base_op) {m_Op_Base=base_op;} + //! Get the operator used for this engine interface. + virtual const Operator_Base* GetOperator() const {return m_Op_Base;} + + //! Set the current interpolation type \sa GetInterpolationType + void SetInterpolationType(InterpolationType type) {m_InterpolType=type;} + //! Set the current interpolation type \sa GetInterpolationType + void SetInterpolationType(int type) {m_InterpolType=(InterpolationType)type;} + //! Get the current interpolation type as string \sa SetInterpolationType GetInterpolationType GetInterpolationNameByType + std::string GetInterpolationTypeString() {return GetInterpolationNameByType(m_InterpolType);} + //! Get the current interpolation type \sa SetInterpolationType + InterpolationType GetInterpolationType() {return m_InterpolType;} + + //! Get the (interpolated) electric field at \p pos. \sa SetInterpolationType + virtual double* GetEField(const unsigned int* pos, double* out) const =0; + //! Get the (interpolated) magnetic field at \p pos. \sa SetInterpolationType + virtual double* GetHField(const unsigned int* pos, double* out) const =0; + //! Get the (interpolated) electric current density field at \p pos. \sa SetInterpolationType + 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; + + //! Calculate the electric field integral along a given line + virtual double CalcVoltageIntegral(const unsigned int* start, const unsigned int* stop) const =0; + + //! Convert the interpolation type into a string. + static std::string GetInterpolationNameByType(InterpolationType mode); + + //! Get the current simulation time + virtual double GetTime(bool dualTime=false) const =0; + + //! Get the current number of timesteps + virtual unsigned int GetNumberOfTimesteps() const =0; + + //! Calc (roughly) the total energy + /*! + This method only calculates a very rough estimate of the total energy in the simulation domain. + The result may even be roughly proportional to the real system energy only. + Primary goal is speed, not accuracy. + */ + virtual double CalcFastEnergy() const =0; + +protected: + Engine_Interface_Base(Operator_Base* base_op); + + Operator_Base* m_Op_Base; + + InterpolationType m_InterpolType; +}; + +#endif // ENGINE_INTERFACE_BASE_H diff --git a/openEMS/Common/operator_base.cpp b/openEMS/Common/operator_base.cpp new file mode 100644 index 0000000..e5d26f5 --- /dev/null +++ b/openEMS/Common/operator_base.cpp @@ -0,0 +1,154 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "operator_base.h" + +using namespace std; + +Operator_Base::Operator_Base() +{ + Init(); + m_MeshType = CARTESIAN; + m_StoreMaterial[0]=false; + m_StoreMaterial[1]=false; + m_StoreMaterial[2]=false; + m_StoreMaterial[3]=false; +} + +Operator_Base::~Operator_Base() +{ + Delete(); +} + +bool Operator_Base::SetGeometryCSX(ContinuousStructure* geo) +{ + if (geo==NULL) return false; + CSX = geo; + + return true; +} + +std::string Operator_Base::GetDirName(int ny) const +{ + if (ny==0) return "x"; + if (ny==1) return "y"; + if (ny==2) return "z"; + return ""; +} + +void Operator_Base::Init() +{ + CSX = NULL; + + dT = 0; + for (int n=0; n<3; ++n) + discLines[n]=NULL; + for (int n=0; n<6; ++n) + m_BC[n]=0; + + SetBackgroundMaterial(1,1,0,0); +} + +void Operator_Base::Delete() +{ + for (int n=0; n<3; ++n) + { + delete[] discLines[n]; + discLines[n]=0; + } + for (int n=0; n<6; ++n) + m_BC[n]=0; + dT = 0; +} + +void Operator_Base::Reset() +{ + Delete(); +} + +void Operator_Base::SetMaterialStoreFlags(int type, bool val) +{ + if ((type<0) || (type>4)) + return; + m_StoreMaterial[type]=val; +} + +bool Operator_Base::GetCellCenterMaterialAvgCoord(const unsigned int pos[3], double coord[3]) const +{ + int ipos[3] = {(int)pos[0], (int)pos[1], (int)pos[2]}; + return GetCellCenterMaterialAvgCoord(ipos, coord); +} + +void Operator_Base::SetBackgroundMaterial(double epsR, double mueR, double kappa, double sigma, double density) +{ + SetBackgroundEpsR(epsR); + SetBackgroundMueR(mueR); + SetBackgroundKappa(kappa); + SetBackgroundSigma(sigma); + SetBackgroundDensity(density); +} + +void Operator_Base::SetBackgroundEpsR(double val) +{ + if (val<1) + { + cerr << __func__ << ": Warning, a relative electric permittivity <1 it not supported, skipping" << endl; + return; + } + m_BG_epsR=val; +} + +void Operator_Base::SetBackgroundMueR(double val) +{ + if (val<1) + { + cerr << __func__ << ": Warning, a relative magnetic permeability <1 it not supported, skipping" << endl; + return; + } + m_BG_mueR=val; +} + +void Operator_Base::SetBackgroundKappa(double val) +{ + if (val<0) + { + cerr << __func__ << ": Warning, an electric conductivity <0 it not supported, skipping" << endl; + return; + } + m_BG_kappa=val; +} + +void Operator_Base::SetBackgroundSigma(double val) +{ + if (val<0) + { + cerr << __func__ << ": Warning, an artifival magnetic conductivity <0 it not supported, skipping" << endl; + return; + } + m_BG_sigma=val; +} + + +void Operator_Base::SetBackgroundDensity(double val) +{ + if (val<0) + { + cerr << __func__ << ": Warning, a mass density <0 it not supported, skipping" << endl; + return; + } + m_BG_density=val; +} diff --git a/openEMS/Common/operator_base.h b/openEMS/Common/operator_base.h new file mode 100644 index 0000000..cfbd40b --- /dev/null +++ b/openEMS/Common/operator_base.h @@ -0,0 +1,179 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef OPERATOR_BASE_H +#define OPERATOR_BASE_H + +#include "ContinuousStructure.h" +#include "tools/global.h" +#include "Common/processing.h" +#include "string" + +typedef struct +{ + std::vector posPath[3]; + std::vector dir; +} Grid_Path; + +//! Abstract base-class for a common operator +class Operator_Base +{ +public: + virtual ~Operator_Base(); + + virtual bool SetGeometryCSX(ContinuousStructure* geo); + virtual ContinuousStructure* GetGeometryCSX() const {return CSX;} + + //! Get the timestep used by this operator + virtual double GetTimestep() const {return dT;} + + //! Get the number of cells or nodes defined by this operator + virtual double GetNumberCells() const =0; + + //! Get the number of timesteps satisfying the nyquist condition (may depend on the excitation) + virtual unsigned int GetNumberOfNyquistTimesteps() const =0; + + //! Returns the number of lines as needed for post-processing etc. + virtual unsigned int GetNumberOfLines(int ny, bool full=false) const =0; + + //! Get the name for the given direction: 0 -> x, 1 -> y, 2 -> z + virtual std::string GetDirName(int ny) const; + + //! Get the grid drawing unit in m + virtual double GetGridDelta() const =0; + + //! Get the disc line in \a n direction (in drawing units) + virtual double GetDiscLine(int n, unsigned int pos, bool dualMesh=false) const =0; + + //! Get the disc line delta in \a n direction (in drawing units) + virtual double GetDiscDelta(int n, unsigned int pos, bool dualMesh=false) const =0; + + //! Get the node width for a given direction \a n and a given mesh position \a pos + virtual double GetNodeWidth(int ny, const unsigned int pos[3], bool dualMesh = false) const =0; + + //! Get the node area for a given direction \a n and a given mesh position \a pos + virtual double GetNodeArea(int ny, const unsigned int pos[3], bool dualMesh = false) const =0; + + //! Get the length of an FDTD edge (unit is meter). + virtual double GetEdgeLength(int ny, const unsigned int pos[3], bool dualMesh = false) const =0; + + //! Get the area around an edge for a given direction \a n and a given mesh posisition \a pos + /*! + This will return the area around an edge with a given direction, measured at the middle of the edge. + In a cartesian mesh this is equal to the NodeArea, may be different in other coordinate systems. + */ + virtual double GetEdgeArea(int ny, const unsigned int pos[3], bool dualMesh = false) const =0; + + //! Get the volume of an FDTD cell + virtual double GetCellVolume(const unsigned int pos[3], bool dualMesh = false) const =0; + + //! Snap the given coodinates to mesh indices, return box dimension + virtual bool SnapToMesh(const double* coord, unsigned int* uicoord, bool dualMesh=false, bool fullMesh=false, bool* inside=NULL) const =0; + + //! Snap a given box to the operator mesh, uiStart will be always <= uiStop + /*! + \param[in] start the box-start coorindate + \param[in] stop the box-stopt coorindate + \param[out] uiStart the snapped box-start coorindate index + \param[out] uiStop the snapped box-stop coorindate index + \param[in] dualMesh snap to main or dual mesh (default is main mesh) + \param[in] SnapMethod Snapping method, 0=snap to closest line, 1/(2)=snap such that given box is inside (outside) the snapped lines + \return returns the box dimension or -1 if box is not inside the simulation domain + */ + virtual int SnapBox2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh=false, bool fullMesh=false, int SnapMethod=0, bool* bStartIn=NULL, bool* bStopIn=NULL) const =0; + + //! Set the boundary conditions + virtual void SetBoundaryCondition(int* BCs) {for (int n=0; n<6; ++n) m_BC[n]=BCs[n];} + + //! Set flags to store material data for post-processing + virtual void SetMaterialStoreFlags(int type, bool val); + + //! Check storage flags and cleanup + virtual void CleanupMaterialStorage() = 0; + + //! Get stored discrete material (if storage is enabled). + virtual double GetDiscMaterial(int type, int ny, const unsigned int pos[3]) const = 0; + + //! Get the cell center coordinate usable for material averaging (Warning, may not be the yee cell center) + bool GetCellCenterMaterialAvgCoord(const unsigned int pos[3], double coord[3]) const; + + //! Get the cell center coordinate usable for material averaging (Warning, may not be the yee cell center) + virtual bool GetCellCenterMaterialAvgCoord(const int pos[3], double coord[3]) const = 0; + + virtual std::vector GetPrimitivesBoundBox(int posX, int posY, int posZ, CSProperties::PropertyType type=CSProperties::ANY) const = 0; + + //! Set the background material (default is vacuum) + virtual void SetBackgroundMaterial(double epsR=0, double mueR=0, double kappa=0, double sigma=0, double density=0); + + //! Get background rel. electric permittivity + double GetBackgroundEpsR() const {return m_BG_epsR;} + //! Set background rel. electric permittivity + void SetBackgroundEpsR(double val); + + //! Get background rel. magnetic permeability + double GetBackgroundMueR() const {return m_BG_mueR;} + //! Set background rel. magnetic permeability + void SetBackgroundMueR(double val); + + //! Get background electric conductivity + double GetBackgroundKappa() const {return m_BG_kappa;} + //! Set background electric conductivity + void SetBackgroundKappa(double val); + + //! Get background magnetic conductivity (artificial) + double GetBackgroundSigma() const {return m_BG_sigma;} + //! Set background magnetic conductivity (artificial) + void SetBackgroundSigma(double val); + + //! Get background mass density + double GetBackgroundDensity() const {return m_BG_density;} + //! Set background mass density + void SetBackgroundDensity(double val); + +protected: + Operator_Base(); + + ContinuousStructure* CSX; + + virtual void Init(); + //! Cleanup data and reset + void Delete(); + virtual void Reset(); + + //! boundary conditions + int m_BC[6]; + + //! The operator timestep + double dT; + + //! bool flag array to store material data for post-processing + bool m_StoreMaterial[4]; + + //! background materials + double m_BG_epsR; + double m_BG_mueR; + double m_BG_kappa; + double m_BG_sigma; + double m_BG_density; + + CoordinateSystem m_MeshType; + unsigned int numLines[3]; + double* discLines[3]; + double gridDelta; +}; + +#endif // OPERATOR_BASE_H diff --git a/openEMS/Common/processcurrent.cpp b/openEMS/Common/processcurrent.cpp new file mode 100644 index 0000000..8c35bf0 --- /dev/null +++ b/openEMS/Common/processcurrent.cpp @@ -0,0 +1,168 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "tools/global.h" +#include "processcurrent.h" +#include "FDTD/engine_interface_fdtd.h" +#include + +ProcessCurrent::ProcessCurrent(Engine_Interface_Base* eng_if) : ProcessIntegral(eng_if) +{ + m_SnapMethod=1; +} + +ProcessCurrent::~ProcessCurrent() +{ +} + +string ProcessCurrent::GetIntegralName(int row) const +{ + if (row==0) + return "current"; + return "unknown"; +} + +void ProcessCurrent::DefineStartStopCoord(double* dstart, double* dstop) +{ + ProcessIntegral::DefineStartStopCoord(dstart, dstop); + + if ((m_normDir<0) || (m_normDir>2)) + { + if (m_Dimension!=2) + { + cerr << "ProcessCurrent::DefineStartStopCoord(): Warning Current Integration Box \"" << m_filename << "\" is not a surface (found dimension: " << m_Dimension << ") nor has it set a valid normal direction! --> disabled" << endl; + SetEnable(false); + return; + } + + for (int n=0; n<3; ++n) + { + if (stop[n] == start[n]) + m_normDir = n; + } + } + else + { + //expand dimension to 2 if possible + m_Dimension = 0; + for (int n=0; n<3; ++n) + { + if (n==m_normDir) + continue; + if (dstart[n]==dstop[n]) + { + if ((Op->GetDiscLine( n, start[n], true ) > dstart[n]) && (start[n]>0)) + --start[n]; + if ((Op->GetDiscLine( n, start[n], true ) < dstart[n]) && (stop[n]GetNumberOfLines(n)-1)) + ++stop[n]; + } + if (stop[n] > start[n]) + ++m_Dimension; + } + } + + if (start[m_normDir]!=stop[m_normDir]) + { + cerr << "ProcessCurrent::DefineStartStopCoord(): Warning Current Integration Box \"" << m_filename << "\" has an expansion in normal direction! --> disabled" << endl; + SetEnable(false); + return; + } + + if ((m_normDir<0) || (m_normDir>2)) + { + cerr << "ProcessCurrent::DefineStartStopCoord(): Warning Current Integration Box \"" << m_filename << "\" has an invalid normal direction --> disabled" << endl; + SetEnable(false); + return; + } +} + +double ProcessCurrent::CalcIntegral() +{ + FDTD_FLOAT current=0; + + Engine_Interface_FDTD* EI_FDTD = dynamic_cast(m_Eng_Interface); + + if (EI_FDTD) + { + const Engine* Eng = EI_FDTD->GetFDTDEngine(); + + + switch (m_normDir) + { + case 0: + //y-current + if (m_stop_inside[0] && m_start_inside[2]) + for (unsigned int i=start[1]+1; i<=stop[1]; ++i) + current+=Eng->GetCurr(1,stop[0],i,start[2]); + //z-current + if (m_stop_inside[0] && m_stop_inside[1]) + for (unsigned int i=start[2]+1; i<=stop[2]; ++i) + current+=Eng->GetCurr(2,stop[0],stop[1],i); + //y-current + if (m_start_inside[0] && m_stop_inside[2]) + for (unsigned int i=start[1]+1; i<=stop[1]; ++i) + current-=Eng->GetCurr(1,start[0],i,stop[2]); + //z-current + if (m_start_inside[0] && m_start_inside[1]) + for (unsigned int i=start[2]+1; i<=stop[2]; ++i) + current-=Eng->GetCurr(2,start[0],start[1],i); + break; + case 1: + //z-current + if (m_start_inside[0] && m_start_inside[1]) + for (unsigned int i=start[2]+1; i<=stop[2]; ++i) + current+=Eng->GetCurr(2,start[0],start[1],i); + //x-current + if (m_stop_inside[1] && m_stop_inside[2]) + for (unsigned int i=start[0]+1; i<=stop[0]; ++i) + current+=Eng->GetCurr(0,i,stop[1],stop[2]); + //z-current + if (m_stop_inside[0] && m_stop_inside[1]) + for (unsigned int i=start[2]+1; i<=stop[2]; ++i) + current-=Eng->GetCurr(2,stop[0],stop[1],i); + //x-current + if (m_start_inside[1] && m_start_inside[2]) + for (unsigned int i=start[0]+1; i<=stop[0]; ++i) + current-=Eng->GetCurr(0,i,start[1],start[2]); + break; + case 2: + //x-current + if (m_start_inside[1] && m_start_inside[2]) + for (unsigned int i=start[0]+1; i<=stop[0]; ++i) + current+=Eng->GetCurr(0,i,start[1],start[2]); + //y-current + if (m_stop_inside[0] && m_start_inside[2]) + for (unsigned int i=start[1]+1; i<=stop[1]; ++i) + current+=Eng->GetCurr(1,stop[0],i,start[2]); + //x-current + if (m_stop_inside[1] && m_stop_inside[2]) + for (unsigned int i=start[0]+1; i<=stop[0]; ++i) + current-=Eng->GetCurr(0,i,stop[1],stop[2]); + //y-current + if (m_start_inside[0] && m_stop_inside[2]) + for (unsigned int i=start[1]+1; i<=stop[1]; ++i) + current-=Eng->GetCurr(1,start[0],i,stop[2]); + break; + default: + //this cannot happen... + return 0.0; + break; + } + } + + return current; +} diff --git a/openEMS/Common/processcurrent.h b/openEMS/Common/processcurrent.h new file mode 100644 index 0000000..5152b92 --- /dev/null +++ b/openEMS/Common/processcurrent.h @@ -0,0 +1,41 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef PROCESSCURRENT_H +#define PROCESSCURRENT_H + +#include "processintegral.h" + +class ProcessCurrent : public ProcessIntegral +{ +public: + ProcessCurrent(Engine_Interface_Base* eng_if); + virtual ~ProcessCurrent(); + + virtual std::string GetProcessingName() const {return "current integration";} + + virtual std::string GetIntegralName(int row) const; + + virtual void DefineStartStopCoord(double* dstart, double* dstop); + + //! Integrate currents flowing through an area + virtual double CalcIntegral(); + +protected: +}; + +#endif // PROCESSCURRENT_H diff --git a/openEMS/Common/processfieldprobe.cpp b/openEMS/Common/processfieldprobe.cpp new file mode 100644 index 0000000..c456a22 --- /dev/null +++ b/openEMS/Common/processfieldprobe.cpp @@ -0,0 +1,92 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "processfieldprobe.h" + +using namespace std; + +ProcessFieldProbe::ProcessFieldProbe(Engine_Interface_Base* eng_if, int type) : ProcessIntegral(eng_if) +{ + SetFieldType(type); +} + +ProcessFieldProbe::~ProcessFieldProbe() +{ + +} + +string ProcessFieldProbe::GetProcessingName() const +{ + if (m_ModeFieldType==0) + return "electric field probe"; + if (m_ModeFieldType==1) + return "magnetic field probe"; + return "unknown field probe"; +} + +string ProcessFieldProbe::GetIntegralName(int row) const +{ + if (row==0) + { + if (m_ModeFieldType==0) + return "Ex/(V/m)"; + if (m_ModeFieldType==1) + return "Hx/(A/m)"; + } + if (row==1) + { + if (m_ModeFieldType==0) + return "Ey/(V/m)"; + if (m_ModeFieldType==1) + return "Hy/(A/m)"; + } + if (row==2) + { + if (m_ModeFieldType==0) + return "Ez/(V/m)"; + if (m_ModeFieldType==1) + return "Hz/(A/m)"; + } + return "unknown"; +} + +void ProcessFieldProbe::SetFieldType(int type) +{ + if ((type<0) || (type>1)) + { + cerr << "ProcessFieldProbe::SetFieldType: Error: unknown field type... skipping" << endl; + Enabled=false; + } + m_ModeFieldType = type; +} + +double* ProcessFieldProbe::CalcMultipleIntegrals() +{ + m_Eng_Interface->SetInterpolationType(Engine_Interface_Base::NO_INTERPOLATION); + + switch (m_ModeFieldType) + { + case 0: + default: + m_Eng_Interface->GetEField(start,m_Results); + break; + case 1: + m_Eng_Interface->GetHField(start,m_Results); + break; + } + return m_Results; +} diff --git a/openEMS/Common/processfieldprobe.h b/openEMS/Common/processfieldprobe.h new file mode 100644 index 0000000..342eba4 --- /dev/null +++ b/openEMS/Common/processfieldprobe.h @@ -0,0 +1,43 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#ifndef PROCESSFIELDPROBE_H +#define PROCESSFIELDPROBE_H + +#include "processintegral.h" + +class ProcessFieldProbe : public ProcessIntegral +{ +public: + ProcessFieldProbe(Engine_Interface_Base* eng_if, int type=0); + virtual ~ProcessFieldProbe(); + + virtual std::string GetProcessingName() const; + + virtual std::string GetIntegralName(int row) const; + + //! Set the field type (0 electric field, 1 magnetic field) + void SetFieldType(int type); + + virtual int GetNumberOfIntegrals() const {return 3;} + virtual double* CalcMultipleIntegrals(); + +protected: + int m_ModeFieldType; +}; + +#endif // PROCESSFIELDPROBE_H diff --git a/openEMS/Common/processfields.cpp b/openEMS/Common/processfields.cpp new file mode 100644 index 0000000..f52fc14 --- /dev/null +++ b/openEMS/Common/processfields.cpp @@ -0,0 +1,341 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include +#include "tools/global.h" +#include "tools/vtk_file_writer.h" +#include "tools/hdf5_file_writer.h" +#include "processfields.h" +#include "FDTD/engine_interface_fdtd.h" + +ProcessFields::ProcessFields(Engine_Interface_Base* eng_if) : Processing(eng_if) +{ + m_DumpType = E_FIELD_DUMP; + // vtk-file is default + m_fileType = VTK_FILETYPE; + m_SampleType = NONE; + m_Vtk_Dump_File = NULL; + m_HDF5_Dump_File = NULL; + SetPrecision(6); + m_dualTime = false; + + // dump box should be always inside the snapped lines + m_SnapMethod = 1; + + for (int n=0; n<3; ++n) + { + numLines[n]=0; + posLines[n]=NULL; + discLines[n]=NULL; + subSample[n]=1; + optResolution[n]=0; + } +} + +ProcessFields::~ProcessFields() +{ + delete m_Vtk_Dump_File; + m_Vtk_Dump_File = NULL; + for (int n=0; n<3; ++n) + { + delete[] posLines[n]; + posLines[n]=NULL; + delete[] discLines[n]; + discLines[n]=NULL; + } +} + +string ProcessFields::GetFieldNameByType(DumpType type) +{ + switch (type) + { + case E_FIELD_DUMP: + return "E-Field"; + case H_FIELD_DUMP: + return "H-Field"; + case J_FIELD_DUMP: + return "J-Field"; + case ROTH_FIELD_DUMP: + return "RotH-Field"; + case SAR_LOCAL_DUMP: + return "SAR-local"; + case SAR_1G_DUMP: + return "SAR_1g"; + case SAR_10G_DUMP: + return "SAR_10g"; + case SAR_RAW_DATA: + return "SAR_raw_data"; + } + return "unknown field"; +} + +bool ProcessFields::NeedConductivity() const +{ + switch (m_DumpType) + { + case J_FIELD_DUMP: + return true; + default: + return false; + } + return false; +} + +void ProcessFields::InitProcess() +{ + if (Enabled==false) return; + + CalcMeshPos(); + + if (m_fileType==VTK_FILETYPE) + { + delete m_Vtk_Dump_File; + m_Vtk_Dump_File = new VTK_File_Writer(m_filename,(int)m_Mesh_Type); + + #ifdef OUTPUT_IN_DRAWINGUNITS + double discScaling = 1; + #else + double discScaling = Op->GetGridDelta(); + #endif + m_Vtk_Dump_File->SetMeshLines(discLines,numLines,discScaling); + m_Vtk_Dump_File->SetNativeDump(g_settings.NativeFieldDumps()); + } + if (m_fileType==HDF5_FILETYPE) + { + delete m_HDF5_Dump_File; + m_HDF5_Dump_File = new HDF5_File_Writer(m_filename+".h5"); + + #ifdef OUTPUT_IN_DRAWINGUNITS + double discScaling = 1; + #else + double discScaling = Op->GetGridDelta(); + #endif + m_HDF5_Dump_File->WriteRectMesh(numLines,discLines,(int)m_Mesh_Type,discScaling); + + m_HDF5_Dump_File->WriteAtrribute("/","openEMS_HDF5_version",0.2); + } +} + +void ProcessFields::SetDumpMode(Engine_Interface_Base::InterpolationType mode) +{ + m_Eng_Interface->SetInterpolationType(mode); + if (mode==Engine_Interface_Base::CELL_INTERPOLATE) + m_dualMesh=true; + else if (mode==Engine_Interface_Base::NODE_INTERPOLATE) + m_dualMesh=false; + //else keep the preset/user defined case +} + +void ProcessFields::DefineStartStopCoord(double* dstart, double* dstop) +{ + Processing::DefineStartStopCoord(dstart,dstop); + + // normalize order of start and stop + for (int n=0; n<3; ++n) + { + if (start[n]>stop[n]) + { + unsigned int help = start[n]; + start[n]=stop[n]; + stop[n]=help; + } + } +} + +double ProcessFields::CalcTotalEnergyEstimate() const +{ + return m_Eng_Interface->CalcFastEnergy(); +} + +void ProcessFields::SetSubSampling(unsigned int subSampleRate, int dir) +{ + if (dir>2) return; + if (dir<0) + { + subSample[0]=subSampleRate; + subSample[1]=subSampleRate; + subSample[2]=subSampleRate; + } + else subSample[dir]=subSampleRate; + m_SampleType = SUBSAMPLE; +} + +void ProcessFields::SetOptResolution(double optRes, int dir) +{ + if (dir>2) return; + if (dir<0) + { + optResolution[0]=optRes; + optResolution[1]=optRes; + optResolution[2]=optRes; + } + else optResolution[dir]=optRes; + m_SampleType = OPT_RESOLUTION; +} + +void ProcessFields::CalcMeshPos() +{ + if ((m_SampleType==SUBSAMPLE) || (m_SampleType==NONE)) + { + vector tmp_pos; + + for (int n=0; n<3; ++n) + { + // construct new discLines + tmp_pos.clear(); + for (unsigned int i=start[n]; i<=stop[n]; i+=subSample[n]) + tmp_pos.push_back(i); + + numLines[n] = tmp_pos.size(); + delete[] discLines[n]; + discLines[n] = new double[numLines[n]]; + delete[] posLines[n]; + posLines[n] = new unsigned int[numLines[n]]; + for (unsigned int i=0; iGetDiscLine(n,tmp_pos.at(i),m_dualMesh); + } + } + } + if ((m_SampleType==OPT_RESOLUTION)) + { + vector tmp_pos; + double oldPos=0; + for (int n=0; n<3; ++n) + { + // construct new discLines + tmp_pos.clear(); + tmp_pos.push_back(start[n]); + oldPos=Op->GetDiscLine(n,start[n],m_dualMesh); + if (stop[n]==0) + tmp_pos.push_back(stop[n]); + else + for (unsigned int i=start[n]+1; i<=stop[n]-1; ++i) + { + if ( (Op->GetDiscLine(n,i+1,m_dualMesh)-oldPos) >= optResolution[n]) + { + tmp_pos.push_back(i); + oldPos=Op->GetDiscLine(n,i,m_dualMesh); + } + } + if (start[n]!=stop[n]) + tmp_pos.push_back(stop[n]); + numLines[n] = tmp_pos.size(); + delete[] discLines[n]; + discLines[n] = new double[numLines[n]]; + delete[] posLines[n]; + posLines[n] = new unsigned int[numLines[n]]; + for (unsigned int i=0; iGetDiscLine(n,tmp_pos.at(i),m_dualMesh); + } + } + } +} + +FDTD_FLOAT**** ProcessFields::CalcField() +{ + unsigned int pos[3]; + double out[3]; + //create array + FDTD_FLOAT**** field = Create_N_3DArray(numLines); + switch (m_DumpType) + { + case E_FIELD_DUMP: + for (unsigned int i=0; iGetEField(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 H_FIELD_DUMP: + for (unsigned int i=0; iGetHField(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 J_FIELD_DUMP: + for (unsigned int i=0; iGetJField(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 ROTH_FIELD_DUMP: + for (unsigned int i=0; iGetRotHField(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 new file mode 100644 index 0000000..3d4085b --- /dev/null +++ b/openEMS/Common/processfields.h @@ -0,0 +1,104 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef PROCESSFIELDS_H +#define PROCESSFIELDS_H + +#include "processing.h" +#include "tools/array_ops.h" + +#define __VTK_DATA_TYPE__ "double" + +class VTK_File_Writer; +class HDF5_File_Writer; + +class ProcessFields : public Processing +{ +public: + ProcessFields(Engine_Interface_Base* eng_if); + virtual ~ProcessFields(); + + //! File type definition. + enum FileType { VTK_FILETYPE, HDF5_FILETYPE}; + + //! Dump type definitions. + /*! + 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}; + + virtual std::string GetProcessingName() const {return "common field processing";} + + virtual void InitProcess(); + + virtual void DefineStartStopCoord(double* dstart, double* dstop); + + //! Define a field dump sub sampling rate for a given direction (default: \a dir = -1 means all directions) + virtual void SetSubSampling(unsigned int subSampleRate, int dir=-1); + + //! Define a field dump optimal resolution for a given direction (default: \a dir = -1 means all directions) + virtual void SetOptResolution(double optRes, int dir=-1); + + //! Set the filename for a hdf5 data group file (HDF5 FileType only) \sa SetFileType() + void SetFileName(std::string fn) {m_filename=fn;} + std::string SetFileName() const {return m_filename;} + + //! Define the Dump-Mode + void SetDumpMode(Engine_Interface_Base::InterpolationType mode); + //! This methode will dump all fields on a main cell node using 2 E-field and 4 H-fields per direction. + void SetDumpMode2Node() {SetDumpMode(Engine_Interface_Base::NODE_INTERPOLATE);} + //! This methode will dump all fields in the center of a main cell (dual-node) using 4 E-field and 2 H-fields per direction. + void SetDumpMode2Cell() {SetDumpMode(Engine_Interface_Base::CELL_INTERPOLATE);} + + //! Set dump type: 0 for E-fields, 1 for H-fields, 2 for D-fields, 3 for B-fields, 4 for J-fields, etc... + virtual void SetDumpType(DumpType type) {m_DumpType=type;} + + double CalcTotalEnergyEstimate() const; + + void SetFileType(FileType fileType) {m_fileType=fileType;} + + static std::string GetFieldNameByType(DumpType type); + + virtual bool NeedConductivity() const; + +protected: + DumpType m_DumpType; + FileType m_fileType; + + VTK_File_Writer* m_Vtk_Dump_File; + HDF5_File_Writer* m_HDF5_Dump_File; + + enum SampleType {NONE, SUBSAMPLE, OPT_RESOLUTION} m_SampleType; + virtual void CalcMeshPos(); + + //! field dump sub-sampling (if enabled) + unsigned int subSample[3]; + + //! field dump optimal resolution (if enabled) + double optResolution[3]; + + //! dump mesh information + unsigned int numLines[3]; //number of lines to dump + unsigned int* posLines[3]; //grid positions to dump + double* discLines[3]; //mesh disc lines to dump + + //! Calculate and return the defined field. Caller has to cleanup the array. + FDTD_FLOAT**** CalcField(); +}; + +#endif // PROCESSFIELDS_H diff --git a/openEMS/Common/processfields_fd.cpp b/openEMS/Common/processfields_fd.cpp new file mode 100644 index 0000000..ca59b2b --- /dev/null +++ b/openEMS/Common/processfields_fd.cpp @@ -0,0 +1,225 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "processfields_fd.h" +#include "Common/operator_base.h" +#include "tools/vtk_file_writer.h" +#include "tools/hdf5_file_writer.h" +#include +#include +#include + +using namespace std; + +ProcessFieldsFD::ProcessFieldsFD(Engine_Interface_Base* eng_if) : ProcessFields(eng_if) +{ +} + +ProcessFieldsFD::~ProcessFieldsFD() +{ + for (size_t n = 0; nSetHeader(string("openEMS FD Field Dump -- Interpolation: ")+m_Eng_Interface->GetInterpolationTypeString()); + + if (m_HDF5_Dump_File) + { + m_HDF5_Dump_File->SetCurrentGroup("/FieldData/FD"); + m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD","frequency",m_FD_Samples); + } + + //create data structures... + for (size_t n = 0; n**** field_fd = Create_N_3DArray >(numLines); + m_FD_Fields.push_back(field_fd); + } +} + +int ProcessFieldsFD::Process() +{ + if (Enabled==false) return -1; + if (CheckTimestep()==false) return GetNextInterval(); + + if ((m_FD_Interval==0) || (m_Eng_Interface->GetNumberOfTimesteps()%m_FD_Interval!=0)) + return GetNextInterval(); + + FDTD_FLOAT**** field_td = CalcField(); + std::complex**** field_fd = NULL; + + double T = m_Eng_Interface->GetTime(m_dualTime); + unsigned int pos[3]; + for (size_t n = 0; n exp_jwt_2_dt = std::exp( (std::complex)(-2.0 * _I * M_PI * m_FD_Samples.at(n) * T) ); + exp_jwt_2_dt *= 2; // *2 for single-sided spectrum + exp_jwt_2_dt *= Op->GetTimestep() * m_FD_Interval; // multiply with timestep-interval + field_fd = m_FD_Fields.at(n); + for (pos[0]=0; pos[0](field_td,numLines); + ++m_FD_SampleCount; + return GetNextInterval(); +} + +void ProcessFieldsFD::PostProcess() +{ + DumpFDData(); +} + +void ProcessFieldsFD::DumpFDData() +{ + if (m_fileType==VTK_FILETYPE) + { + unsigned int pos[3]; + FDTD_FLOAT**** field = Create_N_3DArray(numLines); + std::complex**** field_fd = NULL; + double angle=0; + int Nr_Ph = 21; + + for (size_t n = 0; n exp_jwt = std::exp( (std::complex)( _I * angle) ); + field_fd = m_FD_Fields.at(n); + for (pos[0]=0; pos[0]SetFilename(ss.str()); + m_Vtk_Dump_File->ClearAllFields(); + m_Vtk_Dump_File->AddVectorField(GetFieldNameByType(m_DumpType),field); + if (m_Vtk_Dump_File->Write()==false) + cerr << "ProcessFieldsFD::Process: can't dump to file... abort! " << endl; + } + + { + //dump phase to vtk-files + for (pos[0]=0; pos[0]SetFilename(ss.str()); + m_Vtk_Dump_File->ClearAllFields(); + m_Vtk_Dump_File->AddVectorField(GetFieldNameByType(m_DumpType),field); + if (m_Vtk_Dump_File->Write()==false) + cerr << "ProcessFieldsFD::Process: can't dump to file... abort! " << endl; + } + } + Delete_N_3DArray(field,numLines); + return; + } + + if (m_fileType==HDF5_FILETYPE) + { + for (size_t n = 0; nWriteVectorField(ss.str(), m_FD_Fields.at(n), datasize)==false) + cerr << "ProcessFieldsFD::Process: can't dump to file...! " << endl; + + //legacy support, use /FieldData/FD frequency-Attribute in the future + float freq[1] = {(float)m_FD_Samples.at(n)}; + if (m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD/"+ss.str()+"_real","frequency",freq,1)==false) + cerr << "ProcessFieldsFD::Process: can't dump to file...! " << endl; + if (m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD/"+ss.str()+"_imag","frequency",freq,1)==false) + cerr << "ProcessFieldsFD::Process: can't dump to file...! " << endl; + } + return; + } + + cerr << "ProcessFieldsFD::Process: unknown File-Type" << endl; +} diff --git a/openEMS/Common/processfields_fd.h b/openEMS/Common/processfields_fd.h new file mode 100644 index 0000000..2049cc3 --- /dev/null +++ b/openEMS/Common/processfields_fd.h @@ -0,0 +1,43 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef PROCESSFIELDS_FD_H +#define PROCESSFIELDS_FD_H + +#include "processfields.h" + +class ProcessFieldsFD : public ProcessFields +{ +public: + ProcessFieldsFD(Engine_Interface_Base* eng_if); + virtual ~ProcessFieldsFD(); + + virtual std::string GetProcessingName() const {return "frequency domain field dump";} + + virtual void InitProcess(); + + virtual int Process(); + virtual void PostProcess(); + +protected: + virtual void DumpFDData(); + + //! frequency domain field storage + std::vector****> m_FD_Fields; +}; + +#endif // PROCESSFIELDS_FD_H diff --git a/openEMS/Common/processfields_sar.cpp b/openEMS/Common/processfields_sar.cpp new file mode 100644 index 0000000..9bbdab2 --- /dev/null +++ b/openEMS/Common/processfields_sar.cpp @@ -0,0 +1,335 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "processfields_sar.h" +#include "operator_base.h" +#include "tools/vtk_file_writer.h" +#include "tools/hdf5_file_writer.h" +#include "tools/sar_calculation.h" + +#include "CSPropMaterial.h" + +using namespace std; + +ProcessFieldsSAR::ProcessFieldsSAR(Engine_Interface_Base* eng_if) : ProcessFieldsFD(eng_if) +{ + m_UseCellKappa = true; + m_SAR_method = "Simple"; +} + +ProcessFieldsSAR::~ProcessFieldsSAR() +{ + for (size_t n = 0; nGetInterpolationType()!=Engine_Interface_Base::CELL_INTERPOLATE) + { + cerr << "ProcessFieldsSAR::InitProcess(): Warning, interpolation type is not supported, resetting to CELL!" << endl; + SetDumpMode2Cell(); + } + + if ((m_DumpType==SAR_RAW_DATA) && (m_fileType!=HDF5_FILETYPE)) + { + Enabled=false; + cerr << "ProcessFieldsSAR::InitProcess(): Error, wrong file type for dumping raw SAR data! skipping" << endl; + return; + + } + + ProcessFieldsFD::InitProcess(); + + if (Enabled==false) return; + + //create data structures... + for (size_t n = 0; n >(numLines)); + if (!m_UseCellKappa) + m_J_FD_Fields.push_back(Create_N_3DArray >(numLines)); + } +} + +int ProcessFieldsSAR::Process() +{ + if (Enabled==false) return -1; + if (CheckTimestep()==false) return GetNextInterval(); + + if ((m_FD_Interval==0) || (m_Eng_Interface->GetNumberOfTimesteps()%m_FD_Interval!=0)) + return GetNextInterval(); + + std::complex**** field_fd = NULL; + unsigned int pos[3]; + double T; + FDTD_FLOAT**** field_td=NULL; + + //save dump type + DumpType save_dump_type = m_DumpType; + + // calc E-field + m_DumpType = E_FIELD_DUMP; + field_td = CalcField(); + T = m_Eng_Interface->GetTime(m_dualTime); + for (size_t n = 0; n exp_jwt_2_dt = std::exp( (std::complex)(-2.0 * _I * M_PI * m_FD_Samples.at(n) * T) ); + exp_jwt_2_dt *= 2; // *2 for single-sided spectrum + exp_jwt_2_dt *= Op->GetTimestep() * m_FD_Interval; // multiply with timestep-interval + field_fd = m_E_FD_Fields.at(n); + for (pos[0]=0; pos[0](field_td,numLines); + + // calc J-field + if (!m_UseCellKappa) + { + m_DumpType = J_FIELD_DUMP; + field_td = CalcField(); + T = m_Eng_Interface->GetTime(m_dualTime); + for (size_t n = 0; n exp_jwt_2_dt = std::exp( (std::complex)(-2.0 * _I * M_PI * m_FD_Samples.at(n) * T) ); + exp_jwt_2_dt *= 2; // *2 for single-sided spectrum + exp_jwt_2_dt *= Op->GetTimestep() * m_FD_Interval; // multiply with timestep-interval + field_fd = m_J_FD_Fields.at(n); + for (pos[0]=0; pos[0](field_td,numLines); + } + + //reset dump type + m_DumpType = save_dump_type; + + ++m_FD_SampleCount; + return GetNextInterval(); +} + +void ProcessFieldsSAR::DumpFDData() +{ + if (Enabled==false) return; + unsigned int pos[3]; + unsigned int orig_pos[3]; + float*** SAR = Create3DArray(numLines); + double coord[3]; + ContinuousStructure* CSX = Op->GetGeometryCSX(); + CSProperties* prop = NULL; + CSPropMaterial* matProp = NULL; + + double power; + + float*** cell_volume = Create3DArray(numLines); + float*** cell_density = Create3DArray(numLines); + float*** cell_kappa = NULL; + if (m_UseCellKappa) + cell_kappa = Create3DArray(numLines); + + bool found_UnIsotropic=false; + + // calculate volumes and masses for all cells + for (pos[0]=0; pos[0] vPrims = Op->GetPrimitivesBoundBox(orig_pos[0], orig_pos[1], -1, CSProperties::MATERIAL); + for (pos[2]=0; pos[2]GetCellVolume(orig_pos); + cell_density[pos[0]][pos[1]][pos[2]] = 0.0; + + Op->GetCellCenterMaterialAvgCoord(orig_pos, coord); + prop = CSX->GetPropertyByCoordPriority(coord, vPrims); +// prop = CSX->GetPropertyByCoordPriority(coord,CSProperties::MATERIAL); + if (prop!=0) + { + matProp = dynamic_cast(prop); + if (matProp) + { + found_UnIsotropic |= !matProp->GetIsotropy(); + cell_density[pos[0]][pos[1]][pos[2]] = matProp->GetDensityWeighted(coord); + if (m_UseCellKappa) + cell_kappa[pos[0]][pos[1]][pos[2]] = matProp->GetKappaWeighted(0,coord); + } + } + } + } + } + if (found_UnIsotropic) + cerr << "ProcessFieldsSAR::DumpFDData(): Warning, found unisotropic material in SAR calculation... this is unsupported!" << endl; + + float* cellWidth[3]; + for (int n=0;n<3;++n) + { + cellWidth[n]=new float[numLines[n]]; + for (unsigned int i=0;iGetDiscDelta(n,posLines[n][i])*Op->GetGridDelta(); + } + + if (m_DumpType == SAR_RAW_DATA) + { + if (m_fileType!=HDF5_FILETYPE) + { + cerr << "ProcessFieldsSAR::DumpFDData(): Error, wrong file type, this should not happen!!! skipped" << endl; + return; + } + + size_t datasize[]={numLines[0],numLines[1],numLines[2]}; + for (size_t n = 0; nWriteVectorField(ss.str(), m_E_FD_Fields.at(n), datasize)==false) + cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl; + } + + m_HDF5_Dump_File->SetCurrentGroup("/CellData"); + if (m_UseCellKappa==false) + cerr << "ProcessFieldsSAR::DumpFDData: Error, cell conductivity data not available, this should not happen... skipping! " << endl; + else if (m_HDF5_Dump_File->WriteScalarField("Conductivity", cell_kappa, datasize)==false) + cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl; + if (m_HDF5_Dump_File->WriteScalarField("Density", cell_density, datasize)==false) + cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl; + if (m_HDF5_Dump_File->WriteScalarField("Volume", cell_volume, datasize)==false) + cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl; + } + else + { + SAR_Calculation SAR_Calc; + SAR_Calc.SetAveragingMethod(m_SAR_method, g_settings.GetVerboseLevel()==0); + SAR_Calc.SetDebugLevel(g_settings.GetVerboseLevel()); + SAR_Calc.SetNumLines(numLines); + if (m_DumpType == SAR_LOCAL_DUMP) + SAR_Calc.SetAveragingMass(0); + else if (m_DumpType == SAR_1G_DUMP) + SAR_Calc.SetAveragingMass(1e-3); + else if (m_DumpType == SAR_10G_DUMP) + SAR_Calc.SetAveragingMass(10e-3); + else + { + cerr << "ProcessFieldsSAR::DumpFDData: unknown SAR dump type...!" << endl; + } + SAR_Calc.SetCellDensities(cell_density); + SAR_Calc.SetCellWidth(cellWidth); + SAR_Calc.SetCellVolumes(cell_volume); + SAR_Calc.SetCellCondictivity(cell_kappa); // cell_kappa will be NULL if m_UseCellKappa is false + + for (size_t n = 0; nWriteScalarField(ss.str(), SAR, datasize)==false) + cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl; + float freq[1] = {(float)m_FD_Samples.at(n)}; + if (m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD/"+ss.str(),"frequency",freq,1)==false) + cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl; + float pow[1] = {(float)power}; + if (m_HDF5_Dump_File->WriteAtrribute("/FieldData/FD/"+ss.str(),"power",pow,1)==false) + cerr << "ProcessFieldsSAR::DumpFDData: can't dump to file...! " << endl; + } + else + cerr << "ProcessFieldsSAR::DumpFDData: unknown File-Type" << endl; + } + } + for (int n=0;n<3;++n) + delete[] cellWidth[n]; + Delete3DArray(cell_volume,numLines); + Delete3DArray(cell_density,numLines); + Delete3DArray(cell_kappa,numLines); + Delete3DArray(SAR,numLines); +} diff --git a/openEMS/Common/processfields_sar.h b/openEMS/Common/processfields_sar.h new file mode 100644 index 0000000..289100d --- /dev/null +++ b/openEMS/Common/processfields_sar.h @@ -0,0 +1,61 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#ifndef PROCESSFIELDS_SAR_H +#define PROCESSFIELDS_SAR_H + +#include "processfields_fd.h" + +class ProcessFieldsSAR : public ProcessFieldsFD +{ +public: + ProcessFieldsSAR(Engine_Interface_Base* eng_if); + virtual ~ProcessFieldsSAR(); + + virtual void SetDumpType(DumpType type); + + virtual bool NeedConductivity() const; + + virtual std::string GetProcessingName() const {return "SAR dump";} + + virtual void InitProcess(); + + virtual int Process(); + + virtual void SetSubSampling(unsigned int subSampleRate, int dir=-1); + + virtual void SetOptResolution(double optRes, int dir=-1); + + //! Set to true for using the conductivity found at the center of a cell, or false for E*J instead + virtual void SetUseCellConductivity(bool val) {m_UseCellKappa=val;} + + virtual void SetSARAveragingMethod(std::string method) {m_SAR_method=method;} + +protected: + virtual void DumpFDData(); + + bool m_UseCellKappa; + + std::string m_SAR_method; + + //! frequency domain electric field storage + std::vector****> m_E_FD_Fields; + //! frequency domain current density storage + std::vector****> m_J_FD_Fields; +}; + +#endif // PROCESSFIELDS_SAR_H diff --git a/openEMS/Common/processfields_td.cpp b/openEMS/Common/processfields_td.cpp new file mode 100644 index 0000000..d67e48b --- /dev/null +++ b/openEMS/Common/processfields_td.cpp @@ -0,0 +1,91 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "processfields_td.h" +#include "Common/operator_base.h" +#include "tools/vtk_file_writer.h" +#include "tools/hdf5_file_writer.h" +#include +#include +#include + +using namespace std; + +ProcessFieldsTD::ProcessFieldsTD(Engine_Interface_Base* eng_if) : ProcessFields(eng_if) +{ + pad_length = 8; +} + +ProcessFieldsTD::~ProcessFieldsTD() +{ +} + +void ProcessFieldsTD::InitProcess() +{ + if (Enabled==false) return; + + ProcessFields::InitProcess(); + + if (m_Vtk_Dump_File) + m_Vtk_Dump_File->SetHeader(string("openEMS TD Field Dump -- Interpolation: ")+m_Eng_Interface->GetInterpolationTypeString()); + + if (m_HDF5_Dump_File) + m_HDF5_Dump_File->SetCurrentGroup("/FieldData/TD"); +} + +int ProcessFieldsTD::Process() +{ + if (Enabled==false) return -1; + if (CheckTimestep()==false) return GetNextInterval(); + + string filename = m_filename; + + float**** field = CalcField(); + bool success = true; + + if (m_fileType==VTK_FILETYPE) + { + m_Vtk_Dump_File->SetTimestep(m_Eng_Interface->GetNumberOfTimesteps()); + m_Vtk_Dump_File->ClearAllFields(); + m_Vtk_Dump_File->AddVectorField(GetFieldNameByType(m_DumpType),field); + success &= m_Vtk_Dump_File->Write(); + } + else if (m_fileType==HDF5_FILETYPE) + { + stringstream ss; + ss << std::setw( pad_length ) << std::setfill( '0' ) << m_Eng_Interface->GetNumberOfTimesteps(); + size_t datasize[]={numLines[0],numLines[1],numLines[2]}; + success &= m_HDF5_Dump_File->WriteVectorField(ss.str(), field, datasize); + float time[1] = {(float)m_Eng_Interface->GetTime(m_dualTime)}; + success &= m_HDF5_Dump_File->WriteAtrribute("/FieldData/TD/"+ss.str(),"time",time,1); + } + else + { + success = false; + cerr << "ProcessFieldsTD::Process: unknown File-Type" << endl; + } + + Delete_N_3DArray(field,numLines); + + if (success==false) + { + SetEnable(false); + cerr << "ProcessFieldsTD::Process: can't dump to file... disabled! " << endl; + } + + return GetNextInterval(); +} diff --git a/openEMS/Common/processfields_td.h b/openEMS/Common/processfields_td.h new file mode 100644 index 0000000..91c4c04 --- /dev/null +++ b/openEMS/Common/processfields_td.h @@ -0,0 +1,42 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef PROCESSFIELDS_TD_H +#define PROCESSFIELDS_TD_H + +#include "processfields.h" + +class ProcessFieldsTD : public ProcessFields +{ +public: + ProcessFieldsTD(Engine_Interface_Base* eng_if); + virtual ~ProcessFieldsTD(); + + virtual std::string GetProcessingName() const {return "time domain field dump";} + + virtual void InitProcess(); + + virtual int Process(); + + //! Set the length of the filename timestep pad filled with zeros (default is 8) + void SetPadLength(int val) {pad_length=val;}; + +protected: + int pad_length; +}; + +#endif // PROCESSFIELDS_TD_H diff --git a/openEMS/Common/processing.cpp b/openEMS/Common/processing.cpp new file mode 100644 index 0000000..a444d9d --- /dev/null +++ b/openEMS/Common/processing.cpp @@ -0,0 +1,372 @@ +/* +* Copyright (C) 2010-2015 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 . +*/ + +#include "tools/global.h" +#include "tools/useful.h" +#include "Common/operator_base.h" +#include +#include "processing.h" +#include + +using namespace std; + +Processing::Processing(Engine_Interface_Base* eng_if) +{ + m_Eng_Interface = NULL; + SetEngineInterface(eng_if); + + Enabled = true; + m_PS_pos = 0; + SetPrecision(12); + ProcessInterval=0; + m_FD_SampleCount=0; + m_FD_Interval=0; + m_weight=1; + m_Flush = false; + m_dualMesh = false; + m_dualTime = false; + m_SnapMethod = 0; + m_Mesh_Type = CARTESIAN_MESH; + + startTS=0; + stopTS =UINT_MAX; + for (int n=0;n<3;++n) + { + start[n]=0; + stop[n]=0; + } +} + +Processing::~Processing() +{ + SetEngineInterface(NULL); + file.close(); +} + +void Processing::Reset() +{ + m_PS_pos=0; +} + +void Processing::SetEngineInterface(Engine_Interface_Base* eng_if) +{ + delete m_Eng_Interface; + m_Eng_Interface = eng_if; + if (m_Eng_Interface) + Op=m_Eng_Interface->GetOperator(); + else + Op=NULL; +} + +void Processing::SetName(string val, int number) +{ + stringstream ss; + ss << val << "_" << number; + SetName(ss.str()); +} + +bool Processing::CheckTimestep() +{ + unsigned int ts = m_Eng_Interface->GetNumberOfTimesteps(); + if (tsstopTS) + return false; + if (m_ProcessSteps.size()>m_PS_pos) + { + if (m_ProcessSteps.at(m_PS_pos)==ts) + { + ++m_PS_pos; + return true; + } + } + if (ProcessInterval) + { + if (ts%ProcessInterval==0) return true; + } + + if (m_FD_Interval) + { + if (ts%m_FD_Interval==0) return true; + } + return false; +} + +int Processing::GetNextInterval() const +{ + if (Enabled==false) return -1; + int next=INT_MAX; + int ts = (int)m_Eng_Interface->GetNumberOfTimesteps(); + if (m_ProcessSteps.size()>m_PS_pos) + { + next = (int)m_ProcessSteps.at(m_PS_pos)-ts; + } + if (ProcessInterval!=0) + { + int next_Interval = (int)ProcessInterval - ts%ProcessInterval; + if (next_Interval steps) +{ + for (size_t n=0; nGetTimestep()); + + if (nyquistTS == 0) + { + cerr << "Processing::AddFrequency: Requested frequency " << freq << " is too high for the current timestep used... skipping..." << endl; + return; + } + else if (nyquistTSGetNumberOfNyquistTimesteps()) + { + cerr << "Processing::AddFrequency: Warning: Requested frequency " << freq << " is higher than maximum excited frequency..." << endl; + } + + if (m_FD_Interval==0) + m_FD_Interval = Op->GetNumberOfNyquistTimesteps(); + if (m_FD_Interval>nyquistTS) + m_FD_Interval = nyquistTS; + + m_FD_Samples.push_back(freq); +} + +void Processing::AddFrequency(vector *freqs) +{ + for (size_t n=0; nsize(); ++n) + { + AddFrequency(freqs->at(n)); + } +} + +void Processing::DefineStartStopCoord(double* dstart, double* dstop) +{ + m_Dimension = Op->SnapBox2Mesh(dstart,dstop,start,stop,m_dualMesh,false,m_SnapMethod, m_start_inside, m_stop_inside); + if (m_Dimension<0) + { + cerr << "Processing::DefineStartStopCoord: Warning in " << m_Name << " (" << GetProcessingName() << ") : Box is outside the field domain!! Disabling" << endl; + Enabled = false; + return; + } +} + +void Processing::ShowSnappedCoords() +{ + cerr << m_Name << ": snapped "; + if (m_dualMesh) + cerr << "dual"; + else + cerr << "primary"; + cerr << " coords: (" << Op->GetDiscLine( 0, start[0], m_dualMesh ) << "," + << Op->GetDiscLine( 1, start[1], m_dualMesh ) << "," << Op->GetDiscLine( 2, start[2], m_dualMesh ) << ") -> (" + << Op->GetDiscLine( 0, stop[0], m_dualMesh ) << ","<< Op->GetDiscLine( 1, stop[1], m_dualMesh ) << "," + << Op->GetDiscLine( 2, stop[2], m_dualMesh ) << ")"; + cerr << " [" << start[0] << "," << start[1] << "," << start[2] << "] -> [" + << stop[0] << "," << stop[1] << "," << stop[2] << "]" << endl; +} + +void Processing::SetProcessStartStopTime(double start, double stop) +{ + double dT = Op->GetTimestep(); + startTS = 0; + stopTS = UINT_MAX; + if (start>0) + startTS = floor(start/dT); + if (stop>0) + stopTS = ceil(stop/dT); + if (stopTS<=startTS) + { + cerr << "Processing::SetProcessStartStopTimestep: Invalid start/stop values! Disabling!" << endl; + startTS = 0; + stopTS = UINT_MAX; + } +} + +void Processing::OpenFile( string outfile ) +{ + if (file.is_open()) + file.close(); + + file.open( outfile.c_str() ); + if (!file.is_open()) + cerr << "Can't open file: " << outfile << endl; + + m_filename = outfile; +} + +void Processing::PostProcess() +{ + FlushData(); +} + +void Processing::DumpBox2File( string vtkfilenameprefix, bool dualMesh ) const +{ + string vtkfilename = vtkfilenameprefix + m_filename + ".vtk"; + + ofstream file( vtkfilename.c_str() ); + if (!file.is_open()) + { + cerr << "Processing::DumpBoxes2File(): Can't open file: " << vtkfilename << endl; + return; + } + + // normalize coordinates + double s1[3], s2[3]; + for (int i=0; i<3; i++) + { + s1[i] = min(Op->GetDiscLine(i,start[i],dualMesh),Op->GetDiscLine(i,stop[i],dualMesh)); + s2[i] = max(Op->GetDiscLine(i,start[i],dualMesh),Op->GetDiscLine(i,stop[i],dualMesh)); + } + + // fix degenerate box/plane -> line (paraview display problem) + if (((s1[0] == s2[0]) && (s1[1] == s2[1])) || ((s1[0] == s2[0]) && (s1[2] == s2[2])) || ((s1[2] == s2[2]) && (s1[1] == s2[1]))) + { + // line are not displayed correctly -> enlarge + for (int i=0; i<3; i++) + { + double delta = min( Op->GetEdgeLength( i, start,dualMesh ), Op->GetEdgeLength( i, stop,dualMesh ) ) / Op->GetGridDelta() / 4.0; + s1[i] -= delta; + s2[i] += delta; + } + } + + // rescale coordinates +#ifndef OUTPUT_IN_DRAWINGUNITS + double scaling = Op->GetGridDelta(); + for (int i=0; i<3; i++) + { + s1[i] *= scaling; + s2[i] *= scaling; + } +#endif + + file << "# vtk DataFile Version 2.0" << endl; + file << "" << endl; + file << "ASCII" << endl; + file << "DATASET POLYDATA" << endl; + + file << "POINTS 8 float" << endl; + file << s1[0] << " " << s1[1] << " " << s1[2] << endl; + file << s2[0] << " " << s1[1] << " " << s1[2] << endl; + file << s2[0] << " " << s2[1] << " " << s1[2] << endl; + file << s1[0] << " " << s2[1] << " " << s1[2] << endl; + file << s1[0] << " " << s1[1] << " " << s2[2] << endl; + file << s2[0] << " " << s1[1] << " " << s2[2] << endl; + file << s2[0] << " " << s2[1] << " " << s2[2] << endl; + file << s1[0] << " " << s2[1] << " " << s2[2] << endl; + + file << "POLYGONS 6 30" << endl; + file << "4 0 1 2 3" << endl; + file << "4 4 5 6 7" << endl; + file << "4 7 6 2 3" << endl; + file << "4 4 5 1 0" << endl; + file << "4 0 4 7 3" << endl; + file << "4 5 6 2 1" << endl; + + file.close(); +} + +void ProcessingArray::AddProcessing(Processing* proc) +{ + ProcessArray.push_back(proc); +} + +void ProcessingArray::InitAll() +{ + for (size_t i=0; iInitProcess(); + } +} + +void ProcessingArray::FlushNext() +{ + for (size_t i=0; iFlushNext(); + } +} + +void ProcessingArray::Reset() +{ + for (size_t i=0; iReset(); + } +} + +void ProcessingArray::DeleteAll() +{ + for (size_t i=0; iPreProcess(); +} + +int ProcessingArray::Process() +{ + int nextProcess=maxInterval; + //this could be done nicely in parallel?? + for (size_t i=0; iProcess(); + if ((step>0) && (stepPostProcess(); +} + +void ProcessingArray::DumpBoxes2File( string vtkfilenameprefix ) const +{ + for (size_t i=0; iDumpBox2File( vtkfilenameprefix ); +} diff --git a/openEMS/Common/processing.h b/openEMS/Common/processing.h new file mode 100644 index 0000000..2042706 --- /dev/null +++ b/openEMS/Common/processing.h @@ -0,0 +1,204 @@ +/* +* Copyright (C) 2010-2015 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 . +*/ + +#ifndef PROCESSING_H +#define PROCESSING_H + +#include +typedef std::complex double_complex; +#define _I double_complex(0.0,1.0) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common/engine_interface_base.h" + +class Operator_Base; + +class Processing +{ +public: + virtual ~Processing(); + + enum MeshType { CARTESIAN_MESH, CYLINDRICAL_MESH}; + + //! Set the interface to the engine. Each processing needs its own engine interface. This class will take ownership and cleanup the interface on deletion! + void SetEngineInterface(Engine_Interface_Base* eng_if); + + virtual void SetName(std::string val) {m_Name=val;} + virtual void SetName(std::string val, int number); + virtual std::string GetName() const {return m_Name;} + + //! Get the name for this processing, will be used in file description. + virtual std::string GetProcessingName() const = 0; + + virtual void InitProcess() {}; + virtual void Reset(); + + virtual void DefineStartStopCoord(double* dstart, double* dstop); + + virtual void ShowSnappedCoords(); + + void SetProcessInterval(unsigned int interval) {ProcessInterval=std::max((unsigned int)1,interval);} + void SetProcessStartStopTime(double start, double stop); + + void AddStep(unsigned int step); + void AddSteps(std::vector steps); + + void AddFrequency(double freq); + void AddFrequency(std::vector *freqs); + + bool CheckTimestep(); + + //! Process data prior to the simulation run. + virtual void PreProcess() {}; + + //! Process data during simulation run. + virtual int Process() {return GetNextInterval();} + + //! Process data after simulation has finished. + virtual void PostProcess(); + + //! If disabled, Process() will do nothing... + virtual void SetEnable(bool val) {Enabled=val;} + //! If disabled, Process() will do nothing... + virtual bool GetEnable() const {return Enabled;} + + virtual void SetWeight(double weight) {m_weight=weight;} + virtual double GetWeight() {return m_weight;} + + //! Invoke this flag to flush all stored data to disk + virtual void FlushNext() {m_Flush = true;} + virtual void FlushData() {}; + + void SetMeshType(MeshType meshType) {m_Mesh_Type=meshType;} + + //! Set the dump precision + void SetPrecision(unsigned int val) {m_precision = val;} + + //! Dump probe geometry to file (will obay main or dual mesh property) + virtual void DumpBox2File(std::string vtkfilenameprefix) const {DumpBox2File(vtkfilenameprefix,m_dualMesh);} + + //! Dump probe geometry to file + virtual void DumpBox2File(std::string vtkfilenameprefix, bool dualMesh) const; + + virtual void SetDualMesh(bool val) {m_dualMesh=val;} + virtual void SetDualTime(bool val) {m_dualTime=val;} + +protected: + Processing(Engine_Interface_Base* eng_if); + Engine_Interface_Base* m_Eng_Interface; + const Operator_Base* Op; + MeshType m_Mesh_Type; + + unsigned int m_precision; + + std::string m_Name; + + bool m_Flush; + + double m_weight; + + bool Enabled; + + int GetNextInterval() const; + unsigned int ProcessInterval; + + size_t m_PS_pos; //! current position in list of processing steps + std::vector m_ProcessSteps; //! list of processing steps + + //! Vector of frequency samples + std::vector m_FD_Samples; + //! Number of samples already processed + unsigned int m_FD_SampleCount; + //! Sampling interval needed for the FD_Samples + unsigned int m_FD_Interval; + + //! define if given coords are on main or dualMesh (default is false) + bool m_dualMesh; + + //! define if given processing uses the dual time concept (default is false); + bool m_dualTime; + + //! define the snap method used for this processing + int m_SnapMethod; + + //! dimension of the snapped box + int m_Dimension; + + //! define/store snapped start/stop coords as mesh index + unsigned int start[3]; + unsigned int stop[3]; + + //! start/stop timestep + unsigned int startTS, stopTS; + + //! define/store if snapped start/stop coords are inside the field domain + bool m_start_inside[3]; + bool m_stop_inside[3]; + + std::ofstream file; + std::string m_filename; + + virtual void OpenFile(std::string outfile); +}; + +class ProcessingArray +{ +public: + ProcessingArray(unsigned int maximalInterval) {maxInterval=maximalInterval;} + ~ProcessingArray() {}; + + void AddProcessing(Processing* proc); + + void InitAll(); + + //! Invoke this flag to flush all stored data to disk for all processings on next Process() + void FlushNext(); + + void Reset(); + + //! Deletes all given processing's, can be helpful, but use carefull!!! + void DeleteAll(); + + //! Invoke PreProcess() on all Processings. + void PreProcess(); + + //! Invoke Process() on all Processings. Will return the smallest next iteration interval. + int Process(); + + //! Invoke PostProcess() on all Processings. + void PostProcess(); + + void DumpBoxes2File(std::string vtkfilenameprefix ) const; + + size_t GetNumberOfProcessings() const {return ProcessArray.size();} + + Processing* GetProcessing(size_t number) {return ProcessArray.at(number);} + +protected: + unsigned int maxInterval; + std::vector ProcessArray; +}; + +#endif // PROCESSING_H diff --git a/openEMS/Common/processintegral.cpp b/openEMS/Common/processintegral.cpp new file mode 100644 index 0000000..b64b479 --- /dev/null +++ b/openEMS/Common/processintegral.cpp @@ -0,0 +1,177 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "processintegral.h" +#include "Common/operator_base.h" +#include "time.h" +#include + +using namespace std; + +ProcessIntegral::ProcessIntegral(Engine_Interface_Base* eng_if) : Processing(eng_if) +{ + m_Results=NULL; + m_FD_Results=NULL; + m_normDir = -1; +} + +ProcessIntegral::~ProcessIntegral() +{ + delete[] m_Results; + delete[] m_FD_Results; + m_Results = NULL; + m_FD_Results = NULL; +} + + +void ProcessIntegral::InitProcess() +{ + delete[] m_Results; m_Results = NULL; + delete[] m_FD_Results; m_FD_Results = NULL; + + if (!Enabled) + return; + + m_Results = new double[GetNumberOfIntegrals()]; + m_FD_Results = new vector[GetNumberOfIntegrals()]; + + m_filename = m_Name; + OpenFile(m_filename); + + //write header + time_t rawTime; + time(&rawTime); + file << "% time-domain " << GetProcessingName() << " by openEMS " << GIT_VERSION << " @" << ctime(&rawTime); + file << "% start-coordinates: (" + << Op->GetDiscLine(0,start[0])*Op->GetGridDelta() << "," + << Op->GetDiscLine(1,start[1])*Op->GetGridDelta() << "," + << Op->GetDiscLine(2,start[2])*Op->GetGridDelta() << ") m -> [" << start[0] << "," << start[1] << "," << start[2] << "]" << endl; + file << "% stop-coordinates: (" + << Op->GetDiscLine(0,stop[0])*Op->GetGridDelta() << "," + << Op->GetDiscLine(1,stop[1])*Op->GetGridDelta() << "," + << Op->GetDiscLine(2,stop[2])*Op->GetGridDelta() << ") m -> [" << stop[0] << "," << stop[1] << "," << stop[2] << "]" << endl; + file << "% t/s"; + for (int n=0;nGetDiscLine(0,start[0])*Op->GetGridDelta() << "," + << Op->GetDiscLine(1,start[1])*Op->GetGridDelta() << "," + << Op->GetDiscLine(2,start[2])*Op->GetGridDelta() << ") m -> [" << start[0] << "," << start[1] << "," << start[2] << "]" << endl; + file << "% stop-coordinates: (" + << Op->GetDiscLine(0,stop[0])*Op->GetGridDelta() << "," + << Op->GetDiscLine(1,stop[1])*Op->GetGridDelta() << "," + << Op->GetDiscLine(2,stop[2])*Op->GetGridDelta() << ") m -> [" << stop[0] << "," << stop[1] << "," << stop[2] << "]" << endl; + file << "% f/Hz"; + for (int n=0;nGetTime(m_dualTime); + + if (ProcessInterval) + { + if (m_Eng_Interface->GetNumberOfTimesteps()%ProcessInterval==0) + { + file << setprecision(m_precision) << time; + for (int n=0; nGetNumberOfTimesteps()%m_FD_Interval==0) + { + for (size_t n=0; nGetTimestep() * (double)m_FD_Interval; + } + ++m_FD_SampleCount; + if (m_Flush) + FlushData(); + m_Flush = false; + } + } + + return GetNextInterval(); +} + +double* ProcessIntegral::CalcMultipleIntegrals() +{ + m_Results[0] = CalcIntegral(); + return m_Results; +} diff --git a/openEMS/Common/processintegral.h b/openEMS/Common/processintegral.h new file mode 100644 index 0000000..1bddfd6 --- /dev/null +++ b/openEMS/Common/processintegral.h @@ -0,0 +1,71 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef PROCESSINTEGRAL_H +#define PROCESSINTEGRAL_H + +#include "processing.h" + +//! Abstract base class for integral parameter processing +/*! + \todo Weighting is applied equally to all integral parameter --> todo: weighting for each result individually + */ +class ProcessIntegral : public Processing +{ +public: + virtual ~ProcessIntegral(); + + virtual void InitProcess(); + + virtual std::string GetProcessingName() const = 0; + + virtual void GetNormalDir(int nd) {m_normDir=nd;} + + //! Flush FD data to disk + virtual void FlushData(); + + //! This method can calculate multiple integral parameter and must be overloaded for each derived class. \sa GetNumberOfIntegrals + /*! + This method will store its integral results internally with a size given by GetNumberOfIntegrals() + It will return the result for the CalcIntegral() as default. + */ + virtual double* CalcMultipleIntegrals(); + + //! Get the name of the integral for the given row. The names will be used in the file header. + virtual std::string GetIntegralName(int row) const = 0; + + //! Number of calculated results produced by this integral processing. \sa CalcMultipleIntegrals + virtual int GetNumberOfIntegrals() const {return 1;} + + //! This method should calculate the integral parameter and must be overloaded for each derived class + virtual double CalcIntegral() {return 0;} + + //! This method will write the TD and FD dump files using CalcIntegral() to calculate the integral parameter + virtual int Process(); + +protected: + ProcessIntegral(Engine_Interface_Base* eng_if); + + void Dump_FD_Data(double factor, std::string filename); + + std::vector *m_FD_Results; + double *m_Results; + + int m_normDir; // normal direction as required by some integral processings +}; + +#endif // PROCESSINTEGRAL_H diff --git a/openEMS/Common/processmodematch.cpp b/openEMS/Common/processmodematch.cpp new file mode 100644 index 0000000..620257d --- /dev/null +++ b/openEMS/Common/processmodematch.cpp @@ -0,0 +1,267 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "processmodematch.h" +#include "CSFunctionParser.h" +#include "Common/operator_base.h" +#include "tools/array_ops.h" + +using namespace std; + +ProcessModeMatch::ProcessModeMatch(Engine_Interface_Base* eng_if) : ProcessIntegral(eng_if) +{ + for (int n=0; n<2; ++n) + { + m_ModeParser[n] = new CSFunctionParser(); + m_ModeDist[n] = NULL; + } + delete[] m_Results; + m_Results = new double[2]; +} + +ProcessModeMatch::~ProcessModeMatch() +{ + for (int n=0; n<2; ++n) + { + delete m_ModeParser[n]; + m_ModeParser[n] = NULL; + } + Reset(); +} + +string ProcessModeMatch::GetIntegralName(int row) const +{ + if (row==0) + { + if (m_ModeFieldType==0) + return "voltage"; + if (m_ModeFieldType==1) + return "current"; + } + if (row==1) + { + return "mode_purity"; + } + return "unknown"; +} + +string ProcessModeMatch::GetProcessingName() const +{ + if (m_ModeFieldType==0) + return "voltage mode matching"; + if (m_ModeFieldType==1) + return "current mode matching"; + return "unknown mode matching"; +} + +void ProcessModeMatch::InitProcess() +{ + if (!Enabled) return; + + if (m_Eng_Interface==NULL) + { + cerr << "ProcessModeMatch::InitProcess: Error, Engine_Interface is NULL, abort mode mathcing..." << endl; + Enabled=false; + return; + } + m_Eng_Interface->SetInterpolationType(Engine_Interface_Base::NODE_INTERPOLATE); + + int Dump_Dim=0; + m_ny = -1; + for (int n=0; n<3; ++n) + { + if (start[n]>stop[n]) + { + unsigned int help=start[n]; + start[n]=stop[n]; + stop[n]=help; + } + + //exclude boundaries from mode-matching + if (start[n]==0) + ++start[n]; + if (stop[n]==Op->GetNumberOfLines(n)-1) + --stop[n]; + + if (stop[n]!=start[n]) + ++Dump_Dim; + + if (stop[n] == start[n]) + m_ny = n; + } + + if ((Dump_Dim!=2) || (m_ny<0)) + { + cerr << "ProcessModeMatch::InitProcess(): Warning Mode Matching Integration Box \"" << m_filename << "\" is not a surface (found dimension: " << Dump_Dim << ")" << endl; + SetEnable(false); + Reset(); + return; + } + + int nP = (m_ny+1)%3; + int nPP = (m_ny+2)%3; + m_numLines[0] = stop[nP] - start[nP] + 1; + m_numLines[1] = stop[nPP] - start[nPP] + 1; + + for (int n=0; n<2; ++n) + { + int ny = (m_ny+n+1)%3; + int res = m_ModeParser[n]->Parse(m_ModeFunction[ny], "x,y,z,rho,a,r,t"); + if (res >= 0) + { + cerr << "ProcessModeMatch::InitProcess(): Warning, an error occured parsing the mode matching function (see below) ..." << endl; + cerr << m_ModeFunction[ny] << "\n" << string(res, ' ') << "^\n" << m_ModeParser[n]->ErrorMsg() << "\n"; + SetEnable(false); + Reset(); + } + } + + for (int n=0; n<2; ++n) + { + m_ModeDist[n] = Create2DArray(m_numLines); + } + + bool dualMesh = m_ModeFieldType==1; + unsigned int pos[3] = {0,0,0}; + double discLine[3] = {0,0,0}; + double gridDelta = 1; // 1 -> mode-matching function is definied in drawing units... + double var[7]; + pos[m_ny] = start[m_ny]; + discLine[m_ny] = Op->GetDiscLine(m_ny,pos[m_ny],dualMesh); + double norm = 0; + double area = 0; + for (unsigned int posP = 0; posPGetDiscLine(nP,pos[nP],dualMesh); + for (unsigned int posPP = 0; posPPGetDiscLine(nPP,pos[nPP],dualMesh); + + var[0] = discLine[0] * gridDelta; // x + var[1] = discLine[1] * gridDelta; // y + var[2] = discLine[2] * gridDelta; // z + var[3] = sqrt(discLine[0]*discLine[0] + discLine[1]*discLine[1]) * gridDelta; // rho = sqrt(x^2 + y^2) + var[4] = atan2(discLine[1], discLine[0]); // a = atan(y,x) + var[5] = sqrt(pow(discLine[0],2)+pow(discLine[1],2)+pow(discLine[2],2)) * gridDelta; // r + var[6] = asin(1)-atan(var[2]/var[3]); //theta (t) + + if (m_Mesh_Type == CYLINDRICAL_MESH) + { + var[3] = discLine[0] * gridDelta; // rho + var[4] = discLine[1]; // a + var[0] = discLine[0] * cos(discLine[1]) * gridDelta; // x = r*cos(a) + var[1] = discLine[0] * sin(discLine[1]) * gridDelta; // y = r*sin(a) + var[5] = sqrt(pow(discLine[0],2)+pow(discLine[2],2)) * gridDelta; // r + var[6] = asin(1)-atan(var[2]/var[3]); //theta (t) + } + area = Op->GetNodeArea(m_ny,pos,dualMesh); + 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]))) + m_ModeDist[n][posP][posPP] = 0.0; + norm += pow(m_ModeDist[n][posP][posPP],2) * area; + } +// cerr << discLine[0] << " " << discLine[1] << " : " << m_ModeDist[0][posP][posPP] << " , " << m_ModeDist[1][posP][posPP] << endl; + } + } + + norm = sqrt(norm); +// cerr << norm << endl; + // normalize template function... + for (unsigned int posP = 0; posP(m_ModeDist[n],m_numLines); + m_ModeDist[n] = NULL; + } +} + + +void ProcessModeMatch::SetModeFunction(int ny, string function) +{ + if ((ny<0) || (ny>2)) return; + m_ModeFunction[ny] = function; +} + +void ProcessModeMatch::SetFieldType(int type) +{ + m_ModeFieldType = type; + if ((type<0) || (type>1)) + cerr << "ProcessModeMatch::SetFieldType: Warning, unknown field type..." << endl; +} + +double* ProcessModeMatch::CalcMultipleIntegrals() +{ + double value = 0; + double field = 0; + double purity = 0; + double area = 0; + bool dualMesh = m_ModeFieldType==1; + + int nP = (m_ny+1)%3; + int nPP = (m_ny+2)%3; + + unsigned int pos[3] = {0,0,0}; + pos[m_ny] = start[m_ny]; + + double out[3]={0,0,0}; + + for (unsigned int posP = 0; posPGetNodeArea(m_ny,pos,dualMesh); + if (m_ModeFieldType==0) + m_Eng_Interface->GetEField(pos,out); + if (m_ModeFieldType==1) + m_Eng_Interface->GetHField(pos,out); + + for (int n=0; n<2; ++n) + { + field = out[(m_ny+n+1)%3]; + value += field * m_ModeDist[n][posP][posPP] * area; + purity += field*field * area; + } + } + } + if (purity!=0) + m_Results[1] = value*value/purity; + else + m_Results[1] = 0; + m_Results[0] = value; + return m_Results; +} diff --git a/openEMS/Common/processmodematch.h b/openEMS/Common/processmodematch.h new file mode 100644 index 0000000..0bb03b7 --- /dev/null +++ b/openEMS/Common/processmodematch.h @@ -0,0 +1,68 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef PROCESSMODEMATCH_H +#define PROCESSMODEMATCH_H + +#include "processintegral.h" + +class CSFunctionParser; + +//! Processing class to match a mode to a given analytic function and return the integral value. +/*! + The analytric function has to be definied in drawing units. + It will return the integral value and the mode purity as a secondary value. + */ +class ProcessModeMatch : public ProcessIntegral +{ +public: + ProcessModeMatch(Engine_Interface_Base* eng_if); + virtual ~ProcessModeMatch(); + + virtual std::string GetProcessingName() const; + + virtual std::string GetIntegralName(int row) const; + + virtual void InitProcess(); + virtual void Reset(); + + //! Set the field type (0 electric field, 1 magnetic field) + void SetFieldType(int type); + //! Set the mode function in the given direction ny. For example: SetModeFunction(0,"cos(pi/1000*x)*sin(pi/500*y)"); + void SetModeFunction(int ny, std::string function); + + virtual int GetNumberOfIntegrals() const {return 2;} + virtual double* CalcMultipleIntegrals(); + +protected: + //normal direction of the mode plane + int m_ny; + + int m_ModeFieldType; + + double GetField(int ny, const unsigned int pos[3]); + double GetEField(int ny, const unsigned int pos[3]); + double GetHField(int ny, const unsigned int pos[3]); + + std::string m_ModeFunction[3]; + CSFunctionParser* m_ModeParser[2]; + + unsigned int m_numLines[2]; + double** m_ModeDist[2]; +}; + +#endif // PROCESSMODEMATCH_H diff --git a/openEMS/Common/processvoltage.cpp b/openEMS/Common/processvoltage.cpp new file mode 100644 index 0000000..6875b03 --- /dev/null +++ b/openEMS/Common/processvoltage.cpp @@ -0,0 +1,40 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "processvoltage.h" +#include + +ProcessVoltage::ProcessVoltage(Engine_Interface_Base* eng_if) : ProcessIntegral(eng_if) +{ +} + +ProcessVoltage::~ProcessVoltage() +{ +} + +std::string ProcessVoltage::GetIntegralName(int row) const +{ + if (row==0) + return "voltage"; + return "unknown"; +} + +double ProcessVoltage::CalcIntegral() +{ + //integrate voltages from start to stop on a line + return m_Eng_Interface->CalcVoltageIntegral(start,stop); +} diff --git a/openEMS/Common/processvoltage.h b/openEMS/Common/processvoltage.h new file mode 100644 index 0000000..509ddbf --- /dev/null +++ b/openEMS/Common/processvoltage.h @@ -0,0 +1,39 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef PROCESSVOLTAGE_H +#define PROCESSVOLTAGE_H + +#include "processintegral.h" + +//! Process voltage along a line from start to stop coordinates. ATM integration along the axis e.g.: in x, then y then z direction (Future: diagonal integration) +class ProcessVoltage : public ProcessIntegral +{ +public: + ProcessVoltage(Engine_Interface_Base* eng_if); + virtual ~ProcessVoltage(); + + virtual std::string GetProcessingName() const {return "voltage integration";} + + virtual std::string GetIntegralName(int row) const; + + virtual double CalcIntegral(); + +protected: +}; + +#endif // PROCESSVOLTAGE_H diff --git a/openEMS/Common/readme.txt b/openEMS/Common/readme.txt new file mode 100644 index 0000000..8c62be8 --- /dev/null +++ b/openEMS/Common/readme.txt @@ -0,0 +1,6 @@ +readme for openEMS/Common + +- This folder contains all classes common for all numerical solver included in openEMS (currently only EC-FDTD) + - Operator-Base class + - Engine-Interface classes + - Common processing classes diff --git a/openEMS/Doxyfile b/openEMS/Doxyfile new file mode 100644 index 0000000..0b67b59 --- /dev/null +++ b/openEMS/Doxyfile @@ -0,0 +1,1551 @@ +# Doxyfile 1.6.3 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = openEMS + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it parses. +# With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this tag. +# The format is ext=language, where ext is a file extension, and language is one of +# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, +# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by +# doxygen. The layout file controls the global structure of the generated output files +# in an output format independent way. The create the layout file that represents +# doxygen's defaults, run doxygen with the -l option. You can optionally specify a +# file name after the option, if omitted DoxygenLayout.xml will be used as the name +# of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . FDTD FDTD/extensions Common tools + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER +# are set, an additional index file will be generated that can be used as input for +# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated +# HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. +# For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's +# filter section matches. +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be implemented using a PHP enabled web server instead of at the web client using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server based approach is that it scales better to large projects and allows full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = YES + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/openEMS/FDTD/CMakeLists.txt b/openEMS/FDTD/CMakeLists.txt new file mode 100644 index 0000000..b0358d3 --- /dev/null +++ b/openEMS/FDTD/CMakeLists.txt @@ -0,0 +1,30 @@ + +if (WITH_MPI) + set(MPI_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/openems_fdtd_mpi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_mpi.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_mpi.cpp + ) +endif() + +set(SOURCES + ${SOURCES} + ${MPI_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/engine.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_multithread.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_cylinder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_cylinder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_sse.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_sse.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_sse_compressed.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_sse_compressed.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_multithread.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/excitation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_cylindermultigrid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_cylindermultigrid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_interface_fdtd.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_interface_sse_fdtd.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_interface_cylindrical_fdtd.cpp + PARENT_SCOPE +) diff --git a/openEMS/FDTD/engine.cpp b/openEMS/FDTD/engine.cpp new file mode 100644 index 0000000..26725e6 --- /dev/null +++ b/openEMS/FDTD/engine.cpp @@ -0,0 +1,232 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "engine.h" +#include "extensions/engine_extension.h" +#include "extensions/operator_extension.h" +#include "tools/array_ops.h" + +//! \brief construct an Engine instance +//! it's the responsibility of the caller to free the returned pointer +Engine* Engine::New(const Operator* op) +{ + cout << "Create FDTD engine" << endl; + Engine* e = new Engine(op); + e->Init(); + return e; +} + +Engine::Engine(const Operator* op) +{ + m_type = BASIC; + numTS = 0; + Op = op; + for (int n=0; n<3; ++n) + numLines[n] = Op->GetNumberOfLines(n, true); + volt=NULL; + curr=NULL; +} + +Engine::~Engine() +{ + this->Reset(); +} + +void Engine::Init() +{ + numTS = 0; + volt = Create_N_3DArray(numLines); + curr = Create_N_3DArray(numLines); + + InitExtensions(); + SortExtensionByPriority(); +} + +void Engine::InitExtensions() +{ + for (size_t n=0; nGetNumberOfExtentions(); ++n) + { + Operator_Extension* op_ext = Op->GetExtension(n); + Engine_Extension* eng_ext = op_ext->CreateEngineExtention(); + if (eng_ext) + { + eng_ext->SetEngine(this); + m_Eng_exts.push_back(eng_ext); + } + } +} + +void Engine::ClearExtensions() +{ + for (size_t n=0; n1) + { + cout << "--- Engine::SortExtensionByPriority() ---" << endl; + for (size_t n=0; nGetExtensionName() << " (" << m_Eng_exts.at(n)->GetPriority() << ")" << endl; + } +} + +void Engine::Reset() +{ + Delete_N_3DArray(volt,numLines); + volt=NULL; + Delete_N_3DArray(curr,numLines); + curr=NULL; + + ClearExtensions(); +} + +void Engine::UpdateVoltages(unsigned int startX, unsigned int numX) +{ + unsigned int pos[3]; + bool shift[3]; + + pos[0] = startX; + //voltage updates + for (unsigned int posX=0; posXvv[0][pos[0]][pos[1]][pos[2]]; + volt[0][pos[0]][pos[1]][pos[2]] += Op->vi[0][pos[0]][pos[1]][pos[2]] * ( curr[2][pos[0]][pos[1]][pos[2]] - curr[2][pos[0]][pos[1]-shift[1]][pos[2]] - curr[1][pos[0]][pos[1]][pos[2]] + curr[1][pos[0]][pos[1]][pos[2]-shift[2]]); + + //for y + volt[1][pos[0]][pos[1]][pos[2]] *= Op->vv[1][pos[0]][pos[1]][pos[2]]; + volt[1][pos[0]][pos[1]][pos[2]] += Op->vi[1][pos[0]][pos[1]][pos[2]] * ( curr[0][pos[0]][pos[1]][pos[2]] - curr[0][pos[0]][pos[1]][pos[2]-shift[2]] - curr[2][pos[0]][pos[1]][pos[2]] + curr[2][pos[0]-shift[0]][pos[1]][pos[2]]); + + //for z + volt[2][pos[0]][pos[1]][pos[2]] *= Op->vv[2][pos[0]][pos[1]][pos[2]]; + volt[2][pos[0]][pos[1]][pos[2]] += Op->vi[2][pos[0]][pos[1]][pos[2]] * ( curr[1][pos[0]][pos[1]][pos[2]] - curr[1][pos[0]-shift[0]][pos[1]][pos[2]] - curr[0][pos[0]][pos[1]][pos[2]] + curr[0][pos[0]][pos[1]-shift[1]][pos[2]]); + } + } + ++pos[0]; + } +} + +void Engine::UpdateCurrents(unsigned int startX, unsigned int numX) +{ + unsigned int pos[3]; + pos[0] = startX; + for (unsigned int posX=0; posXii[0][pos[0]][pos[1]][pos[2]]; + curr[0][pos[0]][pos[1]][pos[2]] += Op->iv[0][pos[0]][pos[1]][pos[2]] * ( volt[2][pos[0]][pos[1]][pos[2]] - volt[2][pos[0]][pos[1]+1][pos[2]] - volt[1][pos[0]][pos[1]][pos[2]] + volt[1][pos[0]][pos[1]][pos[2]+1]); + + //for y + curr[1][pos[0]][pos[1]][pos[2]] *= Op->ii[1][pos[0]][pos[1]][pos[2]]; + curr[1][pos[0]][pos[1]][pos[2]] += Op->iv[1][pos[0]][pos[1]][pos[2]] * ( volt[0][pos[0]][pos[1]][pos[2]] - volt[0][pos[0]][pos[1]][pos[2]+1] - volt[2][pos[0]][pos[1]][pos[2]] + volt[2][pos[0]+1][pos[1]][pos[2]]); + + //for z + curr[2][pos[0]][pos[1]][pos[2]] *= Op->ii[2][pos[0]][pos[1]][pos[2]]; + curr[2][pos[0]][pos[1]][pos[2]] += Op->iv[2][pos[0]][pos[1]][pos[2]] * ( volt[1][pos[0]][pos[1]][pos[2]] - volt[1][pos[0]+1][pos[1]][pos[2]] - volt[0][pos[0]][pos[1]][pos[2]] + volt[0][pos[0]][pos[1]+1][pos[2]]); + } + } + ++pos[0]; + } +} + +void Engine::DoPreVoltageUpdates() +{ + //execute extensions in reverse order -> highest priority gets access to the voltages last + for (int n=m_Eng_exts.size()-1; n>=0; --n) + m_Eng_exts.at(n)->DoPreVoltageUpdates(); + +} + +void Engine::DoPostVoltageUpdates() +{ + //execute extensions in normal order -> highest priority gets access to the voltages first + for (size_t n=0; nDoPostVoltageUpdates(); +} + +void Engine::Apply2Voltages() +{ + //execute extensions in normal order -> highest priority gets access to the voltages first + for (size_t n=0; nApply2Voltages(); +} + +void Engine::DoPreCurrentUpdates() +{ + //execute extensions in reverse order -> highest priority gets access to the currents last + for (int n=m_Eng_exts.size()-1; n>=0; --n) + m_Eng_exts.at(n)->DoPreCurrentUpdates(); +} + +void Engine::DoPostCurrentUpdates() +{ + //execute extensions in normal order -> highest priority gets access to the currents first + for (size_t n=0; nDoPostCurrentUpdates(); +} + +void Engine::Apply2Current() +{ + //execute extensions in normal order -> highest priority gets access to the currents first + for (size_t n=0; nApply2Current(); +} + +bool Engine::IterateTS(unsigned int iterTS) +{ + for (unsigned int iter=0; iter. +*/ + +#ifndef ENGINE_H +#define ENGINE_H + +#include +#include "operator.h" + +namespace NS_Engine_Multithread +{ +class thread; // evil hack to access numTS from multithreading context +} + +class Engine_Extension; + +class Engine +{ +public: + enum EngineType + { + BASIC, SSE, UNKNOWN + }; + + static Engine* New(const Operator* op); + virtual ~Engine(); + + virtual void Init(); + virtual void Reset(); + + //!Iterate a number of timesteps + virtual bool IterateTS(unsigned int iterTS); + + virtual unsigned int GetNumberOfTimesteps() {return numTS;} + + //this access functions muss be overloaded by any new engine using a different storage model + inline virtual FDTD_FLOAT GetVolt( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return volt[n][x][y][z]; } + inline virtual FDTD_FLOAT GetVolt( unsigned int n, const unsigned int pos[3] ) const { return volt[n][pos[0]][pos[1]][pos[2]]; } + inline virtual FDTD_FLOAT GetCurr( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return curr[n][x][y][z]; } + inline virtual FDTD_FLOAT GetCurr( unsigned int n, const unsigned int pos[3] ) const { return curr[n][pos[0]][pos[1]][pos[2]]; } + + inline virtual void SetVolt( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value) { volt[n][x][y][z]=value; } + inline virtual void SetVolt( unsigned int n, const unsigned int pos[3], FDTD_FLOAT value ) { volt[n][pos[0]][pos[1]][pos[2]]=value; } + inline virtual void SetCurr( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value) { curr[n][x][y][z]=value; } + inline virtual void SetCurr( unsigned int n, const unsigned int pos[3], FDTD_FLOAT value ) { curr[n][pos[0]][pos[1]][pos[2]]=value; } + + //! Execute Pre-Voltage extension updates + virtual void DoPreVoltageUpdates(); + //! Main FDTD engine voltage updates + virtual void UpdateVoltages(unsigned int startX, unsigned int numX); + //! Execute Post-Voltage extension updates + virtual void DoPostVoltageUpdates(); + //! Apply extension voltage changes + virtual void Apply2Voltages(); + + //! Execute Pre-Current extension updates + virtual void DoPreCurrentUpdates(); + //! Main FDTD engine current updates + virtual void UpdateCurrents(unsigned int startX, unsigned int numX); + //! Execute Post-Current extension updates + virtual void DoPostCurrentUpdates(); + //! Apply extension current changes + virtual void Apply2Current(); + + inline size_t GetExtensionCount() {return m_Eng_exts.size();} + inline Engine_Extension* GetExtension(size_t nr) {return m_Eng_exts.at(nr);} + virtual void SortExtensionByPriority(); + + EngineType GetType() const {return m_type;} + +protected: + EngineType m_type; + + Engine(const Operator* op); + const Operator* Op; + + unsigned int numLines[3]; + + FDTD_FLOAT**** volt; + FDTD_FLOAT**** curr; + unsigned int numTS; + + virtual void InitExtensions(); + virtual void ClearExtensions(); + vector m_Eng_exts; + + friend class NS_Engine_Multithread::thread; // evil hack to access numTS from multithreading context +}; + +#endif // ENGINE_H diff --git a/openEMS/FDTD/engine_cylinder.cpp b/openEMS/FDTD/engine_cylinder.cpp new file mode 100644 index 0000000..8d62cb9 --- /dev/null +++ b/openEMS/FDTD/engine_cylinder.cpp @@ -0,0 +1,38 @@ +/* +* Copyright (C) 2012 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 . +*/ + +#include "engine_cylinder.h" + +Engine_Cylinder::Engine_Cylinder(const Operator_Cylinder* op) : Engine_Multithread(op) +{ + m_Op_Cyl = op; +} + +Engine_Cylinder::~Engine_Cylinder() +{ + +} + +Engine_Cylinder* Engine_Cylinder::New(const Operator_Cylinder* op, unsigned int numThreads) +{ + cout << "Create FDTD engine (cylindrical mesh using sse compression + multithreading)" << endl; + Engine_Cylinder* e = new Engine_Cylinder(op); + e->setNumThreads(numThreads); + e->Init(); + return e; +} + diff --git a/openEMS/FDTD/engine_cylinder.h b/openEMS/FDTD/engine_cylinder.h new file mode 100644 index 0000000..cbf33c0 --- /dev/null +++ b/openEMS/FDTD/engine_cylinder.h @@ -0,0 +1,36 @@ +/* +* Copyright (C) 2012 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 . +*/ + +#ifndef ENGINE_CYLINDER_H +#define ENGINE_CYLINDER_H + +#include "operator_cylinder.h" +#include "engine_multithread.h" + +class Engine_Cylinder : public Engine_Multithread +{ +public: + static Engine_Cylinder* New(const Operator_Cylinder* op, unsigned int numThreads = 0); + virtual ~Engine_Cylinder(); + +protected: + Engine_Cylinder(const Operator_Cylinder* op); + + const Operator_Cylinder* m_Op_Cyl; +}; + +#endif // ENGINE_CYLINDER_H diff --git a/openEMS/FDTD/engine_cylindermultigrid.cpp b/openEMS/FDTD/engine_cylindermultigrid.cpp new file mode 100644 index 0000000..8e5ce85 --- /dev/null +++ b/openEMS/FDTD/engine_cylindermultigrid.cpp @@ -0,0 +1,226 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "engine_cylindermultigrid.h" +#include "operator_cylindermultigrid.h" +#include "extensions/engine_ext_cylindermultigrid.h" + +Engine_CylinderMultiGrid* Engine_CylinderMultiGrid::New(const Operator_CylinderMultiGrid* op, unsigned int numThreads) +{ + cout << "Create FDTD engine (cylindrical multi grid mesh using sse compression + multithreading)" << endl; + Engine_CylinderMultiGrid* e = new Engine_CylinderMultiGrid(op); + e->setNumThreads( numThreads ); + e->Init(); + return e; +} + +Engine_CylinderMultiGrid::Engine_CylinderMultiGrid(const Operator_CylinderMultiGrid* op) : Engine_Cylinder(op) +{ + Op_CMG = op; + + m_WaitOnBase = new boost::barrier(2); + m_WaitOnChild = new boost::barrier(2); + m_WaitOnSync = new boost::barrier(2); + + m_Eng_Ext_MG = new Engine_Ext_CylinderMultiGrid(NULL,true); + m_Eng_Ext_MG->SetBarrier(m_WaitOnBase, m_WaitOnChild, m_WaitOnSync); + m_Eng_Ext_MG->SetEngine(this); + + Engine* eng = op->GetInnerOperator()->CreateEngine(); + m_InnerEngine = dynamic_cast(eng); + + Engine_Ext_CylinderMultiGrid* m_InnerEng_Ext_MG = new Engine_Ext_CylinderMultiGrid(NULL,false); + m_InnerEng_Ext_MG->SetBarrier(m_WaitOnBase, m_WaitOnChild, m_WaitOnSync); + + // if already has a base extension, switch places ... seems to be faster... + for (size_t n=0; nm_Eng_exts.size(); ++n) + { + Engine_Ext_CylinderMultiGrid* eng_mg = dynamic_cast(m_InnerEngine->m_Eng_exts.at(n)); + if (eng_mg) + { + m_InnerEngine->m_Eng_exts.at(n) = m_InnerEng_Ext_MG; + m_InnerEng_Ext_MG = eng_mg; + break; + } + } + m_InnerEngine->m_Eng_exts.push_back(m_InnerEng_Ext_MG); +} + +Engine_CylinderMultiGrid::~Engine_CylinderMultiGrid() +{ +#ifdef MPI_SUPPORT + delete m_InnerEngine->m_MPI_Barrier; + m_InnerEngine->m_MPI_Barrier = NULL; +#endif + + m_Thread_NumTS = 0; + m_startBarrier->wait(); + + m_IteratorThread_Group.join_all(); + + delete m_InnerEngine; + m_InnerEngine = NULL; + + delete m_WaitOnBase; + m_WaitOnBase = NULL; + delete m_WaitOnChild; + m_WaitOnChild = NULL; + delete m_WaitOnSync; + m_WaitOnSync = NULL; + + delete m_startBarrier; + m_startBarrier = NULL; + delete m_stopBarrier; + m_stopBarrier = NULL; +} + +void Engine_CylinderMultiGrid::Init() +{ + Engine_Multithread::Init(); + + m_Eng_exts.push_back(m_Eng_Ext_MG); + + m_startBarrier = new boost::barrier(3); //both engines + organizer + m_stopBarrier = new boost::barrier(3); //both engines + organizer + + boost::thread *t = NULL; + + t = new boost::thread( Engine_CylinderMultiGrid_Thread(this,m_startBarrier,m_stopBarrier,&m_Thread_NumTS, true) ); + m_IteratorThread_Group.add_thread( t ); + + t = new boost::thread( Engine_CylinderMultiGrid_Thread(m_InnerEngine,m_startBarrier,m_stopBarrier,&m_Thread_NumTS, false) ); + m_IteratorThread_Group.add_thread( t ); + + m_InnerEngine->SortExtensionByPriority(); + SortExtensionByPriority(); + +#ifdef MPI_SUPPORT + //assign an MPI barrier to inner Engine + m_InnerEngine->m_MPI_Barrier = new boost::barrier(2); +#endif +} + +bool Engine_CylinderMultiGrid::IterateTS(unsigned int iterTS) +{ + m_Thread_NumTS = iterTS; + + m_startBarrier->wait(); //start base and child iterations + + m_stopBarrier->wait(); //tell base and child to wait for another start event... + + //interpolate child data to base mesh... + for (unsigned int n=0; nm_Split_Pos-1; ++n) + InterpolVoltChild2Base(n); + for (unsigned int n=0; nm_Split_Pos-2; ++n) + InterpolCurrChild2Base(n); + + return true; +} + +void Engine_CylinderMultiGrid::InterpolVoltChild2Base(unsigned int rPos) +{ + //interpolate voltages from child engine to the base engine... + unsigned int pos[3]; + pos[0] = rPos; + for (pos[1]=0; pos[1]f4_interpol_v_2p[0][pos[1]].v * m_InnerEngine->f4_volt[0][pos[0]][Op_CMG->m_interpol_pos_v_2p[0][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_v_2pp[0][pos[1]].v * m_InnerEngine->f4_volt[0][pos[0]][Op_CMG->m_interpol_pos_v_2pp[0][pos[1]]][pos[2]].v; + + //z - direction + f4_volt[2][pos[0]][pos[1]][pos[2]].v = Op_CMG->f4_interpol_v_2p[0][pos[1]].v * m_InnerEngine->f4_volt[2][pos[0]][Op_CMG->m_interpol_pos_v_2p[0][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_v_2pp[0][pos[1]].v * m_InnerEngine->f4_volt[2][pos[0]][Op_CMG->m_interpol_pos_v_2pp[0][pos[1]]][pos[2]].v; + + //alpha - direction + f4_volt[1][pos[0]][pos[1]][pos[2]].v = Op_CMG->f4_interpol_v_2p[1][pos[1]].v * m_InnerEngine->f4_volt[1][pos[0]][Op_CMG->m_interpol_pos_v_2p[1][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_v_2pp[1][pos[1]].v * m_InnerEngine->f4_volt[1][pos[0]][Op_CMG->m_interpol_pos_v_2pp[1][pos[1]]][pos[2]].v; + } + } +} + +void Engine_CylinderMultiGrid::InterpolCurrChild2Base(unsigned int rPos) +{ + //interpolate voltages from child engine to the base engine... + unsigned int pos[3]; + pos[0] = rPos; + for (pos[1]=0; pos[1]f4_interpol_i_2p[0][pos[1]].v * m_InnerEngine->f4_curr[0][pos[0]][Op_CMG->m_interpol_pos_i_2p[0][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_i_2pp[0][pos[1]].v * m_InnerEngine->f4_curr[0][pos[0]][Op_CMG->m_interpol_pos_i_2pp[0][pos[1]]][pos[2]].v; + + //z - direction + f4_curr[2][pos[0]][pos[1]][pos[2]].v = Op_CMG->f4_interpol_i_2p[0][pos[1]].v * m_InnerEngine->f4_curr[2][pos[0]][Op_CMG->m_interpol_pos_i_2p[0][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_i_2pp[0][pos[1]].v * m_InnerEngine->f4_curr[2][pos[0]][Op_CMG->m_interpol_pos_i_2pp[0][pos[1]]][pos[2]].v; + + //alpha - direction + f4_curr[1][pos[0]][pos[1]][pos[2]].v = Op_CMG->f4_interpol_i_2p[1][pos[1]].v * m_InnerEngine->f4_curr[1][pos[0]][Op_CMG->m_interpol_pos_i_2p[1][pos[1]]][pos[2]].v + + Op_CMG->f4_interpol_i_2pp[1][pos[1]].v * m_InnerEngine->f4_curr[1][pos[0]][Op_CMG->m_interpol_pos_i_2pp[1][pos[1]]][pos[2]].v; + } + } +} + +#ifdef MPI_SUPPORT + void Engine_CylinderMultiGrid::SendReceiveVoltages() + { + //do the local voltage sync, child is waiting... + Engine_Multithread::SendReceiveVoltages(); + + //run inner voltage sync + m_InnerEngine->m_MPI_Barrier->wait(); + } + + void Engine_CylinderMultiGrid::SendReceiveCurrents() + { + //do the local current sync, child is waiting... + Engine_Multithread::SendReceiveCurrents(); + + //run inner voltage sync + m_InnerEngine->m_MPI_Barrier->wait(); + } + +#endif + +/****************************************************************************************/ +Engine_CylinderMultiGrid_Thread::Engine_CylinderMultiGrid_Thread( Engine_Multithread* engine, boost::barrier *start, boost::barrier *stop, volatile unsigned int* numTS, bool isBase) +{ + m_startBarrier = start; + m_stopBarrier = stop; + m_Eng=engine; + m_isBase=isBase; + m_numTS = numTS; +} + +void Engine_CylinderMultiGrid_Thread::operator()() +{ + m_startBarrier->wait(); //wait for Base engine to start the iterations... + + while (*m_numTS>0) //m_numTS==0 request to terminate this thread... + { + if (m_isBase) + m_Eng->Engine_Multithread::IterateTS(*m_numTS); + else + m_Eng->IterateTS(*m_numTS); + m_stopBarrier->wait(); //sync all workers after iterations are performed + m_startBarrier->wait(); //wait for Base engine to start the iterations again ... + } +} diff --git a/openEMS/FDTD/engine_cylindermultigrid.h b/openEMS/FDTD/engine_cylindermultigrid.h new file mode 100644 index 0000000..66f337f --- /dev/null +++ b/openEMS/FDTD/engine_cylindermultigrid.h @@ -0,0 +1,85 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef ENGINE_CYLINDERMULTIGRID_H +#define ENGINE_CYLINDERMULTIGRID_H + +#include "engine_cylinder.h" + +class Operator_CylinderMultiGrid; +class Engine_CylinderMultiGrid_Thread; +class Engine_Ext_CylinderMultiGrid; + +class Engine_CylinderMultiGrid : public Engine_Cylinder +{ + friend class Engine_Ext_CylinderMultiGrid; +public: +// Engine_CylinderMultiGrid(); + + static Engine_CylinderMultiGrid* New(const Operator_CylinderMultiGrid* op, unsigned int numThreads = 0); + virtual ~Engine_CylinderMultiGrid(); + + virtual void InterpolVoltChild2Base(unsigned int rPos); + virtual void InterpolCurrChild2Base(unsigned int rPos); + + virtual void Init(); + + //! Iterate \a iterTS number of timesteps + virtual bool IterateTS(unsigned int iterTS); + +protected: + Engine_CylinderMultiGrid(const Operator_CylinderMultiGrid* op); + const Operator_CylinderMultiGrid* Op_CMG; + + Engine_Multithread* m_InnerEngine; + + volatile unsigned int m_Thread_NumTS; + boost::thread_group m_IteratorThread_Group; + boost::barrier *m_startBarrier; + boost::barrier *m_stopBarrier; + Engine_CylinderMultiGrid_Thread* m_IteratorThread; + Engine_CylinderMultiGrid_Thread* m_InnerIteratorThread; + + //extension barrier + boost::barrier *m_WaitOnBase; + boost::barrier *m_WaitOnChild; + boost::barrier *m_WaitOnSync; + + Engine_Ext_CylinderMultiGrid* m_Eng_Ext_MG; + +#ifdef MPI_SUPPORT + virtual void SendReceiveVoltages(); + virtual void SendReceiveCurrents(); +#endif +}; + + +class Engine_CylinderMultiGrid_Thread +{ +public: + Engine_CylinderMultiGrid_Thread( Engine_Multithread* engine, boost::barrier *start, boost::barrier *stop, volatile unsigned int* numTS, bool isBase); + void operator()(); + +protected: + Engine_Multithread *m_Eng; + bool m_isBase; + boost::barrier *m_startBarrier; + boost::barrier *m_stopBarrier; + volatile unsigned int *m_numTS; +}; + +#endif // ENGINE_CYLINDERMULTIGRID_H diff --git a/openEMS/FDTD/engine_interface_cylindrical_fdtd.cpp b/openEMS/FDTD/engine_interface_cylindrical_fdtd.cpp new file mode 100644 index 0000000..065a4ef --- /dev/null +++ b/openEMS/FDTD/engine_interface_cylindrical_fdtd.cpp @@ -0,0 +1,64 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "engine_interface_cylindrical_fdtd.h" + +Engine_Interface_Cylindrical_FDTD::Engine_Interface_Cylindrical_FDTD(Operator_sse* op) : Engine_Interface_SSE_FDTD(op) +{ + m_Op_Cyl = dynamic_cast(op); + if (m_Op_Cyl==NULL) + { + cerr << "Engine_Interface_Cylindrical_FDTD::Engine_Interface_Cylindrical_FDTD: Error: Operator is not a cylindrical operator! Exit!" << endl; + exit(1); + } +} + +Engine_Interface_Cylindrical_FDTD::~Engine_Interface_Cylindrical_FDTD() +{ +} + +double* Engine_Interface_Cylindrical_FDTD::GetHField(const unsigned int* pos, double* out) const +{ + if (m_Op_Cyl->GetClosedAlpha()==false) + return Engine_Interface_FDTD::GetHField(pos, out); + + unsigned int iPos[] = {pos[0],pos[1],pos[2]}; + + if ((m_InterpolType==CELL_INTERPOLATE) && (pos[1]==m_Op->GetNumberOfLines(1))) + iPos[1]=0; + + if ((m_InterpolType==NODE_INTERPOLATE) && (iPos[1]==0)) + iPos[1]=m_Op->GetNumberOfLines(1); + + return Engine_Interface_FDTD::GetHField(iPos, out); +} + +double* Engine_Interface_Cylindrical_FDTD::GetRawInterpolatedField(const unsigned int* pos, double* out, int type) const +{ + if (m_Op_Cyl->GetClosedAlpha()==false) + return Engine_Interface_FDTD::GetRawInterpolatedField(pos,out,type); + + unsigned int iPos[] = {pos[0],pos[1],pos[2]}; + + if ((m_InterpolType==NODE_INTERPOLATE) && (pos[1]==0)) + iPos[1]=m_Op->GetNumberOfLines(1); + + if ((m_InterpolType==CELL_INTERPOLATE) && (pos[1]==m_Op->GetNumberOfLines(1))) + iPos[1]=0; + + return Engine_Interface_FDTD::GetRawInterpolatedField(iPos,out,type); +} diff --git a/openEMS/FDTD/engine_interface_cylindrical_fdtd.h b/openEMS/FDTD/engine_interface_cylindrical_fdtd.h new file mode 100644 index 0000000..adbe184 --- /dev/null +++ b/openEMS/FDTD/engine_interface_cylindrical_fdtd.h @@ -0,0 +1,39 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "engine_interface_sse_fdtd.h" +#include "operator_cylinder.h" + +#ifndef ENGINE_INTERFACE_CYLINDRICAL_FDTD_H +#define ENGINE_INTERFACE_CYLINDRICAL_FDTD_H + +class Engine_Interface_Cylindrical_FDTD : public Engine_Interface_SSE_FDTD +{ +public: + Engine_Interface_Cylindrical_FDTD(Operator_sse* op); + virtual ~Engine_Interface_Cylindrical_FDTD(); + + virtual double* GetHField(const unsigned int* pos, double* out) const; + +protected: + Operator_Cylinder* m_Op_Cyl; + + //! Internal method to get an interpolated field of a given type. (0: E, 1: J, 2: rotH) + virtual double* GetRawInterpolatedField(const unsigned int* pos, double* out, int type) const; +}; + +#endif // ENGINE_INTERFACE_CYLINDRICAL_FDTD_H diff --git a/openEMS/FDTD/engine_interface_fdtd.cpp b/openEMS/FDTD/engine_interface_fdtd.cpp new file mode 100644 index 0000000..b8fd9de --- /dev/null +++ b/openEMS/FDTD/engine_interface_fdtd.cpp @@ -0,0 +1,274 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "engine_interface_fdtd.h" + +Engine_Interface_FDTD::Engine_Interface_FDTD(Operator* op) : Engine_Interface_Base(op) +{ + if (op==NULL) + { + cerr << "Engine_Interface_FDTD::Engine_Interface_FDTD: Error: Operator is not set! Exit!" << endl; + exit(1); + } + m_Op = op; + m_Eng = m_Op->GetEngine(); + if (m_Eng==NULL) + { + cerr << "Engine_Interface_FDTD::Engine_Interface_FDTD: Error: Engine is not set! Exit!" << endl; + exit(1); + } +} + +Engine_Interface_FDTD::~Engine_Interface_FDTD() +{ +} + +double* Engine_Interface_FDTD::GetEField(const unsigned int* pos, double* out) const +{ + return GetRawInterpolatedField(pos, out, 0); +} + +double* Engine_Interface_FDTD::GetJField(const unsigned int* pos, double* out) const +{ + return GetRawInterpolatedField(pos, out, 1); +} + +double* Engine_Interface_FDTD::GetRotHField(const unsigned int* pos, double* out) const +{ + return GetRawInterpolatedField(pos, out, 2); +} + +double* Engine_Interface_FDTD::GetRawInterpolatedField(const unsigned int* pos, double* out, int type) const +{ + unsigned int iPos[] = {pos[0],pos[1],pos[2]}; + int nP,nPP; + double delta; + switch (m_InterpolType) + { + default: + case NO_INTERPOLATION: + for (int n=0; n<3; ++n) + out[n] = GetRawField(n,pos,type); + break; + case NODE_INTERPOLATE: + for (int n=0; n<3; ++n) + { + if (pos[n]==m_Op->GetNumberOfLines(n, true)-1) // use only the "lower value" at the upper bound + { + --iPos[n]; + out[n] = (double)GetRawField(n,iPos,type); + ++iPos[n]; + continue; + } + delta = m_Op->GetEdgeLength(n,iPos); + out[n] = GetRawField(n,iPos,type); + if (delta==0) + { + out[n]=0; + continue; + } + if (pos[n]==0) // use only the "upper value" at the lower bound + continue; + --iPos[n]; + double deltaDown = m_Op->GetEdgeLength(n,iPos); + double deltaRel = delta / (delta+deltaDown); + out[n] = out[n]*(1.0-deltaRel) + (double)GetRawField(n,iPos,type)*deltaRel; + ++iPos[n]; + } + break; + case CELL_INTERPOLATE: + for (int n=0; n<3; ++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + if ((pos[0]==m_Op->GetNumberOfLines(0,true)-1) || (pos[1]==m_Op->GetNumberOfLines(1,true)-1) || (pos[2]==m_Op->GetNumberOfLines(2,true)-1)) + { + out[n] = 0; //electric field outside the field domain is always zero + continue; + } + out[n]=GetRawField(n,iPos,type); + ++iPos[nP]; + out[n]+=GetRawField(n,iPos,type); + ++iPos[nPP]; + out[n]+=GetRawField(n,iPos,type); + --iPos[nP]; + out[n]+=GetRawField(n,iPos,type); + --iPos[nPP]; + out[n]/=4; + } + break; + } + return out; +} + +double* Engine_Interface_FDTD::GetHField(const unsigned int* pos, double* out) const +{ + unsigned int iPos[] = {pos[0],pos[1],pos[2]}; + int nP,nPP; + double delta; + switch (m_InterpolType) + { + 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); + break; + case NODE_INTERPOLATE: + for (int n=0; n<3; ++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + if ((pos[0]==m_Op->GetNumberOfLines(0,true)-1) || (pos[1]==m_Op->GetNumberOfLines(1,true)-1) || (pos[2]==m_Op->GetNumberOfLines(2,true)-1) || (pos[nP]==0) || (pos[nPP]==0)) + { + out[n] = 0; + continue; + } + out[n]=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true); + --iPos[nP]; + out[n]+=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true); + --iPos[nPP]; + out[n]+=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true); + ++iPos[nP]; + out[n]+=m_Eng->GetCurr(n,iPos)/m_Op->GetEdgeLength(n,iPos,true); + ++iPos[nPP]; + out[n]/=4; + } + break; + case CELL_INTERPOLATE: + for (int n=0; n<3; ++n) + { + delta = m_Op->GetEdgeLength(n,iPos,true); + out[n] = m_Eng->GetCurr(n,iPos); + if ((pos[n]>=m_Op->GetNumberOfLines(n,true)-1)) + { + out[n] = 0; //magnetic field on the outer boundaries is always zero + continue; + } + ++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; + --iPos[n]; + } + break; + } + + return out; +} + +double Engine_Interface_FDTD::CalcVoltageIntegral(const unsigned int* start, const unsigned int* stop) const +{ + double result=0; + for (int n=0; n<3; ++n) + { + if (start[n]GetVolt(n,pos[0],pos[1],pos[2]); + } + else + { + unsigned int pos[3]={stop[0],stop[1],stop[2]}; + for (; pos[n]GetVolt(n,pos[0],pos[1],pos[2]); + } + } + return result; +} + + +double Engine_Interface_FDTD::GetRawField(unsigned int n, const unsigned int* pos, int type) const +{ + double value = m_Eng->GetVolt(n,pos[0],pos[1],pos[2]); + double delta = m_Op->GetEdgeLength(n,pos); + if ((type==0) && (delta)) + 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==2) //calc rot(H) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + unsigned int locPos[] = {pos[0],pos[1],pos[2]}; + double area = m_Op->GetEdgeArea(n,pos); + value = m_Eng->GetCurr(nPP,pos); + value -= m_Eng->GetCurr(nP,pos); + if (pos[nPP]>0) + { + --locPos[nPP]; + value += m_Eng->GetCurr(nP,locPos); + ++locPos[nPP]; + } + if (pos[nP]>0) + { + --locPos[nP]; + value -= m_Eng->GetCurr(nPP,locPos); + } + return value/area; + } + + return 0.0; +} + +double Engine_Interface_FDTD::CalcFastEnergy() const +{ + double E_energy=0.0; + double H_energy=0.0; + + unsigned int pos[3]; + if (m_Eng->GetType()==Engine::BASIC) + { + for (pos[0]=0; pos[0]GetNumberOfLines(0)-1; ++pos[0]) + { + for (pos[1]=0; pos[1]GetNumberOfLines(1)-1; ++pos[1]) + { + for (pos[2]=0; pos[2]GetNumberOfLines(2)-1; ++pos[2]) + { + E_energy+=m_Eng->Engine::GetVolt(0,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetVolt(0,pos[0],pos[1],pos[2]); + E_energy+=m_Eng->Engine::GetVolt(1,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetVolt(1,pos[0],pos[1],pos[2]); + E_energy+=m_Eng->Engine::GetVolt(2,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetVolt(2,pos[0],pos[1],pos[2]); + + H_energy+=m_Eng->Engine::GetCurr(0,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetCurr(0,pos[0],pos[1],pos[2]); + H_energy+=m_Eng->Engine::GetCurr(1,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetCurr(1,pos[0],pos[1],pos[2]); + H_energy+=m_Eng->Engine::GetCurr(2,pos[0],pos[1],pos[2]) * m_Eng->Engine::GetCurr(2,pos[0],pos[1],pos[2]); + } + } + } + } + else + { + for (pos[0]=0; pos[0]GetNumberOfLines(0)-1; ++pos[0]) + { + for (pos[1]=0; pos[1]GetNumberOfLines(1)-1; ++pos[1]) + { + for (pos[2]=0; pos[2]GetNumberOfLines(2)-1; ++pos[2]) + { + E_energy+=m_Eng->GetVolt(0,pos[0],pos[1],pos[2]) * m_Eng->GetVolt(0,pos[0],pos[1],pos[2]); + E_energy+=m_Eng->GetVolt(1,pos[0],pos[1],pos[2]) * m_Eng->GetVolt(1,pos[0],pos[1],pos[2]); + E_energy+=m_Eng->GetVolt(2,pos[0],pos[1],pos[2]) * m_Eng->GetVolt(2,pos[0],pos[1],pos[2]); + + H_energy+=m_Eng->GetCurr(0,pos[0],pos[1],pos[2]) * m_Eng->GetCurr(0,pos[0],pos[1],pos[2]); + H_energy+=m_Eng->GetCurr(1,pos[0],pos[1],pos[2]) * m_Eng->GetCurr(1,pos[0],pos[1],pos[2]); + H_energy+=m_Eng->GetCurr(2,pos[0],pos[1],pos[2]) * m_Eng->GetCurr(2,pos[0],pos[1],pos[2]); + } + } + } + } + return __EPS0__*E_energy + __MUE0__*H_energy; +} diff --git a/openEMS/FDTD/engine_interface_fdtd.h b/openEMS/FDTD/engine_interface_fdtd.h new file mode 100644 index 0000000..4e824ac --- /dev/null +++ b/openEMS/FDTD/engine_interface_fdtd.h @@ -0,0 +1,65 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef ENGINE_INTERFACE_FDTD_H +#define ENGINE_INTERFACE_FDTD_H + +#include + +#include "Common/engine_interface_base.h" +#include "operator.h" +#include "engine.h" + +class Engine_Interface_FDTD : public Engine_Interface_Base +{ +public: + Engine_Interface_FDTD(Operator* op); + virtual ~Engine_Interface_FDTD(); + + //! Set the FDTD operator + virtual void SetFDTDOperator(Operator* op) {SetOperator(op); m_Op=op;} + //! Set the FDTD engine + virtual void SetFDTDEngine(Engine* eng) {m_Eng=eng;} + + //! Get the FDTD engine in case direct access is needed. Direct access is not recommended! + const Engine* GetFDTDEngine() const {return m_Eng;} + //! Get the FDTD operator in case direct access is needed. Direct access is not recommended! + const Operator* GetFDTDOperator() const {return m_Op;} + + virtual double* GetEField(const unsigned int* pos, double* out) const; + 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 CalcVoltageIntegral(const unsigned int* start, const unsigned int* stop) const; + + virtual double GetTime(bool dualTime=false) const {return ((double)m_Eng->GetNumberOfTimesteps() + (double)dualTime*0.5)*m_Op->GetTimestep();}; + virtual unsigned int GetNumberOfTimesteps() const {return m_Eng->GetNumberOfTimesteps();} + + virtual double CalcFastEnergy() const; + +protected: + Operator* m_Op; + Engine* m_Eng; + + //! Internal method to get an interpolated field of a given type. (0: E, 1: J, 2: rotH) + 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) + virtual double GetRawField(unsigned int n, const unsigned int* pos, int type) const; +}; + +#endif // ENGINE_INTERFACE_FDTD_H diff --git a/openEMS/FDTD/engine_interface_sse_fdtd.cpp b/openEMS/FDTD/engine_interface_sse_fdtd.cpp new file mode 100644 index 0000000..b7e9a3c --- /dev/null +++ b/openEMS/FDTD/engine_interface_sse_fdtd.cpp @@ -0,0 +1,69 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "engine_interface_sse_fdtd.h" + +Engine_Interface_SSE_FDTD::Engine_Interface_SSE_FDTD(Operator_sse* op) : Engine_Interface_FDTD(op) +{ + m_Op_SSE = op; + m_Eng_SSE = dynamic_cast(m_Op_SSE->GetEngine()); + if (m_Eng_SSE==NULL) + { + cerr << "Engine_Interface_SSE_FDTD::Engine_Interface_SSE_FDTD: Error: SSE-Engine is not set! Exit!" << endl; + exit(1); + } +} + +Engine_Interface_SSE_FDTD::~Engine_Interface_SSE_FDTD() +{ + m_Op_SSE=NULL; + m_Eng_SSE=NULL; +} + +double Engine_Interface_SSE_FDTD::CalcFastEnergy() const +{ + f4vector E_energy; + E_energy.f[0]=0; + E_energy.f[1]=0; + E_energy.f[2]=0; + E_energy.f[3]=0; + f4vector H_energy; + H_energy = E_energy; + + if (m_Eng_SSE->GetType()!=Engine::SSE) + return Engine_Interface_FDTD::CalcFastEnergy(); + + unsigned int pos[3]; + for (pos[0]=0; pos[0]GetNumberOfLines(0)-1; ++pos[0]) + { + for (pos[1]=0; pos[1]GetNumberOfLines(1)-1; ++pos[1]) + { + for (pos[2]=0; pos[2]numVectors; ++pos[2]) + { + E_energy.v += m_Eng_SSE->Engine_sse::f4_volt[0][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_volt[0][pos[0]][pos[1]][pos[2]].v; + E_energy.v += m_Eng_SSE->Engine_sse::f4_volt[1][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_volt[1][pos[0]][pos[1]][pos[2]].v; + E_energy.v += m_Eng_SSE->Engine_sse::f4_volt[2][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_volt[2][pos[0]][pos[1]][pos[2]].v; + + H_energy.v += m_Eng_SSE->Engine_sse::f4_curr[0][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_curr[0][pos[0]][pos[1]][pos[2]].v; + H_energy.v += m_Eng_SSE->Engine_sse::f4_curr[1][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_curr[1][pos[0]][pos[1]][pos[2]].v; + H_energy.v += m_Eng_SSE->Engine_sse::f4_curr[2][pos[0]][pos[1]][pos[2]].v * m_Eng_SSE->Engine_sse::f4_curr[2][pos[0]][pos[1]][pos[2]].v; + } + } + } + + return __EPS0__*(E_energy.f[0]+E_energy.f[1]+E_energy.f[2]+E_energy.f[3]) + __MUE0__*(H_energy.f[0]+H_energy.f[1]+H_energy.f[2]+H_energy.f[3]); +} diff --git a/openEMS/FDTD/engine_interface_sse_fdtd.h b/openEMS/FDTD/engine_interface_sse_fdtd.h new file mode 100644 index 0000000..b8f837a --- /dev/null +++ b/openEMS/FDTD/engine_interface_sse_fdtd.h @@ -0,0 +1,38 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#ifndef ENGINE_INTERFACE_SSE_FDTD_H +#define ENGINE_INTERFACE_SSE_FDTD_H + +#include "engine_interface_fdtd.h" +#include "operator_sse.h" +#include "engine_sse.h" + +class Engine_Interface_SSE_FDTD : public Engine_Interface_FDTD +{ +public: + Engine_Interface_SSE_FDTD(Operator_sse* op); + virtual ~Engine_Interface_SSE_FDTD(); + + virtual double CalcFastEnergy() const; + +protected: + Operator_sse* m_Op_SSE; + Engine_sse* m_Eng_SSE; +}; + +#endif // ENGINE_INTERFACE_SSE_FDTD_H diff --git a/openEMS/FDTD/engine_mpi.cpp b/openEMS/FDTD/engine_mpi.cpp new file mode 100644 index 0000000..c6a5b2c --- /dev/null +++ b/openEMS/FDTD/engine_mpi.cpp @@ -0,0 +1,211 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "engine_mpi.h" + +Engine_MPI* Engine_MPI::New(const Operator_MPI* op) +{ + cout << "Create FDTD engine (compressed SSE + MPI)" << endl; + Engine_MPI* e = new Engine_MPI(op); + e->Init(); + return e; +} + +Engine_MPI::Engine_MPI(const Operator_MPI* op) : Engine_SSE_Compressed(op) +{ + m_Op_MPI = op; +} + +Engine_MPI::~Engine_MPI() +{ + Reset(); +} + +void Engine_MPI::Init() +{ + Engine_SSE_Compressed::Init(); + + for (int i=0;i<3;++i) + { + m_BufferUp[i]=NULL; + m_BufferDown[i]=NULL; + m_BufferSize[i]=0; + } + + if (m_Op_MPI->GetMPIEnabled()) + { + // init buffers, nx*ny*2 for the tangential electric or magnetic fields at the interface + for (int n=0;n<3;++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + m_BufferSize[n] = m_Op_MPI->numLines[nP]*m_Op_MPI->numLines[nPP]; + + if (m_Op_MPI->m_NeighborDown[n]>=0) + { + m_BufferDown[n] = new float[m_BufferSize[n]*2]; + } + if (m_Op_MPI->m_NeighborUp[n]>=0) + { + m_BufferUp[n] = new float[m_BufferSize[n]*2]; + } + } + } +} + +void Engine_MPI::Reset() +{ + for (int i=0;i<3;++i) + { + delete[] m_BufferUp[i]; + delete[] m_BufferDown[i]; + m_BufferUp[i]=NULL; + m_BufferDown[i]=NULL; + m_BufferSize[i]=0; + } + + Engine_SSE_Compressed::Reset(); +} + +void Engine_MPI::SendReceiveVoltages() +{ + unsigned int pos[3]; + + //non-blocking prepare for receive... + for (int n=0;n<3;++n) + if (m_Op_MPI->m_NeighborDown[n]>=0) + MPI_Irecv( m_BufferDown[n] , m_BufferSize[n]*2, MPI_FLOAT, m_Op_MPI->m_NeighborDown[n], m_Op_MPI->m_MyTag, MPI_COMM_WORLD, &Recv_Request[n]); + + for (int n=0;n<3;++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + + //send voltages + unsigned int iPos=0; + pos[n]=numLines[n]-2; + if (m_Op_MPI->m_NeighborUp[n]>=0) + { + for (pos[nP]=0; pos[nP]m_NeighborUp[n], m_Op_MPI->m_MyTag, MPI_COMM_WORLD, &Send_Request[n]); + } + + //receive voltages + pos[n]=0; + iPos=0; + if (m_Op_MPI->m_NeighborDown[n]>=0) + { + //wait for receive to finish... + MPI_Wait(&Recv_Request[n],&stat); + for (pos[nP]=0; pos[nP]m_NeighborUp[n]>=0) + MPI_Irecv( m_BufferUp[n] , m_BufferSize[n]*2, MPI_FLOAT, m_Op_MPI->m_NeighborUp[n], m_Op_MPI->m_MyTag, MPI_COMM_WORLD, &Recv_Request[n]); + + for (int n=0;n<3;++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + + //send currents + unsigned int iPos=0; + pos[n]=0; + if (m_Op_MPI->m_NeighborDown[n]>=0) + { + for (pos[nP]=0; pos[nP]m_NeighborDown[n], m_Op_MPI->m_MyTag, MPI_COMM_WORLD, &Send_Request[n]); + } + + //receive currents + pos[n]=numLines[n]-2; + iPos=0; + if (m_Op_MPI->m_NeighborUp[n]>=0) + { + //wait for receive to finish... + MPI_Wait(&Recv_Request[n],&stat); + for (pos[nP]=0; pos[nP]GetMPIEnabled()) + { + return Engine_SSE_Compressed::IterateTS(iterTS); + } + + for (unsigned int iter=0; iter. +*/ + +#ifndef ENGINE_MPI_H +#define ENGINE_MPI_H + +#include "operator_mpi.h" +#include "engine_sse_compressed.h" +#include "mpi.h" + +class Engine_MPI : public Engine_SSE_Compressed +{ +public: + Engine_MPI(); + + static Engine_MPI* New(const Operator_MPI* op); + virtual ~Engine_MPI(); + + virtual void Init(); + virtual void Reset(); + + virtual bool IterateTS(unsigned int iterTS); + +protected: + Engine_MPI(const Operator_MPI* op); + const Operator_MPI* m_Op_MPI; + + MPI_Status stat; + MPI_Request Send_Request[3]; + MPI_Request Recv_Request[3]; + + //field buffer for MPI transfer... + unsigned int m_BufferSize[3]; + float* m_BufferUp[3]; + float* m_BufferDown[3]; + + //! Transfer all tangential voltages at the upper bounds to the lower bounds of the neighbouring MPI-processes + virtual void SendReceiveVoltages(); + //! Transfer all tangential currents at the lower bounds to the upper bounds of the neighbouring MPI-processes + virtual void SendReceiveCurrents(); +}; + +#endif // ENGINE_MPI_H diff --git a/openEMS/FDTD/engine_multithread.cpp b/openEMS/FDTD/engine_multithread.cpp new file mode 100644 index 0000000..7370198 --- /dev/null +++ b/openEMS/FDTD/engine_multithread.cpp @@ -0,0 +1,343 @@ +/* +* Copyright (C) 2010 Sebastian Held (sebastian.held@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 . +*/ + +//#define ENABLE_DEBUG_TIME + +#ifdef ENABLE_DEBUG_TIME +#define DEBUG_TIME(x) x; +#else +#define DEBUG_TIME(x) ; +#endif + + + +#include "engine_multithread.h" +#include "extensions/engine_extension.h" +#include "tools/array_ops.h" + +#include "boost/date_time/posix_time/posix_time.hpp" +#include "boost/date_time/gregorian/gregorian.hpp" +#include +#include + +//! \brief construct an Engine_Multithread instance +//! it's the responsibility of the caller to free the returned pointer +Engine_Multithread* Engine_Multithread::New(const Operator_Multithread* op, unsigned int numThreads) +{ + cout << "Create FDTD engine (compressed SSE + multi-threading)" << endl; + Engine_Multithread* e = new Engine_Multithread(op); + e->setNumThreads( numThreads ); + e->Init(); + return e; +} + +Engine_Multithread::Engine_Multithread(const Operator_Multithread* op) : ENGINE_MULTITHREAD_BASE(op) +{ + m_Op_MT = op; + m_type = SSE; + m_IterateBarrier = 0; + m_startBarrier = 0; + m_stopBarrier = 0; + +#ifdef ENABLE_DEBUG_TIME + m_MPI_Barrier = 0; +#endif +} + +Engine_Multithread::~Engine_Multithread() +{ +#ifdef ENABLE_DEBUG_TIME + NS_Engine_Multithread::DBG().cout() << "Engine_Multithread::~Engine_Multithread()" << endl; + std::map >::iterator it; + for (it=m_timer_list.begin(); it!=m_timer_list.end(); it++) + { + NS_Engine_Multithread::DBG().cout() << "*** DEBUG Thread: " << it->first << std::endl; + std::vector::iterator it2; + for (it2=it->second.begin(); it2second.end();) + { + NS_Engine_Multithread::DBG().cout() << "after voltage update, before barrier1: " << fixed << setprecision(6) << *(it2++) << std::endl; + NS_Engine_Multithread::DBG().cout() << "after barrier1, before barrier2: " << fixed << setprecision(6) << *(it2++) << std::endl; + NS_Engine_Multithread::DBG().cout() << "after barrier2, before current update: " << fixed << setprecision(6) << *(it2++) << std::endl; + NS_Engine_Multithread::DBG().cout() << "after current update, before barrier3: " << fixed << setprecision(6) << *(it2++) << std::endl; + NS_Engine_Multithread::DBG().cout() << "after barrier3: " << fixed << setprecision(6) << *(it2++) << std::endl; + } + } +#endif + + Reset(); +} + +void Engine_Multithread::setNumThreads( unsigned int numThreads ) +{ + m_numThreads = numThreads; +} + +void Engine_Multithread::Init() +{ + m_stopThreads = true; + ENGINE_MULTITHREAD_BASE::Init(); + + // initialize threads + m_stopThreads = false; + if (m_numThreads == 0) + m_numThreads = boost::thread::hardware_concurrency(); + + vector m_Start_Lines; + vector m_Stop_Lines; + m_Op_MT->CalcStartStopLines( m_numThreads, m_Start_Lines, m_Stop_Lines ); + + if (g_settings.GetVerboseLevel()>0) + cout << "Multithreaded engine using " << m_numThreads << " threads. Utilization: ("; + m_IterateBarrier = new boost::barrier(m_numThreads); // numThread workers + + m_startBarrier = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + m_stopBarrier = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller +#ifdef MPI_SUPPORT + m_MPI_Barrier = 0; +#endif + + for (unsigned int n=0; n0) + cout << stop-start+1 << ")" << endl; + } + else + if (g_settings.GetVerboseLevel()>0) + cout << stop-start+1 << ";"; +// NS_Engine_Multithread::DBG().cout() << "###DEBUG## Thread " << n << ": start=" << start << " stop=" << stop << " stop_h=" << stop_h << std::endl; + boost::thread *t = new boost::thread( NS_Engine_Multithread::thread(this,start,stop,stop_h,n) ); + m_thread_group.add_thread( t ); + } + + for (size_t n=0; nSetNumberOfThreads(m_numThreads); +} + +void Engine_Multithread::Reset() +{ + if (!m_stopThreads) // prevent multiple invocations + { + ClearExtensions(); //prevent extensions from interfering with thread reset... + + // stop the threads + //NS_Engine_Multithread::DBG().cout() << "stopping all threads" << endl; + m_iterTS = 1; + m_startBarrier->wait(); // start the threads + m_stopThreads = true; + m_stopBarrier->wait(); // wait for the threads to finish + m_thread_group.join_all(); // wait for termination + delete m_IterateBarrier; + m_IterateBarrier = 0; + delete m_startBarrier; + m_startBarrier = 0; + delete m_stopBarrier; + m_stopBarrier = 0; + } + + ENGINE_MULTITHREAD_BASE::Reset(); +} + +bool Engine_Multithread::IterateTS(unsigned int iterTS) +{ + m_iterTS = iterTS; + + //cout << "bool Engine_Multithread::IterateTS(): starting threads ..."; + m_startBarrier->wait(); // start the threads + + //cout << "... threads started"; + + m_stopBarrier->wait(); // wait for the threads to finish time steps + return true; +} + +void Engine_Multithread::DoPreVoltageUpdates(int threadID) +{ + //execute extensions in reverse order -> highest priority gets access to the voltages last + for (int n=m_Eng_exts.size()-1; n>=0; --n) + { + m_Eng_exts.at(n)->DoPreVoltageUpdates(threadID); + m_IterateBarrier->wait(); + } + +} + +void Engine_Multithread::DoPostVoltageUpdates(int threadID) +{ + //execute extensions in normal order -> highest priority gets access to the voltages first + for (size_t n=0; nDoPostVoltageUpdates(threadID); + m_IterateBarrier->wait(); + } +} + +void Engine_Multithread::Apply2Voltages(int threadID) +{ + //execute extensions in normal order -> highest priority gets access to the voltages first + for (size_t n=0; nApply2Voltages(threadID); + m_IterateBarrier->wait(); + } +} + +void Engine_Multithread::DoPreCurrentUpdates(int threadID) +{ + //execute extensions in reverse order -> highest priority gets access to the currents last + for (int n=m_Eng_exts.size()-1; n>=0; --n) + { + m_Eng_exts.at(n)->DoPreCurrentUpdates(threadID); + m_IterateBarrier->wait(); + } +} + +void Engine_Multithread::DoPostCurrentUpdates(int threadID) +{ + //execute extensions in normal order -> highest priority gets access to the currents first + for (size_t n=0; nDoPostCurrentUpdates(threadID); + m_IterateBarrier->wait(); + } +} + +void Engine_Multithread::Apply2Current(int threadID) +{ + //execute extensions in normal order -> highest priority gets access to the currents first + for (size_t n=0; nApply2Current(threadID); + m_IterateBarrier->wait(); + } +} + +// +// ************************************************************************************************************************* +// +namespace NS_Engine_Multithread +{ + +thread::thread( Engine_Multithread* ptr, unsigned int start, unsigned int stop, unsigned int stop_h, unsigned int threadID ) +{ + m_enginePtr = ptr; + m_start = start; + m_stop = stop; + m_stop_h = stop_h; + m_threadID = threadID; +} + +void thread::operator()() +{ + //std::cout << "thread::operator() Parameters: " << m_start << " " << m_stop << std::endl; + //DBG().cout() << "Thread " << m_threadID << " (" << boost::this_thread::get_id() << ") started." << endl; + + // speed up the calculation of denormal floating point values (flush-to-zero) +#ifndef SSE_CORRECT_DENORMALS + unsigned int oldMXCSR = _mm_getcsr(); //read the old MXCSR setting + unsigned int newMXCSR = oldMXCSR | 0x8040; // set DAZ and FZ bits + _mm_setcsr( newMXCSR ); //write the new MXCSR setting to the MXCSR +#endif + + while (!m_enginePtr->m_stopThreads) + { + // wait for start + //DBG().cout() << "Thread " << m_threadID << " (" << boost::this_thread::get_id() << ") waiting..." << endl; + m_enginePtr->m_startBarrier->wait(); + //cout << "Thread " << boost::this_thread::get_id() << " waiting... started." << endl; + + DEBUG_TIME( Timer timer1 ); + + for (unsigned int iter=0; iterm_iterTS; ++iter) + { + // pre voltage stuff... + m_enginePtr->DoPreVoltageUpdates(m_threadID); + + //voltage updates + m_enginePtr->UpdateVoltages(m_start,m_stop-m_start+1); + + // record time + DEBUG_TIME( m_enginePtr->m_timer_list[boost::this_thread::get_id()].push_back( timer1.elapsed() ); ) + + //cout << "Thread " << boost::this_thread::get_id() << " m_barrier1 waiting..." << endl; + m_enginePtr->m_IterateBarrier->wait(); + + // record time + DEBUG_TIME( m_enginePtr->m_timer_list[boost::this_thread::get_id()].push_back( timer1.elapsed() ); ) + + //post voltage stuff... + m_enginePtr->DoPostVoltageUpdates(m_threadID); + m_enginePtr->Apply2Voltages(m_threadID); + +#ifdef MPI_SUPPORT + if (m_threadID==0) + { + if (m_enginePtr->m_MPI_Barrier) + m_enginePtr->m_MPI_Barrier->wait(); + m_enginePtr->SendReceiveVoltages(); + } + m_enginePtr->m_IterateBarrier->wait(); +#endif + + // record time + DEBUG_TIME( m_enginePtr->m_timer_list[boost::this_thread::get_id()].push_back( timer1.elapsed() ); ) + + //pre current stuff + m_enginePtr->DoPreCurrentUpdates(m_threadID); + + //current updates + m_enginePtr->UpdateCurrents(m_start,m_stop_h-m_start+1); + + // record time + DEBUG_TIME( m_enginePtr->m_timer_list[boost::this_thread::get_id()].push_back( timer1.elapsed() ); ) + m_enginePtr->m_IterateBarrier->wait(); + + // record time + DEBUG_TIME( m_enginePtr->m_timer_list[boost::this_thread::get_id()].push_back( timer1.elapsed() ); ) + + //post current stuff + m_enginePtr->DoPostCurrentUpdates(m_threadID); + m_enginePtr->Apply2Current(m_threadID); + +#ifdef MPI_SUPPORT + if (m_threadID==0) + { + if (m_enginePtr->m_MPI_Barrier) + m_enginePtr->m_MPI_Barrier->wait(); + m_enginePtr->SendReceiveCurrents(); + } + m_enginePtr->m_IterateBarrier->wait(); +#endif + + if (m_threadID == 0) + ++m_enginePtr->numTS; // only the first thread increments numTS + } + + m_enginePtr->m_stopBarrier->wait(); + } + + //DBG().cout() << "Thread " << m_threadID << " (" << boost::this_thread::get_id() << ") finished." << endl; +} + +} // namespace + diff --git a/openEMS/FDTD/engine_multithread.h b/openEMS/FDTD/engine_multithread.h new file mode 100644 index 0000000..20e7073 --- /dev/null +++ b/openEMS/FDTD/engine_multithread.h @@ -0,0 +1,127 @@ +/* +* Copyright (C) 2010 Sebastian Held (sebastian.held@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 . +*/ + +#ifndef ENGINE_MULTITHREAD_H +#define ENGINE_MULTITHREAD_H + +#include "operator_multithread.h" +#include "engine_sse_compressed.h" + +#include +#include +#include +#include + +//#ifdef WIN32 +//#include // for struct timeval +//#endif + +#include + +#ifdef MPI_SUPPORT + #define ENGINE_MULTITHREAD_BASE Engine_MPI + #include "engine_mpi.h" +#else + #define ENGINE_MULTITHREAD_BASE Engine_SSE_Compressed +#endif + + +class Engine_Multithread; + +namespace NS_Engine_Multithread +{ + +class DBG // debug +{ +public: + DBG() {} + ~DBG() { std::cout << os.str();} + std::ostringstream& cout() {return os;} +protected: + std::ostringstream os; +}; + +class Timer //debug +{ +public: + Timer() {gettimeofday(&t1,NULL);} + double elapsed() {gettimeofday(&t2,NULL); return (t2.tv_sec-t1.tv_sec) + (t2.tv_usec-t1.tv_usec)*1e-6;} +protected: + timeval t1,t2; +}; + +class thread +{ +public: + thread( Engine_Multithread* ptr, unsigned int start, unsigned int stop, unsigned int stop_h, unsigned int threadID ); + void operator()(); + +protected: + unsigned int m_start, m_stop, m_stop_h, m_threadID; + Engine_Multithread *m_enginePtr; +}; +} // namespace + + +class Engine_Multithread : public ENGINE_MULTITHREAD_BASE +{ + friend class NS_Engine_Multithread::thread; + friend class Engine_CylinderMultiGrid; +public: + static Engine_Multithread* New(const Operator_Multithread* op, unsigned int numThreads = 0); + virtual ~Engine_Multithread(); + + virtual void setNumThreads( unsigned int numThreads ); + virtual void Init(); + virtual void Reset(); + + //! Iterate \a iterTS number of timesteps + virtual bool IterateTS(unsigned int iterTS); + + virtual void DoPreVoltageUpdates(int threadID); + virtual void DoPostVoltageUpdates(int threadID); + virtual void Apply2Voltages(int threadID); + + virtual void DoPreCurrentUpdates(int threadID); + virtual void DoPostCurrentUpdates(int threadID); + virtual void Apply2Current(int threadID); + +protected: + Engine_Multithread(const Operator_Multithread* op); + const Operator_Multithread* m_Op_MT; + boost::thread_group m_thread_group; + boost::barrier *m_startBarrier, *m_stopBarrier; + boost::barrier *m_IterateBarrier; + volatile unsigned int m_iterTS; + unsigned int m_numThreads; //!< number of worker threads + volatile bool m_stopThreads; + +#ifdef MPI_SUPPORT + /*! Workaround needed for subgridding scheme... (see Engine_CylinderMultiGrid) + Some engines may need an additional barrier for synchronizing MPI communication. + This engine will not initialize or cleanup this barrier, but check for it and wait before executing any MPI sync. + Make sure to cleanup (delete) this barriere before Engine_Multithread::Reset() is called. + */ + boost::barrier *m_MPI_Barrier; +#endif + +#ifdef ENABLE_DEBUG_TIME + std::map > m_timer_list; +#endif +}; + +#endif // ENGINE_MULTITHREAD_H diff --git a/openEMS/FDTD/engine_sse.cpp b/openEMS/FDTD/engine_sse.cpp new file mode 100644 index 0000000..660e6d6 --- /dev/null +++ b/openEMS/FDTD/engine_sse.cpp @@ -0,0 +1,176 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include +#include "engine_sse.h" + +//! \brief construct an Engine_sse instance +//! it's the responsibility of the caller to free the returned pointer +Engine_sse* Engine_sse::New(const Operator_sse* op) +{ + cout << "Create FDTD engine (SSE)" << endl; + Engine_sse* e = new Engine_sse(op); + e->Init(); + return e; +} + +Engine_sse::Engine_sse(const Operator_sse* op) : Engine(op) +{ + m_type = SSE; + Op = op; + f4_volt = 0; + f4_curr = 0; + numVectors = ceil((double)numLines[2]/4.0); + + // speed up the calculation of denormal floating point values (flush-to-zero) +#ifndef SSE_CORRECT_DENORMALS + unsigned int oldMXCSR = _mm_getcsr(); //read the old MXCSR setting + unsigned int newMXCSR = oldMXCSR | 0x8040; // set DAZ and FZ bits + _mm_setcsr( newMXCSR ); //write the new MXCSR setting to the MXCSR +#endif +} + +Engine_sse::~Engine_sse() +{ + //_mm_setcsr( oldMXCSR ); // restore old setting + Reset(); +} + +void Engine_sse::Init() +{ + Engine::Init(); + + Delete_N_3DArray(volt,numLines); + volt=NULL; // not used + Delete_N_3DArray(curr,numLines); + curr=NULL; // not used + + f4_volt = Create_N_3DArray_v4sf(numLines); + f4_curr = Create_N_3DArray_v4sf(numLines); +} + +void Engine_sse::Reset() +{ + Engine::Reset(); + Delete_N_3DArray_v4sf(f4_volt,numLines); + f4_volt = 0; + Delete_N_3DArray_v4sf(f4_curr,numLines); + f4_curr = 0; +} + +void Engine_sse::UpdateVoltages(unsigned int startX, unsigned int numX) +{ + unsigned int pos[3]; + bool shift[2]; + f4vector temp; + + pos[0] = startX; + for (unsigned int posX=0; posXf4_vv[0][pos[0]][pos[1]][pos[2]].v; + f4_volt[0][pos[0]][pos[1]][pos[2]].v += Op->f4_vi[0][pos[0]][pos[1]][pos[2]].v * ( f4_curr[2][pos[0]][pos[1]][pos[2]].v - f4_curr[2][pos[0]][pos[1]-shift[1]][pos[2]].v - f4_curr[1][pos[0]][pos[1]][pos[2]].v + f4_curr[1][pos[0]][pos[1]][pos[2]-1].v ); + + // y-polarization + f4_volt[1][pos[0]][pos[1]][pos[2]].v *= Op->f4_vv[1][pos[0]][pos[1]][pos[2]].v; + f4_volt[1][pos[0]][pos[1]][pos[2]].v += Op->f4_vi[1][pos[0]][pos[1]][pos[2]].v * ( f4_curr[0][pos[0]][pos[1]][pos[2]].v - f4_curr[0][pos[0]][pos[1]][pos[2]-1].v - f4_curr[2][pos[0]][pos[1]][pos[2]].v + f4_curr[2][pos[0]-shift[0]][pos[1]][pos[2]].v); + + // z-polarization + f4_volt[2][pos[0]][pos[1]][pos[2]].v *= Op->f4_vv[2][pos[0]][pos[1]][pos[2]].v; + f4_volt[2][pos[0]][pos[1]][pos[2]].v += Op->f4_vi[2][pos[0]][pos[1]][pos[2]].v * ( f4_curr[1][pos[0]][pos[1]][pos[2]].v - f4_curr[1][pos[0]-shift[0]][pos[1]][pos[2]].v - f4_curr[0][pos[0]][pos[1]][pos[2]].v + f4_curr[0][pos[0]][pos[1]-shift[1]][pos[2]].v); + } + + // for pos[2] = 0 + // x-polarization + temp.f[0] = 0; + temp.f[1] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[0]; + temp.f[2] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[1]; + temp.f[3] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[2]; + f4_volt[0][pos[0]][pos[1]][0].v *= Op->f4_vv[0][pos[0]][pos[1]][0].v; + f4_volt[0][pos[0]][pos[1]][0].v += Op->f4_vi[0][pos[0]][pos[1]][0].v * ( f4_curr[2][pos[0]][pos[1]][0].v - f4_curr[2][pos[0]][pos[1]-shift[1]][0].v - f4_curr[1][pos[0]][pos[1]][0].v + temp.v ); + + // y-polarization + temp.f[0] = 0; + temp.f[1] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[0]; + temp.f[2] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[1]; + temp.f[3] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[2]; + f4_volt[1][pos[0]][pos[1]][0].v *= Op->f4_vv[1][pos[0]][pos[1]][0].v; + f4_volt[1][pos[0]][pos[1]][0].v += Op->f4_vi[1][pos[0]][pos[1]][0].v * ( f4_curr[0][pos[0]][pos[1]][0].v - temp.v - f4_curr[2][pos[0]][pos[1]][0].v + f4_curr[2][pos[0]-shift[0]][pos[1]][0].v); + + // z-polarization + f4_volt[2][pos[0]][pos[1]][0].v *= Op->f4_vv[2][pos[0]][pos[1]][0].v; + f4_volt[2][pos[0]][pos[1]][0].v += Op->f4_vi[2][pos[0]][pos[1]][0].v * ( f4_curr[1][pos[0]][pos[1]][0].v - f4_curr[1][pos[0]-shift[0]][pos[1]][0].v - f4_curr[0][pos[0]][pos[1]][0].v + f4_curr[0][pos[0]][pos[1]-shift[1]][0].v); + } + ++pos[0]; + } +} + +void Engine_sse::UpdateCurrents(unsigned int startX, unsigned int numX) +{ + unsigned int pos[5]; + f4vector temp; + + pos[0] = startX; + for (unsigned int posX=0; posXf4_ii[0][pos[0]][pos[1]][pos[2]].v; + f4_curr[0][pos[0]][pos[1]][pos[2]].v += Op->f4_iv[0][pos[0]][pos[1]][pos[2]].v * ( f4_volt[2][pos[0]][pos[1]][pos[2]].v - f4_volt[2][pos[0]][pos[1]+1][pos[2]].v - f4_volt[1][pos[0]][pos[1]][pos[2]].v + f4_volt[1][pos[0]][pos[1]][pos[2]+1].v); + + // y-pol + f4_curr[1][pos[0]][pos[1]][pos[2]].v *= Op->f4_ii[1][pos[0]][pos[1]][pos[2]].v; + f4_curr[1][pos[0]][pos[1]][pos[2]].v += Op->f4_iv[1][pos[0]][pos[1]][pos[2]].v * ( f4_volt[0][pos[0]][pos[1]][pos[2]].v - f4_volt[0][pos[0]][pos[1]][pos[2]+1].v - f4_volt[2][pos[0]][pos[1]][pos[2]].v + f4_volt[2][pos[0]+1][pos[1]][pos[2]].v); + + // z-pol + f4_curr[2][pos[0]][pos[1]][pos[2]].v *= Op->f4_ii[2][pos[0]][pos[1]][pos[2]].v; + f4_curr[2][pos[0]][pos[1]][pos[2]].v += Op->f4_iv[2][pos[0]][pos[1]][pos[2]].v * ( f4_volt[1][pos[0]][pos[1]][pos[2]].v - f4_volt[1][pos[0]+1][pos[1]][pos[2]].v - f4_volt[0][pos[0]][pos[1]][pos[2]].v + f4_volt[0][pos[0]][pos[1]+1][pos[2]].v); + } + + // for pos[2] = numVectors-1 + // x-pol + temp.f[0] = f4_volt[1][pos[0]][pos[1]][0].f[1]; + temp.f[1] = f4_volt[1][pos[0]][pos[1]][0].f[2]; + temp.f[2] = f4_volt[1][pos[0]][pos[1]][0].f[3]; + temp.f[3] = 0; + f4_curr[0][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii[0][pos[0]][pos[1]][numVectors-1].v; + f4_curr[0][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv[0][pos[0]][pos[1]][numVectors-1].v * ( f4_volt[2][pos[0]][pos[1]][numVectors-1].v - f4_volt[2][pos[0]][pos[1]+1][numVectors-1].v - f4_volt[1][pos[0]][pos[1]][numVectors-1].v + temp.v); + + // y-pol + temp.f[0] = f4_volt[0][pos[0]][pos[1]][0].f[1]; + temp.f[1] = f4_volt[0][pos[0]][pos[1]][0].f[2]; + temp.f[2] = f4_volt[0][pos[0]][pos[1]][0].f[3]; + temp.f[3] = 0; + f4_curr[1][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii[1][pos[0]][pos[1]][numVectors-1].v; + f4_curr[1][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv[1][pos[0]][pos[1]][numVectors-1].v * ( f4_volt[0][pos[0]][pos[1]][numVectors-1].v - temp.v - f4_volt[2][pos[0]][pos[1]][numVectors-1].v + f4_volt[2][pos[0]+1][pos[1]][numVectors-1].v); + + // z-pol + f4_curr[2][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii[2][pos[0]][pos[1]][numVectors-1].v; + f4_curr[2][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv[2][pos[0]][pos[1]][numVectors-1].v * ( f4_volt[1][pos[0]][pos[1]][numVectors-1].v - f4_volt[1][pos[0]+1][pos[1]][numVectors-1].v - f4_volt[0][pos[0]][pos[1]][numVectors-1].v + f4_volt[0][pos[0]][pos[1]+1][numVectors-1].v); + } + ++pos[0]; + } +} diff --git a/openEMS/FDTD/engine_sse.h b/openEMS/FDTD/engine_sse.h new file mode 100644 index 0000000..9389f84 --- /dev/null +++ b/openEMS/FDTD/engine_sse.h @@ -0,0 +1,60 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef ENGINE_SSE_H +#define ENGINE_SSE_H + +#include "engine.h" +#include "operator_sse.h" + +class Engine_sse : public Engine +{ +public: + static Engine_sse* New(const Operator_sse* op); + virtual ~Engine_sse(); + + virtual void Init(); + virtual void Reset(); + + virtual unsigned int GetNumberOfTimesteps() {return numTS;}; + + //this access functions muss be overloaded by any new engine using a different storage model + inline virtual FDTD_FLOAT GetVolt( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_volt[n][x][y][z%numVectors].f[z/numVectors]; } + inline virtual FDTD_FLOAT GetVolt( unsigned int n, const unsigned int pos[3] ) const { return f4_volt[n][pos[0]][pos[1]][pos[2]%numVectors].f[pos[2]/numVectors]; } + inline virtual FDTD_FLOAT GetCurr( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_curr[n][x][y][z%numVectors].f[z/numVectors]; } + inline virtual FDTD_FLOAT GetCurr( unsigned int n, const unsigned int pos[3] ) const { return f4_curr[n][pos[0]][pos[1]][pos[2]%numVectors].f[pos[2]/numVectors]; } + + inline virtual void SetVolt( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value) { f4_volt[n][x][y][z%numVectors].f[z/numVectors]=value; } + inline virtual void SetVolt( unsigned int n, const unsigned int pos[3], FDTD_FLOAT value ) { f4_volt[n][pos[0]][pos[1]][pos[2]%numVectors].f[pos[2]/numVectors]=value; } + inline virtual void SetCurr( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value) { f4_curr[n][x][y][z%numVectors].f[z/numVectors]=value; } + inline virtual void SetCurr( unsigned int n, const unsigned int pos[3], FDTD_FLOAT value ) { f4_curr[n][pos[0]][pos[1]][pos[2]%numVectors].f[pos[2]/numVectors]=value; } + +protected: + Engine_sse(const Operator_sse* op); + const Operator_sse* Op; + + virtual void UpdateVoltages(unsigned int startX, unsigned int numX); + virtual void UpdateCurrents(unsigned int startX, unsigned int numX); + + unsigned int numVectors; + +public: //public access to the sse arrays for efficient extensions access... use careful... + f4vector**** f4_volt; + f4vector**** f4_curr; +}; + +#endif // ENGINE_SSE_H diff --git a/openEMS/FDTD/engine_sse_compressed.cpp b/openEMS/FDTD/engine_sse_compressed.cpp new file mode 100644 index 0000000..8e83387 --- /dev/null +++ b/openEMS/FDTD/engine_sse_compressed.cpp @@ -0,0 +1,163 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "engine_sse_compressed.h" +#ifdef __SSE2__ +#include +#endif + +Engine_SSE_Compressed* Engine_SSE_Compressed::New(const Operator_SSE_Compressed* op) +{ + cout << "Create FDTD engine (compressed SSE)" << endl; + Engine_SSE_Compressed* e = new Engine_SSE_Compressed(op); + e->Init(); + return e; +} + +Engine_SSE_Compressed::Engine_SSE_Compressed(const Operator_SSE_Compressed* op) : Engine_sse(op) +{ + Op = op; +} + +Engine_SSE_Compressed::~Engine_SSE_Compressed() +{ +} + +void Engine_SSE_Compressed::UpdateVoltages(unsigned int startX, unsigned int numX) +{ + unsigned int pos[3]; + bool shift[2]; + f4vector temp; + + pos[0] = startX; + unsigned int index=0; + for (unsigned int posX=0; posXm_Op_index[pos[0]][pos[1]][pos[2]]; + // x-polarization + f4_volt[0][pos[0]][pos[1]][pos[2]].v *= Op->f4_vv_Compressed[0][index].v; + f4_volt[0][pos[0]][pos[1]][pos[2]].v += Op->f4_vi_Compressed[0][index].v * ( f4_curr[2][pos[0]][pos[1]][pos[2]].v - f4_curr[2][pos[0]][pos[1]-shift[1]][pos[2]].v - f4_curr[1][pos[0]][pos[1]][pos[2]].v + f4_curr[1][pos[0]][pos[1]][pos[2]-1].v ); + + // y-polarization + f4_volt[1][pos[0]][pos[1]][pos[2]].v *= Op->f4_vv_Compressed[1][index].v; + f4_volt[1][pos[0]][pos[1]][pos[2]].v += Op->f4_vi_Compressed[1][index].v * ( f4_curr[0][pos[0]][pos[1]][pos[2]].v - f4_curr[0][pos[0]][pos[1]][pos[2]-1].v - f4_curr[2][pos[0]][pos[1]][pos[2]].v + f4_curr[2][pos[0]-shift[0]][pos[1]][pos[2]].v); + + // z-polarization + f4_volt[2][pos[0]][pos[1]][pos[2]].v *= Op->f4_vv_Compressed[2][index].v; + f4_volt[2][pos[0]][pos[1]][pos[2]].v += Op->f4_vi_Compressed[2][index].v * ( f4_curr[1][pos[0]][pos[1]][pos[2]].v - f4_curr[1][pos[0]-shift[0]][pos[1]][pos[2]].v - f4_curr[0][pos[0]][pos[1]][pos[2]].v + f4_curr[0][pos[0]][pos[1]-shift[1]][pos[2]].v); + } + + // for pos[2] = 0 + // x-polarization + index = Op->m_Op_index[pos[0]][pos[1]][0]; +#ifdef __SSE2__ + temp.v = (__m128)_mm_slli_si128( (__m128i)f4_curr[1][pos[0]][pos[1]][numVectors-1].v, 4 ); +#else + temp.f[0] = 0; + temp.f[1] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[0]; + temp.f[2] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[1]; + temp.f[3] = f4_curr[1][pos[0]][pos[1]][numVectors-1].f[2]; +#endif + f4_volt[0][pos[0]][pos[1]][0].v *= Op->f4_vv_Compressed[0][index].v; + f4_volt[0][pos[0]][pos[1]][0].v += Op->f4_vi_Compressed[0][index].v * ( f4_curr[2][pos[0]][pos[1]][0].v - f4_curr[2][pos[0]][pos[1]-shift[1]][0].v - f4_curr[1][pos[0]][pos[1]][0].v + temp.v ); + + // y-polarization +#ifdef __SSE2__ + temp.v = (__m128)_mm_slli_si128( (__m128i)f4_curr[0][pos[0]][pos[1]][numVectors-1].v, 4 ); +#else + temp.f[0] = 0; + temp.f[1] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[0]; + temp.f[2] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[1]; + temp.f[3] = f4_curr[0][pos[0]][pos[1]][numVectors-1].f[2]; +#endif + f4_volt[1][pos[0]][pos[1]][0].v *= Op->f4_vv_Compressed[1][index].v; + f4_volt[1][pos[0]][pos[1]][0].v += Op->f4_vi_Compressed[1][index].v * ( f4_curr[0][pos[0]][pos[1]][0].v - temp.v - f4_curr[2][pos[0]][pos[1]][0].v + f4_curr[2][pos[0]-shift[0]][pos[1]][0].v); + + // z-polarization + f4_volt[2][pos[0]][pos[1]][0].v *= Op->f4_vv_Compressed[2][index].v; + f4_volt[2][pos[0]][pos[1]][0].v += Op->f4_vi_Compressed[2][index].v * ( f4_curr[1][pos[0]][pos[1]][0].v - f4_curr[1][pos[0]-shift[0]][pos[1]][0].v - f4_curr[0][pos[0]][pos[1]][0].v + f4_curr[0][pos[0]][pos[1]-shift[1]][0].v); + } + ++pos[0]; + } +} + +void Engine_SSE_Compressed::UpdateCurrents(unsigned int startX, unsigned int numX) +{ + unsigned int pos[3]; + f4vector temp; + + pos[0] = startX; + unsigned int index; + for (unsigned int posX=0; posXm_Op_index[pos[0]][pos[1]][pos[2]]; + // x-pol + f4_curr[0][pos[0]][pos[1]][pos[2]].v *= Op->f4_ii_Compressed[0][index].v; + f4_curr[0][pos[0]][pos[1]][pos[2]].v += Op->f4_iv_Compressed[0][index].v * ( f4_volt[2][pos[0]][pos[1]][pos[2]].v - f4_volt[2][pos[0]][pos[1]+1][pos[2]].v - f4_volt[1][pos[0]][pos[1]][pos[2]].v + f4_volt[1][pos[0]][pos[1]][pos[2]+1].v); + + // y-pol + f4_curr[1][pos[0]][pos[1]][pos[2]].v *= Op->f4_ii_Compressed[1][index].v; + f4_curr[1][pos[0]][pos[1]][pos[2]].v += Op->f4_iv_Compressed[1][index].v * ( f4_volt[0][pos[0]][pos[1]][pos[2]].v - f4_volt[0][pos[0]][pos[1]][pos[2]+1].v - f4_volt[2][pos[0]][pos[1]][pos[2]].v + f4_volt[2][pos[0]+1][pos[1]][pos[2]].v); + + // z-pol + f4_curr[2][pos[0]][pos[1]][pos[2]].v *= Op->f4_ii_Compressed[2][index].v; + f4_curr[2][pos[0]][pos[1]][pos[2]].v += Op->f4_iv_Compressed[2][index].v * ( f4_volt[1][pos[0]][pos[1]][pos[2]].v - f4_volt[1][pos[0]+1][pos[1]][pos[2]].v - f4_volt[0][pos[0]][pos[1]][pos[2]].v + f4_volt[0][pos[0]][pos[1]+1][pos[2]].v); + } + + index = Op->m_Op_index[pos[0]][pos[1]][numVectors-1]; + // for pos[2] = numVectors-1 + // x-pol +#ifdef __SSE2__ + temp.v = (__m128)_mm_srli_si128( (__m128i)f4_volt[1][pos[0]][pos[1]][0].v, 4 ); +#else + temp.f[0] = f4_volt[1][pos[0]][pos[1]][0].f[1]; + temp.f[1] = f4_volt[1][pos[0]][pos[1]][0].f[2]; + temp.f[2] = f4_volt[1][pos[0]][pos[1]][0].f[3]; + temp.f[3] = 0; +#endif + f4_curr[0][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii_Compressed[0][index].v; + f4_curr[0][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv_Compressed[0][index].v * ( f4_volt[2][pos[0]][pos[1]][numVectors-1].v - f4_volt[2][pos[0]][pos[1]+1][numVectors-1].v - f4_volt[1][pos[0]][pos[1]][numVectors-1].v + temp.v); + + // y-pol +#ifdef __SSE2__ + temp.v = (__m128)_mm_srli_si128( (__m128i)f4_volt[0][pos[0]][pos[1]][0].v, 4 ); +#else + temp.f[0] = f4_volt[0][pos[0]][pos[1]][0].f[1]; + temp.f[1] = f4_volt[0][pos[0]][pos[1]][0].f[2]; + temp.f[2] = f4_volt[0][pos[0]][pos[1]][0].f[3]; + temp.f[3] = 0; +#endif + f4_curr[1][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii_Compressed[1][index].v; + f4_curr[1][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv_Compressed[1][index].v * ( f4_volt[0][pos[0]][pos[1]][numVectors-1].v - temp.v - f4_volt[2][pos[0]][pos[1]][numVectors-1].v + f4_volt[2][pos[0]+1][pos[1]][numVectors-1].v); + + // z-pol + f4_curr[2][pos[0]][pos[1]][numVectors-1].v *= Op->f4_ii_Compressed[2][index].v; + f4_curr[2][pos[0]][pos[1]][numVectors-1].v += Op->f4_iv_Compressed[2][index].v * ( f4_volt[1][pos[0]][pos[1]][numVectors-1].v - f4_volt[1][pos[0]+1][pos[1]][numVectors-1].v - f4_volt[0][pos[0]][pos[1]][numVectors-1].v + f4_volt[0][pos[0]][pos[1]+1][numVectors-1].v); + } + ++pos[0]; + } +} diff --git a/openEMS/FDTD/engine_sse_compressed.h b/openEMS/FDTD/engine_sse_compressed.h new file mode 100644 index 0000000..ab86cc8 --- /dev/null +++ b/openEMS/FDTD/engine_sse_compressed.h @@ -0,0 +1,38 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef ENGINE_SSE_COMPRESSED_H +#define ENGINE_SSE_COMPRESSED_H + +#include "engine_sse.h" +#include "operator_sse_compressed.h" + +class Engine_SSE_Compressed : public Engine_sse +{ +public: + static Engine_SSE_Compressed* New(const Operator_SSE_Compressed* op); + virtual ~Engine_SSE_Compressed(); + +protected: + Engine_SSE_Compressed(const Operator_SSE_Compressed* op); + const Operator_SSE_Compressed* Op; + + virtual void UpdateVoltages(unsigned int startX, unsigned int numX); + virtual void UpdateCurrents(unsigned int startX, unsigned int numX); +}; + +#endif // ENGINE_SSE_COMPRESSED_H diff --git a/openEMS/FDTD/excitation.cpp b/openEMS/FDTD/excitation.cpp new file mode 100644 index 0000000..4e1ba85 --- /dev/null +++ b/openEMS/FDTD/excitation.cpp @@ -0,0 +1,299 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "tools/array_ops.h" +#include "tools/useful.h" +#include +#include +#include "fparser.hh" +#include "excitation.h" + +using namespace std; + +Excitation::Excitation() +{ + Signal_volt = 0; + Signal_curr = 0; + + this->Reset(0); + + m_Excit_Type = Excitation::UNDEFINED; + m_SignalPeriod = 0; +} + +Excitation::~Excitation() +{ + this->Reset(0); +} + +void Excitation::Reset( double timestep ) +{ + delete[] Signal_volt; + Signal_volt = 0; + delete[] Signal_curr; + Signal_curr = 0; + + dT = timestep; + m_nyquistTS = 0; + m_f_max = 0; + m_foi = 0; +} + +bool Excitation::SetupGaussianPulse(double f0, double fc) +{ + m_Excit_Type = Excitation::GaissianPulse; + m_f0 = f0; + m_fc = fc; + m_f_max = f0+fc; + m_SignalPeriod = 0; +} + +bool Excitation::SetupSinusoidal(double f0) +{ + m_Excit_Type = Excitation::Sinusoidal; + m_f0 = f0; + m_f_max = f0; + m_SignalPeriod = 1/f0; +} + +bool Excitation::SetupDiracPulse(double fmax) +{ + m_Excit_Type = Excitation::DiracPulse; + m_SignalPeriod = 0; + m_f_max = fmax; +} + +bool 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) +{ + m_Excit_Type = Excitation::CustomExcite; + m_CustomExc_Str = str; + m_f0 = f0; + m_SignalPeriod = 0; + m_f_max = fmax; +} + +bool Excitation::buildExcitationSignal(unsigned int maxTS) +{ + if (dT<=0) + { + cerr << "Excitation::setupExcitation: Error, invalid timestep... " << endl; + return false; + } + + switch (m_Excit_Type) + { + case Excitation::GaissianPulse: + CalcGaussianPulsExcitation(m_f0,m_fc,maxTS); + break; + case Excitation::Sinusoidal: + CalcSinusExcitation(m_f0,maxTS); + break; + case Excitation::DiracPulse: + CalcDiracPulsExcitation(); + break; + case Excitation::Step: + CalcStepExcitation(); + break; + case Excitation::CustomExcite: + CalcCustomExcitation(m_f0,maxTS,m_CustomExc_Str); + break; + default: + cerr << "Excitation::buildExcitationSignal: Unknown excitation type: \"" << m_Excit_Type<< "\" !!" << endl; + m_Excit_Type = Excitation::UNDEFINED; + return false; + } + + if (GetNyquistNum() == 0) + { + cerr << "Excitation::buildExcitationSignal: Unknown error... excitation setup failed!!" << endl; + return false; + } + + return true; +} + +unsigned int Excitation::GetMaxExcitationTimestep() const +{ + FDTD_FLOAT maxAmp=0; + unsigned int maxStep=0; + for (unsigned int n=0; nmaxAmp) + { + maxAmp = fabs(Signal_volt[n]); + maxStep = n; + } + } + return maxStep; +} + +void Excitation::CalcGaussianPulsExcitation(double f0, double fc, int nTS) +{ + if (dT==0) return; + + Length = (unsigned int)ceil(2.0 * 9.0/(2.0*PI*fc) / dT); + if (Length>(unsigned int)nTS) + { + cerr << "Operator::CalcGaussianPulsExcitation: Requested excitation pusle would be " << Length << " timesteps or " << Length * dT << " s long. Cutting to max number of timesteps!" << endl; + Length=(unsigned int)nTS; + } + delete[] Signal_volt; + delete[] Signal_curr; + Signal_volt = new FDTD_FLOAT[Length]; + Signal_curr = new FDTD_FLOAT[Length]; + for (unsigned int n=0; n. +*/ + +#ifndef EXCITATION_H +#define EXCITATION_H + +#include +#include +#include "tools/constants.h" + +class Excitation +{ +public: + enum ExciteTypes {UNDEFINED=-1, GaissianPulse=0, Sinusoidal=1, DiracPulse=2, Step=3, CustomExcite=10}; + Excitation(); + virtual ~Excitation(); + + 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); + + double GetCenterFreq() {return m_f0;} + double GetCutOffFreq() {return m_fc;} + double GetMaxFreq() {return m_f_max;} + + bool buildExcitationSignal(unsigned int maxTS); + + //! Get the excitation timestep with the (first) max amplitude + virtual unsigned int GetMaxExcitationTimestep() const; + + void SetNyquistNum(unsigned int nyquist) {m_nyquistTS=nyquist;} + unsigned int GetNyquistNum() const {return m_nyquistTS;} + + //! Dump voltage excitation signal to ASCII file + void DumpVoltageExcite(std::string filename); + + //! Dump current excitation signal to ASCII file + void DumpCurrentExcite(std::string filename); + + //! Get the used timestep + double GetTimestep() const {return dT;} + + //! Get the type of excitation + int GetExciteType() const {return m_Excit_Type;} + + //! Get the length of the excitation signal + unsigned int GetLength() const {return Length;} + + //! Get the max frequeny excited by this signal + double GetMaxFrequency() const {return m_f_max;} + + //! Get the frequency of interest + double GetFrequencyOfInterest() const {return m_foi;} + + //! Get the signal period, 0 if not a periodical signal + double GetSignalPeriod() const {return m_SignalPeriod;} + + FDTD_FLOAT* GetVoltageSignal() const {return Signal_volt;} + FDTD_FLOAT* GetCurrentSignal() const {return Signal_curr;} + +protected: + double dT; + unsigned int m_nyquistTS; + double m_SignalPeriod; + ExciteTypes m_Excit_Type; + + //Excitation time-signal + unsigned int Length; + FDTD_FLOAT* Signal_volt; + FDTD_FLOAT* Signal_curr; + + // center frequency + double m_f0; + + // cutoff-frequency (Gaussian pulse only) + double m_fc; + + std::string m_CustomExc_Str; + + // max frequency + double m_f_max; + // frequency of interest + double m_foi; + + //! Calculate a custom signal + virtual void CalcCustomExcitation(double f0, int nTS, std::string signal); + //! Calculate an excitation with center of \a f0 and the half bandwidth \a fc + virtual void CalcGaussianPulsExcitation(double f0, double fc, int nTS); + //! Calculate a sinusoidal excitation with frequency \a f0 and a duration of \a nTS number of timesteps + virtual void CalcSinusExcitation(double f0, int nTS); + //! Calculate a dirac impuls excitation + virtual void CalcDiracPulsExcitation(); + //! Calculate a step excitation + virtual void CalcStepExcitation(); +}; + +#endif // EXCITATION_H diff --git a/openEMS/FDTD/extensions/CMakeLists.txt b/openEMS/FDTD/extensions/CMakeLists.txt new file mode 100644 index 0000000..3566944 --- /dev/null +++ b/openEMS/FDTD/extensions/CMakeLists.txt @@ -0,0 +1,32 @@ + +#INCLUDE_DIRECTORIES( ${openEMS_SOURCE_DIR} ) +#INCLUDE_DIRECTORIES( ${CSXCAD_SOURCE_DIR}/src ) + +set(SOURCES + ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/engine_extension.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_dispersive.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_lorentzmaterial.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_conductingsheet.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_dispersive.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_lorentzmaterial.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_cylindermultigrid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_upml.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_upml.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_extension.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_mur_abc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_mur_abc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_cylinder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_cylinder.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_excitation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_excitation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_tfsf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_tfsf.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/operator_ext_steadystate.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/engine_ext_steadystate.cpp + PARENT_SCOPE +) + +# FDTD/extensions lib +#add_library( extensions STATIC ${SOURCES} ) + diff --git a/openEMS/FDTD/extensions/OptimizeCondSheetParameter.m b/openEMS/FDTD/extensions/OptimizeCondSheetParameter.m new file mode 100644 index 0000000..12ac8ec --- /dev/null +++ b/openEMS/FDTD/extensions/OptimizeCondSheetParameter.m @@ -0,0 +1,107 @@ +function OptimizeCondSheetParameter +% function OptimizeCondSheetParameter +% +% internal openEMS function to create the "cond_sheet_parameter.h" header +% file containing optimized parameter values for the conducting sheet model +% +% (c) 2012: Thorsten Liebig, thorsten.liebig@gmx.de + + +close all +clear +clc + + +X = [1 1 1 1 1]; +lb = zeros(size(X)); +ub = ones(size(X))*1000; + + +Omega = linspace(0,20,51); +Omega = Omega(2:end); + +Omega_fine = linspace(0,20,15001); +Omega_fine = Omega_fine(2:end); + +options = optimset('fzero'); +% options = optimset(options,'Display','iter') +options = optimset(options,'MaxFunEvals',5000); +options = optimset(options,'MaxIter',5000); + +omg_stop_str = []; +omg_critical_20 = []; +omg_critical_5 = []; +g_str = []; +r1_str= []; +r2_str= []; +l1_str= []; +l2_str= []; + +numPara = 30; +factor = 1.5; + +for p = 1:numPara + + X = lsqnonlin(@(X)CalcYDiff(Omega,X),X,lb,ub,options); + + omg_stop_str = [omg_stop_str num2str(Omega(end),10) ',']; + g_str = [g_str num2str(X(1),10) ',']; + r1_str = [r1_str num2str(X(2),10) ',']; + l1_str = [l1_str num2str(X(3),10) ',']; + r2_str = [r2_str num2str(X(4),10) ',']; + l2_str = [l2_str num2str(X(5),10) ',']; + + Ys = tanh((1+1j)*sqrt(Omega_fine))/(1+1j)./sqrt(Omega_fine); + + err = (CalcYDiff(Omega_fine,X))./real(1./Ys); + + fc = Omega_fine(find(abs(err)>0.2,1,'last')); + if (isempty(fc)) + fc = 0; + end + omg_critical_20 = [omg_critical_20 num2str(fc,10) ',']; + + fc = Omega_fine(find(abs(err)>0.05,1,'last')); + if (isempty(fc)) + fc = 0; + end + omg_critical_5 = [omg_critical_5 num2str(fc,10) ',']; + +% disp(['max error: ' num2str(max(abs(err)*100)) ]) +% figure +% plot(Omega_fine,err*100,'g--'); + + Omega_fine = Omega_fine*factor; + Omega = Omega*factor; +end + +%% write to file +fid = fopen('cond_sheet_parameter.h','w'); + +fprintf(fid,'// This is a list of conducting sheet model parameter for different ranges of omega = w/w0\n'); +fprintf(fid,'// This file was created automatically using Matlab: OptimizeCondSheetParameter.m \n'); +fprintf(fid,'// Do not change this file! \n'); +fprintf(fid,'// Creation: %s \n\n',datestr(now)); + + + +fprintf(fid,'unsigned int numOptPara=%d;\n',numPara); + +fprintf(fid,'double omega_stop[%d]={%s};\n',numPara,omg_stop_str(1:end-1)); +fprintf(fid,'double omega_critical_5[%d]={%s};\n',numPara,omg_critical_5(1:end-1)); +fprintf(fid,'double omega_critical_20[%d]={%s};\n',numPara,omg_critical_20(1:end-1)); +fprintf(fid,'double g[%d]={%s};\n',numPara,g_str(1:end-1)); +fprintf(fid,'double r1[%d]={%s};\n',numPara,r1_str(1:end-1)); +fprintf(fid,'double l1[%d]={%s};\n',numPara,l1_str(1:end-1)); +fprintf(fid,'double r2[%d]={%s};\n',numPara,r2_str(1:end-1)); +fprintf(fid,'double l2[%d]={%s};\n',numPara,l2_str(1:end-1)); + +fclose(fid); + +function Ydiff = CalcYDiff(omega, X) + +Ys = tanh((1+1j)*sqrt(omega))/(1+1j)./sqrt(omega); + +Y = X(1) + 1./(X(2)+1j*omega*X(3)) + 1./(X(4)+1j*omega*X(5)); + +Ydiff = real(1./Ys)-real(1./Y); \ No newline at end of file diff --git a/openEMS/FDTD/extensions/cond_sheet_parameter.h b/openEMS/FDTD/extensions/cond_sheet_parameter.h new file mode 100644 index 0000000..b3fc77b --- /dev/null +++ b/openEMS/FDTD/extensions/cond_sheet_parameter.h @@ -0,0 +1,14 @@ +// This is a list of conducting sheet model parameter for different ranges of omega = w/w0 +// This file was created automatically using Matlab: OptimizeCondSheetParameter.m +// Do not change this file! +// Creation: 08-May-2012 09:49:53 + +unsigned int numOptPara=30; +double omega_stop[30]={20,30,45,67.5,101.25,151.875,227.8125,341.71875,512.578125,768.8671875,1153.300781,1729.951172,2594.926758,3892.390137,5838.585205,8757.877808,13136.81671,19705.22507,29557.8376,44336.7564,66505.1346,99757.7019,149636.5529,224454.8293,336682.2439,505023.3659,757535.0488,1136302.573,1704453.86,2556680.79}; +double omega_critical_5[30]={0,0,0,1.566,6.8445,10.4085,15.1419375,22.30284375,33.45426562,50.28391406,75.42587109,113.1388066,169.70821,254.5623149,381.8434724,572.7652086,859.1478129,1288.721719,1933.082579,2899.623869,4349.435803,6524.153704,9786.230557,14679.34583,22019.01875,33028.52813,35503.14262,119084.5097,180444.8486,704280.3349}; +double omega_critical_20[30]={0,0,0,0,1.41075,2.7135,4.100625,5.90034375,8.6113125,12.86571094,19.37545312,29.06317969,43.59476953,65.3921543,98.08823145,147.1323472,220.6985208,331.0477811,496.5716717,744.8575075,1117.286261,1675.929392,2513.894088,3770.841132,5656.261698,8484.392547,10504.48601,11363.02573,11135.76522,7499.596983}; +double g[30]={0.1370843401,0.1244327709,0.1087425925,0.09215450299,0.07639249525,0.06239206861,0.05068701937,0.04124161681,0.03364925947,0.0274825647,0.02244156564,0.01832317373,0.01496080786,0.01221545053,0.009973874666,0.008143635713,0.006649251918,0.005429092739,0.00443283702,0.003619397792,0.002955227653,0.002412935361,0.001970156167,0.001608629812,0.001313423397,0.001072422468,0.0009031383439,0.0007674973627,0.0006482579571,0.0005450699565}; +double r1[30]={1.302754546,1.2992612,1.320033314,1.41829213,1.674326257,2.138770494,2.769126112,3.498802047,4.311446869,5.266204065,6.443980095,7.893402541,9.667414736,11.84010502,14.50110421,17.76014698,21.75163911,26.64019322,32.6274156,39.96021835,48.94100192,59.94011376,73.41109983,89.90930992,110.1195785,134.8631576,149.2770459,153.5258961,148.9373215,119.3522908}; +double l1[30]={0.9542567116,0.9412051444,0.8999655165,0.8189903271,0.702028543,0.5718817624,0.4577262324,0.3689027719,0.3004106661,0.2455514861,0.2005633225,0.1637496639,0.1337010005,0.1091664663,0.0891340699,0.07277768839,0.05942276018,0.04851850861,0.03961522618,0.03234573021,0.02641021614,0.02156389712,0.0176069076,0.01437606898,0.0117376269,0.009584103516,0.008750848841,0.008547706786,0.00854127488,0.008801399365}; +double r2[30]={10.62245057,10.21952962,10.24755832,10.99147713,12.70450822,15.59830718,19.55714986,24.32580904,29.88733852,36.55680626,44.75374078,54.81575133,67.13533424,82.22360504,100.7029064,123.3353165,151.0542147,185.0027444,226.5809553,277.5035137,339.8704104,416.2534638,509.8022059,624.3729288,764.7279941,936.5525496,1000,999.9999981,999.999984,999.9999985}; +double l2[30]={0.7925524826,0.6926195458,0.5814718257,0.4784644339,0.3916667501,0.3204661897,0.2620413998,0.2140939121,0.1748272154,0.1427375388,0.1165424396,0.09515681664,0.07769522035,0.06343788358,0.05179681795,0.04229192785,0.03453121766,0.02819462457,0.0230208182,0.01879642336,0.01534721999,0.01253095815,0.01023149158,0.008353988465,0.006820957973,0.005569332359,0.004553963932,0.003696380632,0.002978504727,0.002391295771}; diff --git a/openEMS/FDTD/extensions/engine_ext_cylinder.cpp b/openEMS/FDTD/extensions/engine_ext_cylinder.cpp new file mode 100644 index 0000000..e240f1b --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_cylinder.cpp @@ -0,0 +1,101 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "FDTD/engine.h" +#include "engine_ext_cylinder.h" +#include "operator_ext_cylinder.h" +#include "FDTD/engine_sse.h" + +Engine_Ext_Cylinder::Engine_Ext_Cylinder(Operator_Ext_Cylinder* op_ext) : Engine_Extension(op_ext) +{ + cyl_Op = op_ext; + m_Eng_SSE = NULL; + + CC_closedAlpha = op_ext->CC_closedAlpha; + CC_R0_included = op_ext->CC_R0_included; + + for (int n=0; n<3; ++n) + numLines[n] = op_ext->m_Op->GetNumberOfLines(n,true); + + //this cylindrical extension should be executed first? + m_Priority = ENG_EXT_PRIO_CYLINDER; +} + +void Engine_Ext_Cylinder::SetEngine(Engine* eng) +{ + Engine_Extension::SetEngine(eng); + m_Eng_SSE = dynamic_cast(m_Eng); +} + +void Engine_Ext_Cylinder::DoPostVoltageUpdates() +{ + if (CC_closedAlpha==false) return; + + if (CC_R0_included) + { + unsigned int pos[3]; + pos[0] = 0; + FDTD_FLOAT volt=0; + for (pos[2]=0; pos[2]Engine_sse::GetVolt(2,0,0,pos[2])*cyl_Op->vv_R0[pos[2]]; + for (pos[1]=0; pos[1]vi_R0[pos[2]] * m_Eng_SSE->Engine_sse::GetCurr(1,0,pos[1],pos[2]); + m_Eng_SSE->Engine_sse::SetVolt(2,0,0,pos[2], volt); + } + + for (pos[1]=0; pos[1]Engine_sse::SetVolt(1,0,pos[1],pos[2], 0); //no voltage in alpha-direction at r=0 + m_Eng_SSE->Engine_sse::SetVolt(2,0,pos[1],pos[2], m_Eng_SSE->Engine_sse::GetVolt(2,0,0,pos[2]) ); + } + } + } + + //close alpha + unsigned int pos[3]; + // copy tangential voltages from last alpha-plane to first + unsigned int last_A_Line = numLines[1]-2; + for (pos[0]=0; pos[0]Engine_sse::SetVolt(0,pos[0],0,pos[2], m_Eng_SSE->Engine_sse::GetVolt(0,pos[0],last_A_Line,pos[2]) ); + m_Eng_SSE->Engine_sse::SetVolt(2,pos[0],0,pos[2], m_Eng_SSE->Engine_sse::GetVolt(2,pos[0],last_A_Line,pos[2]) ); + } + } +} + +void Engine_Ext_Cylinder::DoPostCurrentUpdates() +{ + if (CC_closedAlpha==false) return; + + //close alpha + unsigned int pos[3]; + // copy tangential currents from first alpha-plane to last + for (pos[0]=0; pos[0]Engine_sse::SetCurr(0,pos[0],last_A_Line,pos[2], m_Eng_SSE->Engine_sse::GetCurr(0,pos[0],0,pos[2]) ); + m_Eng_SSE->Engine_sse::SetCurr(2,pos[0],last_A_Line,pos[2], m_Eng_SSE->Engine_sse::GetCurr(2,pos[0],0,pos[2]) ); + } + } +} diff --git a/openEMS/FDTD/extensions/engine_ext_cylinder.h b/openEMS/FDTD/extensions/engine_ext_cylinder.h new file mode 100644 index 0000000..c996a9d --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_cylinder.h @@ -0,0 +1,49 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef ENGINE_CYLINDER_H +#define ENGINE_CYLINDER_H + +#include "FDTD/engine.h" +#include "engine_extension.h" +#include "FDTD/operator_cylinder.h" + +class Operator_Ext_Cylinder; +class Engine_sse; + +class Engine_Ext_Cylinder : public Engine_Extension +{ +public: + Engine_Ext_Cylinder(Operator_Ext_Cylinder* op_ext); + + virtual void DoPostVoltageUpdates(); + + virtual void DoPostCurrentUpdates(); + + virtual void SetEngine(Engine* eng); + +protected: + Operator_Ext_Cylinder* cyl_Op; + Engine_sse* m_Eng_SSE; + + unsigned int numLines[3]; + + bool CC_closedAlpha; + bool CC_R0_included; +}; + +#endif // ENGINE_CYLINDER_H diff --git a/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.cpp b/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.cpp new file mode 100644 index 0000000..eca2c9e --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.cpp @@ -0,0 +1,165 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "FDTD/engine.h" +#include "engine_ext_cylindermultigrid.h" +#include "FDTD/engine_cylindermultigrid.h" + +Engine_Ext_CylinderMultiGrid::Engine_Ext_CylinderMultiGrid(Operator_Extension* op_ext, bool isBase) : Engine_Extension(op_ext) +{ + m_IsBase = isBase; + m_Eng_MG = NULL; + + // the multi-grid should be applies last? + m_Priority = ENG_EXT_PRIO_CYLINDERMULTIGRID; +} + +Engine_Ext_CylinderMultiGrid::~Engine_Ext_CylinderMultiGrid() +{ +} + +void Engine_Ext_CylinderMultiGrid::SetBarrier(boost::barrier* waitBase, boost::barrier* waitChild, boost::barrier* waitSync) +{ + m_WaitOnBase = waitBase; + m_WaitOnChild = waitChild; + m_WaitOnSync = waitSync; +} + +void Engine_Ext_CylinderMultiGrid::SetEngine(Engine* eng) +{ + m_Eng_MG = dynamic_cast(eng); + if (m_Eng_MG==NULL) + { + cerr << "Engine_Ext_CylinderMultiGrid::SetEngine(): Error" << endl; + exit(0); + } +} + +void Engine_Ext_CylinderMultiGrid::DoPreVoltageUpdates() +{ + //cerr << "Engine_Ext_CylinderMultiGrid::DoPreVoltageUpdates() for " << m_IsBase << endl; + if (!m_IsBase) + { + //cerr << "child: volt wait on base " << endl; + m_WaitOnBase->wait(); //wait on base to finisch current sync and/or to finisch voltage updates, than start child voltage updates + } +} + +void Engine_Ext_CylinderMultiGrid::DoPostVoltageUpdates() +{ + +} + +void Engine_Ext_CylinderMultiGrid::Apply2Voltages() +{ + if (m_IsBase) + { + m_WaitOnBase->wait(); //base voltage updates are done, tell child to start its voltage updates + m_WaitOnChild->wait(); //wait for child to finisch its updates + SyncVoltages(); //child is finisch, run sync and go to current updates next + m_WaitOnSync->wait(); //sync is done... move on and tell child to move on... + } + else + { + m_WaitOnChild->wait(); //child is finished voltage updates, will tell base to run sync + m_WaitOnSync->wait(); //wait for base to finisch sync before going to wait for current updates + } +} + +void Engine_Ext_CylinderMultiGrid::SyncVoltages() +{ + if (m_Eng_MG==NULL) + { + cerr << "Engine_Ext_CylinderMultiGrid::SyncVoltages: Error engine is NULL" << endl; + return; + } + + unsigned int* numLines = m_Eng_MG->numLines; + + Engine_Multithread* m_InnerEng = m_Eng_MG->m_InnerEngine; + + //interpolate voltages from base engine to child engine... + unsigned int pos[3]; + pos[0] = m_Eng_MG->Op_CMG->GetSplitPos()-1; + unsigned int pos1_half = 0; + f4vector v_null; + v_null.f[0] = 0; + v_null.f[1] = 0; + v_null.f[2] = 0; + v_null.f[3] = 0; + for (pos[1]=0; pos[1]numVectors; ++pos[2]) + { + //r - direczion + m_InnerEng->f4_volt[0][pos[0]][pos1_half][pos[2]].v = v_null.v; + + //z - direction + m_InnerEng->f4_volt[2][pos[0]][pos1_half][pos[2]].v = m_Eng_MG->f4_volt[2][pos[0]][pos[1]][pos[2]].v; + + //alpha - direction + m_InnerEng->f4_volt[1][pos[0]][pos1_half][pos[2]].v = m_Eng_MG->f4_volt[1][pos[0]][pos[1]][pos[2]].v; + m_InnerEng->f4_volt[1][pos[0]][pos1_half][pos[2]].v += m_Eng_MG->f4_volt[1][pos[0]][pos[1]+1][pos[2]].v; + } + } +} + +void Engine_Ext_CylinderMultiGrid::DoPreCurrentUpdates() +{ + //cerr << "Engine_Ext_CylinderMultiGrid::DoPreCurrentUpdates() for " << m_IsBase << endl; + if (!m_IsBase) + { + //cerr << "child: curr wait on base " << endl; + m_WaitOnBase->wait(); //wait on base to finisch voltage sync and current updates, than start child current updates + } +} + +void Engine_Ext_CylinderMultiGrid::DoPostCurrentUpdates() +{ + +} + +void Engine_Ext_CylinderMultiGrid::Apply2Current() +{ + if (m_IsBase) + { + //cerr << "Base: curr wait on base done, wait on sync" << endl; + m_WaitOnBase->wait(); //base current updates are done, tell child to start its current updates + m_WaitOnChild->wait(); //wait for child to finisch its updates + SyncCurrents(); //child is finisch, run sync and go to voltage updates next + m_WaitOnSync->wait(); //sync is done... move on and tell child to move on... + } + else + { + m_WaitOnChild->wait(); //child is finished current updates, will tell base to run sync... + m_WaitOnSync->wait(); //wait for base to finisch sync before going to wait for next voltage updates + //cerr << "Child: curr done, wait on sync" << endl; + } +} + +void Engine_Ext_CylinderMultiGrid::SyncCurrents() +{ + if (m_Eng_MG==NULL) + { + cerr << "Engine_Ext_CylinderMultiGrid::SyncCurrents: Error engine is NULL" << endl; + return; + } + + m_Eng_MG->InterpolCurrChild2Base(m_Eng_MG->Op_CMG->GetSplitPos()-2); + return; +} diff --git a/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.h b/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.h new file mode 100644 index 0000000..e9226f5 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_cylindermultigrid.h @@ -0,0 +1,58 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef ENGINE_EXT_CYLINDERMULTIGRID_H +#define ENGINE_EXT_CYLINDERMULTIGRID_H + +#include "FDTD/engine_cylindermultigrid.h" +#include "engine_extension.h" +#include "FDTD/operator_cylindermultigrid.h" + +class Operator_Ext_CylinderMultiGrid; + +class Engine_Ext_CylinderMultiGrid : public Engine_Extension +{ +public: + Engine_Ext_CylinderMultiGrid(Operator_Extension* op_ext, bool isBase); + virtual ~Engine_Ext_CylinderMultiGrid(); + + void SetBarrier(boost::barrier* waitBase, boost::barrier* waitChild, boost::barrier* waitSync); + + virtual void DoPreVoltageUpdates(); + virtual void DoPostVoltageUpdates(); + virtual void Apply2Voltages(); + + virtual void DoPreCurrentUpdates(); + virtual void DoPostCurrentUpdates(); + virtual void Apply2Current(); + + virtual void SetEngine(Engine* eng); + +protected: + void SyncVoltages(); + void SyncCurrents(); + + Engine_CylinderMultiGrid* m_Eng_MG; + + boost::barrier *m_WaitOnBase; + boost::barrier *m_WaitOnChild; + boost::barrier *m_WaitOnSync; + + bool m_IsBase; +}; + +#endif // ENGINE_EXT_CYLINDERMULTIGRID_H diff --git a/openEMS/FDTD/extensions/engine_ext_dispersive.cpp b/openEMS/FDTD/extensions/engine_ext_dispersive.cpp new file mode 100644 index 0000000..d9c431b --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_dispersive.cpp @@ -0,0 +1,162 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "engine_ext_dispersive.h" +#include "operator_ext_dispersive.h" +#include "FDTD/engine_sse.h" + +Engine_Ext_Dispersive::Engine_Ext_Dispersive(Operator_Ext_Dispersive* op_ext_disp) : Engine_Extension(op_ext_disp) +{ + m_Op_Ext_Disp = op_ext_disp; + int order = m_Op_Ext_Disp->m_Order; + curr_ADE = new FDTD_FLOAT**[order]; + volt_ADE = new FDTD_FLOAT**[order]; + for (int o=0;om_curr_ADE_On[o]==true) + { + curr_ADE[o][n] = new FDTD_FLOAT[m_Op_Ext_Disp->m_LM_Count[o]]; + for (unsigned int i=0; im_LM_Count[o]; ++i) + curr_ADE[o][n][i]=0.0; + } + else + curr_ADE[o][n] = NULL; + if (m_Op_Ext_Disp->m_volt_ADE_On[o]==true) + { + volt_ADE[o][n] = new FDTD_FLOAT[m_Op_Ext_Disp->m_LM_Count[o]]; + for (unsigned int i=0; im_LM_Count[o]; ++i) + volt_ADE[o][n][i]=0.0; + } + else + volt_ADE[o][n] = NULL; + } + } +} + +Engine_Ext_Dispersive::~Engine_Ext_Dispersive() +{ + if (curr_ADE==NULL && volt_ADE==NULL) + return; + + for (int o=0;om_Order;++o) + { + for (int n=0; n<3; ++n) + { + delete[] curr_ADE[o][n]; + delete[] volt_ADE[o][n]; + } + delete[] curr_ADE[o]; + delete[] volt_ADE[o]; + } + delete[] curr_ADE; + curr_ADE=NULL; + + delete[] volt_ADE; + volt_ADE=NULL; +} + +void Engine_Ext_Dispersive::Apply2Voltages() +{ + for (int o=0;om_Order;++o) + { + if (m_Op_Ext_Disp->m_volt_ADE_On[o]==false) continue; + + unsigned int **pos = m_Op_Ext_Disp->m_LM_pos[o]; + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + m_Eng->Engine::SetVolt(0,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetVolt(0,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][0][i]); + m_Eng->Engine::SetVolt(1,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetVolt(1,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][1][i]); + m_Eng->Engine::SetVolt(2,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetVolt(2,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + eng_sse->Engine_sse::SetVolt(0,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetVolt(0,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][0][i]); + eng_sse->Engine_sse::SetVolt(1,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetVolt(1,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][1][i]); + eng_sse->Engine_sse::SetVolt(2,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetVolt(2,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][2][i]); + } + break; + } + default: + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + m_Eng->SetVolt(0,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetVolt(0,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][0][i]); + m_Eng->SetVolt(1,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetVolt(1,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][1][i]); + m_Eng->SetVolt(2,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetVolt(2,pos[0][i],pos[1][i],pos[2][i]) - volt_ADE[o][2][i]); + } + break; + } + } +} + +void Engine_Ext_Dispersive::Apply2Current() +{ + for (int o=0;om_Order;++o) + { + if (m_Op_Ext_Disp->m_curr_ADE_On[o]==false) continue; + + unsigned int **pos = m_Op_Ext_Disp->m_LM_pos[o]; + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + m_Eng->Engine::SetCurr(0,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetCurr(0,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][0][i]); + m_Eng->Engine::SetCurr(1,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetCurr(1,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][1][i]); + m_Eng->Engine::SetCurr(2,pos[0][i],pos[1][i],pos[2][i], m_Eng->Engine::GetCurr(2,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + eng_sse->Engine_sse::SetCurr(0,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetCurr(0,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][0][i]); + eng_sse->Engine_sse::SetCurr(1,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetCurr(1,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][1][i]); + eng_sse->Engine_sse::SetCurr(2,pos[0][i],pos[1][i],pos[2][i], eng_sse->Engine_sse::GetCurr(2,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][2][i]); + } + break; + } + default: + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + m_Eng->SetCurr(0,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetCurr(0,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][0][i]); + m_Eng->SetCurr(1,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetCurr(1,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][1][i]); + m_Eng->SetCurr(2,pos[0][i],pos[1][i],pos[2][i], m_Eng->GetCurr(2,pos[0][i],pos[1][i],pos[2][i]) - curr_ADE[o][2][i]); + } + break; + } + } +} diff --git a/openEMS/FDTD/extensions/engine_ext_dispersive.h b/openEMS/FDTD/extensions/engine_ext_dispersive.h new file mode 100644 index 0000000..c1b84ea --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_dispersive.h @@ -0,0 +1,51 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef ENGINE_EXT_DISPERSIVE_H +#define ENGINE_EXT_DISPERSIVE_H + +#include "engine_extension.h" +#include "FDTD/engine.h" +#include "FDTD/operator.h" + +class Operator_Ext_Dispersive; + +class Engine_Ext_Dispersive : public Engine_Extension +{ +public: + Engine_Ext_Dispersive(Operator_Ext_Dispersive* op_ext_disp); + virtual ~Engine_Ext_Dispersive(); + + virtual void Apply2Voltages(); + virtual void Apply2Current(); + +protected: + Operator_Ext_Dispersive* m_Op_Ext_Disp; + + //! Dispersive order + int m_Order; + + //! ADE currents + // Array setup: curr_ADE[N_order][direction][mesh_pos] + FDTD_FLOAT ***curr_ADE; + + //! ADE voltages + // Array setup: volt_ADE[N_order][direction][mesh_pos] + FDTD_FLOAT ***volt_ADE; +}; + +#endif // ENGINE_EXT_DISPERSIVE_H diff --git a/openEMS/FDTD/extensions/engine_ext_excitation.cpp b/openEMS/FDTD/extensions/engine_ext_excitation.cpp new file mode 100644 index 0000000..402193a --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_excitation.cpp @@ -0,0 +1,170 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "engine_ext_excitation.h" +#include "operator_ext_excitation.h" +#include "FDTD/engine_sse.h" + +Engine_Ext_Excitation::Engine_Ext_Excitation(Operator_Ext_Excitation* op_ext) : Engine_Extension(op_ext) +{ + m_Op_Exc = op_ext; + m_Priority = ENG_EXT_PRIO_EXCITATION; +} + +Engine_Ext_Excitation::~Engine_Ext_Excitation() +{ + +} + +void Engine_Ext_Excitation::Apply2Voltages() +{ + //soft voltage excitation here (E-field excite) + int exc_pos; + unsigned int ny; + unsigned int pos[3]; + int numTS = m_Eng->GetNumberOfTimesteps(); + unsigned int length = m_Op_Exc->m_Exc->GetLength(); + FDTD_FLOAT* exc_volt = m_Op_Exc->m_Exc->GetVoltageSignal(); + + int p = numTS+1; + if (m_Op_Exc->m_Exc->GetSignalPeriod()>0) + p = int(m_Op_Exc->m_Exc->GetSignalPeriod()/m_Op_Exc->m_Exc->GetTimestep()); + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int n=0; nVolt_Count; ++n) + { + exc_pos = numTS - (int)m_Op_Exc->Volt_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<(int)length); + ny = m_Op_Exc->Volt_dir[n]; + pos[0]=m_Op_Exc->Volt_index[0][n]; + pos[1]=m_Op_Exc->Volt_index[1][n]; + pos[2]=m_Op_Exc->Volt_index[2][n]; + m_Eng->Engine::SetVolt(ny,pos, m_Eng->Engine::GetVolt(ny,pos) + m_Op_Exc->Volt_amp[n]*exc_volt[exc_pos]); + } + break; + } + case Engine::SSE: + { + for (unsigned int n=0; nVolt_Count; ++n) + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + exc_pos = numTS - (int)m_Op_Exc->Volt_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<(int)length); + ny = m_Op_Exc->Volt_dir[n]; + pos[0]=m_Op_Exc->Volt_index[0][n]; + pos[1]=m_Op_Exc->Volt_index[1][n]; + pos[2]=m_Op_Exc->Volt_index[2][n]; + eng_sse->Engine_sse::SetVolt(ny,pos, eng_sse->Engine_sse::GetVolt(ny,pos) + m_Op_Exc->Volt_amp[n]*exc_volt[exc_pos]); + } + break; + } + default: + { + for (unsigned int n=0; nVolt_Count; ++n) + { + exc_pos = numTS - (int)m_Op_Exc->Volt_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<(int)length); + ny = m_Op_Exc->Volt_dir[n]; + pos[0]=m_Op_Exc->Volt_index[0][n]; + pos[1]=m_Op_Exc->Volt_index[1][n]; + pos[2]=m_Op_Exc->Volt_index[2][n]; + m_Eng->SetVolt(ny,pos, m_Eng->GetVolt(ny,pos) + m_Op_Exc->Volt_amp[n]*exc_volt[exc_pos]); + } + break; + } + } +} + +void Engine_Ext_Excitation::Apply2Current() +{ + //soft current excitation here (H-field excite) + + int exc_pos; + unsigned int ny; + unsigned int pos[3]; + int numTS = m_Eng->GetNumberOfTimesteps(); + unsigned int length = m_Op_Exc->m_Exc->GetLength(); + FDTD_FLOAT* exc_curr = m_Op_Exc->m_Exc->GetCurrentSignal(); + + int p = numTS+1; + if (m_Op_Exc->m_Exc->GetSignalPeriod()>0) + p = int(m_Op_Exc->m_Exc->GetSignalPeriod()/m_Op_Exc->m_Exc->GetTimestep()); + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int n=0; nCurr_Count; ++n) + { + exc_pos = numTS - (int)m_Op_Exc->Curr_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<(int)length); + ny = m_Op_Exc->Curr_dir[n]; + pos[0]=m_Op_Exc->Curr_index[0][n]; + pos[1]=m_Op_Exc->Curr_index[1][n]; + pos[2]=m_Op_Exc->Curr_index[2][n]; + m_Eng->Engine::SetCurr(ny,pos, m_Eng->Engine::GetCurr(ny,pos) + m_Op_Exc->Curr_amp[n]*exc_curr[exc_pos]); + } + break; + } + case Engine::SSE: + { + for (unsigned int n=0; nCurr_Count; ++n) + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + exc_pos = numTS - (int)m_Op_Exc->Curr_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<(int)length); + ny = m_Op_Exc->Curr_dir[n]; + pos[0]=m_Op_Exc->Curr_index[0][n]; + pos[1]=m_Op_Exc->Curr_index[1][n]; + pos[2]=m_Op_Exc->Curr_index[2][n]; + eng_sse->Engine_sse::SetCurr(ny,pos, eng_sse->Engine_sse::GetCurr(ny,pos) + m_Op_Exc->Curr_amp[n]*exc_curr[exc_pos]); + } + break; + } + default: + { + for (unsigned int n=0; nCurr_Count; ++n) + { + exc_pos = numTS - (int)m_Op_Exc->Curr_delay[n]; + exc_pos *= (exc_pos>0); + exc_pos %= p; + exc_pos *= (exc_pos<(int)length); + ny = m_Op_Exc->Curr_dir[n]; + pos[0]=m_Op_Exc->Curr_index[0][n]; + pos[1]=m_Op_Exc->Curr_index[1][n]; + pos[2]=m_Op_Exc->Curr_index[2][n]; + m_Eng->SetCurr(ny,pos, m_Eng->GetCurr(ny,pos) + m_Op_Exc->Curr_amp[n]*exc_curr[exc_pos]); + } + break; + } + } +} diff --git a/openEMS/FDTD/extensions/engine_ext_excitation.h b/openEMS/FDTD/extensions/engine_ext_excitation.h new file mode 100644 index 0000000..aae58a0 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_excitation.h @@ -0,0 +1,40 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#ifndef ENGINE_EXT_EXCITATION_H +#define ENGINE_EXT_EXCITATION_H + +#include "engine_extension.h" +#include "FDTD/engine.h" +#include "FDTD/operator.h" + +class Operator_Ext_Excitation; + +class Engine_Ext_Excitation : public Engine_Extension +{ +public: + Engine_Ext_Excitation(Operator_Ext_Excitation* op_ext); + virtual ~Engine_Ext_Excitation(); + + virtual void Apply2Voltages(); + virtual void Apply2Current(); + +protected: + Operator_Ext_Excitation* m_Op_Exc; +}; + +#endif // ENGINE_EXT_EXCITATION_H diff --git a/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.cpp b/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.cpp new file mode 100644 index 0000000..9aaa1ff --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.cpp @@ -0,0 +1,322 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "engine_ext_lorentzmaterial.h" +#include "operator_ext_lorentzmaterial.h" +#include "FDTD/engine_sse.h" + +Engine_Ext_LorentzMaterial::Engine_Ext_LorentzMaterial(Operator_Ext_LorentzMaterial* op_ext_lorentz) : Engine_Ext_Dispersive(op_ext_lorentz) +{ + m_Op_Ext_Lor = op_ext_lorentz; + m_Order = m_Op_Ext_Lor->GetDispersionOrder(); + int order = m_Op_Ext_Lor->m_Order; + + curr_Lor_ADE = new FDTD_FLOAT**[order]; + volt_Lor_ADE = new FDTD_FLOAT**[order]; + for (int o=0;om_curr_Lor_ADE_On[o]==true) + { + curr_Lor_ADE[o][n] = new FDTD_FLOAT[m_Op_Ext_Lor->m_LM_Count[o]]; + for (unsigned int i=0; im_LM_Count[o]; ++i) + curr_Lor_ADE[o][n][i]=0.0; + } + else + curr_Lor_ADE[o][n] = NULL; + + if (m_Op_Ext_Lor->m_volt_Lor_ADE_On[o]==true) + { + volt_Lor_ADE[o][n] = new FDTD_FLOAT[m_Op_Ext_Lor->m_LM_Count[o]]; + for (unsigned int i=0; im_LM_Count[o]; ++i) + volt_Lor_ADE[o][n][i]=0.0; + } + else + volt_Lor_ADE[o][n] = NULL; + } + } +} + +Engine_Ext_LorentzMaterial::~Engine_Ext_LorentzMaterial() +{ + if (curr_Lor_ADE==NULL && volt_Lor_ADE==NULL) + return; + + for (int o=0;om_Order;++o) + { + for (int n=0; n<3; ++n) + { + delete[] curr_Lor_ADE[o][n]; + delete[] volt_Lor_ADE[o][n]; + } + delete[] curr_Lor_ADE[o]; + delete[] volt_Lor_ADE[o]; + } + delete[] curr_Lor_ADE; + curr_Lor_ADE=NULL; + + delete[] volt_Lor_ADE; + volt_Lor_ADE=NULL; +} + +void Engine_Ext_LorentzMaterial::DoPreVoltageUpdates() +{ + for (int o=0;om_volt_ADE_On[o]==false) continue; + + unsigned int **pos = m_Op_Ext_Lor->m_LM_pos[o]; + + if (m_Op_Ext_Lor->m_volt_Lor_ADE_On[o]) + { + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + volt_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][0][i]*volt_ADE[o][0][i]; + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * (m_Eng->Engine::GetVolt(0,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][0][i]); + + volt_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][1][i]*volt_ADE[o][1][i]; + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * (m_Eng->Engine::GetVolt(1,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][2][i]); + + volt_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][2][i]*volt_ADE[o][2][i]; + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * (m_Eng->Engine::GetVolt(2,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + volt_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][0][i]*volt_ADE[o][0][i]; + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * (eng_sse->Engine_sse::GetVolt(0,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][0][i]); + + volt_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][1][i]*volt_ADE[o][1][i]; + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * (eng_sse->Engine_sse::GetVolt(1,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][1][i]); + + volt_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][2][i]*volt_ADE[o][2][i]; + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * (eng_sse->Engine_sse::GetVolt(2,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][2][i]); + } + break; + } + default: + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + volt_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][0][i]*volt_ADE[o][0][i]; + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * (m_Eng->GetVolt(0,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][0][i]); + + volt_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][1][i]*volt_ADE[o][1][i]; + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * (m_Eng->GetVolt(1,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][1][i]); + + volt_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->v_Lor_ADE[o][2][i]*volt_ADE[o][2][i]; + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * (m_Eng->GetVolt(2,pos[0][i],pos[1][i],pos[2][i])-volt_Lor_ADE[o][2][i]); + } + break; + } + } + else + { + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * m_Eng->Engine::GetVolt(0,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * m_Eng->Engine::GetVolt(1,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * m_Eng->Engine::GetVolt(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * eng_sse->Engine_sse::GetVolt(0,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * eng_sse->Engine_sse::GetVolt(1,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * eng_sse->Engine_sse::GetVolt(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + default: + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + volt_ADE[o][0][i] *= m_Op_Ext_Lor->v_int_ADE[o][0][i]; + volt_ADE[o][0][i] += m_Op_Ext_Lor->v_ext_ADE[o][0][i] * m_Eng->GetVolt(0,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][1][i] *= m_Op_Ext_Lor->v_int_ADE[o][1][i]; + volt_ADE[o][1][i] += m_Op_Ext_Lor->v_ext_ADE[o][1][i] * m_Eng->GetVolt(1,pos[0][i],pos[1][i],pos[2][i]); + + volt_ADE[o][2][i] *= m_Op_Ext_Lor->v_int_ADE[o][2][i]; + volt_ADE[o][2][i] += m_Op_Ext_Lor->v_ext_ADE[o][2][i] * m_Eng->GetVolt(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + } + } +} + +void Engine_Ext_LorentzMaterial::DoPreCurrentUpdates() +{ + for (int o=0;om_curr_ADE_On[o]==false) continue; + + unsigned int **pos = m_Op_Ext_Lor->m_LM_pos[o]; + + if (m_Op_Ext_Lor->m_curr_Lor_ADE_On[o]) + { + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + curr_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][0][i]*curr_ADE[o][0][i]; + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * (m_Eng->Engine::GetCurr(0,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][0][i]); + + curr_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][1][i]*curr_ADE[o][1][i]; + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * (m_Eng->Engine::GetCurr(1,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][1][i]); + + curr_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][2][i]*curr_ADE[o][2][i]; + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * (m_Eng->Engine::GetCurr(2,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + curr_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][0][i]*curr_ADE[o][0][i]; + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * (eng_sse->Engine_sse::GetCurr(0,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][0][i]); + + curr_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][1][i]*curr_ADE[o][1][i]; + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * (eng_sse->Engine_sse::GetCurr(1,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][1][i]); + + curr_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][2][i]*curr_ADE[o][2][i]; + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * (eng_sse->Engine_sse::GetCurr(2,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][2][i]); + } + break; + } + default: + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + curr_Lor_ADE[o][0][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][0][i]*curr_ADE[o][0][i]; + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * (m_Eng->GetCurr(0,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][0][i]); + + curr_Lor_ADE[o][1][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][1][i]*curr_ADE[o][1][i]; + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * (m_Eng->GetCurr(1,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][1][i]); + + curr_Lor_ADE[o][2][i]+=m_Op_Ext_Lor->i_Lor_ADE[o][2][i]*curr_ADE[o][2][i]; + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * (m_Eng->GetCurr(2,pos[0][i],pos[1][i],pos[2][i])-curr_Lor_ADE[o][2][i]); + } + break; + } + } + else + { + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * m_Eng->Engine::GetCurr(0,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * m_Eng->Engine::GetCurr(1,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * m_Eng->Engine::GetCurr(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*)m_Eng; + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * eng_sse->Engine_sse::GetCurr(0,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * eng_sse->Engine_sse::GetCurr(1,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * eng_sse->Engine_sse::GetCurr(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + default: + for (unsigned int i=0; im_LM_Count.at(o); ++i) + { + curr_ADE[o][0][i] *= m_Op_Ext_Lor->i_int_ADE[o][0][i]; + curr_ADE[o][0][i] += m_Op_Ext_Lor->i_ext_ADE[o][0][i] * m_Eng->GetCurr(0,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][1][i] *= m_Op_Ext_Lor->i_int_ADE[o][1][i]; + curr_ADE[o][1][i] += m_Op_Ext_Lor->i_ext_ADE[o][1][i] * m_Eng->GetCurr(1,pos[0][i],pos[1][i],pos[2][i]); + + curr_ADE[o][2][i] *= m_Op_Ext_Lor->i_int_ADE[o][2][i]; + curr_ADE[o][2][i] += m_Op_Ext_Lor->i_ext_ADE[o][2][i] * m_Eng->GetCurr(2,pos[0][i],pos[1][i],pos[2][i]); + } + break; + } + } + } +} + diff --git a/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.h b/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.h new file mode 100644 index 0000000..804f49a --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_lorentzmaterial.h @@ -0,0 +1,48 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef ENGINE_EXT_LORENTZMATERIAL_H +#define ENGINE_EXT_LORENTZMATERIAL_H + +#include "engine_ext_dispersive.h" + +class Operator_Ext_LorentzMaterial; + +class Engine_Ext_LorentzMaterial : public Engine_Ext_Dispersive +{ +public: + Engine_Ext_LorentzMaterial(Operator_Ext_LorentzMaterial* op_ext_lorentz); + virtual ~Engine_Ext_LorentzMaterial(); + + virtual void DoPreVoltageUpdates(); + + virtual void DoPreCurrentUpdates(); + +protected: + Operator_Ext_LorentzMaterial* m_Op_Ext_Lor; + + //! ADE Lorentz voltages + // Array setup: volt_Lor_ADE[N_order][direction][mesh_pos] + FDTD_FLOAT ***volt_Lor_ADE; + + //! ADE Lorentz currents + // Array setup: curr_Lor_ADE[N_order][direction][mesh_pos] + FDTD_FLOAT ***curr_Lor_ADE; + +}; + +#endif // ENGINE_EXT_LORENTZMATERIAL_H diff --git a/openEMS/FDTD/extensions/engine_ext_mur_abc.cpp b/openEMS/FDTD/extensions/engine_ext_mur_abc.cpp new file mode 100644 index 0000000..d9f1b17 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_mur_abc.cpp @@ -0,0 +1,263 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "engine_ext_mur_abc.h" +#include "operator_ext_mur_abc.h" +#include "FDTD/engine.h" +#include "FDTD/engine_sse.h" +#include "tools/array_ops.h" +#include "tools/useful.h" +#include "operator_ext_excitation.h" + +Engine_Ext_Mur_ABC::Engine_Ext_Mur_ABC(Operator_Ext_Mur_ABC* op_ext) : Engine_Extension(op_ext) +{ + m_Op_mur = op_ext; + m_numLines[0] = m_Op_mur->m_numLines[0]; + m_numLines[1] = m_Op_mur->m_numLines[1]; + m_ny = m_Op_mur->m_ny; + m_nyP = m_Op_mur->m_nyP; + m_nyPP = m_Op_mur->m_nyPP; + m_LineNr = m_Op_mur->m_LineNr; + m_LineNr_Shift = m_Op_mur->m_LineNr_Shift; + + m_Mur_Coeff_nyP = m_Op_mur->m_Mur_Coeff_nyP; + m_Mur_Coeff_nyPP = m_Op_mur->m_Mur_Coeff_nyPP; + + m_volt_nyP = Create2DArray(m_numLines); + m_volt_nyPP = Create2DArray(m_numLines); + + //find if some excitation is on this mur-abc and find the max length of this excite, so that the abc can start after the excitation is done... + int maxDelay=-1; + Operator_Ext_Excitation* Exc_ext = m_Op_mur->m_Op->GetExcitationExtension(); + for (unsigned int n=0; nGetVoltCount(); ++n) + { + if ( ((Exc_ext->Volt_dir[n]==m_nyP) || (Exc_ext->Volt_dir[n]==m_nyPP)) && (Exc_ext->Volt_index[m_ny][n]==m_LineNr) ) + { + if ((int)Exc_ext->Volt_delay[n]>maxDelay) + maxDelay = (int)Exc_ext->Volt_delay[n]; + } + } + m_start_TS = 0; + if (maxDelay>=0) + { + m_start_TS = maxDelay + m_Op_mur->m_Op->GetExcitationSignal()->GetLength() + 10; //give it some extra timesteps, for the excitation to travel at least one cell away + cerr << "Engine_Ext_Mur_ABC::Engine_Ext_Mur_ABC: Warning: Excitation inside the Mur-ABC #" << m_ny << "-" << (int)(m_LineNr>0) << " found!!!! Mur-ABC will be switched on after excitation is done at " << m_start_TS << " timesteps!!! " << endl; + } + + SetNumberOfThreads(1); +} + +Engine_Ext_Mur_ABC::~Engine_Ext_Mur_ABC() +{ + Delete2DArray(m_volt_nyP,m_numLines); + m_volt_nyP = NULL; + Delete2DArray(m_volt_nyPP,m_numLines); + m_volt_nyPP = NULL; +} + + +void Engine_Ext_Mur_ABC::SetNumberOfThreads(int nrThread) +{ + Engine_Extension::SetNumberOfThreads(nrThread); + + m_numX = AssignJobs2Threads(m_numLines[0],m_NrThreads,false); + m_start.resize(m_NrThreads,0); + m_start.at(0)=0; + for (size_t n=1; n=m_NrThreads) + return; + unsigned int pos[] = {0,0,0}; + unsigned int pos_shift[] = {0,0,0}; + pos[m_ny] = m_LineNr; + pos_shift[m_ny] = m_LineNr_Shift; + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineXEngine::GetVolt(m_nyP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->Engine::GetVolt(m_nyP,pos); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] = m_Eng->Engine::GetVolt(m_nyPP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->Engine::GetVolt(m_nyPP,pos); + } + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineXEngine_sse::GetVolt(m_nyP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * eng_sse->Engine_sse::GetVolt(m_nyP,pos); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] = eng_sse->Engine_sse::GetVolt(m_nyPP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * eng_sse->Engine_sse::GetVolt(m_nyPP,pos); + } + } + break; + } + default: + for (unsigned int lineX=0; lineXGetVolt(m_nyP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->GetVolt(m_nyP,pos); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] = m_Eng->GetVolt(m_nyPP,pos_shift) - m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->GetVolt(m_nyPP,pos); + } + } + break; + } +} + +void Engine_Ext_Mur_ABC::DoPostVoltageUpdates(int threadID) +{ + if (IsActive()==false) return; + if (m_Eng==NULL) return; + if (threadID>=m_NrThreads) + return; + unsigned int pos[] = {0,0,0}; + unsigned int pos_shift[] = {0,0,0}; + pos[m_ny] = m_LineNr; + pos_shift[m_ny] = m_LineNr_Shift; + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineXm_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->Engine::GetVolt(m_nyP,pos_shift); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] += m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->Engine::GetVolt(m_nyPP,pos_shift); + } + } + break; + } + + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineXm_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * eng_sse->Engine_sse::GetVolt(m_nyP,pos_shift); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] += m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * eng_sse->Engine_sse::GetVolt(m_nyPP,pos_shift); + } + } + break; + } + + default: + for (unsigned int lineX=0; lineXm_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->GetVolt(m_nyP,pos_shift); + m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]] += m_Op_mur->m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] * m_Eng->GetVolt(m_nyPP,pos_shift); + } + } + break; + } +} + +void Engine_Ext_Mur_ABC::Apply2Voltages(int threadID) +{ + if (IsActive()==false) return; + if (threadID>=m_NrThreads) + return; + if (m_Eng==NULL) return; + unsigned int pos[] = {0,0,0}; + pos[m_ny] = m_LineNr; + + //switch for different engine types to access faster inline engine functions + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineXEngine::SetVolt(m_nyP,pos, m_volt_nyP[pos[m_nyP]][pos[m_nyPP]]); + m_Eng->Engine::SetVolt(m_nyPP,pos, m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]]); + } + } + break; + } + + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineXEngine_sse::SetVolt(m_nyP,pos, m_volt_nyP[pos[m_nyP]][pos[m_nyPP]]); + eng_sse->Engine_sse::SetVolt(m_nyPP,pos, m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]]); + } + } + break; + } + + default: + for (unsigned int lineX=0; lineXSetVolt(m_nyP,pos, m_volt_nyP[pos[m_nyP]][pos[m_nyPP]]); + m_Eng->SetVolt(m_nyPP,pos, m_volt_nyPP[pos[m_nyP]][pos[m_nyPP]]); + } + } + break; + } + +} diff --git a/openEMS/FDTD/extensions/engine_ext_mur_abc.h b/openEMS/FDTD/extensions/engine_ext_mur_abc.h new file mode 100644 index 0000000..aadb2fd --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_mur_abc.h @@ -0,0 +1,63 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef ENGINE_EXT_MUR_ABC_H +#define ENGINE_EXT_MUR_ABC_H + +#include "engine_extension.h" +#include "FDTD/engine.h" +#include "FDTD/operator.h" + +class Operator_Ext_Mur_ABC; + +class Engine_Ext_Mur_ABC : public Engine_Extension +{ +public: + Engine_Ext_Mur_ABC(Operator_Ext_Mur_ABC* op_ext); + virtual ~Engine_Ext_Mur_ABC(); + + virtual void SetNumberOfThreads(int nrThread); + + virtual void DoPreVoltageUpdates() {Engine_Ext_Mur_ABC::DoPreVoltageUpdates(0);} + virtual void DoPreVoltageUpdates(int threadID); + virtual void DoPostVoltageUpdates() {Engine_Ext_Mur_ABC::DoPostVoltageUpdates(0);} + virtual void DoPostVoltageUpdates(int threadID); + virtual void Apply2Voltages() {Engine_Ext_Mur_ABC::Apply2Voltages(0);} + virtual void Apply2Voltages(int threadID); + +protected: + Operator_Ext_Mur_ABC* m_Op_mur; + + inline bool IsActive() {if (m_Eng->GetNumberOfTimesteps() m_start; + vector m_numX; + + FDTD_FLOAT** m_Mur_Coeff_nyP; + FDTD_FLOAT** m_Mur_Coeff_nyPP; + FDTD_FLOAT** m_volt_nyP; //n+1 direction + FDTD_FLOAT** m_volt_nyPP; //n+2 direction +}; + +#endif // ENGINE_EXT_MUR_ABC_H diff --git a/openEMS/FDTD/extensions/engine_ext_steadystate.cpp b/openEMS/FDTD/extensions/engine_ext_steadystate.cpp new file mode 100644 index 0000000..9e5d0ce --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_steadystate.cpp @@ -0,0 +1,112 @@ +/* +* Copyright (C) 2015 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 . +*/ + +#include "engine_ext_steadystate.h" +#include "operator_ext_steadystate.h" +#include "FDTD/engine_sse.h" +#include "FDTD/engine_interface_fdtd.h" + +Engine_Ext_SteadyState::Engine_Ext_SteadyState(Operator_Ext_SteadyState* op_ext): Engine_Extension(op_ext) +{ + m_Op_SS = op_ext; + m_Priority = ENG_EXT_PRIO_STEADYSTATE; + + for (size_t n=0;nm_E_probe_dir.size();++n) + { + double* rec = new double[m_Op_SS->m_TS_period*2]; + m_E_records.push_back(rec); + } + m_last_max_diff = 1; + last_total_energy = 0; + m_Eng_Interface = NULL; +} + +Engine_Ext_SteadyState::~Engine_Ext_SteadyState() +{ + for (size_t n=0;nm_TS_period; + unsigned int TS = m_Eng->GetNumberOfTimesteps(); + unsigned int rel_pos = m_Eng->GetNumberOfTimesteps()%(2*p); + for (size_t n=0;nGetVolt(m_Op_SS->m_E_probe_dir.at(n), m_Op_SS->m_E_probe_pos[0].at(n), m_Op_SS->m_E_probe_pos[1].at(n), m_Op_SS->m_E_probe_pos[2].at(n)); + if ((TS%(m_Op_SS->m_TS_period)==0) && (TS>=2*p)) + { + bool no_valid = true; + m_last_max_diff = 0; + double curr_total_energy = m_Eng_Interface->CalcFastEnergy(); + if (last_total_energy>0) + { + m_last_max_diff = abs(curr_total_energy-last_total_energy)/last_total_energy; + no_valid = false; + } + //cerr << curr_total_energy << "/" << last_total_energy << "=" << abs(curr_total_energy-last_total_energy)/last_total_energy << endl; + last_total_energy = curr_total_energy; + unsigned int old_pos = 0; + unsigned int new_pos = p; + if (rel_pos<=p) + { + new_pos = 0; + old_pos = p; + } + //cerr << TS << "/" << rel_pos << ": one period complete, new_pos" << new_pos << " old pos: " << old_pos << endl; + double *curr_pow = new double[m_E_records.size()]; + double *diff_pow = new double[m_E_records.size()]; + double max_pow = 0; + for (size_t n=0;nmax_pow*1e-2) + { + m_last_max_diff = max(m_last_max_diff, diff_pow[n]/curr_pow[n]); + //cerr << m_last_max_diff << endl; + no_valid = false; + } + } + if ((no_valid) || (m_last_max_diff>1)) + m_last_max_diff = 1; + delete[] curr_pow; curr_pow = NULL; + //cerr << m_last_max_diff << endl; + } +} + +void Engine_Ext_SteadyState::Apply2Current() +{ + +} diff --git a/openEMS/FDTD/extensions/engine_ext_steadystate.h b/openEMS/FDTD/extensions/engine_ext_steadystate.h new file mode 100644 index 0000000..b66596e --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_steadystate.h @@ -0,0 +1,51 @@ +/* +* Copyright (C) 2015 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 . +*/ + +#ifndef ENGINE_EXT_STEADYSTATE_H +#define ENGINE_EXT_STEADYSTATE_H + +#include "engine_extension.h" +#include "FDTD/engine.h" +#include "FDTD/operator.h" + +class Operator_Ext_SteadyState; +class Engine_Interface_FDTD; + +class Engine_Ext_SteadyState : public Engine_Extension +{ +public: + Engine_Ext_SteadyState(Operator_Ext_SteadyState* op_ext); + virtual ~Engine_Ext_SteadyState(); + + virtual void Apply2Voltages(); + virtual void Apply2Current(); + + void SetEngineInterface(Engine_Interface_FDTD* eng_if) {m_Eng_Interface=eng_if;} + double GetLastDiff() {return m_last_max_diff;} + +protected: + Operator_Ext_SteadyState* m_Op_SS; + double m_last_max_diff; + vector m_E_records; + vector m_H_records; + + double last_total_energy; + Engine_Interface_FDTD* m_Eng_Interface; +}; + + +#endif // ENGINE_EXT_STEADYSTATE_H diff --git a/openEMS/FDTD/extensions/engine_ext_tfsf.cpp b/openEMS/FDTD/extensions/engine_ext_tfsf.cpp new file mode 100644 index 0000000..9942656 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_tfsf.cpp @@ -0,0 +1,215 @@ +/* +* Copyright (C) 2012 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 . +*/ + +#include "engine_ext_tfsf.h" +#include "operator_ext_tfsf.h" +#include "FDTD/engine_sse.h" + +Engine_Ext_TFSF::Engine_Ext_TFSF(Operator_Ext_TFSF* op_ext) : Engine_Extension(op_ext) +{ + m_Op_TFSF = op_ext; + m_Priority = ENG_EXT_PRIO_TFSF; + + m_DelayLookup = new unsigned int[m_Op_TFSF->m_maxDelay+1]; +} + +Engine_Ext_TFSF::~Engine_Ext_TFSF() +{ + delete[] m_DelayLookup; + m_DelayLookup = NULL; +} + +void Engine_Ext_TFSF::DoPostVoltageUpdates() +{ + unsigned int numTS = m_Eng->GetNumberOfTimesteps(); + unsigned int length = m_Op_TFSF->m_Exc->GetLength(); + + int p = int(m_Op_TFSF->m_Exc->GetSignalPeriod()/m_Op_TFSF->m_Exc->GetTimestep()); + + for (unsigned int n=0;n<=m_Op_TFSF->m_maxDelay;++n) + { + if ( numTS < n ) + m_DelayLookup[n]=0; + else if ((numTS-n >= length) && (p==0)) + m_DelayLookup[n]=0; + else + m_DelayLookup[n] = numTS - n; + if (p>0) + m_DelayLookup[n] = (m_DelayLookup[n] % p); + } + + //get the current signal since an H-field is added ... + FDTD_FLOAT* signal = m_Op_TFSF->m_Exc->GetCurrentSignal(); + + int nP,nPP; + unsigned int ui_pos; + unsigned int pos[3]; + for (int n=0;n<3;++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + + // lower plane + pos[nP] = m_Op_TFSF->m_Start[nP]; + ui_pos = 0; + if (m_Op_TFSF->m_ActiveDir[n][0]) + { + + for (unsigned int i=0;im_numLines[nP];++i) + { + pos[nPP] = m_Op_TFSF->m_Start[nPP]; + for (unsigned int j=0;jm_numLines[nPP];++j) + { + // current updates + pos[n] = m_Op_TFSF->m_Start[n]; + + m_Eng->SetVolt(nP,pos, m_Eng->GetVolt(nP,pos) + + (1.0-m_Op_TFSF->m_VoltDelayDelta[n][0][0][ui_pos])*m_Op_TFSF->m_VoltAmp[n][0][0][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_VoltDelay[n][0][0][ui_pos]]] + + m_Op_TFSF->m_VoltDelayDelta[n][0][0][ui_pos] *m_Op_TFSF->m_VoltAmp[n][0][0][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_VoltDelay[n][0][0][ui_pos]]] ); + + m_Eng->SetVolt(nPP,pos, m_Eng->GetVolt(nPP,pos) + + (1.0-m_Op_TFSF->m_VoltDelayDelta[n][0][1][ui_pos])*m_Op_TFSF->m_VoltAmp[n][0][1][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_VoltDelay[n][0][1][ui_pos]]] + + m_Op_TFSF->m_VoltDelayDelta[n][0][1][ui_pos] *m_Op_TFSF->m_VoltAmp[n][0][1][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_VoltDelay[n][0][1][ui_pos]]] ); + + ++pos[nPP]; + ++ui_pos; + } + ++pos[nP]; + } + } + + // upper plane + pos[nP] = m_Op_TFSF->m_Start[nP]; + ui_pos = 0; + if (m_Op_TFSF->m_ActiveDir[n][1]) + { + + for (unsigned int i=0;im_numLines[nP];++i) + { + pos[nPP] = m_Op_TFSF->m_Start[nPP]; + for (unsigned int j=0;jm_numLines[nPP];++j) + { + // current updates + pos[n] = m_Op_TFSF->m_Stop[n]; + + m_Eng->SetVolt(nP,pos, m_Eng->GetVolt(nP,pos) + + (1.0-m_Op_TFSF->m_VoltDelayDelta[n][1][0][ui_pos])*m_Op_TFSF->m_VoltAmp[n][1][0][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_VoltDelay[n][1][0][ui_pos]]] + + m_Op_TFSF->m_VoltDelayDelta[n][1][0][ui_pos] *m_Op_TFSF->m_VoltAmp[n][1][0][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_VoltDelay[n][1][0][ui_pos]]] ); + + m_Eng->SetVolt(nPP,pos, m_Eng->GetVolt(nPP,pos) + + (1.0-m_Op_TFSF->m_VoltDelayDelta[n][1][1][ui_pos])*m_Op_TFSF->m_VoltAmp[n][1][1][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_VoltDelay[n][1][1][ui_pos]]] + + m_Op_TFSF->m_VoltDelayDelta[n][1][1][ui_pos] *m_Op_TFSF->m_VoltAmp[n][1][1][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_VoltDelay[n][1][1][ui_pos]]] ); + + ++pos[nPP]; + ++ui_pos; + } + ++pos[nP]; + } + } + } +} + +void Engine_Ext_TFSF::DoPostCurrentUpdates() +{ + unsigned int numTS = m_Eng->GetNumberOfTimesteps(); + unsigned int length = m_Op_TFSF->m_Exc->GetLength(); + + int p = int(m_Op_TFSF->m_Exc->GetSignalPeriod()/m_Op_TFSF->m_Exc->GetTimestep()); + + for (unsigned int n=0;nm_maxDelay;++n) + { + if ( numTS < n ) + m_DelayLookup[n]=0; + else if ((numTS-n >= length) && (p==0)) + m_DelayLookup[n]=0; + else + m_DelayLookup[n] = numTS - n; + if (p>0) + m_DelayLookup[n] = (m_DelayLookup[n] % p); + } + + //get the current signal since an E-field is added ... + FDTD_FLOAT* signal = m_Op_TFSF->m_Exc->GetVoltageSignal(); + + int nP,nPP; + unsigned int ui_pos; + unsigned int pos[3]; + for (int n=0;n<3;++n) + { + if (!m_Op_TFSF->m_ActiveDir[n][0] && !m_Op_TFSF->m_ActiveDir[n][1]) + continue; + + nP = (n+1)%3; + nPP = (n+2)%3; + + // lower plane + pos[nP] = m_Op_TFSF->m_Start[nP]; + ui_pos = 0; + if (m_Op_TFSF->m_ActiveDir[n][0]) + { + for (unsigned int i=0;im_numLines[nP];++i) + { + pos[nPP] = m_Op_TFSF->m_Start[nPP]; + for (unsigned int j=0;jm_numLines[nPP];++j) + { + // current updates + pos[n] = m_Op_TFSF->m_Start[n]-1; + + m_Eng->SetCurr(nP,pos, m_Eng->GetCurr(nP,pos) + + (1.0-m_Op_TFSF->m_CurrDelayDelta[n][0][0][ui_pos])*m_Op_TFSF->m_CurrAmp[n][0][0][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_CurrDelay[n][0][0][ui_pos]]] + + m_Op_TFSF->m_CurrDelayDelta[n][0][0][ui_pos] *m_Op_TFSF->m_CurrAmp[n][0][0][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_CurrDelay[n][0][0][ui_pos]]] ); + + m_Eng->SetCurr(nPP,pos, m_Eng->GetCurr(nPP,pos) + + (1.0-m_Op_TFSF->m_CurrDelayDelta[n][0][1][ui_pos])*m_Op_TFSF->m_CurrAmp[n][0][1][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_CurrDelay[n][0][1][ui_pos]]] + + m_Op_TFSF->m_CurrDelayDelta[n][0][1][ui_pos] *m_Op_TFSF->m_CurrAmp[n][0][1][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_CurrDelay[n][0][1][ui_pos]]] ); + + ++pos[nPP]; + ++ui_pos; + } + ++pos[nP]; + } + } + + // upper plane + pos[nP] = m_Op_TFSF->m_Start[nP]; + ui_pos = 0; + if (m_Op_TFSF->m_ActiveDir[n][1]) + { + for (unsigned int i=0;im_numLines[nP];++i) + { + pos[nPP] = m_Op_TFSF->m_Start[nPP]; + for (unsigned int j=0;jm_numLines[nPP];++j) + { + // current updates + pos[n] = m_Op_TFSF->m_Stop[n]; + + m_Eng->SetCurr(nP,pos, m_Eng->GetCurr(nP,pos) + + (1.0-m_Op_TFSF->m_CurrDelayDelta[n][1][0][ui_pos])*m_Op_TFSF->m_CurrAmp[n][1][0][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_CurrDelay[n][1][0][ui_pos]]] + + m_Op_TFSF->m_CurrDelayDelta[n][1][0][ui_pos] *m_Op_TFSF->m_CurrAmp[n][1][0][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_CurrDelay[n][1][0][ui_pos]]] ); + + m_Eng->SetCurr(nPP,pos, m_Eng->GetCurr(nPP,pos) + + (1.0-m_Op_TFSF->m_CurrDelayDelta[n][1][1][ui_pos])*m_Op_TFSF->m_CurrAmp[n][1][1][ui_pos]*signal[m_DelayLookup[ m_Op_TFSF->m_CurrDelay[n][1][1][ui_pos]]] + + m_Op_TFSF->m_CurrDelayDelta[n][1][1][ui_pos] *m_Op_TFSF->m_CurrAmp[n][1][1][ui_pos]*signal[m_DelayLookup[1+m_Op_TFSF->m_CurrDelay[n][1][1][ui_pos]]] ); + + ++pos[nPP]; + ++ui_pos; + } + ++pos[nP]; + } + } + } +} diff --git a/openEMS/FDTD/extensions/engine_ext_tfsf.h b/openEMS/FDTD/extensions/engine_ext_tfsf.h new file mode 100644 index 0000000..d4e662a --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_tfsf.h @@ -0,0 +1,40 @@ +/* +* Copyright (C) 2012 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 . +*/ + +#ifndef ENGINE_EXT_TFSF_H +#define ENGINE_EXT_TFSF_H + +#include "engine_extension.h" + +class Operator_Ext_TFSF; + +class Engine_Ext_TFSF : public Engine_Extension +{ +public: + Engine_Ext_TFSF(Operator_Ext_TFSF* op_ext); + virtual ~Engine_Ext_TFSF(); + + virtual void DoPostVoltageUpdates(); + virtual void DoPostCurrentUpdates(); + +protected: + Operator_Ext_TFSF* m_Op_TFSF; + + unsigned int* m_DelayLookup; +}; + +#endif // ENGINE_EXT_TFSF_H diff --git a/openEMS/FDTD/extensions/engine_ext_upml.cpp b/openEMS/FDTD/extensions/engine_ext_upml.cpp new file mode 100644 index 0000000..8cb365f --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_upml.cpp @@ -0,0 +1,493 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "engine_ext_upml.h" +#include "operator_ext_upml.h" +#include "FDTD/engine.h" +#include "FDTD/engine_sse.h" +#include "tools/array_ops.h" +#include "tools/useful.h" + +Engine_Ext_UPML::Engine_Ext_UPML(Operator_Ext_UPML* op_ext) : Engine_Extension(op_ext) +{ + m_Op_UPML = op_ext; + + //this ABC extension should be executed first! + m_Priority = ENG_EXT_PRIO_UPML; + + volt_flux = Create_N_3DArray(m_Op_UPML->m_numLines); + curr_flux = Create_N_3DArray(m_Op_UPML->m_numLines); + + SetNumberOfThreads(1); +} + +Engine_Ext_UPML::~Engine_Ext_UPML() +{ + Delete_N_3DArray(volt_flux,m_Op_UPML->m_numLines); + volt_flux=NULL; + Delete_N_3DArray(curr_flux,m_Op_UPML->m_numLines); + curr_flux=NULL; +} + +void Engine_Ext_UPML::SetNumberOfThreads(int nrThread) +{ + Engine_Extension::SetNumberOfThreads(nrThread); + + m_numX = AssignJobs2Threads(m_Op_UPML->m_numLines[0],m_NrThreads,false); + m_start.resize(m_NrThreads,0); + m_start.at(0)=0; + for (size_t n=1; n=m_NrThreads) + return; + + unsigned int pos[3]; + unsigned int loc_pos[3]; + FDTD_FLOAT f_help; + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = m_Op_UPML->vv[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::GetVolt(0,pos) + - m_Op_UPML->vvfo[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->Engine::SetVolt(0,pos, volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->vv[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::GetVolt(1,pos) + - m_Op_UPML->vvfo[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->Engine::SetVolt(1,pos, volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->vv[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::GetVolt(2,pos) + - m_Op_UPML->vvfo[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->Engine::SetVolt(2,pos, volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + } + } + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = m_Op_UPML->vv[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::GetVolt(0,pos) + - m_Op_UPML->vvfo[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + eng_sse->Engine_sse::SetVolt(0,pos, volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->vv[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::GetVolt(1,pos) + - m_Op_UPML->vvfo[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + eng_sse->Engine_sse::SetVolt(1,pos, volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->vv[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::GetVolt(2,pos) + - m_Op_UPML->vvfo[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + eng_sse->Engine_sse::SetVolt(2,pos, volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + } + } + } + break; + } + default: + { + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = m_Op_UPML->vv[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetVolt(0,pos) + - m_Op_UPML->vvfo[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->SetVolt(0,pos, volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->vv[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetVolt(1,pos) + - m_Op_UPML->vvfo[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->SetVolt(1,pos, volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->vv[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetVolt(2,pos) + - m_Op_UPML->vvfo[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->SetVolt(2,pos, volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + } + } + } + break; + } + } + +} + +void Engine_Ext_UPML::DoPostVoltageUpdates(int threadID) +{ + if (m_Eng==NULL) + return; + if (threadID>=m_NrThreads) + return; + + unsigned int pos[3]; + unsigned int loc_pos[3]; + FDTD_FLOAT f_help; + + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetVolt(0,pos); + m_Eng->Engine::SetVolt(0,pos, f_help + m_Op_UPML->vvfn[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetVolt(1,pos); + m_Eng->Engine::SetVolt(1,pos, f_help + m_Op_UPML->vvfn[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetVolt(2,pos); + m_Eng->Engine::SetVolt(2,pos, f_help + m_Op_UPML->vvfn[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + } + } + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetVolt(0,pos); + eng_sse->Engine_sse::SetVolt(0,pos, f_help + m_Op_UPML->vvfn[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetVolt(1,pos); + eng_sse->Engine_sse::SetVolt(1,pos, f_help + m_Op_UPML->vvfn[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetVolt(2,pos); + eng_sse->Engine_sse::SetVolt(2,pos, f_help + m_Op_UPML->vvfn[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + } + } + } + break; + } + default: + { + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetVolt(0,pos); + m_Eng->SetVolt(0,pos, f_help + m_Op_UPML->vvfn[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetVolt(1,pos); + m_Eng->SetVolt(1,pos, f_help + m_Op_UPML->vvfn[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetVolt(2,pos); + m_Eng->SetVolt(2,pos, f_help + m_Op_UPML->vvfn[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * volt_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + } + } + } + break; + } + } + +} + +void Engine_Ext_UPML::DoPreCurrentUpdates(int threadID) +{ + if (m_Eng==NULL) + return; + if (threadID>=m_NrThreads) + return; + + unsigned int pos[3]; + unsigned int loc_pos[3]; + FDTD_FLOAT f_help; + + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = m_Op_UPML->ii[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::GetCurr(0,pos) + - m_Op_UPML->iifo[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->Engine::SetCurr(0,pos, curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->ii[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::GetCurr(1,pos) + - m_Op_UPML->iifo[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->Engine::SetCurr(1,pos, curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->ii[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->Engine::GetCurr(2,pos) + - m_Op_UPML->iifo[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->Engine::SetCurr(2,pos, curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + } + } + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = m_Op_UPML->ii[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::GetCurr(0,pos) + - m_Op_UPML->iifo[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + eng_sse->Engine_sse::SetCurr(0,pos, curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->ii[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::GetCurr(1,pos) + - m_Op_UPML->iifo[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + eng_sse->Engine_sse::SetCurr(1,pos, curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->ii[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * eng_sse->Engine_sse::GetCurr(2,pos) + - m_Op_UPML->iifo[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + eng_sse->Engine_sse::SetCurr(2,pos, curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + } + } + } + break; + } + default: + { + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = m_Op_UPML->ii[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetCurr(0,pos) + - m_Op_UPML->iifo[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->SetCurr(0,pos, curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->ii[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetCurr(1,pos) + - m_Op_UPML->iifo[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->SetCurr(1,pos, curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + + f_help = m_Op_UPML->ii[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * m_Eng->GetCurr(2,pos) + - m_Op_UPML->iifo[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + m_Eng->SetCurr(2,pos, curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = f_help; + } + } + } + break; + } + } +} + +void Engine_Ext_UPML::DoPostCurrentUpdates(int threadID) +{ + if (m_Eng==NULL) + return; + if (threadID>=m_NrThreads) + return; + + unsigned int pos[3]; + unsigned int loc_pos[3]; + FDTD_FLOAT f_help; + + switch (m_Eng->GetType()) + { + case Engine::BASIC: + { + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetCurr(0,pos); + m_Eng->Engine::SetCurr(0,pos, f_help + m_Op_UPML->iifn[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetCurr(1,pos); + m_Eng->Engine::SetCurr(1,pos, f_help + m_Op_UPML->iifn[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->Engine::GetCurr(2,pos); + m_Eng->Engine::SetCurr(2,pos, f_help + m_Op_UPML->iifn[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + } + } + } + break; + } + case Engine::SSE: + { + Engine_sse* eng_sse = (Engine_sse*) m_Eng; + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetCurr(0,pos); + eng_sse->Engine_sse::SetCurr(0,pos, f_help + m_Op_UPML->iifn[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetCurr(1,pos); + eng_sse->Engine_sse::SetCurr(1,pos, f_help + m_Op_UPML->iifn[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = eng_sse->Engine_sse::GetCurr(2,pos); + eng_sse->Engine_sse::SetCurr(2,pos, f_help + m_Op_UPML->iifn[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + } + } + } + break; + } + default: + { + for (unsigned int lineX=0; lineXm_StartPos[0]; + for (loc_pos[1]=0; loc_pos[1]m_numLines[1]; ++loc_pos[1]) + { + pos[1] = loc_pos[1] + m_Op_UPML->m_StartPos[1]; + for (loc_pos[2]=0; loc_pos[2]m_numLines[2]; ++loc_pos[2]) + { + pos[2] = loc_pos[2] + m_Op_UPML->m_StartPos[2]; + + f_help = curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetCurr(0,pos); + m_Eng->SetCurr(0,pos, f_help + m_Op_UPML->iifn[0][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[0][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetCurr(1,pos); + m_Eng->SetCurr(1,pos, f_help + m_Op_UPML->iifn[1][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[1][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + + f_help = curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]; + curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] = m_Eng->GetCurr(2,pos); + m_Eng->SetCurr(2,pos, f_help + m_Op_UPML->iifn[2][loc_pos[0]][loc_pos[1]][loc_pos[2]] * curr_flux[2][loc_pos[0]][loc_pos[1]][loc_pos[2]]); + } + } + } + break; + } + } +} diff --git a/openEMS/FDTD/extensions/engine_ext_upml.h b/openEMS/FDTD/extensions/engine_ext_upml.h new file mode 100644 index 0000000..283c886 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_ext_upml.h @@ -0,0 +1,55 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef ENGINE_EXT_UPML_H +#define ENGINE_EXT_UPML_H + +#include "engine_extension.h" +#include "FDTD/engine.h" +#include "FDTD/operator.h" + +class Operator_Ext_UPML; + +class Engine_Ext_UPML : public Engine_Extension +{ +public: + Engine_Ext_UPML(Operator_Ext_UPML* op_ext); + virtual ~Engine_Ext_UPML(); + + virtual void SetNumberOfThreads(int nrThread); + + virtual void DoPreVoltageUpdates() {Engine_Ext_UPML::DoPreVoltageUpdates(0);}; + virtual void DoPreVoltageUpdates(int threadID); + virtual void DoPostVoltageUpdates() {Engine_Ext_UPML::DoPostVoltageUpdates(0);}; + virtual void DoPostVoltageUpdates(int threadID); + + virtual void DoPreCurrentUpdates() {Engine_Ext_UPML::DoPreCurrentUpdates(0);}; + virtual void DoPreCurrentUpdates(int threadID); + virtual void DoPostCurrentUpdates() {Engine_Ext_UPML::DoPostCurrentUpdates(0);}; + virtual void DoPostCurrentUpdates(int threadID); + +protected: + Operator_Ext_UPML* m_Op_UPML; + + vector m_start; + vector m_numX; + + FDTD_FLOAT**** volt_flux; + FDTD_FLOAT**** curr_flux; +}; + +#endif // ENGINE_EXT_UPML_H diff --git a/openEMS/FDTD/extensions/engine_extension.cpp b/openEMS/FDTD/extensions/engine_extension.cpp new file mode 100644 index 0000000..6f688a3 --- /dev/null +++ b/openEMS/FDTD/extensions/engine_extension.cpp @@ -0,0 +1,95 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "engine_extension.h" +#include "operator_extension.h" + +#include "FDTD/engine.h" + +Engine_Extension::Engine_Extension(Operator_Extension* op_ext) +{ + m_Op_ext = op_ext; + m_Eng = NULL; + m_Priority = ENG_EXT_PRIO_DEFAULT; + m_NrThreads = 1; +} + +Engine_Extension::~Engine_Extension() +{ +} + +void Engine_Extension::SetNumberOfThreads(int nrThread) +{ + if (nrThread<1) + return; + m_NrThreads=nrThread; +} + +string Engine_Extension::GetExtensionName() const +{ + if (m_Op_ext) + return m_Op_ext->GetExtensionName(); + else + return "Unknown Extension"; +} + +void Engine_Extension::DoPreVoltageUpdates(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + DoPreVoltageUpdates(); +} + +void Engine_Extension::DoPostVoltageUpdates(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + DoPostVoltageUpdates(); +} + +void Engine_Extension::Apply2Voltages(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + Apply2Voltages(); +} + +void Engine_Extension::DoPreCurrentUpdates(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + DoPreCurrentUpdates(); +} + +void Engine_Extension::DoPostCurrentUpdates(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + DoPostCurrentUpdates(); +} + +void Engine_Extension::Apply2Current(int threadID) +{ + //if this method gets called the derived extension obviously doesn't support multithrading, calling non-MT method... + if (threadID==0) + Apply2Current(); +} + +bool Engine_Extension::operator< (const Engine_Extension& other) +{ + return (GetPriority(). +*/ + +#ifndef ENGINE_EXTENSION_H +#define ENGINE_EXTENSION_H + +#define ENG_EXT_PRIO_DEFAULT 0 //default engine extension priority + +// priority definitions for some important extensions +#define ENG_EXT_PRIO_STEADYSTATE +2e6 //steady state extension priority +#define ENG_EXT_PRIO_UPML +1e6 //unaxial pml extension priority +#define ENG_EXT_PRIO_CYLINDER +1e5 //cylindrial extension priority +#define ENG_EXT_PRIO_TFSF +5e4 //total-field/scattered-field extension priority +#define ENG_EXT_PRIO_EXCITATION -1000 //excitation priority +#define ENG_EXT_PRIO_CYLINDERMULTIGRID -3000 //cylindrial multi-grid extension priority + +#include + +class Operator_Extension; +class Engine; + +//! Abstract base-class for all engine extensions +class Engine_Extension +{ +public: + virtual ~Engine_Extension(); + + virtual void SetNumberOfThreads(int nrThread); + + //! This methode will be called __before__ the main engine does the usual voltage updates. This methode may __not__ change the engine voltages!!! + virtual void DoPreVoltageUpdates() {} + virtual void DoPreVoltageUpdates(int threadID); + //! This methode will be called __after__ the main engine does the usual voltage updates. This methode may __not__ change the engine voltages!!! + virtual void DoPostVoltageUpdates() {} + virtual void DoPostVoltageUpdates(int threadID); + //! This methode will be called __after__ all updates to the voltages and extensions and may add/set its results to the engine voltages, but may __not__ rely on the current value of the engine voltages!!! + virtual void Apply2Voltages() {} + virtual void Apply2Voltages(int threadID); + + //! This methode will be called __before__ the main engine does the usual current updates. This methode may __not__ change the engine current!!! + virtual void DoPreCurrentUpdates() {} + virtual void DoPreCurrentUpdates(int threadID); + //! This methode will be called __after__ the main engine does the usual current updates. This methode may __not__ change the engine current!!! + virtual void DoPostCurrentUpdates() {} + virtual void DoPostCurrentUpdates(int threadID); + //! This methode will be called __after__ all updates to the current and extensions and may add/set its results to the engine current, but may __not__ rely on the current value of the engine current!!! + virtual void Apply2Current() {} + virtual void Apply2Current(int threadID); + + //! Set the Engine to this extention. This will usually done automatically by Engine::AddExtension + virtual void SetEngine(Engine* eng) {m_Eng=eng;} + + //! Get the priority for this extension + virtual int GetPriority() const {return m_Priority;} + + //! Set the priority for this extension + virtual void SetPriority(int val) {m_Priority=val;} + + virtual bool operator< (const Engine_Extension& other); + + virtual std::string GetExtensionName() const; + +protected: + Engine_Extension(Operator_Extension* op_ext); + + Operator_Extension* m_Op_ext; + Engine* m_Eng; + + int m_Priority; + + int m_NrThreads; +}; + +#endif // ENGINE_EXTENSION_H diff --git a/openEMS/FDTD/extensions/operator_ext_conductingsheet.cpp b/openEMS/FDTD/extensions/operator_ext_conductingsheet.cpp new file mode 100644 index 0000000..28c51bb --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_conductingsheet.cpp @@ -0,0 +1,261 @@ +/* +* Copyright (C) 2012 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 . +*/ + +#include "operator_ext_conductingsheet.h" +#include "tools/array_ops.h" +#include "tools/constants.h" +#include "cond_sheet_parameter.h" + +#include "CSPropConductingSheet.h" + +Operator_Ext_ConductingSheet::Operator_Ext_ConductingSheet(Operator* op, double f_max) : Operator_Ext_LorentzMaterial(op) +{ + m_f_max = f_max; +} + +Operator_Ext_ConductingSheet::Operator_Ext_ConductingSheet(Operator* op, Operator_Ext_ConductingSheet* op_ext) : Operator_Ext_LorentzMaterial(op, op_ext) +{ + m_f_max = op_ext->m_f_max; +} + +Operator_Extension* Operator_Ext_ConductingSheet::Clone(Operator* op) +{ + if (dynamic_cast(this)==NULL) + return NULL; + return new Operator_Ext_ConductingSheet(op, this); +} + +bool Operator_Ext_ConductingSheet::BuildExtension() +{ + double dT = m_Op->GetTimestep(); + unsigned int pos[] = {0,0,0}; + double coord[3]; + unsigned int numLines[3] = {m_Op->GetNumberOfLines(0,true),m_Op->GetNumberOfLines(1,true),m_Op->GetNumberOfLines(2,true)}; + + m_Order = 0; + vector v_pos[3]; + int ****tanDir = Create_N_3DArray(numLines); + float ****Conductivity = Create_N_3DArray(numLines); + float ****Thickness = Create_N_3DArray(numLines); + + CSPrimitives* cs_sheet = NULL; + double box[6]; + int nP, nPP; + bool b_pos_on; + bool disable_pos; + for (pos[0]=0; pos[0] vPrims = m_Op->GetPrimitivesBoundBox(pos[0], pos[1], -1, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL)); + for (pos[2]=0; pos[2]GetBCSize(2*m)) || (pos[m]>=(numLines[m]-m_Op->GetBCSize(2*m+1)-1))) + disable_pos = true; + + for (int n=0; n<3; ++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + + tanDir[n][pos[0]][pos[1]][pos[2]] = -1; //deactivate by default + Conductivity[n][pos[0]][pos[1]][pos[2]] = 0; //deactivate by default + Thickness[n][pos[0]][pos[1]][pos[2]] = 0; //deactivate by default + + if (m_Op->GetYeeCoords(n,pos,coord,false)==false) + continue; + + // Ez at r==0 not supported --> set to PEC + if (m_CC_R0_included && (n==2) && (pos[0]==0)) + disable_pos = true; + +// CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord,(CSProperties::PropertyType)(CSProperties::METAL | CSProperties::MATERIAL), false, &cs_sheet); + CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, vPrims, false, &cs_sheet); + CSPropConductingSheet* cs_prop = dynamic_cast(prop); + if (cs_prop) + { + if (cs_sheet==NULL) + return false; //sanity check, this should never happen + if (cs_sheet->GetDimension()!=2) + { + cerr << "Operator_Ext_ConductingSheet::BuildExtension: A conducting sheet primitive (ID: " << cs_sheet->GetID() << ") with dimension: " << cs_sheet->GetDimension() << " found, fallback to PEC!" << endl; + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetVI(n,pos[0],pos[1],pos[2], 0 ); + ++m_Op->m_Nr_PEC[n]; + continue; + } + cs_sheet->SetPrimitiveUsed(true); + + if (disable_pos) + { + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetVI(n,pos[0],pos[1],pos[2], 0 ); + ++m_Op->m_Nr_PEC[n]; + continue; + } + + Conductivity[n][pos[0]][pos[1]][pos[2]] = cs_prop->GetConductivity(); + Thickness[n][pos[0]][pos[1]][pos[2]] = cs_prop->GetThickness(); + + if ((Conductivity[n][pos[0]][pos[1]][pos[2]]<=0) || (Thickness[n][pos[0]][pos[1]][pos[2]]<=0)) + { + cerr << "Operator_Ext_ConductingSheet::BuildExtension: Warning: Zero conductivity or thickness detected... fallback to PEC!" << endl; + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetVI(n,pos[0],pos[1],pos[2], 0 ); + ++m_Op->m_Nr_PEC[n]; + continue; + } + + cs_sheet->GetBoundBox(box); + if (box[2*nP]!=box[2*nP+1]) + tanDir[n][pos[0]][pos[1]][pos[2]] = nP; + if (box[2*nPP]!=box[2*nPP+1]) + tanDir[n][pos[0]][pos[1]][pos[2]] = nPP; + b_pos_on = true; + } + } + if (b_pos_on) + { + for (int n=0; n<3; ++n) + v_pos[n].push_back(pos[n]); + } + } + } + } + + size_t numCS = v_pos[0].size(); + if (numCS==0) + return false; + + m_LM_Count.push_back(numCS); + m_LM_Count.push_back(numCS); + + m_Order = 2; + m_volt_ADE_On = new bool[m_Order]; + m_volt_ADE_On[0] = m_volt_ADE_On[1]=true; + m_curr_ADE_On = new bool[m_Order]; + m_curr_ADE_On[0] = m_curr_ADE_On[1]=false; + + m_volt_Lor_ADE_On = new bool[m_Order]; + m_volt_Lor_ADE_On[0] = m_volt_Lor_ADE_On[1]=false; + m_curr_Lor_ADE_On = new bool[m_Order]; + m_curr_Lor_ADE_On[0] = m_curr_Lor_ADE_On[1]=false; + + m_LM_pos = new unsigned int**[m_Order]; + m_LM_pos[0] = new unsigned int*[3]; + m_LM_pos[1] = new unsigned int*[3]; + + v_int_ADE = new FDTD_FLOAT**[m_Order]; + v_ext_ADE = new FDTD_FLOAT**[m_Order]; + + v_int_ADE[0] = new FDTD_FLOAT*[3]; + v_ext_ADE[0] = new FDTD_FLOAT*[3]; + v_int_ADE[1] = new FDTD_FLOAT*[3]; + v_ext_ADE[1] = new FDTD_FLOAT*[3]; + + for (int n=0; n<3; ++n) + { + m_LM_pos[0][n] = new unsigned int[numCS]; + m_LM_pos[1][n] = new unsigned int[numCS]; + for (unsigned int i=0; iMainOp->SetPos(pos[0],pos[1],pos[2]); + for (int n=0;n<3;++n) + { + tpos[0]=pos[0];tpos[1]=pos[1];tpos[2]=pos[2]; + t_dir = tanDir[n][pos[0]][pos[1]][pos[2]]; + G0 = Conductivity[n][pos[0]][pos[1]][pos[2]]*Thickness[n][pos[0]][pos[1]][pos[2]]; + w0 = 8.0/ G0 / Thickness[n][pos[0]][pos[1]][pos[2]]/__MUE0__; + Omega_max = w_stop/w0; + for (optParaPos=0;optParaPosOmega_max) + break; + if (optParaPos>=numOptPara) + { + cerr << "Operator_Ext_ConductingSheet::BuildExtension(): Error, conductor thickness, conductivity or max. simulation frequency of interest is too high! Check parameter!" << endl; + cerr << " --> max f: " << m_f_max << "Hz, Conductivity: " << Conductivity[n][pos[0]][pos[1]][pos[2]] << "S/m, Thickness " << Thickness[n][pos[0]][pos[1]][pos[2]]*1e6 << "um" << endl; + optParaPos = numOptPara-1; + } + v_int_ADE[0][n][i]=0; + v_ext_ADE[0][n][i]=0; + v_int_ADE[1][n][i]=0; + v_ext_ADE[1][n][i]=0; + if (t_dir>=0) + { + wtl = m_Op->GetEdgeLength(n,pos)/m_Op->GetNodeWidth(t_dir,pos); + factor = 1; + if (tanDir[t_dir][tpos[0]][tpos[1]][tpos[2]]<0) + factor = 2; + --tpos[t_dir]; + if (tanDir[t_dir][tpos[0]][tpos[1]][tpos[2]]<0) + factor = 2; + + L1 = l1[optParaPos]/G0/w0*factor; + L2 = l2[optParaPos]/G0/w0*factor; + R1 = r1[optParaPos]/G0*factor; + R2 = r2[optParaPos]/G0*factor; + G = G0*g[optParaPos]/factor; + + L1*=wtl; + L2*=wtl; + R1*=wtl; + R2*=wtl; + G/=wtl; + + Lmin = L1; + if (L2EC_G[n][index]= G; + m_Op->EC_C[n][index]= dT*dT/4.0*(16.0/Lmin + 1/L1 + 1/L2); + m_Op->Calc_ECOperatorPos(n,pos); + + v_int_ADE[0][n][i]=(2.0*L1-dT*R1)/(2.0*L1+dT*R1); + v_ext_ADE[0][n][i]=dT/(L1+dT*R1/2.0)*m_Op->GetVI(n,pos[0],pos[1],pos[2]); + v_int_ADE[1][n][i]=(2.0*L2-dT*R2)/(2.0*L2+dT*R2); + v_ext_ADE[1][n][i]=dT/(L2+dT*R2/2.0)*m_Op->GetVI(n,pos[0],pos[1],pos[2]); + } + } + } + return true; +} diff --git a/openEMS/FDTD/extensions/operator_ext_conductingsheet.h b/openEMS/FDTD/extensions/operator_ext_conductingsheet.h new file mode 100644 index 0000000..f84dc4b --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_conductingsheet.h @@ -0,0 +1,51 @@ +/* +* Copyright (C) 2012 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 . +*/ + +#ifndef OPERATOR_EXT_CONDUCTINGSHEET_H +#define OPERATOR_EXT_CONDUCTINGSHEET_H + +#include "FDTD/operator.h" +#include "operator_ext_lorentzmaterial.h" + +/*! + FDTD extension for a conducting sheet model as described in: + Lauer, A.; Wolff, I.; , "A conducting sheet model for efficient wide band FDTD analysis of planar waveguides and circuits," Microwave Symposium Digest, 1999 IEEE MTT-S International , vol.4, no., pp.1589-1592 vol.4, 1999 + doi: 10.1109/MWSYM.1999.780262 + URL: http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=780262&isnumber=16934 + */ +class Operator_Ext_ConductingSheet : public Operator_Ext_LorentzMaterial +{ +public: + Operator_Ext_ConductingSheet(Operator* op, double f_max); + + virtual Operator_Extension* Clone(Operator* op); + + virtual bool BuildExtension(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return true;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return true;} + virtual bool IsMPISave() const {return true;} + + virtual string GetExtensionName() const {return string("Conducting Sheet Extension");} + +protected: + //! Copy constructor + Operator_Ext_ConductingSheet(Operator* op, Operator_Ext_ConductingSheet* op_ext); + double m_f_max; +}; + +#endif // OPERATOR_EXT_CONDUCTINGSHEET_H diff --git a/openEMS/FDTD/extensions/operator_ext_cylinder.cpp b/openEMS/FDTD/extensions/operator_ext_cylinder.cpp new file mode 100644 index 0000000..d400bf8 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_cylinder.cpp @@ -0,0 +1,114 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "operator_ext_cylinder.h" +#include "FDTD/operator_cylinder.h" +#include "engine_ext_cylinder.h" + +Operator_Ext_Cylinder::Operator_Ext_Cylinder(Operator_Cylinder* op) : Operator_Extension(op) +{ + m_Op_Cyl = op; + + CC_R0_included=m_Op_Cyl->GetR0Included(); + CC_closedAlpha=m_Op_Cyl->GetClosedAlpha(); + + vv_R0 = NULL; + vi_R0 = NULL; +} + +Operator_Ext_Cylinder::~Operator_Ext_Cylinder() +{ + delete[] vv_R0; + vv_R0=NULL; + delete[] vi_R0; + vi_R0=NULL; +} + +bool Operator_Ext_Cylinder::BuildExtension() +{ + delete[] vv_R0; + vv_R0=NULL; + delete[] vi_R0; + vi_R0=NULL; + + //if r=0 is not included -> obviously no special treatment for r=0 + //if alpha direction is not closed, PEC-BC at r=0 necessary and already set... + if (CC_R0_included==false) + return true; + + vv_R0 = new FDTD_FLOAT[m_Op->GetNumberOfLines(2,true)]; + vi_R0 = new FDTD_FLOAT[m_Op->GetNumberOfLines(2,true)]; + + unsigned int pos[3]; + double coord[3]; + double inEC[4]; + double dT = m_Op->GetTimestep(); + pos[0]=0; + vector vPrims_metal = m_Op->GetPrimitivesBoundBox(pos[0], -1, -1, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL)); + for (pos[2]=0; pos[2]GetNumberOfLines(2,true); ++pos[2]) + { + double C=0; + double G=0; + vector vPrims_mat = m_Op->GetPrimitivesBoundBox(pos[0], -1, pos[2], CSProperties::MATERIAL); + for (pos[1]=0; pos[1]GetNumberOfLines(1,true)-2; ++pos[1]) + { + m_Op_Cyl->Calc_ECPos(2,pos,inEC,vPrims_mat); + C+=inEC[0]; + G+=inEC[1]; + } + m_Op->SetVV(2,0,0,pos[2], 1); + vv_R0[pos[2]] = (1-dT*G/2/C)/(1+dT*G/2/C); + vi_R0[pos[2]] = (dT/C)/(1+dT*G/2/C); + + for (unsigned int i=0; iGetNumberOfLines(1,true); ++i) + { + m_Op->EC_C[2][m_Op->MainOp->SetPos(0,i,pos[2])] = C; + m_Op->EC_G[2][m_Op->MainOp->SetPos(0,i,pos[2])] = G; + } + + //search for metal on z-axis + m_Op_Cyl->GetYeeCoords(2,pos,coord,false); + CSProperties* prop = m_Op->CSX->GetPropertyByCoordPriority(coord, vPrims_metal, true); + if (prop) + { + if (prop->GetType()==CSProperties::METAL) //set to PEC + { + m_Op->SetVV(2,0,0,pos[2], 0); + vv_R0[pos[2]] = 0; + vi_R0[pos[2]] = 0; + m_Op->EC_C[2][m_Op->MainOp->SetPos(0,0,pos[2])] = 0; + m_Op->EC_G[2][m_Op->MainOp->SetPos(0,0,pos[2])] = 0; + } + } + } + return true; +} + +Engine_Extension* Operator_Ext_Cylinder::CreateEngineExtention() +{ + Engine_Ext_Cylinder* eng_ext = new Engine_Ext_Cylinder(this); + return eng_ext; +} + + +void Operator_Ext_Cylinder::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + string On_Off[2] = {"Off", "On"}; + ostr << " Zeroth Radius\t\t: " << On_Off[CC_R0_included] << endl; + ostr << " Closed Rotation\t: " << On_Off[CC_closedAlpha] << endl; +} diff --git a/openEMS/FDTD/extensions/operator_ext_cylinder.h b/openEMS/FDTD/extensions/operator_ext_cylinder.h new file mode 100644 index 0000000..c8dff2d --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_cylinder.h @@ -0,0 +1,60 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef OPERATOR_EXT_CYLINDER_H +#define OPERATOR_EXT_CYLINDER_H + +#include "operator_extension.h" +#include "FDTD/operator.h" + +class Operator_Cylinder; + +class Operator_Ext_Cylinder : public Operator_Extension +{ + friend class Engine_Ext_Cylinder; + friend class Operator_Ext_LorentzMaterial; +public: + Operator_Ext_Cylinder(Operator_Cylinder* op); + ~Operator_Ext_Cylinder(); + + virtual bool BuildExtension(); + + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return true;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return true;} + + // FIXME, this extension is not save or unknown to be save to use with MPI + virtual bool IsMPISave() const {return false;} + + virtual std::string GetExtensionName() const {return std::string("Extension for the Cylinder-Coords Operator");} + + virtual void ShowStat(ostream &ostr) const; + +protected: + Operator_Cylinder* m_Op_Cyl; + + bool CC_closedAlpha; + bool CC_R0_included; + + //special EC operator for R0 + FDTD_FLOAT* vv_R0; //calc new voltage from old voltage + FDTD_FLOAT* vi_R0; //calc new voltage from old current + +}; + +#endif // OPERATOR_EXT_CYLINDER_H diff --git a/openEMS/FDTD/extensions/operator_ext_dispersive.cpp b/openEMS/FDTD/extensions/operator_ext_dispersive.cpp new file mode 100644 index 0000000..ed01f1d --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_dispersive.cpp @@ -0,0 +1,78 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "operator_ext_dispersive.h" + +#include "tools/array_ops.h" + +using namespace std; + +Operator_Ext_Dispersive::Operator_Ext_Dispersive(Operator* op) : Operator_Extension(op) +{ + m_curr_ADE_On = NULL; + m_volt_ADE_On = NULL; + + m_LM_pos=NULL; + m_curr_ADE_On=NULL; + m_volt_ADE_On=NULL; + + m_Order = 0; +} + +Operator_Ext_Dispersive::Operator_Ext_Dispersive(Operator* op, Operator_Ext_Dispersive* op_ext) : Operator_Extension(op,op_ext) +{ + m_curr_ADE_On = NULL; + m_volt_ADE_On = NULL; + + m_LM_pos=NULL; + m_curr_ADE_On=NULL; + m_volt_ADE_On=NULL; + + m_Order = 0; +} + +Operator_Ext_Dispersive::~Operator_Ext_Dispersive() +{ + delete[] m_curr_ADE_On; + delete[] m_volt_ADE_On; + m_curr_ADE_On=NULL; + m_volt_ADE_On=NULL; + + for (int n=0;n. +*/ + +#ifndef OPERATOR_EXT_DISPERSIVE_H +#define OPERATOR_EXT_DISPERSIVE_H + +//#include "operator.h" +#include "operator_extension.h" +#include "vector" + +//! Abstract base class for all dispersive material models, based on an ADE (additional differential equation) +class Operator_Ext_Dispersive : public Operator_Extension +{ + friend class Engine_Ext_Dispersive; +public: + virtual ~Operator_Ext_Dispersive(); + + virtual int GetDispersionOrder() {return m_Order;} + + virtual std::string GetExtensionName() const {return std::string("Dispersive Material Abstract Base class");} + + virtual void ShowStat(std::ostream &ostr) const; + +protected: + Operator_Ext_Dispersive(Operator* op); + //! Copy constructor + Operator_Ext_Dispersive(Operator* op, Operator_Ext_Dispersive* op_ext); + + //! Dispersive order + int m_Order; + + //! Dispersive material count + std::vector m_LM_Count; + //! Index with dispersive material + // Array setup: m_LM_pos[N_order][direction][mesh_pos] + unsigned int ***m_LM_pos; + + bool *m_curr_ADE_On; + bool *m_volt_ADE_On; +}; + +#endif // OPERATOR_EXT_DISPERSIVE_H diff --git a/openEMS/FDTD/extensions/operator_ext_excitation.cpp b/openEMS/FDTD/extensions/operator_ext_excitation.cpp new file mode 100644 index 0000000..d2085ff --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_excitation.cpp @@ -0,0 +1,372 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "operator_ext_excitation.h" +#include "engine_ext_excitation.h" +#include "FDTD/excitation.h" +#include "ContinuousStructure.h" + +#include "CSPrimCurve.h" +#include "CSPropExcitation.h" + +Operator_Ext_Excitation::Operator_Ext_Excitation(Operator* op) : Operator_Extension(op) +{ + Init(); +} + +Operator_Ext_Excitation::~Operator_Ext_Excitation() +{ + Reset(); +} + +Operator_Extension* Operator_Ext_Excitation::Clone(Operator* op) +{ + Operator_Ext_Excitation* clone = new Operator_Ext_Excitation(op, this); + return clone; +} + +void Operator_Ext_Excitation::Init() +{ + Operator_Extension::Init(); + Volt_delay = 0; + Volt_amp = 0; + Volt_dir = 0; + Volt_Count = 0; + Curr_delay = 0; + Curr_amp = 0; + Curr_dir = 0; + Curr_Count = 0; + + for (int n=0; n<3; ++n) + { + Volt_index[n] = 0; + Curr_index[n] = 0; + Volt_Count_Dir[n] = 0; + Curr_Count_Dir[n] = 0; + } + m_Exc = 0; +} + +void Operator_Ext_Excitation::Reset() +{ + Operator_Extension::Reset(); + delete[] Volt_delay; + Volt_delay = 0; + delete[] Volt_dir; + Volt_dir = 0; + delete[] Volt_amp; + Volt_amp = 0; + delete[] Curr_delay; + Curr_delay = 0; + delete[] Curr_dir; + Curr_dir = 0; + delete[] Curr_amp; + Curr_amp = 0; + + Volt_Count = 0; + Curr_Count = 0; + + for (int n=0; n<3; ++n) + { + delete[] Volt_index[n]; + Volt_index[n] = 0; + delete[] Curr_index[n]; + Curr_index[n] = 0; + + Volt_Count_Dir[n] = 0; + Curr_Count_Dir[n] = 0; + } +} + + +Operator_Ext_Excitation::Operator_Ext_Excitation(Operator* op, Operator_Ext_Excitation* op_ext) : Operator_Extension(op, op_ext) +{ + Init(); +} + +bool Operator_Ext_Excitation::BuildExtension() +{ + m_Exc = m_Op->GetExcitationSignal(); + double dT = m_Op->GetTimestep(); + if (dT==0) + return false; + if (m_Exc==0) + return false; + + Reset(); + ContinuousStructure* CSX = m_Op->GetGeometryCSX(); + + unsigned int pos[3]; + double amp=0; + + vector volt_vIndex[3]; + vector volt_vExcit; + vector volt_vDelay; + vector volt_vDir; + double volt_coord[3]; + + vector curr_vIndex[3]; + vector curr_vExcit; + vector curr_vDelay; + vector curr_vDir; + double curr_coord[3]; + + vector vec_prop = CSX->GetPropertyByType(CSProperties::EXCITATION); + + if (vec_prop.size()==0) + { + cerr << "Operator::CalcFieldExcitation: Warning, no excitation properties found" << endl; + return false; + } + + CSPropExcitation* elec=NULL; + CSProperties* prop=NULL; + int priority=0; + + unsigned int numLines[] = {m_Op->GetNumberOfLines(0,true),m_Op->GetNumberOfLines(1,true),m_Op->GetNumberOfLines(2,true)}; + + for (pos[2]=0; pos[2]GetYeeCoords(n,pos,volt_coord,false)==false) + continue; + if (m_CC_R0_included && (n==2) && (pos[0]==0)) + volt_coord[1] = m_Op->GetDiscLine(1,0); + + if (m_CC_R0_included && (n==1) && (pos[0]==0)) + continue; + + for (size_t p=0; pToExcitation(); + if (elec==NULL) + continue; + if (prop->CheckCoordInPrimitive(volt_coord,priority,true)) + { + if ((elec->GetActiveDir(n)) && ( (elec->GetExcitType()==0) || (elec->GetExcitType()==1) ))//&& (pos[n]GetWeightedExcitation(n,volt_coord)*m_Op->GetEdgeLength(n,pos);// delta[n]*gridDelta; + if (amp!=0) + { + volt_vExcit.push_back(amp); + volt_vDelay.push_back((unsigned int)(elec->GetDelay()/dT)); + volt_vDir.push_back(n); + volt_vIndex[0].push_back(pos[0]); + volt_vIndex[1].push_back(pos[1]); + volt_vIndex[2].push_back(pos[2]); + } + if (elec->GetExcitType()==1) //hard excite + { + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetVI(n,pos[0],pos[1],pos[2], 0 ); + } + } + } + } + } + + //magnetic field excite + for (int n=0; n<3; ++n) + { + if ((pos[0]>=numLines[0]-1) || (pos[1]>=numLines[1]-1) || (pos[2]>=numLines[2]-1)) + continue; //skip the last H-Line which is outside the FDTD-domain + if (m_Op->GetYeeCoords(n,pos,curr_coord,true)==false) + continue; + for (size_t p=0; pToExcitation(); + if (elec==NULL) + continue; + if (prop->CheckCoordInPrimitive(curr_coord,priority,true)) + { + if ((elec->GetActiveDir(n)) && ( (elec->GetExcitType()==2) || (elec->GetExcitType()==3) )) + { + amp = elec->GetWeightedExcitation(n,curr_coord)*m_Op->GetEdgeLength(n,pos,true);// delta[n]*gridDelta; + if (amp!=0) + { + curr_vExcit.push_back(amp); + curr_vDelay.push_back((unsigned int)(elec->GetDelay()/dT)); + curr_vDir.push_back(n); + curr_vIndex[0].push_back(pos[0]); + curr_vIndex[1].push_back(pos[1]); + curr_vIndex[2].push_back(pos[2]); + } + if (elec->GetExcitType()==3) //hard excite + { + m_Op->SetII(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetIV(n,pos[0],pos[1],pos[2], 0 ); + } + } + } + } + } + + } + } + } + + //special treatment for primitives of type curve (treated as wires) see also Calc_PEC + double p1[3]; + double p2[3]; + Grid_Path path; + for (size_t p=0; pToExcitation(); + for (size_t n=0; nGetQtyPrimitives(); ++n) + { + CSPrimitives* prim = prop->GetPrimitive(n); + CSPrimCurve* curv = prim->ToCurve(); + if (curv) + { + for (size_t i=1; iGetNumberOfPoints(); ++i) + { + curv->GetPoint(i-1,p1,m_Op->m_MeshType); + curv->GetPoint(i,p2,m_Op->m_MeshType); + path = m_Op->FindPath(p1,p2); + if (path.dir.size()>0) + prim->SetPrimitiveUsed(true); + for (size_t t=0; tGetYeeCoords(n,pos,volt_coord,false); + if (elec!=NULL) + { + if ((elec->GetActiveDir(n)) && (pos[n]GetExcitType()==0) || (elec->GetExcitType()==1) )) + { + amp = elec->GetWeightedExcitation(n,volt_coord)*m_Op->GetEdgeLength(n,pos); + if (amp!=0) + { + volt_vExcit.push_back(amp); + volt_vDelay.push_back((unsigned int)(elec->GetDelay()/dT)); + volt_vDir.push_back(n); + volt_vIndex[0].push_back(pos[0]); + volt_vIndex[1].push_back(pos[1]); + volt_vIndex[2].push_back(pos[2]); + } + if (elec->GetExcitType()==1) //hard excite + { + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + m_Op->SetVI(n,pos[0],pos[1],pos[2], 0 ); + } + } + } + } + } + } + } + } + + // set voltage excitations + setupVoltageExcitation( volt_vIndex, volt_vExcit, volt_vDelay, volt_vDir ); + + // set current excitations + setupCurrentExcitation( curr_vIndex, curr_vExcit, curr_vDelay, curr_vDir ); + + return true; +} + +void Operator_Ext_Excitation::setupVoltageExcitation( vector const volt_vIndex[3], vector const& volt_vExcit, + vector const& volt_vDelay, vector const& volt_vDir ) +{ + Volt_Count = volt_vIndex[0].size(); + for (int n=0; n<3; n++) + { + Volt_Count_Dir[n]=0; + delete[] Volt_index[n]; + Volt_index[n] = new unsigned int[Volt_Count]; + } + delete[] Volt_delay; + delete[] Volt_amp; + delete[] Volt_dir; + Volt_delay = new unsigned int[Volt_Count]; + Volt_amp = new FDTD_FLOAT[Volt_Count]; + Volt_dir = new unsigned short[Volt_Count]; + +// cerr << "Excitation::setupVoltageExcitation(): Number of voltage excitation points: " << Volt_Count << endl; +// if (Volt_Count==0) +// cerr << "No E-Field/voltage excitation found!" << endl; + for (int n=0; n<3; n++) + for (unsigned int i=0; i const curr_vIndex[3], vector const& curr_vExcit, + vector const& curr_vDelay, vector const& curr_vDir ) +{ + Curr_Count = curr_vIndex[0].size(); + for (int n=0; n<3; n++) + { + Curr_Count_Dir[n]=0; + delete[] Curr_index[n]; + Curr_index[n] = new unsigned int[Curr_Count]; + } + delete[] Curr_delay; + delete[] Curr_amp; + delete[] Curr_dir; + Curr_delay = new unsigned int[Curr_Count]; + Curr_amp = new FDTD_FLOAT[Curr_Count]; + Curr_dir = new unsigned short[Curr_Count]; + +// cerr << "Excitation::setupCurrentExcitation(): Number of current excitation points: " << Curr_Count << endl; +// if (Curr_Count==0) +// cerr << "No H-Field/current excitation found!" << endl; + for (int n=0; n<3; ++n) + for (unsigned int i=0; iGetLength() << endl; + cout << "Excitation Length (s)\t: " << m_Exc->GetLength()*m_Op->GetTimestep() << endl; +} + diff --git a/openEMS/FDTD/extensions/operator_ext_excitation.h b/openEMS/FDTD/extensions/operator_ext_excitation.h new file mode 100644 index 0000000..2abcef0 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_excitation.h @@ -0,0 +1,84 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#ifndef OPERATOR_EXT_EXCITATION_H +#define OPERATOR_EXT_EXCITATION_H + +#include "operator_extension.h" +#include "FDTD/operator.h" + +class Excitation; + +class Operator_Ext_Excitation : public Operator_Extension +{ + friend class Engine_Ext_Excitation; + friend class Engine_Ext_Mur_ABC; + friend class Operator; +public: + Operator_Ext_Excitation(Operator* op); + ~Operator_Ext_Excitation(); + + virtual Operator_Extension* Clone(Operator* op); + + virtual bool BuildExtension(); + + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return true;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return true;} + virtual bool IsMPISave() const {return true;} + + virtual string GetExtensionName() const {return string("Excitation Extension");} + + virtual void ShowStat(ostream &ostr) const; + + virtual void Init(); + virtual void Reset(); + + unsigned int GetVoltCount() const {return Volt_Count;} + unsigned int GetVoltCount(int ny) const {return Volt_Count_Dir[ny];} + + unsigned int GetCurrCount() const {return Curr_Count;} + unsigned int GetCurrCount(int ny) const {return Curr_Count_Dir[ny];} + +protected: + Operator_Ext_Excitation(Operator* op, Operator_Ext_Excitation* op_ext); + + Excitation* m_Exc; + + void setupVoltageExcitation( vector const volt_vIndex[3], vector const& volt_vExcit, + vector const& volt_vDelay, vector const& volt_vDir ); + void setupCurrentExcitation( vector const curr_vIndex[3], vector const& curr_vExcit, + vector const& curr_vDelay, vector const& curr_vDir ); + //E-Field/voltage Excitation + unsigned int Volt_Count; + unsigned int Volt_Count_Dir[3]; + unsigned int* Volt_index[3]; + unsigned short* Volt_dir; + FDTD_FLOAT* Volt_amp; //represented as edge-voltages!! + unsigned int* Volt_delay; + + //H-Field/current Excitation + unsigned int Curr_Count; + unsigned int Curr_Count_Dir[3]; + unsigned int* Curr_index[3]; + unsigned short* Curr_dir; + FDTD_FLOAT* Curr_amp; //represented as edge-currents!! + unsigned int* Curr_delay; +}; + +#endif // OPERATOR_EXT_EXCITATION_H diff --git a/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp b/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp new file mode 100644 index 0000000..9f386fc --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_lorentzmaterial.cpp @@ -0,0 +1,453 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "operator_ext_lorentzmaterial.h" +#include "engine_ext_lorentzmaterial.h" +#include "operator_ext_cylinder.h" +#include "../operator_cylinder.h" + +#include "CSPropLorentzMaterial.h" +#include "CSPropDebyeMaterial.h" + +Operator_Ext_LorentzMaterial::Operator_Ext_LorentzMaterial(Operator* op) : Operator_Ext_Dispersive(op) +{ + v_int_ADE = NULL; + v_ext_ADE = NULL; + i_int_ADE = NULL; + i_ext_ADE = NULL; + + v_Lor_ADE = NULL; + i_Lor_ADE = NULL; + + m_curr_Lor_ADE_On = NULL; + m_curr_Lor_ADE_On = NULL; +} + +Operator_Ext_LorentzMaterial::Operator_Ext_LorentzMaterial(Operator* op, Operator_Ext_LorentzMaterial* op_ext) : Operator_Ext_Dispersive(op,op_ext) +{ + v_int_ADE = NULL; + v_ext_ADE = NULL; + i_int_ADE = NULL; + i_ext_ADE = NULL; + + v_Lor_ADE = NULL; + i_Lor_ADE = NULL; + + m_curr_Lor_ADE_On = NULL; + m_curr_Lor_ADE_On = NULL; +} + +Operator_Ext_LorentzMaterial::~Operator_Ext_LorentzMaterial() +{ + for (int i=0;i(this)==NULL) + return NULL; + return new Operator_Ext_LorentzMaterial(op, this); +} + +bool Operator_Ext_LorentzMaterial::BuildExtension() +{ + double dT = m_Op->GetTimestep(); + unsigned int pos[] = {0,0,0}; + double coord[3]; + unsigned int numLines[3] = {m_Op->GetNumberOfLines(0,true),m_Op->GetNumberOfLines(1,true),m_Op->GetNumberOfLines(2,true)}; + CSPropLorentzMaterial* mat = NULL; + CSPropDebyeMaterial* debye_mat = NULL; + + bool warn_once = true; + + bool b_pos_on; + vector v_pos[3]; + + // drude material parameter + double w_plasma,t_relax; + double L_D[3], C_D[3]; + double R_D[3], G_D[3]; + vector v_int[3]; + vector v_ext[3]; + vector i_int[3]; + vector i_ext[3]; + + //additional Dorentz material parameter + double w_Lor_Pol; + double C_L[3]; + double L_L[3]; + vector v_Lor[3]; + vector i_Lor[3]; + + m_Order = 0; + vector LD_props = m_Op->CSX->GetPropertyByType(CSProperties::LORENTZMATERIAL); + for (size_t n=0;n(LD_props.at(n)); + if (LorMat==NULL) + return false; //sanity check, this should not happen + if (LorMat->GetDispersionOrder()>m_Order) + m_Order=LorMat->GetDispersionOrder(); + } + LD_props = m_Op->CSX->GetPropertyByType(CSProperties::DEBYEMATERIAL); + for (size_t n=0;n(LD_props.at(n)); + if (DebyeMat==NULL) + return false; //sanity check, this should not happen + if (DebyeMat->GetDispersionOrder()>m_Order) + m_Order=DebyeMat->GetDispersionOrder(); + } + + m_LM_pos = new unsigned int**[m_Order]; + + m_volt_ADE_On = new bool[m_Order]; + m_curr_ADE_On = new bool[m_Order]; + m_volt_Lor_ADE_On = new bool[m_Order]; + m_curr_Lor_ADE_On = new bool[m_Order]; + + v_int_ADE = new FDTD_FLOAT**[m_Order]; + v_ext_ADE = new FDTD_FLOAT**[m_Order]; + i_int_ADE = new FDTD_FLOAT**[m_Order]; + i_ext_ADE = new FDTD_FLOAT**[m_Order]; + + v_Lor_ADE = new FDTD_FLOAT**[m_Order]; + i_Lor_ADE = new FDTD_FLOAT**[m_Order]; + + for (int order=0;order vPrims = m_Op->GetPrimitivesBoundBox(pos[0], pos[1], -1, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL)); + for (pos[2]=0; pos[2]MainOp->SetPos(pos[0],pos[1],pos[2]); + //calc epsilon lorentz material + b_pos_on = false; + for (int n=0; n<3; ++n) + { + L_D[n]=0; + R_D[n]=0; + C_L[n]=0; + if (m_Op->GetYeeCoords(n,pos,coord,false)==false) + continue; + if (m_CC_R0_included && (n==2) && (pos[0]==0)) + coord[1] = m_Op->GetDiscLine(1,0); + + if (m_Op->GetVI(n,pos[0],pos[1],pos[2])==0) + continue; + +// CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord,(CSProperties::PropertyType)(CSProperties::METAL | CSProperties::MATERIAL), true); + CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, vPrims, true); + if ((mat = prop->ToLorentzMaterial())) + { + w_plasma = mat->GetEpsPlasmaFreqWeighted(order,n,coord) * 2 * PI; + if ((w_plasma>0) && (m_Op->EC_C[n][index]>0)) + { + b_pos_on = true; + m_volt_ADE_On[order] = true; + L_D[n] = 1/(w_plasma*w_plasma*m_Op->EC_C[n][index]); + } + t_relax = mat->GetEpsRelaxTimeWeighted(order,n,coord); + if ((t_relax>0) && m_volt_ADE_On[order]) + { + R_D[n] = L_D[n]/t_relax; + } + w_Lor_Pol = mat->GetEpsLorPoleFreqWeighted(order,n,coord) * 2 * PI; + if ((w_Lor_Pol>0) && (L_D[n]>0)) + { + m_volt_Lor_ADE_On[order] = true; + C_L[n] = 1/(w_Lor_Pol*w_Lor_Pol*L_D[n]); + } + } + if ((debye_mat = prop->ToDebyeMaterial())) + { + C_L[n] = 8.85418781762e-12*debye_mat->GetEpsDeltaWeighted(order,n,coord) * m_Op->GetEdgeArea(n, pos) / m_Op->GetEdgeLength(n,pos); + t_relax = debye_mat->GetEpsRelaxTimeWeighted(order,n,coord); + if ((t_relax<2.0*dT) && warn_once) + { + warn_once = false; + cerr << "Operator_Ext_LorentzMaterial::BuildExtension(): Warning, debye relaxation time is to small, skipping..." << endl; + } + if ((C_L[n]>0) && (t_relax>0) && (t_relax>2.0*dT)) + { + R_D[n] = t_relax/C_L[n]; + b_pos_on = true; + m_volt_ADE_On[order] = true; + m_volt_Lor_ADE_On[order] = true; + } + } + } + + for (int n=0; n<3; ++n) + { + C_D[n]=0; + G_D[n]=0; + L_L[n]=0; + if (m_Op->GetYeeCoords(n,pos,coord,true)==false) + continue; + if (m_Op->GetIV(n,pos[0],pos[1],pos[2])==0) + continue; + +// CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord,(CSProperties::PropertyType)(CSProperties::METAL | CSProperties::MATERIAL), true); + CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, vPrims, true); + if ((mat = prop->ToLorentzMaterial())) + { + w_plasma = mat->GetMuePlasmaFreqWeighted(order,n,coord) * 2 * PI; + if ((w_plasma>0) && (m_Op->EC_L[n][index]>0)) + { + b_pos_on = true; + m_curr_ADE_On[order] = true; + C_D[n] = 1/(w_plasma*w_plasma*m_Op->EC_L[n][index]); + } + t_relax = mat->GetMueRelaxTimeWeighted(order,n,coord); + if ((t_relax>0) && m_curr_ADE_On[order]) + { + G_D[n] = C_D[n]/t_relax; + } + w_Lor_Pol = mat->GetMueLorPoleFreqWeighted(order,n,coord) * 2 * PI; + if ((w_Lor_Pol>0) && (C_D[n]>0)) + { + m_curr_Lor_ADE_On[order] = true; + L_L[n] = 1/(w_Lor_Pol*w_Lor_Pol*C_D[n]); + } + } + } + + if (b_pos_on) //this position has active drude material + { + for (unsigned int n=0; n<3; ++n) + { + v_pos[n].push_back(pos[n]); + if (L_D[n]>0) + { + v_int[n].push_back((2.0*L_D[n]-dT*R_D[n])/(2.0*L_D[n]+dT*R_D[n])); + // check for r==0 in clyindrical coords and get special VI cooefficient + if (m_CC_R0_included && n==2 && pos[0]==0) + v_ext[n].push_back(dT/(L_D[n]+dT*R_D[n]/2.0)*m_Op_Cyl->m_Cyl_Ext->vi_R0[pos[2]]); + else + v_ext[n].push_back(dT/(L_D[n]+dT*R_D[n]/2.0)*m_Op->GetVI(n,pos[0],pos[1],pos[2])); + } + else if ((R_D[n]>0) && (C_L[n]>0)) + { + v_int[n].push_back((2.0*dT-R_D[n]*C_L[n])/(C_L[n]*R_D[n])); + v_ext[n].push_back(2.0/R_D[n]*m_Op->GetVI(n,pos[0],pos[1],pos[2])); + } + else + { + v_int[n].push_back(1); + v_ext[n].push_back(0); + } + if (C_D[n]>0) + { + i_int[n].push_back((2.0*C_D[n]-dT*G_D[n])/(2.0*C_D[n]+dT*G_D[n])); + i_ext[n].push_back(dT/(C_D[n]+dT*G_D[n]/2.0)*m_Op->GetIV(n,pos[0],pos[1],pos[2])); + } + else + { + i_int[n].push_back(1); + i_ext[n].push_back(0); + } + if (C_L[n]>0) + v_Lor[n].push_back(dT/C_L[n]/m_Op->GetVI(n,pos[0],pos[1],pos[2])); + else + v_Lor[n].push_back(0); + if (L_L[n]>0) + i_Lor[n].push_back(dT/L_L[n]/m_Op->GetIV(n,pos[0],pos[1],pos[2])); + else + i_Lor[n].push_back(0); + } + } + } + } + } + + //copy all vectors into the array's + m_LM_Count.push_back(v_pos[0].size()); + + m_LM_pos[order] = new unsigned int*[3]; + + if (m_volt_ADE_On[order]) + { + v_int_ADE[order] = new FDTD_FLOAT*[3]; + v_ext_ADE[order] = new FDTD_FLOAT*[3]; + } + else + { + v_int_ADE[order] = NULL; + v_ext_ADE[order] = NULL; + } + + if (m_curr_ADE_On[order]) + { + i_int_ADE[order] = new FDTD_FLOAT*[3]; + i_ext_ADE[order] = new FDTD_FLOAT*[3]; + } + else + { + i_int_ADE[order] = NULL; + i_ext_ADE[order] = NULL; + } + + if (m_volt_Lor_ADE_On[order]) + v_Lor_ADE[order] = new FDTD_FLOAT*[3]; + else + v_Lor_ADE[order] = NULL; + + if (m_curr_Lor_ADE_On[order]) + i_Lor_ADE[order] = new FDTD_FLOAT*[3]; + else + i_Lor_ADE[order] = NULL; + + for (int n=0; n<3; ++n) + { + m_LM_pos[order][n] = new unsigned int[m_LM_Count.at(order)]; + for (unsigned int i=0; i. +*/ + +#ifndef OPERATOR_EXT_LORENTZMATERIAL_H +#define OPERATOR_EXT_LORENTZMATERIAL_H + +#include "FDTD/operator.h" +#include "operator_ext_dispersive.h" + +class Operator_Ext_LorentzMaterial : public Operator_Ext_Dispersive +{ + friend class Engine_Ext_LorentzMaterial; +public: + Operator_Ext_LorentzMaterial(Operator* op); + virtual ~Operator_Ext_LorentzMaterial(); + + virtual Operator_Extension* Clone(Operator* op); + + virtual bool BuildExtension(); + + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return true;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return true;} + virtual bool IsMPISave() const {return true;} + + virtual string GetExtensionName() const {return string("Drude/Lorentz Dispersive Material Extension");} + + virtual void ShowStat(ostream &ostr) const; + +protected: + //! Copy constructor + Operator_Ext_LorentzMaterial(Operator* op, Operator_Ext_LorentzMaterial* op_ext); + + //ADE update coefficients, array setup: coeff[N_order][direction][mesh_pos_index] + FDTD_FLOAT ***v_int_ADE; + FDTD_FLOAT ***v_ext_ADE; + FDTD_FLOAT ***i_int_ADE; + FDTD_FLOAT ***i_ext_ADE; + + bool *m_curr_Lor_ADE_On; + bool *m_volt_Lor_ADE_On; + + FDTD_FLOAT ***v_Lor_ADE; + FDTD_FLOAT ***i_Lor_ADE; +}; + +#endif // OPERATOR_EXT_LORENTZMATERIAL_H diff --git a/openEMS/FDTD/extensions/operator_ext_mur_abc.cpp b/openEMS/FDTD/extensions/operator_ext_mur_abc.cpp new file mode 100644 index 0000000..1df8583 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_mur_abc.cpp @@ -0,0 +1,210 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "operator_ext_mur_abc.h" +#include "engine_ext_mur_abc.h" + +#include "tools/array_ops.h" + +#include "CSPropMaterial.h" + +Operator_Ext_Mur_ABC::Operator_Ext_Mur_ABC(Operator* op) : Operator_Extension(op) +{ + Initialize(); +} + +Operator_Ext_Mur_ABC::~Operator_Ext_Mur_ABC() +{ + Delete2DArray(m_Mur_Coeff_nyP,m_numLines); + m_Mur_Coeff_nyP = NULL; + Delete2DArray(m_Mur_Coeff_nyPP,m_numLines); + m_Mur_Coeff_nyPP = NULL; +} + +Operator_Ext_Mur_ABC::Operator_Ext_Mur_ABC(Operator* op, Operator_Ext_Mur_ABC* op_ext) : Operator_Extension(op, op_ext) +{ + Initialize(); + m_v_phase = op_ext->m_v_phase; + SetDirection(op_ext->m_ny,op_ext->m_top); +} + +Operator_Extension* Operator_Ext_Mur_ABC::Clone(Operator* op) +{ + if (dynamic_cast(this)==NULL) + return NULL; + return new Operator_Ext_Mur_ABC(op, this); +} + +bool Operator_Ext_Mur_ABC::IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const +{ + if ((m_ny==0) && (!m_top) && (R0_included || closedAlpha)) + return false; + if ((m_ny==1) && (closedAlpha)) + return false; + return true; +} + +bool Operator_Ext_Mur_ABC::IsCylindricalMultiGridSave(bool child) const +{ + if (m_ny==2) //always allow in z-direction + return true; + if ((m_ny==0) && (m_top) && (!child)) //if top r-direction and is not a child grid allow Mur... + return true; + //in all other cases this ABC is not save to use in CylindricalMultiGrid + return false; +} + +void Operator_Ext_Mur_ABC::Initialize() +{ + m_ny = -1; + m_nyP = -1; + m_nyPP = -1; + m_LineNr = 0; + m_LineNr_Shift = 0; + + m_v_phase = 0.0; + + m_Mur_Coeff_nyP = NULL; + m_Mur_Coeff_nyPP = NULL; + + m_numLines[0]=0; + m_numLines[1]=0; +} + +void Operator_Ext_Mur_ABC::SetDirection(int ny, bool top_ny) +{ + if ((ny<0) || (ny>2)) + return; + + Delete2DArray(m_Mur_Coeff_nyP,m_numLines); + Delete2DArray(m_Mur_Coeff_nyPP,m_numLines); + + m_ny = ny; + m_top = top_ny; + m_nyP = (ny+1)%3; + m_nyPP = (ny+2)%3; + if (!top_ny) + { + m_LineNr = 0; + m_LineNr_Shift = 1; + } + else + { + m_LineNr = m_Op->GetNumberOfLines(m_ny,true)-1; + m_LineNr_Shift = m_Op->GetNumberOfLines(m_ny,true) - 2; + } + + m_numLines[0] = m_Op->GetNumberOfLines(m_nyP,true); + m_numLines[1] = m_Op->GetNumberOfLines(m_nyPP,true); + + m_Mur_Coeff_nyP = Create2DArray(m_numLines); + m_Mur_Coeff_nyPP = Create2DArray(m_numLines); + +} + +bool Operator_Ext_Mur_ABC::BuildExtension() +{ + if (m_ny<0) + { + cerr << "Operator_Ext_Mur_ABC::BuildExtension: Warning, Extension not initialized! Use SetDirection!! Abort build!!" << endl; + return false; + } + double dT = m_Op->GetTimestep(); + unsigned int pos[] = {0,0,0}; + pos[m_ny] = m_LineNr; + double delta = fabs(m_Op->GetEdgeLength(m_ny,pos)); + double coord[] = {0,0,0}; + coord[0] = m_Op->GetDiscLine(0,pos[0]); + coord[1] = m_Op->GetDiscLine(1,pos[1]); + coord[2] = m_Op->GetDiscLine(2,pos[2]); + + double eps,mue; + double c0t; + + if (m_LineNr==0) + coord[m_ny] = m_Op->GetDiscLine(m_ny,pos[m_ny]) + delta/2 / m_Op->GetGridDelta(); + else + coord[m_ny] = m_Op->GetDiscLine(m_ny,pos[m_ny]) - delta/2 / m_Op->GetGridDelta(); + + int posBB[3]; + posBB[m_ny] =pos[m_ny]; + posBB[m_nyPP]=-1; + + for (pos[m_nyP]=0; pos[m_nyP] vPrims = m_Op->GetPrimitivesBoundBox(posBB[0], posBB[1], posBB[2], CSProperties::MATERIAL); + coord[m_nyP] = m_Op->GetDiscLine(m_nyP,pos[m_nyP]); + for (pos[m_nyPP]=0; pos[m_nyPP]GetDiscLine(m_nyPP,pos[m_nyPP]); +// CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, CSProperties::MATERIAL, false); + CSProperties* prop = m_Op->GetGeometryCSX()->GetPropertyByCoordPriority(coord, vPrims, false); + if (prop) + { + CSPropMaterial* mat = prop->ToMaterial(); + + //nP + eps = mat->GetEpsilonWeighted(m_nyP,coord); + mue = mat->GetMueWeighted(m_nyP,coord); + if (m_v_phase>0.0) + c0t = m_v_phase * dT; + else + c0t = __C0__ * dT / sqrt(eps*mue); + m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] = (c0t - delta) / (c0t + delta); + + //nPP + eps = mat->GetEpsilonWeighted(m_nyPP,coord); + mue = mat->GetMueWeighted(m_nyPP,coord); + if (m_v_phase>0.0) + c0t = m_v_phase * dT; + else + c0t = __C0__ * dT / sqrt(eps*mue); + m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] = (c0t - delta) / (c0t + delta); + + } + else + { + if (m_v_phase>0.0) + c0t = m_v_phase * dT; + else + c0t = __C0__ / sqrt(m_Op->GetBackgroundEpsR()*m_Op->GetBackgroundMueR()) * dT; + m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] = (c0t - delta) / (c0t + delta); + m_Mur_Coeff_nyPP[pos[m_nyP]][pos[m_nyPP]] = m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]]; + } +// cerr << m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] << " : " << m_Mur_Coeff_nyP[pos[m_nyP]][pos[m_nyPP]] << endl; + } + } +// cerr << "Operator_Ext_Mur_ABC::BuildExtension(): " << m_ny << " @ " << m_LineNr << endl; + return true; +} + +Engine_Extension* Operator_Ext_Mur_ABC::CreateEngineExtention() +{ + Engine_Ext_Mur_ABC* eng_ext = new Engine_Ext_Mur_ABC(this); + return eng_ext; +} + + +void Operator_Ext_Mur_ABC::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + string XYZ[3] = {"x","y","z"}; + ostr << " Active direction\t: " << XYZ[m_ny] << " at line: " << m_LineNr << endl; + if (m_v_phase>0.0) + ostr << " Used phase velocity\t: " << m_v_phase << " (" << m_v_phase/__C0__ << " * c_0)" <. +*/ + +#ifndef OPERATOR_EXT_MUR_ABC_H +#define OPERATOR_EXT_MUR_ABC_H + +#include "FDTD/operator.h" +#include "operator_extension.h" + +class Operator_Ext_Mur_ABC : public Operator_Extension +{ + friend class Engine_Ext_Mur_ABC; +public: + Operator_Ext_Mur_ABC(Operator* op); + ~Operator_Ext_Mur_ABC(); + + virtual Operator_Extension* Clone(Operator* op); + + //! Define the direction of this ABC: \a ny=0,1,2 -> x,y,z and if at bottom_ny -> e.g. x=0 or x=end + void SetDirection(int ny, bool top_ny); + + //! Set (override) the expected phase velocity of the incoming wave + void SetPhaseVelocity(double c_phase) {m_v_phase=c_phase;}; + + virtual bool BuildExtension(); + + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const; + virtual bool IsCylindricalMultiGridSave(bool child) const; + virtual bool IsMPISave() const {return true;} + + virtual string GetExtensionName() const {return string("Mur ABC Extension");} + + virtual void ShowStat(ostream &ostr) const; + +protected: + Operator_Ext_Mur_ABC(Operator* op, Operator_Ext_Mur_ABC* op_ext); + void Initialize(); + int m_ny; + int m_nyP,m_nyPP; + bool m_top; + unsigned int m_LineNr; + int m_LineNr_Shift; + + double m_v_phase; + + unsigned int m_numLines[2]; + + FDTD_FLOAT** m_Mur_Coeff_nyP; + FDTD_FLOAT** m_Mur_Coeff_nyPP; +}; + +#endif // OPERATOR_EXT_MUR_ABC_H diff --git a/openEMS/FDTD/extensions/operator_ext_steadystate.cpp b/openEMS/FDTD/extensions/operator_ext_steadystate.cpp new file mode 100644 index 0000000..b8395a8 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_steadystate.cpp @@ -0,0 +1,104 @@ +/* +* Copyright (C) 2015 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 . +*/ + +#include "operator_ext_steadystate.h" +#include "engine_ext_steadystate.h" + +Operator_Ext_SteadyState::Operator_Ext_SteadyState(Operator* op, double period): Operator_Extension(op) +{ + this->Reset(); + m_T_period = period; +} + +Operator_Ext_SteadyState::Operator_Ext_SteadyState(Operator* op, Operator_Ext_SteadyState* op_ext): Operator_Extension(op, op_ext) +{ + this->Reset(); + m_T_period = op_ext->m_T_period; +} + +Operator_Ext_SteadyState::~Operator_Ext_SteadyState() +{ +} + +Operator_Extension* Operator_Ext_SteadyState::Clone(Operator* op) +{ + //disable cloning, only the main operator needs to have a steady state detection + UNUSED(op); + return NULL; +} + +bool Operator_Ext_SteadyState::BuildExtension() +{ + double dT = m_Op->GetTimestep(); + m_TS_period = round(m_T_period/dT); + m_T_period = m_TS_period*dT; + return true; +} + +void Operator_Ext_SteadyState::Reset() +{ + for (int n=0;n<3;++n) + { + m_E_probe_pos[n].clear(); + m_H_probe_pos[n].clear(); + } + m_E_probe_dir.clear(); + m_H_probe_dir.clear(); + m_T_period = 0; + m_TS_period = 0; +} + +bool Operator_Ext_SteadyState::Add_E_Probe(unsigned int pos[3], int dir) +{ + if ((dir<0) || (dir>2)) + return false; + for (int n=0;n<3;++n) + if (pos[n]>=m_Op->GetNumberOfLines(n)) + return false; + for (int n=0;n<3;++n) + m_E_probe_pos[n].push_back(pos[n]); + m_E_probe_dir.push_back(dir); + return true; +} + +bool Operator_Ext_SteadyState::Add_H_Probe(unsigned int pos[3], int dir) +{ + if ((dir<0) || (dir>2)) + return false; + for (int n=0;n<3;++n) + if (pos[n]>=m_Op->GetNumberOfLines(n)) + return false; + for (int n=0;n<3;++n) + m_H_probe_pos[n].push_back(pos[n]); + m_H_probe_dir.push_back(dir); + return true; +} + +Engine_Extension* Operator_Ext_SteadyState::CreateEngineExtention() +{ + m_Eng_Ext = new Engine_Ext_SteadyState(this); + return m_Eng_Ext; +} + +void Operator_Ext_SteadyState::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + cout << "Period time (s): " << m_T_period << "\t Period TS: " << m_TS_period << endl; + cout << "Number of E probes\t: " << m_E_probe_dir.size() << endl; + cout << "Number of H probes\t: " << m_H_probe_dir.size() << endl; +} + diff --git a/openEMS/FDTD/extensions/operator_ext_steadystate.h b/openEMS/FDTD/extensions/operator_ext_steadystate.h new file mode 100644 index 0000000..b735ca3 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_steadystate.h @@ -0,0 +1,61 @@ +/* +* Copyright (C) 2015 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 . +*/ + +#ifndef OPERATOR_EXT_STEADYSTATE_H +#define OPERATOR_EXT_STEADYSTATE_H + +#include "operator_extension.h" +#include "FDTD/operator.h" + +class Engine_Ext_SteadyState; + +class Operator_Ext_SteadyState : public Operator_Extension +{ + friend class Engine_Ext_SteadyState; +public: + Operator_Ext_SteadyState(Operator* op, double period); + virtual ~Operator_Ext_SteadyState(); + + virtual Operator_Extension* Clone(Operator* op); + + virtual bool BuildExtension(); + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return true;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return true;} + virtual bool IsMPISave() const {return true;} + + virtual string GetExtensionName() const {return string("Steady-State Detection Extension");} + + virtual void ShowStat(ostream &ostr) const; + + virtual void Reset(); + + bool Add_E_Probe(unsigned int pos[3], int dir); + bool Add_H_Probe(unsigned int pos[3], int dir); + +protected: + Operator_Ext_SteadyState(Operator* op, Operator_Ext_SteadyState* op_ext); + double m_T_period; + unsigned int m_TS_period; + vector m_E_probe_pos[3]; + vector m_E_probe_dir; + vector m_H_probe_pos[3]; + vector m_H_probe_dir; +}; + +#endif // OPERATOR_EXT_STEADYSTATE_H diff --git a/openEMS/FDTD/extensions/operator_ext_tfsf.cpp b/openEMS/FDTD/extensions/operator_ext_tfsf.cpp new file mode 100644 index 0000000..663dc1f --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_tfsf.cpp @@ -0,0 +1,429 @@ +/* +* Copyright (C) 2012 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 . +*/ + +#include "operator_ext_tfsf.h" +#include "engine_ext_tfsf.h" +#include + +#include "CSPrimBox.h" +#include "CSPropExcitation.h" + +Operator_Ext_TFSF::Operator_Ext_TFSF(Operator* op) : Operator_Extension(op) +{ + Init(); +} + +Operator_Ext_TFSF::~Operator_Ext_TFSF() +{ + Reset(); +} + +void Operator_Ext_TFSF::Init() +{ + for (int n=0;n<3;++n) + for (int l=0;l<2;++l) + for (int c=0;c<2;++c) + { + m_VoltDelay[n][l][c]=NULL; + m_VoltDelayDelta[n][l][c]=NULL; + m_VoltAmp[n][l][c]=NULL; + m_CurrDelay[n][l][c]=NULL; + m_CurrDelayDelta[n][l][c]=NULL; + m_CurrAmp[n][l][c]=NULL; + } + + m_Frequency = 0.0; + m_PhVel = __C0__; + Operator_Extension::Init(); +} + +void Operator_Ext_TFSF::Reset() +{ + for (int n=0;n<3;++n) + for (int l=0;l<2;++l) + for (int c=0;c<2;++c) + { + delete[] m_VoltDelay[n][l][c]; + m_VoltDelay[n][l][c]=NULL; + delete[] m_VoltDelayDelta[n][l][c]; + m_VoltDelayDelta[n][l][c]=NULL; + delete[] m_VoltAmp[n][l][c]; + m_VoltAmp[n][l][c]=NULL; + delete[] m_CurrDelay[n][l][c]; + m_CurrDelay[n][l][c]=NULL; + delete[] m_CurrDelayDelta[n][l][c]; + m_CurrDelayDelta[n][l][c]=NULL; + delete[] m_CurrAmp[n][l][c]; + m_CurrAmp[n][l][c]=NULL; + } + Operator_Extension::Reset(); +} + +Operator_Extension* Operator_Ext_TFSF::Clone(Operator* op) +{ + UNUSED(op); + return NULL; +} + +bool Operator_Ext_TFSF::BuildExtension() +{ + m_Exc = m_Op->GetExcitationSignal(); + double dT = m_Op->GetTimestep(); + if (dT==0) + return false; + if (m_Exc==0) + return false; + + Reset(); + ContinuousStructure* CSX = m_Op->GetGeometryCSX(); + + vector vec_prop = CSX->GetPropertyByType(CSProperties::EXCITATION); + + if (vec_prop.size()==0) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, no excitation properties found" << endl; + SetActive(false); + return false; + } + + double ref_index = sqrt(m_Op->GetBackgroundEpsR()*m_Op->GetBackgroundMueR()); + m_PhVel = __C0__/ref_index; + CSPropExcitation* elec=NULL; + CSProperties* prop=NULL; + CSPrimitives* prim=NULL; + CSPrimBox* box=NULL; + for (size_t p=0; pToExcitation(); + if (elec->GetExcitType()!=10) + continue; + if (prop->GetQtyPrimitives()!=1) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, plane wave excitation found with more (or less) than one primitive, skipping..." << endl; + continue; + } + prim = prop->GetPrimitive(0); + if (prim->GetType()!=CSPrimitives::BOX) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, plane wave excitation found with false non-Box primitive, skipping..." << endl; + continue; + } + box = prim->ToBox(); + if (box==NULL) //sanity check, should not happen! + { + SetActive(false); + return false; + } + + // found a plane-wave excite with exactly one box + for (int n=0;n<3;++n) + m_PropDir[n] = elec->GetPropagationDir(n); + double dir_norm = sqrt(m_PropDir[0]*m_PropDir[0]+m_PropDir[1]*m_PropDir[1]+m_PropDir[2]*m_PropDir[2]); + if (dir_norm==0) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, plane wave direction is zero, skipping..." << endl; + SetActive(false); + return false; + } + + //make it a unit vector + m_PropDir[0]/=dir_norm;m_PropDir[1]/=dir_norm;m_PropDir[2]/=dir_norm; + + if (m_Op->SnapBox2Mesh(box->GetStartCoord()->GetNativeCoords(), box->GetStopCoord()->GetNativeCoords(), m_Start, m_Stop)!=3) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, plane wave box dimension is invalid, skipping..." << endl; + SetActive(false); + return false; + } + + m_Frequency = elec->GetFrequency(); +// if (m_Frequency<=0) +// m_Frequency = m_Op->GetExcitationSignal()->GetFrequencyOfInterest(); + if (m_Frequency<=0) + m_PhVel=__C0__/ref_index; + 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)) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, invalid phase velocity found, resetting to c0! " << endl; + m_PhVel = __C0__/ref_index; + } + + double origin[3]; + unsigned int ui_origin[3]; + for (int n=0;n<3;++n) + { + m_E_Amp[n] = elec->GetExcitation(n); + m_numLines[n] = m_Stop[n]-m_Start[n]+1; + m_IncLow[n] = m_PropDir[n]>=0; + + if (m_Start[n]==0) + m_ActiveDir[n][0]=false; + else + m_ActiveDir[n][0]=true; + if (m_Stop[n]==m_Op->GetNumberOfLines(n,true)-1) + m_ActiveDir[n][1]=false; + else + m_ActiveDir[n][1]=true; + + if (m_IncLow[n]) + { + ui_origin[n] = m_Start[n]-1; + } + else + { + ui_origin[n] = m_Stop[n]+1; + } + origin[n] = m_Op->GetDiscLine(n,ui_origin[n]); + } + + double dotEk = (m_E_Amp[0]*m_PropDir[0] + m_E_Amp[1]*m_PropDir[1] + m_E_Amp[2]*m_PropDir[2]); + double angle = acos( dotEk / (m_E_Amp[0]*m_E_Amp[0] + m_E_Amp[1]*m_E_Amp[1] + m_E_Amp[2]*m_E_Amp[2]) ) / PI * 180; + + if (angle==0) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, plane wave direction and polarization is identical, skipping..." << endl; + SetActive(false); + return false; + } + if (angle!=90) + { + cerr << "Operator_Ext_TFSF::BuildExtension: Warning, angle between propagation direction and polarization is not 90deg, resetting E-polarization to : ("; + for (int n=0;n<3;++n) + m_E_Amp[n]-=m_PropDir[n]*dotEk; + cerr << m_E_Amp[0] << "," << m_E_Amp[1] << "," << m_E_Amp[2] << ")" << endl; + } + + int nP,nPP; + for (int n=0;n<3;++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + m_H_Amp[n] = m_PropDir[nP]*m_E_Amp[nPP] - m_PropDir[nPP]*m_E_Amp[nP]; + m_H_Amp[n] /= __Z0__*sqrt(m_Op->GetBackgroundMueR()/m_Op->GetBackgroundEpsR()); + } + + double coord[3]; + double unit = m_Op->GetGridDelta(); + double delay; + double dist; + unsigned int pos[3]; + unsigned int numP, ui_pos; + m_maxDelay = 0; + for (int n=0;n<3;++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + pos[n] = 0; //unused + pos[nP] = m_Start[nP]; + + numP = m_numLines[nP]*m_numLines[nPP]; + + if (!m_ActiveDir[n][0] && !m_ActiveDir[n][1]) + continue; + + for (int l=0;l<2;++l) + for (int c=0;c<2;++c) + { + if (m_ActiveDir[n][l]) + { + m_VoltDelay[n][l][c]=new unsigned int[numP]; + m_VoltDelayDelta[n][l][c]=new FDTD_FLOAT[numP]; + m_VoltAmp[n][l][c]=new FDTD_FLOAT[numP]; + + m_CurrDelay[n][l][c]=new unsigned int[numP]; + m_CurrDelayDelta[n][l][c]=new FDTD_FLOAT[numP]; + m_CurrAmp[n][l][c]=new FDTD_FLOAT[numP]; + } + } + + ui_pos = 0; + for (unsigned int i=0;iGetYeeCoords(nP,pos,coord,false); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_CurrDelay[n][0][1][ui_pos] = floor(delay); + m_CurrDelayDelta[n][0][1][ui_pos] = delay - floor(delay); + m_CurrAmp[n][0][1][ui_pos] = m_E_Amp[nP]*m_Op->GetEdgeLength(nP,pos); + + m_Op->GetYeeCoords(nPP,pos,coord,false); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_CurrDelay[n][0][0][ui_pos] = floor(delay); + m_CurrDelayDelta[n][0][0][ui_pos] = delay - floor(delay); + m_CurrAmp[n][0][0][ui_pos] = m_E_Amp[nPP]*m_Op->GetEdgeLength(nPP,pos); + + --pos[n]; + m_CurrAmp[n][0][0][ui_pos]*=m_Op->GetIV(nP,pos); + m_CurrAmp[n][0][1][ui_pos]*=m_Op->GetIV(nPP,pos); + } + + if (m_ActiveDir[n][1]) + { + pos[n] = m_Stop[n]; + m_Op->GetYeeCoords(nP,pos,coord,false); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_CurrDelay[n][1][1][ui_pos] = floor(delay); + m_CurrDelayDelta[n][1][1][ui_pos] = delay - floor(delay); + m_CurrAmp[n][1][1][ui_pos] = m_E_Amp[nP]*m_Op->GetEdgeLength(nP,pos); + + m_Op->GetYeeCoords(nPP,pos,coord,false); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_CurrDelay[n][1][0][ui_pos] = floor(delay); + m_CurrDelayDelta[n][1][0][ui_pos] = delay - floor(delay); + m_CurrAmp[n][1][0][ui_pos] = m_E_Amp[nPP]*m_Op->GetEdgeLength(nPP,pos); + + m_CurrAmp[n][1][0][ui_pos]*=m_Op->GetIV(nP,pos); + m_CurrAmp[n][1][1][ui_pos]*=m_Op->GetIV(nPP,pos); + } + + if (m_ActiveDir[n][0]) + m_CurrAmp[n][0][0][ui_pos]*=-1; + if (m_ActiveDir[n][1]) + m_CurrAmp[n][1][1][ui_pos]*=-1; + + if (pos[nP]==m_Stop[nP]) + { + if (m_ActiveDir[n][0]) + m_CurrAmp[n][0][1][ui_pos]=0; + if (m_ActiveDir[n][1]) + m_CurrAmp[n][1][1][ui_pos]=0; + } + if (pos[nPP]==m_Stop[nPP]) + { + if (m_ActiveDir[n][0]) + m_CurrAmp[n][0][0][ui_pos]=0; + if (m_ActiveDir[n][1]) + m_CurrAmp[n][1][0][ui_pos]=0; + } + + // voltage updates + pos[n] = m_Start[n]-1; + if (m_ActiveDir[n][0]) + { + m_Op->GetYeeCoords(nP,pos,coord,true); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT + 1.0; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_VoltDelay[n][0][1][ui_pos] = floor(delay); + m_VoltDelayDelta[n][0][1][ui_pos] = delay - floor(delay); + m_VoltAmp[n][0][1][ui_pos] = m_H_Amp[nP]*m_Op->GetEdgeLength(nP,pos,true); + + m_Op->GetYeeCoords(nPP,pos,coord,true); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT + 1.0; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_VoltDelay[n][0][0][ui_pos] = floor(delay); + m_VoltDelayDelta[n][0][0][ui_pos] = delay - floor(delay); + m_VoltAmp[n][0][0][ui_pos] = m_H_Amp[nPP]*m_Op->GetEdgeLength(nPP,pos,true); + + ++pos[n]; + m_VoltAmp[n][0][0][ui_pos]*=m_Op->GetVI(nP,pos); + m_VoltAmp[n][0][1][ui_pos]*=m_Op->GetVI(nPP,pos); + } + + pos[n] = m_Stop[n]; + if (m_ActiveDir[n][1]) + { + m_Op->GetYeeCoords(nP,pos,coord,true); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT + 1.0; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_VoltDelay[n][1][1][ui_pos] = floor(delay); + m_VoltDelayDelta[n][1][1][ui_pos] = delay - floor(delay); + m_VoltAmp[n][1][1][ui_pos] = m_H_Amp[nP]*m_Op->GetEdgeLength(nP,pos,true); + + m_Op->GetYeeCoords(nPP,pos,coord,true); + dist = fabs((coord[0]-origin[0])*m_PropDir[0])+fabs((coord[1]-origin[1])*m_PropDir[1])+fabs((coord[2]-origin[2])*m_PropDir[2]); + delay = dist*unit/m_PhVel/dT + 1.0; + m_maxDelay = max((unsigned int)delay,m_maxDelay); + m_VoltDelay[n][1][0][ui_pos] = floor(delay); + m_VoltDelayDelta[n][1][0][ui_pos] = delay - floor(delay); + m_VoltAmp[n][1][0][ui_pos] = m_H_Amp[nPP]*m_Op->GetEdgeLength(nPP,pos,true); + + m_VoltAmp[n][1][0][ui_pos]*=m_Op->GetVI(nP,pos); + m_VoltAmp[n][1][1][ui_pos]*=m_Op->GetVI(nPP,pos); + } + + if (m_ActiveDir[n][1]) + m_VoltAmp[n][1][0][ui_pos]*=-1; + if (m_ActiveDir[n][0]) + m_VoltAmp[n][0][1][ui_pos]*=-1; + + if (pos[nP]==m_Stop[nP]) + { + if (m_ActiveDir[n][0]) + m_VoltAmp[n][0][0][ui_pos]=0; + if (m_ActiveDir[n][1]) + m_VoltAmp[n][1][0][ui_pos]=0; + } + if (pos[nPP]==m_Stop[nPP]) + { + if (m_ActiveDir[n][0]) + m_VoltAmp[n][0][1][ui_pos]=0; + if (m_ActiveDir[n][1]) + m_VoltAmp[n][1][1][ui_pos]=0; + } + + ++pos[nPP]; + ++ui_pos; + } + ++pos[nP]; + } + } + ++m_maxDelay; + return true; + } + SetActive(false); + return false; +} + +Engine_Extension* Operator_Ext_TFSF::CreateEngineExtention() +{ + return new Engine_Ext_TFSF(this); +} + +void Operator_Ext_TFSF::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + cout << "Active directions\t: " << "(" << m_ActiveDir[0][0] << "/" << m_ActiveDir[0][1] << ", " << m_ActiveDir[1][0] << "/" << m_ActiveDir[1][1] << ", " << m_ActiveDir[2][0] << "/" << m_ActiveDir[2][1] << ")" << endl; + cout << "Propagation direction\t: " << "(" << m_PropDir[0] << ", " << m_PropDir[1] << ", " << m_PropDir[2] << ")" << endl; + cout << "Rel. propagation speed\t: " << m_PhVel/__C0__ << "*c0 @ " << m_Frequency << " Hz" << endl; + cout << "E-field amplitude (V/m)\t: " << "(" << m_E_Amp[0] << ", " << m_E_Amp[1] << ", " << m_E_Amp[2] << ")" << endl; + cout << "H-field amplitude (A/m)\t: " << "(" << m_H_Amp[0] << ", " << m_H_Amp[1] << ", " << m_H_Amp[2] << ")" << endl; + cout << "Box Dimensions\t\t: " << m_numLines[0] << " x " << m_numLines[1] << " x " << m_numLines[2] << endl; + cout << "Max. Delay (TS)\t\t: " << m_maxDelay << endl; + int dirs = m_ActiveDir[0][0] + m_ActiveDir[0][1] + m_ActiveDir[1][0] + m_ActiveDir[1][1] + m_ActiveDir[2][0] + m_ActiveDir[2][1] ; + cout << "Memory usage (est.)\t: ~" << m_numLines[0] * m_numLines[1] * m_numLines[2] * dirs * 4 * 4 / 1024 << " kiB" << endl; +} diff --git a/openEMS/FDTD/extensions/operator_ext_tfsf.h b/openEMS/FDTD/extensions/operator_ext_tfsf.h new file mode 100644 index 0000000..e1e714e --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_tfsf.h @@ -0,0 +1,82 @@ +/* +* Copyright (C) 2012 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 . +*/ + +#ifndef OPERATOR_EXT_TFSF_H +#define OPERATOR_EXT_TFSF_H + +#include "operator_extension.h" +#include "FDTD/operator.h" +#include "tools/constants.h" + +class Excitation; + +class Operator_Ext_TFSF : public Operator_Extension +{ + friend class Engine_Ext_TFSF; +public: + Operator_Ext_TFSF(Operator* op); + ~Operator_Ext_TFSF(); + + virtual Operator_Extension* Clone(Operator* op); + + virtual bool BuildExtension(); + + virtual Engine_Extension* CreateEngineExtention(); + + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return false;} + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return false;} + + // FIXME, this extension is not save to use with MPI + virtual bool IsMPISave() const {return false;} + + virtual string GetExtensionName() const {return string("Total-Field/Scattered-Field Extension");} + + virtual void ShowStat(ostream &ostr) const; + + virtual void Init(); + virtual void Reset(); + +protected: + Excitation* m_Exc; + + bool m_IncLow[3]; + bool m_ActiveDir[3][2]; // m_ActiveDir[direction][low/high] + unsigned int m_Start[3]; + unsigned int m_Stop[3]; + unsigned int m_numLines[3]; + + double m_PropDir[3]; + double m_E_Amp[3]; + double m_H_Amp[3]; + + double m_Frequency; + double m_PhVel; + + unsigned int m_maxDelay; + + // array setup [direction][low/high][component][ ] + unsigned int* m_VoltDelay[3][2][2]; + FDTD_FLOAT* m_VoltDelayDelta[3][2][2]; + FDTD_FLOAT* m_VoltAmp[3][2][2]; + + unsigned int* m_CurrDelay[3][2][2]; + FDTD_FLOAT* m_CurrDelayDelta[3][2][2]; + FDTD_FLOAT* m_CurrAmp[3][2][2]; + +}; + +#endif // OPERATOR_EXT_TFSF_H diff --git a/openEMS/FDTD/extensions/operator_ext_upml.cpp b/openEMS/FDTD/extensions/operator_ext_upml.cpp new file mode 100644 index 0000000..fc46d85 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_upml.cpp @@ -0,0 +1,478 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "operator_ext_upml.h" +#include "FDTD/operator_cylindermultigrid.h" +#include "engine_ext_upml.h" +#include "tools/array_ops.h" +#include "fparser.hh" + +using namespace std; + +Operator_Ext_UPML::Operator_Ext_UPML(Operator* op) : Operator_Extension(op) +{ + m_GradingFunction = new FunctionParser(); + //default grading function + SetGradingFunction(" -log(1e-6)*log(2.5)/(2*dl*Z*(pow(2.5,W/dl)-1)) * pow(2.5, D/dl) "); + + for (int n=0; n<6; ++n) + { + m_BC[n]=0; + m_Size[n]=0; + } + for (int n=0; n<3; ++n) + { + m_StartPos[n]=0; + m_numLines[n]=0; + } + + vv = NULL; + vvfo = NULL; + vvfn = NULL; + ii = NULL; + iifo = NULL; + iifn = NULL; +} + +Operator_Ext_UPML::~Operator_Ext_UPML() +{ + delete m_GradingFunction; + m_GradingFunction = NULL; + DeleteOp(); +} + +void Operator_Ext_UPML::SetBoundaryCondition(const int* BCs, const unsigned int size[6]) +{ + for (int n=0; n<6; ++n) + { + m_BC[n]=BCs[n]; + m_Size[n]=size[n]; + } +} + +void Operator_Ext_UPML::SetRange(const unsigned int start[3], const unsigned int stop[3]) +{ + for (int n=0; n<3; ++n) + { + m_StartPos[n]=start[n]; + m_numLines[n]=stop[n]-start[n]+1; + } +} + +bool Operator_Ext_UPML::Create_UPML(Operator* op, const int ui_BC[6], const unsigned int ui_size[6], string gradFunc) +{ + int BC[6]={ui_BC[0],ui_BC[1],ui_BC[2],ui_BC[3],ui_BC[4],ui_BC[5]}; + unsigned int size[6]={ui_size[0],ui_size[1],ui_size[2],ui_size[3],ui_size[4],ui_size[5]}; + + //check if mesh is large enough to support the pml + for (int n=0; n<3; ++n) + if ( (size[2*n]*(BC[2*n]==3)+size[2*n+1]*(BC[2*n+1]==3)) >= op->GetNumberOfLines(n,true) ) + { + cerr << "Operator_Ext_UPML::Create_UPML: Warning: Not enough lines in direction: " << n << ", resetting to PEC" << endl; + BC[2*n]=0; + size[2*n]=0; + BC[2*n+1]=0; + size[2*n+1]=0; + } + + //check cylindrical coord compatiblility + Operator_Cylinder* op_cyl = dynamic_cast(op); + if (op_cyl) + { + if ((BC[0]==3) && (op_cyl->GetClosedAlpha() || op_cyl->GetR0Included())) + { + BC[0]=0; + size[0]=0; + cerr << "Operator_Ext_UPML::Create_UPML: Warning: An upml in r-min direction is not possible, resetting to PEC..." << endl; + } + if ( (BC[2]==3) && (op_cyl->GetClosedAlpha()) ) + { + BC[2]=0; + size[2]=0; + cerr << "Operator_Ext_UPML::Create_UPML: Warning: An upml in alpha-min direction is not possible, resetting to PEC..." << endl; + } + if ( (BC[3]==3) && (op_cyl->GetClosedAlpha()) ) + { + BC[3]=0; + size[3]=0; + cerr << "Operator_Ext_UPML::Create_UPML: Warning: An upml in alpha-max direction is not possible, resetting to PEC..." << endl; + } + } + + //check cylindrical coord compatiblility + if (dynamic_cast(op)) + { + if (BC[2]==3) + { + BC[2]=0; + size[2]=0; + cerr << "Operator_Ext_UPML::Create_UPML: Warning: An upml in alpha direction is not possible for a cylindrical multi-grid, resetting to PEC..." << endl; + } + if (BC[3]==3) + { + BC[3]=0; + size[3]=0; + cerr << "Operator_Ext_UPML::Create_UPML: Warning: An upml in alpha direction is not possible for a cylindrical multi-grid, resetting to PEC..." << endl; + } + } + + + Operator_Ext_UPML* op_ext_upml=NULL; + unsigned int start[3]={0 ,0 ,0}; + unsigned int stop[3] ={op->GetNumberOfLines(0,true)-1,op->GetNumberOfLines(1,true)-1,op->GetNumberOfLines(2,true)-1}; + + //create a pml in x-direction over the full width of yz-space + if (BC[0]==3) + { + op_ext_upml = new Operator_Ext_UPML(op); + op_ext_upml->SetGradingFunction(gradFunc); + start[0]=0; + stop[0] =size[0]; + op_ext_upml->SetBoundaryCondition(BC, size); + op_ext_upml->SetRange(start,stop); + op->AddExtension(op_ext_upml); + } + if (BC[1]==3) + { + op_ext_upml = new Operator_Ext_UPML(op); + op_ext_upml->SetGradingFunction(gradFunc); + start[0]=op->GetNumberOfLines(0,true)-1-size[1]; + stop[0] =op->GetNumberOfLines(0,true)-1; + op_ext_upml->SetBoundaryCondition(BC, size); + op_ext_upml->SetRange(start,stop); + op->AddExtension(op_ext_upml); + } + + //create a pml in y-direction over the xz-space (if a pml in x-direction already exists, skip that corner regions) + start[0]=(size[0]+1)*(BC[0]==3); + stop[0] =op->GetNumberOfLines(0,true)-1-(size[0]+1)*(BC[1]==3); + + if (BC[2]==3) + { + op_ext_upml = new Operator_Ext_UPML(op); + op_ext_upml->SetGradingFunction(gradFunc); + start[1]=0; + stop[1] =size[2]; + op_ext_upml->SetBoundaryCondition(BC, size); + op_ext_upml->SetRange(start,stop); + op->AddExtension(op_ext_upml); + } + if (BC[3]==3) + { + op_ext_upml = new Operator_Ext_UPML(op); + op_ext_upml->SetGradingFunction(gradFunc); + start[1]=op->GetNumberOfLines(1,true)-1-size[3]; + stop[1] =op->GetNumberOfLines(1,true)-1; + op_ext_upml->SetBoundaryCondition(BC, size); + op_ext_upml->SetRange(start,stop); + op->AddExtension(op_ext_upml); + } + + //create a pml in z-direction over the xy-space (if a pml in x- and/or y-direction already exists, skip that corner/edge regions) + start[1]=(size[2]+1)*(BC[2]==3); + stop[1] =op->GetNumberOfLines(1,true)-1-(size[3]+1)*(BC[3]==3); + + //exclude x-lines that does not belong to the base multi-grid operator; + Operator_CylinderMultiGrid* op_cyl_MG = dynamic_cast(op); + if (op_cyl_MG) + start[0] = op_cyl_MG->GetSplitPos()-1; + + if (BC[4]==3) + { + op_ext_upml = new Operator_Ext_UPML(op); + op_ext_upml->SetGradingFunction(gradFunc); + start[2]=0; + stop[2] =size[4]; + op_ext_upml->SetBoundaryCondition(BC, size); + op_ext_upml->SetRange(start,stop); + op->AddExtension(op_ext_upml); + } + if (BC[5]==3) + { + op_ext_upml = new Operator_Ext_UPML(op); + op_ext_upml->SetGradingFunction(gradFunc); + start[2]=op->GetNumberOfLines(2,true)-1-size[5]; + stop[2] =op->GetNumberOfLines(2,true)-1; + op_ext_upml->SetBoundaryCondition(BC, size); + op_ext_upml->SetRange(start,stop); + op->AddExtension(op_ext_upml); + } + + BC[1]=0; + size[1]=0; + //create pml extensions (in z-direction only) for child operators in cylindrical multigrid operators + while (op_cyl_MG) + { + Operator_Cylinder* op_child = op_cyl_MG->GetInnerOperator(); + op_cyl_MG = dynamic_cast(op_child); + for (int n=0; n<2; ++n) + { + start[n]=0; + stop[n]=op_child->GetNumberOfLines(n,true)-1; + } + + if (op_cyl_MG) + start[0] = op_cyl_MG->GetSplitPos()-1; + + if (BC[4]==3) + { + op_ext_upml = new Operator_Ext_UPML(op_child); + op_ext_upml->SetGradingFunction(gradFunc); + start[2]=0; + stop[2] =size[4]; + op_ext_upml->SetBoundaryCondition(BC, size); + op_ext_upml->SetRange(start,stop); + op_child->AddExtension(op_ext_upml); + } + if (BC[5]==3) + { + op_ext_upml = new Operator_Ext_UPML(op_child); + op_ext_upml->SetGradingFunction(gradFunc); + start[2]=op->GetNumberOfLines(2,true)-1-size[5]; + stop[2] =op->GetNumberOfLines(2,true)-1; + op_ext_upml->SetBoundaryCondition(BC, size); + op_ext_upml->SetRange(start,stop); + op_child->AddExtension(op_ext_upml); + } + } + + return true; +} + + +void Operator_Ext_UPML::DeleteOp() +{ + Delete_N_3DArray(vv,m_numLines); + vv = NULL; + Delete_N_3DArray(vvfo,m_numLines); + vvfo = NULL; + Delete_N_3DArray(vvfn,m_numLines); + vvfn = NULL; + Delete_N_3DArray(ii,m_numLines); + ii = NULL; + Delete_N_3DArray(iifo,m_numLines); + iifo = NULL; + Delete_N_3DArray(iifn,m_numLines); + iifn = NULL; +} + + +bool Operator_Ext_UPML::SetGradingFunction(string func) +{ + if (func.empty()) + return true; + + m_GradFunc = func; + int res = m_GradingFunction->Parse(m_GradFunc.c_str(), "D,dl,W,Z,N"); + if (res < 0) return true; + + cerr << "Operator_Ext_UPML::SetGradingFunction: Warning, an error occured parsing the pml grading function (see below) ..." << endl; + cerr << func << "\n" << string(res, ' ') << "^\n" << m_GradingFunction->ErrorMsg() << "\n"; + return false; +} + +void Operator_Ext_UPML::CalcGradingKappa(int ny, unsigned int pos[3], double Zm, double kappa_v[3], double kappa_i[3]) +{ + double depth=0; + double width=0; + for (int n=0; n<3; ++n) + { + if ((pos[n] <= m_Size[2*n]) && (m_BC[2*n]==3)) //lower pml in n-dir + { + width = (m_Op->GetDiscLine(n,m_Size[2*n]) - m_Op->GetDiscLine(n,0))*m_Op->GetGridDelta(); + depth = width - (m_Op->GetDiscLine(n,pos[n]) - m_Op->GetDiscLine(n,0))*m_Op->GetGridDelta(); + + if ((m_Op_Cyl) && (n==1)) + { + width *= m_Op_Cyl->GetDiscLine(0,pos[0]); + depth *= m_Op_Cyl->GetDiscLine(0,pos[0]); + } + + if (n==ny) + depth-=m_Op->GetEdgeLength(n,pos)/2; + double vars[5] = {depth, width/m_Size[2*n], width, Zm, (double)m_Size[2*n]}; + if (depth>0) + kappa_v[n] = m_GradingFunction->Eval(vars); + else + kappa_v[n]=0; + if (n==ny) + depth+=m_Op->GetEdgeLength(n,pos)/2; + + if (n!=ny) + depth-=m_Op->GetEdgeLength(n,pos)/2; + if (depth<0) + depth=0; + vars[0]=depth; + if (depth>0) + kappa_i[n] = m_GradingFunction->Eval(vars); + else + kappa_i[n] = 0; + } + else if ((pos[n] >= m_Op->GetNumberOfLines(n,true) -1 -m_Size[2*n+1]) && (m_BC[2*n+1]==3)) //upper pml in n-dir + { + width = (m_Op->GetDiscLine(n,m_Op->GetNumberOfLines(n,true)-1) - m_Op->GetDiscLine(n,m_Op->GetNumberOfLines(n,true)-m_Size[2*n+1]-1))*m_Op->GetGridDelta(); + depth = width - (m_Op->GetDiscLine(n,m_Op->GetNumberOfLines(n,true)-1) - m_Op->GetDiscLine(n,pos[n]))*m_Op->GetGridDelta(); + + if ((m_Op_Cyl) && (n==1)) + { + width *= m_Op_Cyl->GetDiscLine(0,pos[0]); + depth *= m_Op_Cyl->GetDiscLine(0,pos[0]); + } + + if (n==ny) + depth+=m_Op->GetEdgeLength(n,pos)/2; + double vars[5] = {depth, width/(m_Size[2*n]), width, Zm, (double)m_Size[2*n]}; + if (depth>0) + kappa_v[n] = m_GradingFunction->Eval(vars); + else + kappa_v[n]=0; + if (n==ny) + depth-=m_Op->GetEdgeLength(n,pos)/2; + + if (n!=ny) + depth+=m_Op->GetEdgeLength(n,pos)/2; + if (depth>width) + depth=0; + vars[0]=depth; + if (depth>0) + kappa_i[n] = m_GradingFunction->Eval(vars); + else + kappa_i[n]=0; + } + else + { + kappa_v[n] = 0; + kappa_i[n] = 0; + } + } +} + +bool Operator_Ext_UPML::BuildExtension() +{ + /*Calculate the upml coefficients as defined in: + Allen Taflove, computational electrodynamics - the FDTD method, third edition, chapter 7.8, pages 297-300 + - modified by Thorsten Liebig to match the equivalent circuit (EC) FDTD method + - kappa is used for conductivities (instead of sigma) + */ + if (m_Op==NULL) + return false; + + DeleteOp(); + vv = Create_N_3DArray(m_numLines); + vvfo = Create_N_3DArray(m_numLines); + vvfn = Create_N_3DArray(m_numLines); + ii = Create_N_3DArray(m_numLines); + iifo = Create_N_3DArray(m_numLines); + iifn = Create_N_3DArray(m_numLines); + + unsigned int pos[3]; + unsigned int loc_pos[3]; + int nP,nPP; + double kappa_v[3]={0,0,0}; + double kappa_i[3]={0,0,0}; + double eff_Mat[4]; + double dT = m_Op->GetTimestep(); + + for (loc_pos[0]=0; loc_pos[0] vPrims = m_Op->GetPrimitivesBoundBox(pos[0], pos[1], -1, CSProperties::MATERIAL); + for (loc_pos[2]=0; loc_pos[2]Calc_EffMatPos(n,pos,eff_Mat,vPrims); + CalcGradingKappa(n, pos,__Z0__ ,kappa_v ,kappa_i); + nP = (n+1)%3; + nPP = (n+2)%3; + if ((kappa_v[0]+kappa_v[1]+kappa_v[2])!=0) + { + //check if pos is on PEC + if ( (m_Op->GetVV(n,pos[0],pos[1],pos[2]) + m_Op->GetVI(n,pos[0],pos[1],pos[2])) != 0 ) + { + //modify the original operator to perform eq. (7.85) by the main engine (EC-FDTD: equation is multiplied by delta_n) + //the engine extension will replace the original voltages with the "voltage flux" (volt*eps0) prior to the voltage updates + //after the updates are done the extension will calculate the new voltages (see below) and place them back into the main field domain + m_Op->SetVV(n,pos[0],pos[1],pos[2], (2*__EPS0__ - kappa_v[nP]*dT) / (2*__EPS0__ + kappa_v[nP]*dT) ); + m_Op->SetVI(n,pos[0],pos[1],pos[2], (2*__EPS0__*dT) / (2*__EPS0__ + kappa_v[nP]*dT) * m_Op->GetEdgeLength(n,pos) / m_Op->GetEdgeArea(n,pos) ); + + + //operators needed by eq. (7.88) to calculate new voltages from old voltages and old and new "voltage fluxes" + GetVV(n,loc_pos) = (2*__EPS0__ - kappa_v[nPP]*dT) / (2*__EPS0__ + kappa_v[nPP]*dT); + GetVVFN(n,loc_pos) = (2*__EPS0__ + kappa_v[n]*dT) / (2*__EPS0__ + kappa_v[nPP]*dT)/eff_Mat[0]; + GetVVFO(n,loc_pos) = (2*__EPS0__ - kappa_v[n]*dT) / (2*__EPS0__ + kappa_v[nPP]*dT)/eff_Mat[0]; + } + } + else + { + //disable upml + GetVV(n,loc_pos) = m_Op->GetVV(n,pos[0],pos[1],pos[2]); + m_Op->SetVV(n,pos[0],pos[1],pos[2], 0 ); + GetVVFO(n,loc_pos) = 0; + GetVVFN(n,loc_pos) = 1; + } + + if ((kappa_i[0]+kappa_i[1]+kappa_i[2])!=0) + { + //check if pos is on PMC + if ( (m_Op->GetII(n,pos[0],pos[1],pos[2]) + m_Op->GetIV(n,pos[0],pos[1],pos[2])) != 0 ) + { + //modify the original operator to perform eq. (7.89) by the main engine (EC-FDTD: equation is multiplied by delta_n) + //the engine extension will replace the original currents with the "current flux" (curr*mu0) prior to the current updates + //after the updates are done the extension will calculate the new currents (see below) and place them back into the main field domain + m_Op->SetII(n,pos[0],pos[1],pos[2], (2*__EPS0__ - kappa_i[nP]*dT) / (2*__EPS0__ + kappa_i[nP]*dT) ); + m_Op->SetIV(n,pos[0],pos[1],pos[2], (2*__EPS0__*dT) / (2*__EPS0__ + kappa_i[nP]*dT) * m_Op->GetEdgeLength(n,pos,true) / m_Op->GetEdgeArea(n,pos,true) ); + + //operators needed by eq. (7.90) to calculate new currents from old currents and old and new "current fluxes" + GetII(n,loc_pos) = (2*__EPS0__ - kappa_i[nPP]*dT) / (2*__EPS0__ + kappa_i[nPP]*dT); + GetIIFN(n,loc_pos) = (2*__EPS0__ + kappa_i[n]*dT) / (2*__EPS0__ + kappa_i[nPP]*dT)/eff_Mat[2]; + GetIIFO(n,loc_pos) = (2*__EPS0__ - kappa_i[n]*dT) / (2*__EPS0__ + kappa_i[nPP]*dT)/eff_Mat[2]; + } + } + else + { + //disable upml + GetII(n,loc_pos) = m_Op->GetII(n,pos[0],pos[1],pos[2]); + m_Op->SetII(n,pos[0],pos[1],pos[2], 0 ); + GetIIFO(n,loc_pos) = 0; + GetIIFN(n,loc_pos) = 1; + } + } + } + } + } + return true; +} + +Engine_Extension* Operator_Ext_UPML::CreateEngineExtention() +{ + Engine_Ext_UPML* eng_ext = new Engine_Ext_UPML(this); + return eng_ext; +} + +void Operator_Ext_UPML::ShowStat(ostream &ostr) const +{ + Operator_Extension::ShowStat(ostr); + + ostr << " PML range\t\t: " << "[" << m_StartPos[0]<< "," << m_StartPos[1]<< "," << m_StartPos[2]<< "] to [" + << m_StartPos[0]+m_numLines[0]-1 << "," << m_StartPos[1]+m_numLines[1]-1 << "," << m_StartPos[2]+m_numLines[2]-1 << "]" << endl; + ostr << " Grading function\t: \"" << m_GradFunc << "\"" << endl; +} diff --git a/openEMS/FDTD/extensions/operator_ext_upml.h b/openEMS/FDTD/extensions/operator_ext_upml.h new file mode 100644 index 0000000..5256655 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_ext_upml.h @@ -0,0 +1,106 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef OPERATOR_EXT_UPML_H +#define OPERATOR_EXT_UPML_H + +#include "FDTD/operator.h" +#include "operator_extension.h" + +class FunctionParser; + +//! Operator extension implemention an uniaxial perfectly matched layer (upml) +/* + The priority for this extension should be the highest of all extensions since this operator will use the main engine to perform vital parts in the upml implementation. + Therefore the voltages and currents as well as the operator are replaced during these update process. + This extension is propably incompatible with the most other extensions operating in the same regions. + */ +class Operator_Ext_UPML : public Operator_Extension +{ + friend class Engine_Ext_UPML; +public: + virtual ~Operator_Ext_UPML(); + + //! Returns always true, Create_UPML method will take care of creating a valid pml for the cylindrical fdtd + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const { UNUSED(closedAlpha); UNUSED(R0_included); return true;} + + //! Returns always true if base grid, Create_UPML will create proper child pml extensions. + virtual bool IsCylindricalMultiGridSave(bool child) const {if (child) return false; return true;} + + virtual bool IsMPISave() const {return true;} + + void SetBoundaryCondition(const int* BCs, const unsigned int size[6]); + + void SetRange(const unsigned int start[3], const unsigned int stop[3]); + + //! Set the grading function for the pml + /*! + Define the pml grading grading function. + Predefined variables in this grading function are: + D = depth in the pml in meter + dl = mesh delta inside the pml in meter + W = width (length) of the pml in meter + N = number of cells for the pml + Z = wave impedance at the current depth and position + example: SetGradingFunction(" -log(1e-6)*log(2.5)/(2*dl*Z*(pow(2.5,W/dl)-1)) * pow(2.5, D/dl) "); + + An empty function string will be ignored. + */ + virtual bool SetGradingFunction(string func); + + virtual bool BuildExtension(); + + virtual Engine_Extension* CreateEngineExtention(); + + virtual string GetExtensionName() const {return string("Uniaxial PML Extension");} + + virtual void ShowStat(ostream &ostr) const; + + //! Create the UPML + static bool Create_UPML(Operator* op, const int ui_BC[6], const unsigned int ui_size[6], const string gradFunc); + +protected: + Operator_Ext_UPML(Operator* op); + int m_BC[6]; + unsigned int m_Size[6]; + + unsigned int m_StartPos[3]; + unsigned int m_numLines[3]; + + string m_GradFunc; + FunctionParser* m_GradingFunction; + + void CalcGradingKappa(int ny, unsigned int pos[3], double Zm, double kappa_v[3], double kappa_i[3]); + + void DeleteOp(); + + virtual FDTD_FLOAT& GetVV(int ny, unsigned int pos[3]) {return vv[ny][pos[0]][pos[1]][pos[2]];} + virtual FDTD_FLOAT& GetVVFO(int ny, unsigned int pos[3]) {return vvfo[ny][pos[0]][pos[1]][pos[2]];} + virtual FDTD_FLOAT& GetVVFN(int ny, unsigned int pos[3]) {return vvfn[ny][pos[0]][pos[1]][pos[2]];} + virtual FDTD_FLOAT& GetII(int ny, unsigned int pos[3]) {return ii[ny][pos[0]][pos[1]][pos[2]];} + virtual FDTD_FLOAT& GetIIFO(int ny, unsigned int pos[3]) {return iifo[ny][pos[0]][pos[1]][pos[2]];} + virtual FDTD_FLOAT& GetIIFN(int ny, unsigned int pos[3]) {return iifn[ny][pos[0]][pos[1]][pos[2]];} + + FDTD_FLOAT**** vv; //calc new voltage from old voltage + FDTD_FLOAT**** vvfo; //calc new voltage from old voltage flux + FDTD_FLOAT**** vvfn; //calc new voltage from new voltage flux + FDTD_FLOAT**** ii; //calc new current from old current + FDTD_FLOAT**** iifo; //calc new current from old current flux + FDTD_FLOAT**** iifn; //calc new current from new current flux +}; + +#endif // OPERATOR_EXT_UPML_H diff --git a/openEMS/FDTD/extensions/operator_extension.cpp b/openEMS/FDTD/extensions/operator_extension.cpp new file mode 100644 index 0000000..50e7068 --- /dev/null +++ b/openEMS/FDTD/extensions/operator_extension.cpp @@ -0,0 +1,54 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "operator_extension.h" +#include "FDTD/operator.h" +#include "FDTD/operator_cylinder.h" + +using namespace std; + +Operator_Extension::Operator_Extension(Operator* op) +{ + m_Op = op; + m_Active = true; + + m_CC_R0_included = false; + m_Op_Cyl = dynamic_cast(op); + if (m_Op_Cyl) + m_CC_R0_included=m_Op_Cyl->GetR0Included(); + m_Eng_Ext = NULL; +} + +Operator_Extension::~Operator_Extension() +{ +} + +Operator_Extension::Operator_Extension(Operator* op, Operator_Extension* op_ext) +{ + UNUSED(op_ext); + m_Op = op; + m_Op_Cyl = dynamic_cast(op); + m_Active = op_ext->m_Active; + if (m_Op_Cyl) + m_CC_R0_included=m_Op_Cyl->GetR0Included(); + m_Eng_Ext = NULL; +} + +void Operator_Extension::ShowStat(ostream &ostr) const +{ + ostr << "--- " << GetExtensionName() << " ---" << endl; +} diff --git a/openEMS/FDTD/extensions/operator_extension.h b/openEMS/FDTD/extensions/operator_extension.h new file mode 100644 index 0000000..21e42af --- /dev/null +++ b/openEMS/FDTD/extensions/operator_extension.h @@ -0,0 +1,87 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef OPERATOR_EXTENSION_H +#define OPERATOR_EXTENSION_H + +#include + +#include +#include +#include + +#include "tools/global.h" + +class Operator; +class Operator_Cylinder; +class Engine_Extension; + +//! Abstract base-class for all operator extensions +class Operator_Extension +{ + friend class Engine_Extension; +public: + virtual ~Operator_Extension(); + + //! Create a clone of this extension, will return NULL if this is impossible + /*! + Create a clone of this extension, will return NULL if this is impossible (e.g. derived extension has no clone method and copy-constructor)... + BuildExtension has to be called separatly! + */ + virtual Operator_Extension* Clone(Operator* op) {UNUSED(op); return NULL;} + + virtual bool BuildExtension() {return true;} + + virtual Engine_Extension* CreateEngineExtention() {return 0;} + virtual Engine_Extension* GetEngineExtention() {return m_Eng_Ext;} + + //! The cylindrical operator will check whether the extension is save to use. Default is false. Derive this method to override. + virtual bool IsCylinderCoordsSave(bool closedAlpha, bool R0_included) const {UNUSED(closedAlpha); UNUSED(R0_included); return false;} + + //! The cylindrical multi grid operator will check whether the extension is save to use. Default is false. Derive this method to override. + virtual bool IsCylindricalMultiGridSave(bool child) const {UNUSED(child); return false;} + + //! The MPI operator (if enabled) will check whether the extension is compatible with MPI. Default is false. Derive this method to override. + virtual bool IsMPISave() const {return false;} + + virtual std::string GetExtensionName() const {return std::string("Abstract Operator Extension Base Class");} + + virtual void ShowStat(std::ostream &ostr) const; + + virtual bool IsActive() const {return m_Active;} + virtual void SetActive(bool active=true) {m_Active=active;} + + virtual void Init() {} + virtual void Reset() {} + +protected: + Operator_Extension(Operator* op); + //! Copy constructor + Operator_Extension(Operator* op, Operator_Extension* op_ext); + + bool m_Active; + + //FDTD Operator + Operator* m_Op; + Engine_Extension* m_Eng_Ext; + + //Cylindrical FDTD Operator (not NULL if a cylindrical FDTD is used) + Operator_Cylinder* m_Op_Cyl; + bool m_CC_R0_included; +}; + +#endif // OPERATOR_EXTENSION_H diff --git a/openEMS/FDTD/openems_fdtd_mpi.cpp b/openEMS/FDTD/openems_fdtd_mpi.cpp new file mode 100644 index 0000000..964bdd4 --- /dev/null +++ b/openEMS/FDTD/openems_fdtd_mpi.cpp @@ -0,0 +1,546 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "openems_fdtd_mpi.h" +#include "FDTD/engine_interface_fdtd.h" +#include "FDTD/operator_mpi.h" +#include "FDTD/operator_cylinder.h" +#include "FDTD/engine_mpi.h" +#include "Common/processfields.h" +#include "Common/processintegral.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpi.h" +#include "tools/useful.h" +#include "tinyxml.h" + +openEMS_FDTD_MPI::openEMS_FDTD_MPI(bool m_MPI_Debug) : openEMS() +{ + m_MyID = MPI::COMM_WORLD.Get_rank(); + m_NumProc = MPI::COMM_WORLD.Get_size(); + + m_MaxEnergy = 0; + m_EnergyDecrement = 1; + m_MPI_Op = NULL; + + if (m_NumProc>1) + m_MPI_Enabled=true; + else + m_MPI_Enabled=false; + + if (m_MyID==0) + { + m_Gather_Buffer = new int[m_NumProc]; + m_Energy_Buffer = new double[m_NumProc]; + } + else + { + m_Gather_Buffer = NULL; + m_Energy_Buffer = NULL; + } + + m_MPI_Elem = NULL; + m_Original_Grid = NULL; + + //redirect output to file for all ranks > 0 + if ((m_MyID>0) && (m_MPI_Debug==false)) + { + stringstream out_name; + out_name << "ID" << m_MyID << "_" << "output.txt"; + m_Output = new ofstream(); + m_Output->open(out_name.str().c_str()); + cout.rdbuf(m_Output->rdbuf()); + cerr.rdbuf(m_Output->rdbuf()); + } + else + m_Output = NULL; +} + +openEMS_FDTD_MPI::~openEMS_FDTD_MPI() +{ + delete[] m_Gather_Buffer; + m_Gather_Buffer = NULL; + delete[] m_Energy_Buffer; + m_Energy_Buffer = NULL; + delete m_Original_Grid; + m_Original_Grid = NULL; + delete m_Output; + m_Output=NULL; +} + +string openEMS_FDTD_MPI::GetExtLibsInfo() +{ + stringstream str; + + str << openEMS::GetExtLibsInfo(); + + // MPI + str << "\t\t" << "MPI -- Version: " << MPI_VERSION << "." << MPI_SUBVERSION << endl; + str << "\t\t" << " compiled against: "; +#ifdef MPICH2_VERSION + str << "MPICH2 " << MPICH2_VERSION << endl; +#endif + +#ifdef OMPI_MAJOR_VERSION + str << "openMPI" << OMPI_MAJOR_VERSION << "." << OMPI_MINOR_VERSION << "." << OMPI_RELEASE_VERSION << endl; +#endif + + return str.str(); +} + + +bool openEMS_FDTD_MPI::parseCommandLineArgument( const char *argv ) +{ + if (!argv) + return false; + + bool ret = openEMS::parseCommandLineArgument( argv ); + + if (ret) + return ret; + + if (strcmp(argv,"--engine=MPI")==0) + { + cout << "openEMS_FDTD_MPI - enabled MPI parallel processing" << endl; + m_engine = EngineType_MPI; + return true; + } + + return false; +} + +bool openEMS_FDTD_MPI::Parse_XML_FDTDSetup(TiXmlElement* FDTD_Opts) +{ + m_MPI_Elem = FDTD_Opts->FirstChildElement("MPI"); + if (!m_MPI_Enabled) + { + if ((m_MPI_Elem!=NULL)) + cerr << "openEMS_FDTD_MPI::SetupMPI: Warning: Number of MPI processes is 1, skipping MPI engine... " << endl; + return openEMS::Parse_XML_FDTDSetup(FDTD_Opts); + } + + if (m_MPI_Elem==NULL) + { + MPI_Barrier(MPI_COMM_WORLD); + if (m_MyID==0) + cerr << "openEMS_FDTD_MPI::SetupMPI: Error: no MPI settings found, exiting MPI engine... " << endl; + exit(-1); + } + + CSRectGrid* grid = m_CSX->GetGrid(); + delete m_Original_Grid; + m_Original_Grid = CSRectGrid::Clone(grid); + + string arg_Pos_Names[] = {"SplitPos_X", "SplitPos_Y", "SplitPos_Z"}; + string arg_N_Names[] = {"SplitN_X", "SplitN_Y", "SplitN_Z"}; + const char* tmp = NULL; + for (int n=0;n<3;++n) + { + m_SplitNumber[n].clear(); + m_SplitNumber[n].push_back(0); + tmp = m_MPI_Elem->Attribute(arg_Pos_Names[n].c_str()); + if (tmp) //check if a split position is requested + { + vector SplitLines = SplitString2Double(tmp, ','); + bool inside; + unsigned int line; + for (size_t lineN = 0; lineNSnap2LineNumber(n, SplitLines.at(lineN), inside); + if (inside) + m_SplitNumber[n].push_back(line); + } + } + else //check if a number of splits is requested + { + int SplitN=0; + if (m_MPI_Elem->QueryIntAttribute( arg_N_Names[n].c_str(), &SplitN) == TIXML_SUCCESS) + { + if (SplitN>1) + { + + vector jobs = AssignJobs2Threads(m_Original_Grid->GetQtyLines(n)-1, SplitN, true); + unsigned int line=0; + for (size_t i = 0; iGetQtyLines(n)-1); + unique(m_SplitNumber[n].begin(), m_SplitNumber[n].end()); + } + + return openEMS::Parse_XML_FDTDSetup(FDTD_Opts); +} + +bool openEMS_FDTD_MPI::SetupMPI() +{ + if (!m_MPI_Enabled) + return true; + + MPI_Barrier(MPI_COMM_WORLD); + + //validate number of processes + unsigned int numProcs = (m_SplitNumber[0].size()-1)*(m_SplitNumber[1].size()-1)*(m_SplitNumber[2].size()-1); + if (numProcs!=m_NumProc) + { + if (m_MyID==0) + cerr << "openEMS_FDTD_MPI::SetupMPI: Error: Requested splits require " << numProcs << " processes, but " << m_NumProc << " were found! Exit! " << endl; + exit(10); + } + + //create process table + unsigned int procN = 0; + unsigned int splits[] = {(unsigned int)m_SplitNumber[0].size()-1, (unsigned int)m_SplitNumber[1].size()-1, (unsigned int)m_SplitNumber[2].size()-1}; + m_MPI_Op->SetSplitNumbers(0,splits[0]); + m_MPI_Op->SetSplitNumbers(1,splits[1]); + m_MPI_Op->SetSplitNumbers(2,splits[2]); + unsigned int*** procTable=Create3DArray(splits); + for (size_t i=0;iSetProcessTable(procTable); + + CSRectGrid* grid = m_CSX->GetGrid(); + //assign mesh and neighbors to this process + for (size_t i=0;iSetProcessTablePosition(0,i); + m_MPI_Op->SetProcessTablePosition(1,j); + m_MPI_Op->SetProcessTablePosition(2,k); + + grid->ClearLines(0); + grid->ClearLines(1); + grid->ClearLines(2); + + for (unsigned int n=m_SplitNumber[0].at(i);n<=m_SplitNumber[0].at(i+1);++n) + grid->AddDiscLine(0, m_Original_Grid->GetLine(0,n) ); + for (unsigned int n=m_SplitNumber[1].at(j);n<=m_SplitNumber[1].at(j+1);++n) + grid->AddDiscLine(1, m_Original_Grid->GetLine(1,n) ); + for (unsigned int n=m_SplitNumber[2].at(k);n<=m_SplitNumber[2].at(k+1);++n) + grid->AddDiscLine(2, m_Original_Grid->GetLine(2,n) ); + + m_MPI_Op->SetSplitPos(0,m_SplitNumber[0].at(i)); + m_MPI_Op->SetSplitPos(1,m_SplitNumber[1].at(j)); + m_MPI_Op->SetSplitPos(2,m_SplitNumber[2].at(k)); + + if (i>0) + m_MPI_Op->SetNeighborDown(0,procTable[i-1][j][k]); + if (iAddDiscLine(0, m_Original_Grid->GetLine(0,m_SplitNumber[0].at(i+1)+1 )); + m_MPI_Op->SetNeighborUp(0,procTable[i+1][j][k]); + } + + if (j>0) + m_MPI_Op->SetNeighborDown(1,procTable[i][j-1][k]); + if (jAddDiscLine(1, m_Original_Grid->GetLine(1,m_SplitNumber[1].at(j+1)+1 )); + m_MPI_Op->SetNeighborUp(1,procTable[i][j+1][k]); + } + + if (k>0) + m_MPI_Op->SetNeighborDown(2,procTable[i][j][k-1]); + if (kAddDiscLine(2, m_Original_Grid->GetLine(2,m_SplitNumber[2].at(k+1)+1 )); + m_MPI_Op->SetNeighborUp(2,procTable[i][j][k+1]); + } + + } + } + } + } + + m_MPI_Op->SetOriginalMesh(m_Original_Grid); + + m_MPI_Op->SetTag(0); + + return true; +} + + +bool openEMS_FDTD_MPI::SetupOperator() +{ + bool ret = true; + if (m_engine == EngineType_MPI) + { + FDTD_Op = Operator_MPI::New(); + } + else + { + ret = openEMS::SetupOperator(); + } + + m_MPI_Op = dynamic_cast(FDTD_Op); + + if ((m_MPI_Enabled) && (m_MPI_Op==NULL)) + { + cerr << "openEMS_FDTD_MPI::SetupOperator: Error: MPI is enabled but requested engine does not support MPI... EXIT!!!" << endl; + MPI_Barrier(MPI_COMM_WORLD); + exit(0); + } + + ret &= SetupMPI(); + + return ret; +} + +unsigned int openEMS_FDTD_MPI::GetNextStep() +{ + //start processing and get local next step + int step=PA->Process(); + double currTS = FDTD_Eng->GetNumberOfTimesteps(); + if ((step<0) || (step>(int)(NrTS - currTS))) step=NrTS - currTS; + + int local_step=step; + + //find the smallest next step requestes by all processings + MPI_Reduce(&local_step, &step, 1, MPI_INT, MPI_MIN, 0, MPI_COMM_WORLD); + //send the smallest next step to all + MPI_Bcast(&step, 1, MPI_INT, 0, MPI_COMM_WORLD); + + return step; +} + +bool openEMS_FDTD_MPI::CheckEnergyCalc() +{ + int local_Check = (int)m_ProcField->CheckTimestep(); + int result; + + //check if some process request an energy calculation --> the sum is larger than 0 + MPI_Reduce(&local_Check, &result, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); + //send result to all + MPI_Bcast(&result, 1, MPI_INT, 0, MPI_COMM_WORLD); + + //calc energy if result is non-zero + return result>0; +} + +double openEMS_FDTD_MPI::CalcEnergy() +{ + double energy = 0; + double loc_energy= m_ProcField->CalcTotalEnergyEstimate(); + + //calc the sum of all local energies + MPI_Reduce(&loc_energy, &energy, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD); + //send sum-energy to all processes + MPI_Bcast(&energy, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if (energy>m_MaxEnergy) + m_MaxEnergy = energy; + if (m_MaxEnergy) + m_EnergyDecrement = energy/m_MaxEnergy; + + return energy; +} + +bool openEMS_FDTD_MPI::SetupProcessing() +{ + bool ret = openEMS::SetupProcessing(); + + //search for active processings in different processes + size_t numProc = PA->GetNumberOfProcessings(); + int active=0; + bool deactivate = false; + bool rename = false; + for (size_t n=0;nGetProcessing(n); + int isActive = (int)proc->GetEnable(); + //sum of all active processings + MPI_Reduce(&isActive, &active, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); + deactivate = false; + rename = false; + if ((m_MyID==0) && (active>1)) //more than one active processing... + { + deactivate = true; //default + if (dynamic_cast(proc)!=NULL) + { + //type is integral processing --> disable! Needs to be fixed! + cerr << "openEMS_FDTD_MPI::SetupProcessing(): Warning: Processing: " << proc->GetName() << " occures multiple times and is being deactivated..." << endl; + cerr << "openEMS_FDTD_MPI::SetupProcessing(): Note: Processing: Make sure that there are no splits inside probes or sources." << endl; + deactivate = true; + rename = false; + } + if (dynamic_cast(proc)!=NULL) + { + //type is field processing --> renameing! Needs to be fixed! + cerr << "openEMS_FDTD_MPI::SetupProcessing(): Warning: Processing: " << proc->GetName() << " occures multiple times and is being renamed..." << endl; + deactivate = false; + rename = true; + } + } + //broadcast informations to all + MPI_Bcast(&deactivate, 1, MPI::BOOL, 0, MPI_COMM_WORLD); + MPI_Bcast(&rename, 1, MPI::BOOL, 0, MPI_COMM_WORLD); + if (deactivate) + proc->SetEnable(false); + if (rename) + { + ProcessFields* ProcField = dynamic_cast(proc); + if (ProcField) + { + stringstream name_ss; + name_ss << "ID" << m_MyID << "_" << ProcField->GetName(); + ProcField->SetName(name_ss.str()); + ProcField->SetFileName(name_ss.str()); + } + } + } + return ret; +} + +int openEMS_FDTD_MPI::SetupFDTD() +{ + return openEMS::SetupFDTD(); +} + +void openEMS_FDTD_MPI::RunFDTD() +{ + if (!m_MPI_Enabled) + return openEMS::RunFDTD(); + + cout << "Running MPI-FDTD engine... this may take a while... grab a cup of coffee?!?" << endl; + + //get the sum of all cells + unsigned int local_NrCells=FDTD_Op->GetNumberCells(); + MPI_Reduce(&local_NrCells, &m_NumberCells, 1, MPI_UNSIGNED, MPI_SUM, 0, MPI_COMM_WORLD); + MPI_Bcast(&m_NumberCells, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD); + + //special handling of a field processing, needed to realize the end criteria... + m_ProcField = new ProcessFields(NewEngineInterface()); + PA->AddProcessing(m_ProcField); + + //init processings + PA->InitAll(); + + double currE=0; + + //add all timesteps to end-crit field processing with max excite amplitude + unsigned int maxExcite = FDTD_Op->GetExcitationSignal()->GetMaxExcitationTimestep(); +// for (unsigned int n=0; nExc->Volt_Count; ++n) +// m_ProcField->AddStep(FDTD_Op->Exc->Volt_delay[n]+maxExcite); + m_ProcField->AddStep(maxExcite); + + int prevTS=0,currTS=0; + double numCells = FDTD_Op->GetNumberCells(); + double speed = 0; + double t_diff; + double t_run; + + timeval currTime; + gettimeofday(&currTime,NULL); + timeval startTime = currTime; + timeval prevTime= currTime; + + if (m_DumpStats) + InitRunStatistics(__OPENEMS_RUN_STAT_FILE__); + //*************** simulate ************// + PA->PreProcess(); + int step = GetNextStep(); + + while ((step>0) && !CheckAbortCond()) + { + FDTD_Eng->IterateTS(step); + step = GetNextStep(); + + currTS = FDTD_Eng->GetNumberOfTimesteps(); + + currE = 0; + gettimeofday(&currTime,NULL); + t_diff = CalcDiffTime(currTime,prevTime); + + if (CheckEnergyCalc()) + currE = CalcEnergy(); + + //make sure all processes are at the same simulation time + MPI_Bcast(&t_diff, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + if (t_diff>4) + { + if (currE==0) + currE = CalcEnergy(); + if (m_MyID==0) + { + t_run = CalcDiffTime(currTime,startTime); + speed = numCells*(currTS-prevTS)/t_diff; + cout << "[@" << FormatTime(t_run) << "] Timestep: " << setw(12) << currTS ; + cout << " || Speed: " << setw(6) << setprecision(1) << std::fixed << speed*1e-6 << " MC/s (" << setw(4) << setprecision(3) << std::scientific << t_diff/(currTS-prevTS) << " s/TS)" ; + cout << " || Energy: ~" << setw(6) << setprecision(2) << std::scientific << currE << " (-" << setw(5) << setprecision(2) << std::fixed << fabs(10.0*log10(m_EnergyDecrement)) << "dB)" << endl; + + //set step to zero to abort simulation and send to all + if (m_EnergyDecrementFlushNext(); + } + } + if ((m_MyID==0) && (m_EnergyDecrement>endCrit) && (FDTD_Op->GetExcitationSignal()->GetExciteType()==0)) + cerr << "RunFDTD: max. number of timesteps was reached before the end-criteria of -" << fabs(10.0*log10(endCrit)) << "dB was reached... " << endl << \ + "\tYou may want to choose a higher number of max. timesteps... " << endl; + + gettimeofday(&currTime,NULL); + + t_diff = CalcDiffTime(currTime,startTime); + + if (m_MyID==0) + { + cout << "Time for " << FDTD_Eng->GetNumberOfTimesteps() << " iterations with " << FDTD_Op->GetNumberCells() << " cells : " << t_diff << " sec" << endl; + cout << "Speed: " << numCells*(double)FDTD_Eng->GetNumberOfTimesteps()/t_diff*1e-6 << " MCells/s " << endl; + + if (m_DumpStats) + DumpStatistics(__OPENEMS_STAT_FILE__, t_diff); + } + + //*************** postproc ************// + PA->PostProcess(); +} diff --git a/openEMS/FDTD/openems_fdtd_mpi.h b/openEMS/FDTD/openems_fdtd_mpi.h new file mode 100644 index 0000000..efb1f00 --- /dev/null +++ b/openEMS/FDTD/openems_fdtd_mpi.h @@ -0,0 +1,72 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#ifndef OPENEMS_FDTD_MPI_H +#define OPENEMS_FDTD_MPI_H + +#include "openems.h" + +class ProcessFields; +class Operator_MPI; +class CSRectGrid; + +class openEMS_FDTD_MPI : public openEMS +{ +public: + openEMS_FDTD_MPI(bool m_MPI_Debug=false); + virtual ~openEMS_FDTD_MPI(); + + virtual bool Parse_XML_FDTDSetup(TiXmlElement* FDTD_Opts); + virtual int SetupFDTD(); + virtual void RunFDTD(); + + virtual bool parseCommandLineArgument( const char *argv ); + + static std::string GetExtLibsInfo(); + +protected: + Operator_MPI* m_MPI_Op; + CSRectGrid* m_Original_Grid; + unsigned int m_MyID; + unsigned int m_NumProc; + bool m_MPI_Enabled; + unsigned int m_NumberCells; + + std::vector m_SplitNumber[3]; + TiXmlElement* m_MPI_Elem; + virtual bool SetupMPI(); + virtual bool SetupOperator(); + + int* m_Gather_Buffer; + unsigned int GetNextStep(); + + ProcessFields* m_ProcField; + double m_MaxEnergy; + double m_EnergyDecrement; + double* m_Energy_Buffer; + //! Check if energy calc is requested... + bool CheckEnergyCalc(); + //! Calc energy in all processes and add up + double CalcEnergy(); + + virtual bool SetupProcessing(); + + //output redirection to file for ranks > 0 + std::ofstream* m_Output; +}; + +#endif // OPENEMS_FDTD_MPI_H diff --git a/openEMS/FDTD/operator.cpp b/openEMS/FDTD/operator.cpp new file mode 100644 index 0000000..a7582aa --- /dev/null +++ b/openEMS/FDTD/operator.cpp @@ -0,0 +1,2131 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include +#include +#include "operator.h" +#include "engine.h" +#include "extensions/operator_extension.h" +#include "extensions/operator_ext_excitation.h" +#include "Common/processfields.h" +#include "tools/array_ops.h" +#include "tools/vtk_file_writer.h" +#include "fparser.hh" +#include "extensions/operator_ext_excitation.h" + +#include "vtkPolyData.h" +#include "vtkCellArray.h" +#include "vtkPoints.h" +#include "vtkXMLPolyDataWriter.h" +#include "CSPrimBox.h" +#include "CSPrimCurve.h" + +#include "CSPropMaterial.h" +#include "CSPropLumpedElement.h" + +Operator* Operator::New() +{ + cout << "Create FDTD operator" << endl; + Operator* op = new Operator(); + op->Init(); + return op; +} + +Operator::Operator() : Operator_Base() +{ + m_Exc = 0; + m_InvaildTimestep = false; + m_TimeStepVar = 3; +} + +Operator::~Operator() +{ + for (size_t n=0; n2)) return 0.0; + if (pos>=numLines[n]) return 0.0; + if (dualMesh==false) + return discLines[n][pos]; + + // return dual mesh node + if (pos2)) return 0.0; + if (pos>=numLines[n]) return 0.0; + double delta=0; + if (dualMesh==false) + { + if (pos0) + delta = GetDiscLine(n,pos,true) - GetDiscLine(n,pos-1,true); + else + delta = GetDiscLine(n,1,false) - GetDiscLine(n,0,false); + return delta; + } +} + +bool Operator::GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const +{ + for (int n=0;n<3;++n) + coords[n]=GetDiscLine(n,pos[n],dualMesh); + coords[ny]=GetDiscLine(ny,pos[ny],!dualMesh); + + //check if position is inside the FDTD domain + if (dualMesh==false) //main grid + { + if (pos[ny]>=numLines[ny]-1) + return false; + } + else //dual grid + { + int nP = (ny+1)%3; + int nPP = (ny+2)%3; + if ((pos[nP]>=numLines[nP]-1) || (pos[nPP]>=numLines[nPP]-1)) + return false; + } + return true; +} + +bool Operator::GetNodeCoords(const unsigned int pos[3], double* coords, bool dualMesh, CoordinateSystem c_system) const +{ + for (int n=0;n<3;++n) + coords[n]=GetDiscLine(n,pos[n],dualMesh); + TransformCoordSystem(coords,coords,m_MeshType,c_system); + return true; +} + +double Operator::GetEdgeLength(int n, const unsigned int* pos, bool dualMesh) const +{ + return GetDiscDelta(n,pos[n],dualMesh)*gridDelta; +} + +double Operator::GetCellVolume(const unsigned int pos[3], bool dualMesh) const +{ + double vol=1; + for (int n=0;n<3;++n) + vol*=GetEdgeLength(n,pos,dualMesh); + return vol; +} + +double Operator::GetNodeWidth(int ny, const int pos[3], bool dualMesh) const +{ + if ( (pos[0]<0) || (pos[1]<0) || (pos[2]<0) ) + return 0.0; + + //call the unsigned int version of GetNodeWidth + unsigned int uiPos[]={(unsigned int)pos[0],(unsigned int)pos[1],(unsigned int)pos[2]}; + return GetNodeWidth(ny, uiPos, dualMesh); +} + +double Operator::GetNodeArea(int ny, const unsigned int pos[3], bool dualMesh) const +{ + int nyP = (ny+1)%3; + int nyPP = (ny+2)%3; + return GetNodeWidth(nyP,pos,dualMesh) * GetNodeWidth(nyPP,pos,dualMesh); +} + +double Operator::GetNodeArea(int ny, const int pos[3], bool dualMesh) const +{ + if ( (pos[0]<0) || (pos[1]<0) || (pos[2]<0) ) + return 0.0; + + //call the unsigned int version of GetNodeArea + unsigned int uiPos[]={(unsigned int)pos[0],(unsigned int)pos[1],(unsigned int)pos[2]}; + return GetNodeArea(ny, uiPos, dualMesh); +} + +unsigned int Operator::SnapToMeshLine(int ny, double coord, bool &inside, bool dualMesh, bool fullMesh) const +{ + inside = false; + if ((ny<0) || (ny>2)) + return 0; + if (coordGetDiscLine(ny,numLines-1)) + return numLines-1; + inside=true; + if (dualMesh==false) + { + for (unsigned int n=0;nmax) && (l_stop[n]>max)) ) + { + return -2; + } + } + + SnapToMesh(l_start, uiStart, dualMesh, fullMesh, bStartIn); + SnapToMesh(l_stop, uiStop, dualMesh, fullMesh, bStopIn); + int iDim = 0; + + if (SnapMethod==0) + { + for (int n=0;n<3;++n) + if (uiStop[n]>uiStart[n]) + ++iDim; + return iDim; + } + else if (SnapMethod==1) + { + for (int n=0;n<3;++n) + { + if (uiStop[n]>uiStart[n]) + { + if ((GetDiscLine( n, uiStart[n], dualMesh ) > l_start[n]) && (uiStart[n]>0)) + --uiStart[n]; + if ((GetDiscLine( n, uiStop[n], dualMesh ) < l_stop[n]) && (uiStop[n]uiStart[n]) + ++iDim; + } + return iDim; + } + else if (SnapMethod==2) + { + for (int n=0;n<3;++n) + { + if (uiStop[n]>uiStart[n]) + { + if ((GetDiscLine( n, uiStart[n], dualMesh ) < l_start[n]) && (uiStart[n] l_stop[n]) && (uiStop[n]>0)) + --uiStop[n]; + } + if (uiStop[n]>uiStart[n]) + ++iDim; + } + return iDim; + } + else + cerr << "Operator::SnapBox2Mesh: Unknown snapping method!" << endl; + return -1; +} + +int Operator::SnapLine2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh, bool fullMesh) const +{ + bool bStartIn[3]; + bool bStopIn[3]; + SnapToMesh(start, uiStart, dualMesh, fullMesh, bStartIn); + SnapToMesh(stop, uiStop, dualMesh, fullMesh, bStopIn); + + for (int n=0;n<3;++n) + { + if ((start[n]GetDiscLine(n,GetNumberOfLines(n,true)-1)) && (stop[n]>GetDiscLine(n,GetNumberOfLines(n,true)-1))) + return -1; //upper bound violation + } + + int ret = 0; + if (!(bStartIn[0] && bStartIn[1] && bStartIn[2])) + ret = ret + 1; + if (!(bStopIn[0] && bStopIn[1] && bStopIn[2])) + ret = ret + 2; + if (ret==0) + return ret; + + //fixme, do we need to do something about start or stop being outside the field domain? + //maybe caclulate the intersection point and snap to that? + //it seems to work like this as well... + + return ret; +} + + +Grid_Path Operator::FindPath(double start[], double stop[]) +{ + Grid_Path path; + unsigned int uiStart[3],uiStop[3],currPos[3]; + + int ret = SnapLine2Mesh(start, stop, uiStart, uiStop, false, true); + if (ret<0) + return path; + + currPos[0]=uiStart[0]; + currPos[1]=uiStart[1]; + currPos[2]=uiStart[2]; + double meshStart[3] = {discLines[0][uiStart[0]], discLines[1][uiStart[1]], discLines[2][uiStart[2]]}; + double meshStop[3] = {discLines[0][uiStop[0]], discLines[1][uiStop[1]], discLines[2][uiStop[2]]}; + bool UpDir = false; + double foot=0,dist=0,minFoot=0,minDist=0; + int minDir=0; + unsigned int minPos[3]; + double startFoot,stopFoot,currFoot; + Point_Line_Distance(meshStart,start,stop,startFoot,dist, m_MeshType); + Point_Line_Distance(meshStop,start,stop,stopFoot,dist, m_MeshType); + currFoot=startFoot; + minFoot=startFoot; + double P[3]; + + while (minFoot=0) + { + P[n] = discLines[n][currPos[n]-1]; + Point_Line_Distance(P,start,stop,foot,dist, m_MeshType); + if ((foot>currFoot) && (distcurrFoot) && (dist=numLines[n]) + { + cerr << __func__ << ": Error, path went out of simulation domain, skipping path!" << endl; + Grid_Path empty; + return empty; + } + path.posPath[0].push_back(minPos[0]); + path.posPath[1].push_back(minPos[1]); + path.posPath[2].push_back(minPos[2]); + currFoot=minFoot; + path.dir.push_back(minDir); + } + + //close missing edges, if currPos is not equal to uiStopPos + for (int n=0; n<3; ++n) + { + if (currPos[n]>uiStop[n]) + { + --currPos[n]; + path.posPath[0].push_back(currPos[0]); + path.posPath[1].push_back(currPos[1]); + path.posPath[2].push_back(currPos[2]); + path.dir.push_back(n); + } + else if (currPos[n]GetNyquistNum() << endl; + cout << "Nyquist criteria (s)\t: " << m_Exc->GetNyquistNum()*dT << endl; + cout << "-----------------------------------" << endl; +} + +void Operator::ShowExtStat() const +{ + if (m_Op_exts.size()==0) return; + cout << "-----------------------------------" << endl; + for (size_t n=0; nShowStat(cout); + cout << "-----------------------------------" << endl; +} + +void Operator::DumpOperator2File(string filename) +{ +#ifdef OUTPUT_IN_DRAWINGUNITS + double discLines_scaling = 1; +#else + double discLines_scaling = GetGridDelta(); +#endif + + cout << "Operator: Dumping FDTD operator information to vtk file: " << filename << " ..." << flush; + + VTK_File_Writer* vtk_Writer = new VTK_File_Writer(filename.c_str(), m_MeshType); + vtk_Writer->SetMeshLines(discLines,numLines,discLines_scaling); + vtk_Writer->SetHeader("openEMS - Operator dump"); + + vtk_Writer->SetNativeDump(true); + + //find excitation extension + Operator_Ext_Excitation* Op_Ext_Exc=GetExcitationExtension(); + + if (Op_Ext_Exc) + { + FDTD_FLOAT**** exc = NULL; + if (Op_Ext_Exc->Volt_Count>0) + { + exc = Create_N_3DArray(numLines); + for (unsigned int n=0; n< Op_Ext_Exc->Volt_Count; ++n) + exc[ Op_Ext_Exc->Volt_dir[n]][ Op_Ext_Exc->Volt_index[0][n]][ Op_Ext_Exc->Volt_index[1][n]][ Op_Ext_Exc->Volt_index[2][n]] = Op_Ext_Exc->Volt_amp[n]; + vtk_Writer->AddVectorField("exc_volt",exc); + Delete_N_3DArray(exc,numLines); + } + + if ( Op_Ext_Exc->Curr_Count>0) + { + exc = Create_N_3DArray(numLines); + for (unsigned int n=0; n< Op_Ext_Exc->Curr_Count; ++n) + exc[ Op_Ext_Exc->Curr_dir[n]][ Op_Ext_Exc->Curr_index[0][n]][ Op_Ext_Exc->Curr_index[1][n]][ Op_Ext_Exc->Curr_index[2][n]] = Op_Ext_Exc->Curr_amp[n]; + vtk_Writer->AddVectorField("exc_curr",exc); + Delete_N_3DArray(exc,numLines); + } + } + + FDTD_FLOAT**** vv_temp = Create_N_3DArray(numLines); + FDTD_FLOAT**** vi_temp = Create_N_3DArray(numLines); + FDTD_FLOAT**** iv_temp = Create_N_3DArray(numLines); + FDTD_FLOAT**** ii_temp = Create_N_3DArray(numLines); + + unsigned int pos[3], n; + for (n=0; n<3; n++) + for (pos[0]=0; pos[0]AddVectorField("vv",vv_temp); + Delete_N_3DArray(vv_temp,numLines); + vtk_Writer->AddVectorField("vi",vi_temp); + Delete_N_3DArray(vi_temp,numLines); + vtk_Writer->AddVectorField("iv",iv_temp); + Delete_N_3DArray(iv_temp,numLines); + vtk_Writer->AddVectorField("ii",ii_temp); + Delete_N_3DArray(ii_temp,numLines); + + if (vtk_Writer->Write()==false) + cerr << "Operator::DumpOperator2File: Error: Can't write file... skipping!" << endl; + + delete vtk_Writer; +} + +//! \brief dump PEC (perfect electric conductor) information (into VTK-file) +//! visualization via paraview +//! visualize only one component (x, y or z) +void Operator::DumpPEC2File(string filename , unsigned int *range) +{ + cout << "Operator: Dumping PEC information to vtk file: " << filename << " ..." << flush; + +#ifdef OUTPUT_IN_DRAWINGUNITS + double scaling = 1.0; +#else + double scaling = GetGridDelta();; +#endif + + unsigned int start[3] = {0, 0, 0}; + unsigned int stop[3] = {numLines[0]-1,numLines[1]-1,numLines[2]-1}; + + if (range!=NULL) + for (int n=0;n<3;++n) + { + start[n] = range[2*n]; + stop[n] = range[2*n+1]; + } + + vtkPolyData* polydata = vtkPolyData::New(); + vtkCellArray *poly = vtkCellArray::New(); + vtkPoints *points = vtkPoints::New(); + + int* pointIdx[2]; + pointIdx[0] = new int[numLines[0]*numLines[1]]; + pointIdx[1] = new int[numLines[0]*numLines[1]]; + // init point idx + for (unsigned int n=0;n0) && (pos[nPP]>0)) + { + rpos[0]=pos[0]; + rpos[1]=pos[1]; + rpos[2]=pos[2]; + + poly->InsertNextCell(2); + + mesh_idx = rpos[0] + rpos[1]*numLines[0]; + if (pointIdx[0][mesh_idx]<0) + { + for (int m=0;m<3;++m) + coord[m] = discLines[m][rpos[m]]; + TransformCoordSystem(coord, coord, m_MeshType, CARTESIAN); + for (int m=0;m<3;++m) + coord[m] *= scaling; + pointIdx[0][mesh_idx] = (int)points->InsertNextPoint(coord); + } + poly->InsertCellPoint(pointIdx[0][mesh_idx]); + + ++rpos[n]; + mesh_idx = rpos[0] + rpos[1]*numLines[0]; + if (pointIdx[n==2][mesh_idx]<0) + { + for (int m=0;m<3;++m) + coord[m] = discLines[m][rpos[m]]; + TransformCoordSystem(coord, coord, m_MeshType, CARTESIAN); + for (int m=0;m<3;++m) + coord[m] *= scaling; + pointIdx[n==2][mesh_idx] = (int)points->InsertNextPoint(coord); + } + poly->InsertCellPoint(pointIdx[n==2][mesh_idx]); + } + } + } + } + delete[] pointIdx[0]; + delete[] pointIdx[1]; + + polydata->SetPoints(points); + points->Delete(); + polydata->SetLines(poly); + poly->Delete(); + + vtkXMLPolyDataWriter* writer = vtkXMLPolyDataWriter::New(); + filename += ".vtp"; + writer->SetFileName(filename.c_str()); + +#if VTK_MAJOR_VERSION>=6 + writer->SetInputData(polydata); +#else + writer->SetInput(polydata); +#endif + writer->Write(); + + writer->Delete(); + polydata->Delete(); + cout << " done." << endl; +} + +void Operator::DumpMaterial2File(string filename) +{ +#ifdef OUTPUT_IN_DRAWINGUNITS + double discLines_scaling = 1; +#else + double discLines_scaling = GetGridDelta(); +#endif + + cout << "Operator: Dumping material information to vtk file: " << filename << " ..." << flush; + + FDTD_FLOAT**** epsilon = Create_N_3DArray(numLines); + FDTD_FLOAT**** mue = Create_N_3DArray(numLines); + FDTD_FLOAT**** kappa = Create_N_3DArray(numLines); + FDTD_FLOAT**** sigma = Create_N_3DArray(numLines); + + unsigned int pos[3]; + for (pos[0]=0; pos[0] vPrims = this->GetPrimitivesBoundBox(pos[0], pos[1], -1, CSProperties::MATERIAL); + for (pos[2]=0; pos[2]SetMeshLines(discLines,numLines,discLines_scaling); + vtk_Writer->SetHeader("openEMS - material dump"); + + vtk_Writer->SetNativeDump(true); + + vtk_Writer->AddVectorField("epsilon",epsilon); + Delete_N_3DArray(epsilon,numLines); + vtk_Writer->AddVectorField("mue",mue); + Delete_N_3DArray(mue,numLines); + vtk_Writer->AddVectorField("kappa",kappa); + Delete_N_3DArray(kappa,numLines); + vtk_Writer->AddVectorField("sigma",sigma); + Delete_N_3DArray(sigma,numLines); + + if (vtk_Writer->Write()==false) + cerr << "Operator::DumpMaterial2File: Error: Can't write file... skipping!" << endl; + + delete vtk_Writer; +} + + bool Operator::SetupCSXGrid(CSRectGrid* grid) + { + for (int n=0; n<3; ++n) + { + discLines[n] = grid->GetLines(n,discLines[n],numLines[n],true); + if (numLines[n]<3) + { + cerr << "CartOperator::SetupCSXGrid: you need at least 3 disc-lines in every direction (3D!)!!!" << endl; + Reset(); + return false; + } + } + MainOp = new AdrOp(numLines[0],numLines[1],numLines[2]); + MainOp->SetGrid(discLines[0],discLines[1],discLines[2]); + if (grid->GetDeltaUnit()<=0) + { + cerr << "CartOperator::SetupCSXGrid: grid delta unit must not be <=0 !!!" << endl; + Reset(); + return false; + } + else gridDelta=grid->GetDeltaUnit(); + MainOp->SetGridDelta(1); + MainOp->AddCellAdrOp(); + + //delete the grid clone... + delete grid; + return true; + } + +bool Operator::SetGeometryCSX(ContinuousStructure* geo) +{ + if (geo==NULL) return false; + + CSX = geo; + + CSBackgroundMaterial* bg_mat=CSX->GetBackgroundMaterial(); + SetBackgroundEpsR(bg_mat->GetEpsilon()); + SetBackgroundMueR(bg_mat->GetMue()); + SetBackgroundKappa(bg_mat->GetKappa()); + SetBackgroundSigma(bg_mat->GetSigma()); + SetBackgroundDensity(0); + + CSRectGrid* grid=CSX->GetGrid(); + return SetupCSXGrid(CSRectGrid::Clone(grid)); +} + +void Operator::InitOperator() +{ + Delete_N_3DArray(vv,numLines); + Delete_N_3DArray(vi,numLines); + Delete_N_3DArray(iv,numLines); + Delete_N_3DArray(ii,numLines); + vv = Create_N_3DArray(numLines); + vi = Create_N_3DArray(numLines); + iv = Create_N_3DArray(numLines); + ii = Create_N_3DArray(numLines); +} + +void Operator::InitDataStorage() +{ + if (m_StoreMaterial[0]) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::InitDataStorage(): Storing epsR material data..." << endl; + Delete_N_3DArray(m_epsR,numLines); + m_epsR = Create_N_3DArray(numLines); + } + if (m_StoreMaterial[1]) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::InitDataStorage(): Storing kappa material data..." << endl; + Delete_N_3DArray(m_kappa,numLines); + m_kappa = Create_N_3DArray(numLines); + } + if (m_StoreMaterial[2]) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::InitDataStorage(): Storing muR material data..." << endl; + Delete_N_3DArray(m_mueR,numLines); + m_mueR = Create_N_3DArray(numLines); + } + if (m_StoreMaterial[3]) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::InitDataStorage(): Storing sigma material data..." << endl; + Delete_N_3DArray(m_sigma,numLines); + m_sigma = Create_N_3DArray(numLines); + } +} + +void Operator::CleanupMaterialStorage() +{ + if (!m_StoreMaterial[0] && m_epsR) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::CleanupMaterialStorage(): Delete epsR material data..." << endl; + Delete_N_3DArray(m_epsR,numLines); + m_epsR = NULL; + } + if (!m_StoreMaterial[1] && m_kappa) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::CleanupMaterialStorage(): Delete kappa material data..." << endl; + Delete_N_3DArray(m_kappa,numLines); + m_kappa = NULL; + } + if (!m_StoreMaterial[2] && m_mueR) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::CleanupMaterialStorage(): Delete mueR material data..." << endl; + Delete_N_3DArray(m_mueR,numLines); + m_mueR = NULL; + } + if (!m_StoreMaterial[3] && m_sigma) + { + if (g_settings.GetVerboseLevel()>0) + cerr << "Operator::CleanupMaterialStorage(): Delete sigma material data..." << endl; + Delete_N_3DArray(m_sigma,numLines); + m_sigma = NULL; + } +} + +double Operator::GetDiscMaterial(int type, int n, const unsigned int pos[3]) const +{ + switch (type) + { + case 0: + if (m_epsR==0) + return 0; + return m_epsR[n][pos[0]][pos[1]][pos[2]]; + case 1: + if (m_kappa==0) + return 0; + return m_kappa[n][pos[0]][pos[1]][pos[2]]; + case 2: + if (m_mueR==0) + return 0; + return m_mueR[n][pos[0]][pos[1]][pos[2]]; + case 3: + if (m_sigma==0) + return 0; + return m_sigma[n][pos[0]][pos[1]][pos[2]]; + } + return 0; +} + +void Operator::SetExcitationSignal(Excitation* exc) +{ + m_Exc=exc; +} + +void Operator::Calc_ECOperatorPos(int n, unsigned int* pos) +{ + unsigned int i = MainOp->SetPos(pos[0],pos[1],pos[2]); + double C = EC_C[n][i]; + double G = EC_G[n][i]; + if (C>0) + { + SetVV(n,pos[0],pos[1],pos[2], (1.0-dT*G/2.0/C)/(1.0+dT*G/2.0/C) ); + SetVI(n,pos[0],pos[1],pos[2], (dT/C)/(1.0+dT*G/2.0/C) ); + } + else + { + SetVV(n,pos[0],pos[1],pos[2], 0 ); + SetVI(n,pos[0],pos[1],pos[2], 0 ); + } + + double L = EC_L[n][i]; + double R = EC_R[n][i]; + if (L>0) + { + SetII(n,pos[0],pos[1],pos[2], (1.0-dT*R/2.0/L)/(1.0+dT*R/2.0/L) ); + SetIV(n,pos[0],pos[1],pos[2], (dT/L)/(1.0+dT*R/2.0/L) ); + } + else + { + SetII(n,pos[0],pos[1],pos[2], 0 ); + SetIV(n,pos[0],pos[1],pos[2], 0 ); + } +} + +int Operator::CalcECOperator( DebugFlags debugFlags ) +{ + Init_EC(); + InitDataStorage(); + + if (Calc_EC()==0) + return -1; + + m_InvaildTimestep = false; + opt_dT = 0; + if (dT>0) + { + double save_dT = dT; + CalcTimestep(); + opt_dT = dT; + if (dTGetSignalPeriod()>0) + { + unsigned int TS = ceil(m_Exc->GetSignalPeriod()/dT); + double new_dT = m_Exc->GetSignalPeriod()/TS; + cout << "Operartor::CalcECOperator: Decreasing timestep by " << round((dT-new_dT)/dT*1000)/10.0 << "% to " << new_dT << " (" << dT << ") to match periodic signal" << endl; + dT = new_dT; + } + + m_Exc->Reset(dT); + + InitOperator(); + + unsigned int pos[3]; + + for (int n=0; n<3; ++n) + { + for (pos[0]=0; pos[0]BuildExtension(); + + //remove inactive extensions + vector::iterator it = m_Op_exts.begin(); + while (it!=m_Op_exts.end()) + { + if ( (*it)->IsActive() == false) + { + DeleteExtension((*it)); + it = m_Op_exts.begin(); //restart search for inactive extension + } + else + ++it; + } + + if (debugFlags & debugMaterial) + DumpMaterial2File( "material_dump" ); + if (debugFlags & debugOperator) + DumpOperator2File( "operator_dump" ); + if (debugFlags & debugPEC) + DumpPEC2File( "PEC_dump" ); + + //cleanup + for (int n=0; n<3; ++n) + { + delete[] EC_C[n]; + EC_C[n]=NULL; + delete[] EC_G[n]; + EC_G[n]=NULL; + delete[] EC_L[n]; + EC_L[n]=NULL; + delete[] EC_R[n]; + EC_R[n]=NULL; + } + + return 0; +} + +void Operator::ApplyElectricBC(bool* dirs) +{ + if (!dirs) + return; + + unsigned int pos[3]; + for (int n=0; n<3; ++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + for (pos[nP]=0; pos[nP] vPrims) const +{ + double EffMat[4]; + Calc_EffMatPos(ny,pos,EffMat, vPrims); + + if (m_epsR) + m_epsR[ny][pos[0]][pos[1]][pos[2]] = EffMat[0]; + if (m_kappa) + m_kappa[ny][pos[0]][pos[1]][pos[2]] = EffMat[1]; + if (m_mueR) + m_mueR[ny][pos[0]][pos[1]][pos[2]] = EffMat[2]; + if (m_sigma) + m_sigma[ny][pos[0]][pos[1]][pos[2]] = EffMat[3]; + + double delta = GetEdgeLength(ny,pos); + double area = GetEdgeArea(ny,pos); + +// if (isnan(EffMat[0])) +// { +// cerr << ny << " " << pos[0] << " " << pos[1] << " " << pos[2] << " : " << EffMat[0] << endl; +// } + + if (delta) + { + EC[0] = EffMat[0] * area/delta; + EC[1] = EffMat[1] * area/delta; + } + else + { + EC[0] = 0; + EC[1] = 0; + } + + delta = GetEdgeLength(ny,pos,true); + area = GetEdgeArea(ny,pos,true); + + if (delta) + { + EC[2] = EffMat[2] * area/delta; + EC[3] = EffMat[3] * area/delta; + } + else + { + EC[2] = 0; + EC[3] = 0; + } + + return true; +} + +double Operator::GetRawDiscDelta(int ny, const int pos) const +{ + //numLines[ny] is expected to be larger then 1 ! + + if (pos<0) + return (discLines[ny][0] - discLines[ny][1]); + if (pos>=(int)numLines[ny]-1) + return (discLines[ny][numLines[ny]-2] - discLines[ny][numLines[ny]-1]); + + return (discLines[ny][pos+1] - discLines[ny][pos]); +} + +bool Operator::GetCellCenterMaterialAvgCoord(const int pos[], double coord[3]) const +{ + unsigned int ui_pos[3]; + for (int n=0;n<3;++n) + { + if ((pos[n]<0) || (pos[n]>=(int)numLines[n])) + return false; + ui_pos[n] = pos[n]; + } + GetNodeCoords(ui_pos, coord, true); + return true; +} + +double Operator::GetMaterial(int ny, const double* coords, int MatType, vector vPrims, bool markAsUsed) const +{ + CSProperties* prop = CSX->GetPropertyByCoordPriority(coords,vPrims,markAsUsed); +// CSProperties* old_prop = CSX->GetPropertyByCoordPriority(coords,CSProperties::MATERIAL,markAsUsed); +// if (old_prop!=prop) +// { +// cerr << "ERROR: Unequal properties!" << endl; +// exit(-1); +// } + + CSPropMaterial* mat = dynamic_cast(prop); + if (mat) + { + switch (MatType) + { + case 0: + return mat->GetEpsilonWeighted(ny,coords); + case 1: + return mat->GetKappaWeighted(ny,coords); + case 2: + return mat->GetMueWeighted(ny,coords); + case 3: + return mat->GetSigmaWeighted(ny,coords); + case 4: + return mat->GetDensityWeighted(coords); + default: + cerr << "Operator::GetMaterial: Error: unknown material type" << endl; + return 0; + } + } + + switch (MatType) + { + case 0: + return GetBackgroundEpsR(); + case 1: + return GetBackgroundKappa(); + case 2: + return GetBackgroundMueR(); + case 3: + return GetBackgroundSigma(); + case 4: + return GetBackgroundDensity(); + default: + cerr << "Operator::GetMaterial: Error: unknown material type" << endl; + return 0; + } +} + +bool Operator::AverageMatCellCenter(int ny, const unsigned int* pos, double* EffMat, vector vPrims) const +{ + int n=ny; + double coord[3]; + int nP = (n+1)%3; + int nPP = (n+2)%3; + + int loc_pos[3] = {(int)pos[0],(int)pos[1],(int)pos[2]}; + double A_n; + double area = 0; + EffMat[0] = 0; + EffMat[1] = 0; + EffMat[2] = 0; + EffMat[3] = 0; + + //******************************* epsilon,kappa averaging *****************************// + //shift up-right + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n; + area+=A_n; + } + + //shift up-left + --loc_pos[nP]; + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n; + area+=A_n; + } + + //shift down-right + ++loc_pos[nP]; + --loc_pos[nPP]; + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n; + area+=A_n; + } + + //shift down-left + --loc_pos[nP]; + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, coord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, coord, 1, vPrims)*A_n; + area+=A_n; + } + + EffMat[0]*=__EPS0__/area; + EffMat[1]/=area; + + //******************************* mu,sigma averaging *****************************// + loc_pos[0]=pos[0]; + loc_pos[1]=pos[1]; + loc_pos[2]=pos[2]; + double length=0; + double delta_ny,sigma; + //shift down + --loc_pos[n]; + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + delta_ny = GetNodeWidth(n,loc_pos,true); + EffMat[2] += delta_ny / GetMaterial(n, coord, 2, vPrims); + sigma = GetMaterial(n, coord, 3, vPrims); + if (sigma) + EffMat[3] += delta_ny / sigma; + else + EffMat[3] = 0; + length+=delta_ny; + } + + //shift up + ++loc_pos[n]; + if (GetCellCenterMaterialAvgCoord(loc_pos,coord)) + { + delta_ny = GetNodeWidth(n,loc_pos,true); + EffMat[2] += delta_ny / GetMaterial(n, coord, 2, vPrims); + sigma = GetMaterial(n, coord, 3, vPrims); + if (sigma) + EffMat[3] += delta_ny / sigma; + else + EffMat[3] = 0; + length+=delta_ny; + } + + EffMat[2] = length * __MUE0__ / EffMat[2]; + if (EffMat[3]) EffMat[3]=length / EffMat[3]; + + for (int n=0; n<4; ++n) + if (isnan(EffMat[n]) || isinf(EffMat[n])) + { + cerr << "Operator::" << __func__ << ": Error, an effective material parameter is not a valid result, this should NOT have happend... exit..." << endl; + cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << "," << pos[2] << endl; + exit(0); + } + return true; +} + +bool Operator::AverageMatQuarterCell(int ny, const unsigned int* pos, double* EffMat, vector vPrims) const +{ + int n=ny; + double coord[3]; + double shiftCoord[3]; + int nP = (n+1)%3; + int nPP = (n+2)%3; + coord[0] = discLines[0][pos[0]]; + coord[1] = discLines[1][pos[1]]; + coord[2] = discLines[2][pos[2]]; + double delta=GetRawDiscDelta(n,pos[n]); + double deltaP=GetRawDiscDelta(nP,pos[nP]); + double deltaPP=GetRawDiscDelta(nPP,pos[nPP]); + double delta_M=GetRawDiscDelta(n,pos[n]-1); + double deltaP_M=GetRawDiscDelta(nP,pos[nP]-1); + double deltaPP_M=GetRawDiscDelta(nPP,pos[nPP]-1); + + int loc_pos[3] = {(int)pos[0],(int)pos[1],(int)pos[2]}; + double A_n; + double area = 0; + + //******************************* epsilon,kappa averaging *****************************// + //shift up-right + shiftCoord[n] = coord[n]+delta*0.5; + shiftCoord[nP] = coord[nP]+deltaP*0.25; + shiftCoord[nPP] = coord[nPP]+deltaPP*0.25; + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] = GetMaterial(n, shiftCoord, 0, vPrims)*A_n; + EffMat[1] = GetMaterial(n, shiftCoord, 1, vPrims)*A_n; + area+=A_n; + + //shift up-left + shiftCoord[n] = coord[n]+delta*0.5; + shiftCoord[nP] = coord[nP]-deltaP_M*0.25; + shiftCoord[nPP] = coord[nPP]+deltaPP*0.25; + + --loc_pos[nP]; + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, shiftCoord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, shiftCoord, 1, vPrims)*A_n; + area+=A_n; + + //shift down-right + shiftCoord[n] = coord[n]+delta*0.5; + shiftCoord[nP] = coord[nP]+deltaP*0.25; + shiftCoord[nPP] = coord[nPP]-deltaPP_M*0.25; + ++loc_pos[nP]; + --loc_pos[nPP]; + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, shiftCoord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, shiftCoord, 1, vPrims)*A_n; + area+=A_n; + + //shift down-left + shiftCoord[n] = coord[n]+delta*0.5; + shiftCoord[nP] = coord[nP]-deltaP_M*0.25; + shiftCoord[nPP] = coord[nPP]-deltaPP_M*0.25; + --loc_pos[nP]; + A_n = GetNodeArea(ny,loc_pos,true); + EffMat[0] += GetMaterial(n, shiftCoord, 0, vPrims)*A_n; + EffMat[1] += GetMaterial(n, shiftCoord, 1, vPrims)*A_n; + area+=A_n; + + EffMat[0]*=__EPS0__/area; + EffMat[1]/=area; + + //******************************* mu,sigma averaging *****************************// + loc_pos[0]=pos[0]; + loc_pos[1]=pos[1]; + loc_pos[2]=pos[2]; + double length=0; + + //shift down + shiftCoord[n] = coord[n]-delta_M*0.25; + shiftCoord[nP] = coord[nP]+deltaP*0.5; + shiftCoord[nPP] = coord[nPP]+deltaPP*0.5; + --loc_pos[n]; + double delta_ny = GetNodeWidth(n,loc_pos,true); + EffMat[2] = delta_ny / GetMaterial(n, shiftCoord, 2, vPrims); + double sigma = GetMaterial(n, shiftCoord, 3, vPrims); + if (sigma) + EffMat[3] = delta_ny / sigma; + else + EffMat[3] = 0; + length=delta_ny; + + //shift up + shiftCoord[n] = coord[n]+delta*0.25; + shiftCoord[nP] = coord[nP]+deltaP*0.5; + shiftCoord[nPP] = coord[nPP]+deltaPP*0.5; + ++loc_pos[n]; + delta_ny = GetNodeWidth(n,loc_pos,true); + EffMat[2] += delta_ny / GetMaterial(n, shiftCoord, 2, vPrims); + sigma = GetMaterial(n, shiftCoord, 3, vPrims); + if (sigma) + EffMat[3] += delta_ny / sigma; + else + EffMat[3] = 0; + length+=delta_ny; + + EffMat[2] = length * __MUE0__ / EffMat[2]; + if (EffMat[3]) EffMat[3]=length / EffMat[3]; + + for (int n=0; n<4; ++n) + if (isnan(EffMat[n]) || isinf(EffMat[n])) + { + cerr << "Operator::" << __func__ << ": Error, An effective material parameter is not a valid result, this should NOT have happend... exit..." << endl; + cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << "," << pos[2] << endl; + exit(0); + } + + return true; +} + +bool Operator::Calc_EffMatPos(int ny, const unsigned int* pos, double* EffMat, vector vPrims) const +{ + switch (m_MatAverageMethod) + { + case QuarterCell: + return AverageMatQuarterCell(ny, pos, EffMat, vPrims); + case CentralCell: + return AverageMatCellCenter(ny, pos, EffMat, vPrims); + default: + cerr << "Operator:: " << __func__ << ": Error, unknown material averaging method... exit" << endl; + exit(1); + } + return false; +} + +bool Operator::Calc_LumpedElements() +{ + vector props = CSX->GetPropertyByType(CSProperties::LUMPED_ELEMENT); + for (size_t i=0;i(props.at(i)); + if (PLE==NULL) + return false; //sanity check: this should never happen! + vector prims = PLE->GetAllPrimitives(); + for (size_t bn=0;bn(prims.at(bn)); + if (box) + { //calculate lumped element parameter + + double C = PLE->GetCapacity(); + if (C<=0) + C = NAN; + double R = PLE->GetResistance(); + if (R<0) + R = NAN; + + if ((isnan(R)) && (isnan(C))) + { + cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element R or C not specified! skipping. " + << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + continue; + } + + int ny = PLE->GetDirection(); + if ((ny<0) || (ny>2)) + { + cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element direction is invalid! skipping. " + << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + continue; + } + int nyP = (ny+1)%3; + int nyPP = (ny+2)%3; + + unsigned int uiStart[3]; + unsigned int uiStop[3]; + // snap to the native coordinate system + int Snap_Dimension = Operator::SnapBox2Mesh(box->GetStartCoord()->GetCoords(m_MeshType), box->GetStopCoord()->GetCoords(m_MeshType), uiStart, uiStop, false, true); + if (Snap_Dimension<=0) + { + if (Snap_Dimension>=-1) + cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element snapping failed! Dimension is: " << Snap_Dimension << " skipping. " + << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + // Snap_Dimension == -2 means outside the simulation domain --> no special warning, but box probably marked as unused! + continue; + } + + if (uiStart[ny]==uiStop[ny]) + { + cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element with zero (snapped) length is invalid! skipping. " + << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + continue; + } + + //calculate geometric property for this lumped element + unsigned int pos[3]; + double unitGC=0; + int ipos=0; + for (pos[ny]=uiStart[ny];pos[ny]GetCaps(); + double kappa = 0; + double epsilon = 0; + if (R>0) + kappa = 1 / R / unitGC; + if (C>0) + { + epsilon = C / unitGC; + + if (epsilon< __EPS0__) + { + cerr << "Operator::Calc_LumpedElements(): Warning: Lumped Element capacity is too small for its size! skipping. " + << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + C = 0; + } + } + + for (pos[ny]=uiStart[ny];pos[ny]SetPos(pos[0],pos[1],pos[2]); + if (C>0) + EC_C[ny][ipos] = epsilon * GetEdgeArea(ny,pos)/GetEdgeLength(ny,pos); + if (R>0) + EC_G[ny][ipos] = kappa * GetEdgeArea(ny,pos)/GetEdgeLength(ny,pos); + + if (R==0) //make lumped element a PEC if resistance is zero + { + SetVV(ny,pos[0],pos[1],pos[2], 0 ); + SetVI(ny,pos[0],pos[1],pos[2], 0 ); + } + else //recalculate operator inside the lumped element + Calc_ECOperatorPos(ny,pos); + } + } + } + + // setup metal caps + if (caps) + { + for (pos[nyP]=uiStart[nyP];pos[nyP]<=uiStop[nyP];++pos[nyP]) + { + for (pos[nyPP]=uiStart[nyPP];pos[nyPP]<=uiStop[nyPP];++pos[nyPP]) + { + pos[ny]=uiStart[ny]; + if (pos[nyP]SetPrimitiveUsed(true); + + } + else + cerr << "Operator::Calc_LumpedElements(): Warning: Primitves other than boxes are not supported for lumped elements! skipping " + << prims.at(bn)->GetTypeName() << " ID: " << prims.at(bn)->GetID() << " @ Property: " << PLE->GetName() << endl; + } + } + return true; +} + +void Operator::Init_EC() +{ + for (int n=0; n<3; ++n) + { + //init x-cell-array + delete[] EC_C[n]; + delete[] EC_G[n]; + delete[] EC_L[n]; + delete[] EC_R[n]; + EC_C[n] = new FDTD_FLOAT[MainOp->GetSize()]; + EC_G[n] = new FDTD_FLOAT[MainOp->GetSize()]; + EC_L[n] = new FDTD_FLOAT[MainOp->GetSize()]; + EC_R[n] = new FDTD_FLOAT[MainOp->GetSize()]; + for (unsigned int i=0; iGetSize(); i++) //init all + { + EC_C[n][i]=0; + EC_G[n][i]=0; + EC_L[n][i]=0; + EC_R[n][i]=0; + } + } +} + +bool Operator::Calc_EC() +{ + if (CSX==NULL) + { + cerr << "CartOperator::Calc_EC: CSX not given or invalid!!!" << endl; + return false; + } + + MainOp->SetPos(0,0,0); + Calc_EC_Range(0,numLines[0]-1); + return true; +} + +vector Operator::GetPrimitivesBoundBox(int posX, int posY, int posZ, CSProperties::PropertyType type) const +{ + double boundBox[6]; + int BBpos[3] = {posX, posY, posZ}; + for (int n=0;n<3;++n) + { + if (BBpos[n]<0) + { + boundBox[2*n] = this->GetDiscLine(n,0); + boundBox[2*n+1] = this->GetDiscLine(n,numLines[n]-1); + } + else + { + boundBox[2*n] = this->GetDiscLine(n, max(0, BBpos[n]-1)); + boundBox[2*n+1] = this->GetDiscLine(n, min(int(numLines[n])-1, BBpos[n]+1)); + } + } + + vector vPrim = this->CSX->GetPrimitivesByBoundBox(boundBox, true, type); + return vPrim; +} + +void Operator::Calc_EC_Range(unsigned int xStart, unsigned int xStop) +{ +// vector vPrims = this->CSX->GetAllPrimitives(true, CSProperties::MATERIAL); + unsigned int ipos; + unsigned int pos[3]; + double inEC[4]; + for (pos[0]=xStart; pos[0]<=xStop; ++pos[0]) + { + for (pos[1]=0; pos[1] vPrims = this->GetPrimitivesBoundBox(pos[0], pos[1], -1, CSProperties::MATERIAL); + for (pos[2]=0; pos[2]GetPos(pos[0],pos[1],pos[2]); + for (int n=0; n<3; ++n) + { + Calc_ECPos(n,pos,inEC,vPrims); + EC_C[n][ipos]=inEC[0]; + EC_G[n][ipos]=inEC[1]; + EC_L[n][ipos]=inEC[2]; + EC_R[n][ipos]=inEC[3]; + } + } + } + } +} + +void Operator::SetTimestepFactor(double factor) +{ + if ((factor<=0) || (factor>1)) + { + cerr << "Operator::SetTimestepFactor: Warning, invalid timestep factor, skipping!" << endl; + return; + } + + cout << "Operator::SetTimestepFactor: Setting timestep factor to " << factor << endl; + m_TimeStepFactor=factor; +} + +double Operator::CalcTimestep() +{ + if (m_TimeStepVar==3) + return CalcTimestep_Var3(); //the biggest one for cartesian meshes + + //variant 1 is default + return CalcTimestep_Var1(); +} + +////Berechnung nach Andreas Rennings Dissertation 2008, Seite 66, Formel 4.52 +double Operator::CalcTimestep_Var1() +{ + m_Used_TS_Name = string("Rennings_1"); +// cout << "Operator::CalcTimestep(): Using timestep algorithm by Andreas Rennings, Dissertation @ University Duisburg-Essen, 2008, pp. 66, eq. 4.52" << endl; + dT=1e200; + double newT; + unsigned int pos[3]; + unsigned int smallest_pos[3] = {0, 0, 0}; + unsigned int smallest_n = 0; + unsigned int ipos; + unsigned int ipos_PM; + unsigned int ipos_PPM; + MainOp->SetReflection2Cell(); + for (int n=0; n<3; ++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + + for (pos[2]=0; pos[2]SetPos(pos[0],pos[1],pos[2]); + ipos_PM = MainOp->Shift(nP,-1); + MainOp->ResetShift(); + ipos_PPM= MainOp->Shift(nPP,-1); + MainOp->ResetShift(); + newT = 2/sqrt( ( 4/EC_L[nP][ipos] + 4/EC_L[nP][ipos_PPM] + 4/EC_L[nPP][ipos] + 4/EC_L[nPP][ipos_PM]) / EC_C[n][ipos] ); + if ((newT0.0)) + { + dT=newT; + smallest_pos[0]=pos[0];smallest_pos[1]=pos[1];smallest_pos[2]=pos[2]; + smallest_n = n; + } + } + } + } + } + if (dT==0) + { + cerr << "Operator::CalcTimestep: Timestep is zero... this is not supposed to happen!!! exit!" << endl; + exit(3); + } + if (g_settings.GetVerboseLevel()>1) + { + cout << "Operator::CalcTimestep_Var1: Smallest timestep (" << dT << "s) found at position: " << smallest_n << " : " << smallest_pos[0] << ";" << smallest_pos[1] << ";" << smallest_pos[2] << endl; + } + return 0; +} + +double min(double* val, unsigned int count) +{ + if (count==0) + return 0.0; + double min = val[0]; + for (unsigned int n=1; nSetReflection2Cell(); + for (int n=0; n<3; ++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + + for (pos[2]=0; pos[2]ResetShift(); + ipos = MainOp->SetPos(pos[0],pos[1],pos[2]); + wqp = 1/(EC_L[nPP][ipos]*EC_C[n][MainOp->GetShiftedPos(nP ,1)]) + 1/(EC_L[nPP][ipos]*EC_C[n][ipos]); + wqp += 1/(EC_L[nP ][ipos]*EC_C[n][MainOp->GetShiftedPos(nPP,1)]) + 1/(EC_L[nP ][ipos]*EC_C[n][ipos]); + ipos = MainOp->Shift(nP,-1); + wqp += 1/(EC_L[nPP][ipos]*EC_C[n][MainOp->GetShiftedPos(nP ,1)]) + 1/(EC_L[nPP][ipos]*EC_C[n][ipos]); + ipos = MainOp->Shift(nPP,-1); + wqp += 1/(EC_L[nP ][ipos]*EC_C[n][MainOp->GetShiftedPos(nPP,1)]) + 1/(EC_L[nP ][ipos]*EC_C[n][ipos]); + + MainOp->ResetShift(); + ipos = MainOp->SetPos(pos[0],pos[1],pos[2]); + wt_4[0] = 1/(EC_L[nPP][ipos] *EC_C[nP ][ipos]); + wt_4[1] = 1/(EC_L[nPP][MainOp->GetShiftedPos(nP ,-1)] *EC_C[nP ][ipos]); + wt_4[2] = 1/(EC_L[nP ][ipos] *EC_C[nPP][ipos]); + wt_4[3] = 1/(EC_L[nP ][MainOp->GetShiftedPos(nPP,-1)] *EC_C[nPP][ipos]); + + wt1 = wt_4[0]+wt_4[1]+wt_4[2]+wt_4[3] - 2*min(wt_4,4); + + MainOp->ResetShift(); + ipos = MainOp->SetPos(pos[0],pos[1],pos[2]); + wt_4[0] = 1/(EC_L[nPP][ipos] *EC_C[nP ][MainOp->GetShiftedPos(n,1)]); + wt_4[1] = 1/(EC_L[nPP][MainOp->GetShiftedPos(nP ,-1)] *EC_C[nP ][MainOp->GetShiftedPos(n,1)]); + wt_4[2] = 1/(EC_L[nP ][ipos] *EC_C[nPP][MainOp->GetShiftedPos(n,1)]); + wt_4[3] = 1/(EC_L[nP ][MainOp->GetShiftedPos(nPP,-1)] *EC_C[nPP][MainOp->GetShiftedPos(n,1)]); + + wt2 = wt_4[0]+wt_4[1]+wt_4[2]+wt_4[3] - 2*min(wt_4,4); + + w_total = wqp + wt1 + wt2; + newT = 2/sqrt( w_total ); + if ((newT0.0)) + { + dT=newT; + smallest_pos[0]=pos[0];smallest_pos[1]=pos[1];smallest_pos[2]=pos[2]; + smallest_n = n; + } + } + } + } + } + if (dT==0) + { + cerr << "Operator::CalcTimestep: Timestep is zero... this is not supposed to happen!!! exit!" << endl; + exit(3); + } + if (g_settings.GetVerboseLevel()>1) + { + cout << "Operator::CalcTimestep_Var3: Smallest timestep (" << dT << "s) found at position: " << smallest_n << " : " << smallest_pos[0] << ";" << smallest_pos[1] << ";" << smallest_pos[2] << endl; + } + return 0; +} + +bool Operator::CalcPEC() +{ + m_Nr_PEC[0]=0; + m_Nr_PEC[1]=0; + m_Nr_PEC[2]=0; + + CalcPEC_Range(0,numLines[0]-1,m_Nr_PEC); + + CalcPEC_Curves(); + + return true; +} + +void Operator::CalcPEC_Range(unsigned int startX, unsigned int stopX, unsigned int* counter) +{ + double coord[3]; + unsigned int pos[3]; + for (pos[0]=startX; pos[0]<=stopX; ++pos[0]) + { + for (pos[1]=0; pos[1] vPrims = this->GetPrimitivesBoundBox(pos[0], pos[1], -1, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL)); + for (pos[2]=0; pos[2]GetPropertyByCoordPriority(coord, vPrims, true); +// CSProperties* old_prop = CSX->GetPropertyByCoordPriority(coord, (CSProperties::PropertyType)(CSProperties::MATERIAL | CSProperties::METAL), true); +// if (old_prop!=prop) +// { +// cerr << "CalcPEC_Range: " << old_prop << " vs " << prop << endl; +// exit(-1); +// } + if (prop) + { + if (prop->GetType()==CSProperties::METAL) //set to PEC + { + SetVV(n,pos[0],pos[1],pos[2], 0 ); + SetVI(n,pos[0],pos[1],pos[2], 0 ); + ++counter[n]; + } + } + } + } + } + } +} + +void Operator::CalcPEC_Curves() +{ + //special treatment for primitives of type curve (treated as wires) + double p1[3]; + double p2[3]; + Grid_Path path; + vector vec_prop = CSX->GetPropertyByType(CSProperties::METAL); + for (size_t p=0; pGetQtyPrimitives(); ++n) + { + CSPrimitives* prim = prop->GetPrimitive(n); + CSPrimCurve* curv = prim->ToCurve(); + if (curv) + { + for (size_t i=1; iGetNumberOfPoints(); ++i) + { + curv->GetPoint(i-1,p1,m_MeshType); + curv->GetPoint(i,p2,m_MeshType); + path = FindPath(p1,p2); + if (path.dir.size()>0) + prim->SetPrimitiveUsed(true); + for (size_t t=0; t(m_Op_exts.at(n)); + if (Op_Ext_Exc) + break; + } + return Op_Ext_Exc; +} + +void Operator::AddExtension(Operator_Extension* op_ext) +{ + m_Op_exts.push_back(op_ext); +} + +void Operator::DeleteExtension(Operator_Extension* op_ext) +{ + for (size_t n=0;nerr_est) + { + ++it_count; + old_phv=phv; + fk=0; + fdk=0; + for (int n=0;n<3;++n) + { + fk+= pow(sin(propDir[n]*k*average_mesh_disc[n]/2)/average_mesh_disc[n],2); + fdk+= propDir[n]*sin(propDir[n]*k*average_mesh_disc[n]/2)*cos(propDir[n]*k*average_mesh_disc[n]/2)/average_mesh_disc[n]; + } + fk -= RHS; + k-=fk/fdk; + + // do not allow a speed greater than c0 due to a numerical inaccuracy + if (k99) + { + cerr << "Operator::CalcNumericPhaseVelocity: Error, newton iteration estimation can't find a solution!!" << endl; + break; + } + } + + if (g_settings.GetVerboseLevel()>1) + cerr << "Operator::CalcNumericPhaseVelocity: Newton iteration estimated solution: " << phv/__C0__ << "*c0 in " << it_count << " iterations." << endl; + + return phv; +} diff --git a/openEMS/FDTD/operator.h b/openEMS/FDTD/operator.h new file mode 100644 index 0000000..8fc0409 --- /dev/null +++ b/openEMS/FDTD/operator.h @@ -0,0 +1,287 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef OPERATOR_H +#define OPERATOR_H + +#include "tools/AdrOp.h" +#include "tools/constants.h" +#include "excitation.h" +#include "Common/operator_base.h" + +class Operator_Extension; +class Operator_Ext_Excitation; +class Engine; +class TiXmlElement; + +//! Basic FDTD-operator +class Operator : public Operator_Base +{ + friend class Engine; + friend class Engine_Interface_FDTD; + friend class Operator_Ext_LorentzMaterial; //we need to find a way around this... friend class Operator_Extension only would be nice + friend class Operator_Ext_ConductingSheet; //we need to find a way around this... friend class Operator_Extension only would be nice + friend class Operator_Ext_PML_SF_Plane; + friend class Operator_Ext_Excitation; + friend class Operator_Ext_UPML; + friend class Operator_Ext_Cylinder; +public: + enum DebugFlags {None=0,debugMaterial=1,debugOperator=2,debugPEC=4}; + + enum MatAverageMethods {QuarterCell=0, CentralCell=1}; + + //! Create a new operator + static Operator* New(); + virtual ~Operator(); + + virtual Engine* CreateEngine(); + virtual Engine* GetEngine() const {return m_Engine;} + + virtual bool SetGeometryCSX(ContinuousStructure* geo); + + virtual int CalcECOperator( DebugFlags debugFlags = None ); + + // the next four functions need to be reimplemented in a derived class + inline virtual FDTD_FLOAT GetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return vv[n][x][y][z]; } + inline virtual FDTD_FLOAT GetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return vi[n][x][y][z]; } + inline virtual FDTD_FLOAT GetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return ii[n][x][y][z]; } + inline virtual FDTD_FLOAT GetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return iv[n][x][y][z]; } + + // convenient access functions + inline virtual FDTD_FLOAT GetVV( unsigned int n, unsigned int pos[3] ) const { return GetVV(n,pos[0],pos[1],pos[2]); } + inline virtual FDTD_FLOAT GetVI( unsigned int n, unsigned int pos[3] ) const { return GetVI(n,pos[0],pos[1],pos[2]); } + inline virtual FDTD_FLOAT GetII( unsigned int n, unsigned int pos[3] ) const { return GetII(n,pos[0],pos[1],pos[2]); } + inline virtual FDTD_FLOAT GetIV( unsigned int n, unsigned int pos[3] ) const { return GetIV(n,pos[0],pos[1],pos[2]); } + + // the next four functions need to be reimplemented in a derived class + inline virtual void SetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { vv[n][x][y][z] = value; } + inline virtual void SetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { vi[n][x][y][z] = value; } + inline virtual void SetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { ii[n][x][y][z] = value; } + inline virtual void SetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { iv[n][x][y][z] = value; } + + virtual void ApplyElectricBC(bool* dirs); //applied by default to all boundaries + virtual void ApplyMagneticBC(bool* dirs); + + virtual void SetBCSize(int dir, int size) {m_BC_Size[dir]=size;} + virtual int GetBCSize(int dir) {return m_BC_Size[dir];} + + //! Set a forced timestep to use by the operator + virtual void SetTimestep(double ts) {dT = ts;} + virtual void SetTimestepFactor(double factor); + bool GetTimestepValid() const {return !m_InvaildTimestep;} + + //! Choose a time step method (0=auto, 1=CFL, 3=Rennings) + void SetTimeStepMethod(int var) {m_TimeStepVar=var;} + + //! Set the material averaging method /sa MatAverageMethods + void SetMaterialAvgMethod(MatAverageMethods method); + + //! Set material averaging method to the advanced quarter cell material interpolation (default) + void SetQuarterCellMaterialAvg() {m_MatAverageMethod=QuarterCell;} + + //! Set operator to assume a constant material inside a cell (material probing in the cell center) + void SetCellConstantMaterial() {m_MatAverageMethod=CentralCell;} + + virtual double GetNumberCells() const; + + virtual unsigned int GetNumberOfNyquistTimesteps() const {return m_Exc->GetNyquistNum();} + + virtual unsigned int GetNumberOfLines(int ny, bool full=false) const {UNUSED(full);return numLines[ny];} + + virtual void ShowStat() const; + virtual void ShowExtStat() const; + + virtual double GetGridDelta() const {return gridDelta;} + + //! Get the disc line in \a n direction (in drawing units) + virtual double GetDiscLine(int n, unsigned int pos, bool dualMesh=false) const; + + //! Get the disc line delta in \a n direction (in drawing units) + virtual double GetDiscDelta(int n, unsigned int pos, bool dualMesh=false) const; + + //! Get the coordinates for a given node index and component, according to the yee-algorithm. Returns true if inside the FDTD domain. + virtual bool GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const; + + virtual bool GetNodeCoords(const unsigned int pos[3], double* coords, bool dualMesh=false, CoordinateSystem c_system=UNDEFINED_CS) const; + + //! Get the node width for a given direction \a n and a given mesh position \a pos + virtual double GetNodeWidth(int ny, const unsigned int pos[3], bool dualMesh = false) const {return GetEdgeLength(ny,pos,!dualMesh);} + //! Get the node width for a given direction \a n and a given mesh position \a pos + virtual double GetNodeWidth(int ny, const int pos[3], bool dualMesh = false) const; + + //! Get the node area for a given direction \a n and a given mesh position \a pos + virtual double GetNodeArea(int ny, const unsigned int pos[3], bool dualMesh = false) const; + //! Get the node area for a given direction \a n and a given mesh position \a pos + virtual double GetNodeArea(int ny, const int pos[3], bool dualMesh = false) const; + + //! Get the length of an FDTD edge (unit is meter). + virtual double GetEdgeLength(int ny, const unsigned int pos[3], bool dualMesh = false) const; + + //! Get the volume of an FDTD cell + virtual double GetCellVolume(const unsigned int pos[3], bool dualMesh = false) const; + + //! Get the area around an edge for a given direction \a n and a given mesh posisition \a pos + /*! + This will return the area around an edge with a given direction, measured at the middle of the edge. + In a cartesian mesh this is equal to the NodeArea, may be different in other coordinate systems. + */ + virtual double GetEdgeArea(int ny, const unsigned int pos[3], bool dualMesh = false) const {return GetNodeArea(ny,pos,dualMesh);} + + virtual unsigned int SnapToMeshLine(int ny, double coord, bool &inside, bool dualMesh=false, bool fullMesh=false) const; + + //! Snap the given coodinates to mesh indices + virtual bool SnapToMesh(const double* coord, unsigned int* uicoord, bool dualMesh=false, bool fullMesh=false, bool* inside=NULL) const; + + //! Snap a given box to the FDTD mesh + virtual int SnapBox2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh=false, bool fullMesh=false, int SnapMethod=0, bool* bStartIn=NULL, bool* bStopIn=NULL) const; + + //! Snap a given line to the operator mesh + /*! + \param[in] start coorindate of the line + \param[in] stop coorindate of the line + \param[out] uiStart the snapped line-start coorindate index + \param[out] uiStop the snapped line-stop coorindate index + \param[in] dualMesh snap to main or dual mesh (default is main mesh) + \return returns a status, 0 = success, 1 = start outside, 2 = stop outside, 3 = both outside + */ + virtual int SnapLine2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh=false, bool fullMesh=false) const; + + virtual void AddExtension(Operator_Extension* op_ext); + virtual void DeleteExtension(Operator_Extension* op_ext); + virtual size_t GetNumberOfExtentions() const {return m_Op_exts.size();} + virtual Operator_Extension* GetExtension(size_t index) const {return m_Op_exts.at(index);} + + virtual void CleanupMaterialStorage(); + + virtual double GetDiscMaterial(int type, int ny, const unsigned int pos[3]) const; + + //! Get the cell center coordinate usable for material averaging (Warning, may not be the yee cell center) + virtual bool GetCellCenterMaterialAvgCoord(const int pos[3], double coord[3]) const; + + virtual void SetExcitationSignal(Excitation* exc); + virtual Excitation* GetExcitationSignal() const {return m_Exc;} + + Operator_Ext_Excitation* GetExcitationExtension() const; + + virtual double CalcNumericPhaseVelocity(unsigned int start[3], unsigned int stop[3], double propDir[3], float freq) const; + + virtual vector GetPrimitivesBoundBox(int posX, int posY, int posZ, CSProperties::PropertyType type=CSProperties::ANY) const; + +protected: + //! use New() for creating a new Operator + Operator(); + + virtual void Init(); + void Delete(); + virtual void Reset(); + virtual void InitOperator(); + virtual void InitDataStorage(); + + virtual bool SetupCSXGrid(CSRectGrid* grid); + + virtual Grid_Path FindPath(double start[], double stop[]); + + // debug + virtual void DumpOperator2File(string filename); + virtual void DumpMaterial2File(string filename); + virtual void DumpPEC2File( string filename, unsigned int *range = NULL ); + + unsigned int m_Nr_PEC[3]; //count PEC edges + virtual bool CalcPEC(); + virtual void CalcPEC_Range(unsigned int startX, unsigned int stopX, unsigned int* counter); //internal to CalcPEC + virtual void CalcPEC_Curves(); //internal to CalcPEC + + //Calc timestep only internal use + int m_TimeStepVar; + double m_TimeStepFactor; + virtual double CalcTimestep(); + double opt_dT; + bool m_InvaildTimestep; + string m_Used_TS_Name; + + double CalcTimestep_Var1(); + double CalcTimestep_Var3(); + + //! Calculate the FDTD equivalent circuit parameter for the given position and direction ny. \sa Calc_EffMat_Pos + virtual bool Calc_ECPos(int ny, const unsigned int* pos, double* EC, vector vPrims) const; + + //! Get the FDTD raw disc delta, needed by Calc_EffMatPos() \sa Calc_EffMatPos + /*! + Get the raw disc delta for a given position and direction. + The result will be positive if a disc delta inside the simulation domain is requested. + The result will be the negative value of the first or last disc delta respectivly if the position is outside the field domain. + */ + virtual double GetRawDiscDelta(int ny, const int pos) const; + + //! Get the material at a given coordinate, direction and type from CSX (internal use only) + virtual double GetMaterial(int ny, const double coords[3], int MatType, vector vPrims, bool markAsUsed=true) const; + + MatAverageMethods m_MatAverageMethod; + + //! Calculate the effective/averaged material properties at the given position and direction ny. + virtual bool Calc_EffMatPos(int ny, const unsigned int* pos, double* EffMat, vector vPrims) const; + + virtual bool AverageMatCellCenter(int ny, const unsigned int* pos, double* EffMat, vector vPrims) const; + virtual bool AverageMatQuarterCell(int ny, const unsigned int* pos, double* EffMat, vector vPrims) const; + + //! Calc operator at certain \a pos + virtual void Calc_ECOperatorPos(int n, unsigned int* pos); + + //! Calculate and setup lumped elements + virtual bool Calc_LumpedElements(); + + //! Store the size of the applied boundary conditions + int m_BC_Size[6]; + + //store material properties for post-processing + float**** m_epsR; + float**** m_kappa; + float**** m_mueR; + float**** m_sigma; + + //EC elements, internal only! + virtual void Init_EC(); + virtual bool Calc_EC(); + virtual void Calc_EC_Range(unsigned int xStart, unsigned int xStop); + FDTD_FLOAT* EC_C[3]; + FDTD_FLOAT* EC_G[3]; + FDTD_FLOAT* EC_L[3]; + FDTD_FLOAT* EC_R[3]; + + AdrOp* MainOp; + + vector m_Op_exts; + + Engine* m_Engine; + + // excitation classes + Excitation* m_Exc; // excitation time signal class +// Operator_Ext_Excitation* m_Op_Ext_Exc; // excitation extension + + // engine/post-proc needs access +public: + //EC operator + FDTD_FLOAT**** vv; //calc new voltage from old voltage + FDTD_FLOAT**** vi; //calc new voltage from old current + FDTD_FLOAT**** ii; //calc new current from old current + FDTD_FLOAT**** iv; //calc new current from old voltage +}; + +inline Operator::DebugFlags operator|( Operator::DebugFlags a, Operator::DebugFlags b ) { return static_cast(static_cast(a) | static_cast(b)); } +inline Operator::DebugFlags& operator|=( Operator::DebugFlags& a, const Operator::DebugFlags& b ) { return a = a | b; } + +#endif // OPERATOR_H diff --git a/openEMS/FDTD/operator_cylinder.cpp b/openEMS/FDTD/operator_cylinder.cpp new file mode 100644 index 0000000..342415f --- /dev/null +++ b/openEMS/FDTD/operator_cylinder.cpp @@ -0,0 +1,576 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "engine.h" +#include "engine_cylinder.h" +#include "Common/processfields.h" +#include "operator_cylinder.h" +#include "extensions/operator_extension.h" +#include "extensions/operator_ext_cylinder.h" +#include "tools/useful.h" + +Operator_Cylinder* Operator_Cylinder::New(unsigned int numThreads) +{ + cout << "Create cylindrical FDTD operator" << endl; + Operator_Cylinder* op = new Operator_Cylinder(); + op->setNumThreads(numThreads); + op->Init(); + return op; +} + +Operator_Cylinder::Operator_Cylinder() : Operator_Multithread() +{ + m_MeshType = CYLINDRICAL; + m_Cyl_Ext = NULL; +} + +Operator_Cylinder::~Operator_Cylinder() +{ +} + + +Engine* Operator_Cylinder::CreateEngine() +{ + //! create a special cylindrical-engine + m_Engine = Engine_Cylinder::New(this, m_numThreads); + return m_Engine; +} + +void Operator_Cylinder::Init() +{ + CC_closedAlpha = false; + CC_R0_included = false; + Operator_Multithread::Init(); +} + +double Operator_Cylinder::GetRawDiscDelta(int ny, const int pos) const +{ + if (CC_closedAlpha && ny==1 && pos==-1) + return (discLines[1][numLines[1]-2] - discLines[1][numLines[1]-3]); + if (CC_closedAlpha && ny==1 && (pos==(int)numLines[ny]-1)) + return (discLines[1][2] - discLines[1][1]); + + return Operator_Multithread::GetRawDiscDelta(ny,pos); +} + +double Operator_Cylinder::GetMaterial(int ny, const double* coords, int MatType, vector vPrims, bool markAsUsed) const +{ + double l_coords[] = {coords[0],coords[1],coords[2]}; + if (CC_closedAlpha && (coords[1]>GetDiscLine(1,0,false)+2*PI)) + l_coords[1]-=2*PI; + if (CC_closedAlpha && (coords[1]=GetDiscLine(1,0,false)+2*PI)) + coords[1]-=2*PI; + if (CC_closedAlpha && (coords[1]2)) return 0.0; + if (pos[ny]>=numLines[ny]) return 0.0; + double width = Operator_Multithread::GetEdgeLength(ny,pos,!dualMesh); + if (ny==1) + width *= GetDiscLine(0,pos[0],dualMesh); + return width; +} + +double Operator_Cylinder::GetNodeWidth(int ny, const int pos[3], bool dualMesh) const +{ + if ( (pos[0]<0) || (pos[1]<0 && CC_closedAlpha==false) || (pos[2]<0) ) + return 0.0; + + unsigned int uiPos[]={(unsigned int)pos[0],(unsigned int)pos[1],(unsigned int)pos[2]}; + if (pos[1]<0 && CC_closedAlpha==true) + uiPos[1]+=numLines[1]-2; + + return GetNodeWidth(ny, uiPos, dualMesh); +} + +double Operator_Cylinder::GetNodeArea(int ny, const unsigned int pos[3], bool dualMesh) const +{ + if (pos[ny]>=numLines[ny]) return 0.0; + if (pos[0]>=numLines[0]) return 0.0; + if (ny==2) + { + double da = Operator_Multithread::GetEdgeLength(1,pos,dualMesh)/gridDelta; + double r1,r2; + + if (dualMesh) + { + r1 = GetDiscLine(0,pos[0],false)*gridDelta; + r2 = r1 + GetEdgeLength(0,pos,false); + } + else + { + r2 = GetDiscLine(0,pos[0],!dualMesh)*gridDelta; + r1 = r2 - GetEdgeLength(0,pos,true); + } + + if (r1<=0) + return da/2 * pow(r2,2); + else + return da/2* (pow(r2,2) - pow(r1,2)); + } + + return Operator_Multithread::GetNodeArea(ny,pos,dualMesh); +} + +double Operator_Cylinder::GetNodeArea(int ny, const int pos[3], bool dualMesh) const +{ + if ( (pos[0]<0) || (pos[1]<0 && CC_closedAlpha==false) || (pos[2]<0) ) + return 0.0; + + unsigned int uiPos[]={(unsigned int)pos[0],(unsigned int)pos[1],(unsigned int)pos[2]}; + if (pos[1]<0 && CC_closedAlpha==true) + uiPos[1]+=numLines[1]-2; + + return GetNodeArea(ny, uiPos, dualMesh); +} + +double Operator_Cylinder::GetEdgeLength(int ny, const unsigned int pos[3], bool dualMesh) const +{ + double length = Operator_Multithread::GetEdgeLength(ny,pos,dualMesh); + if (ny!=1) + return length; + return length * GetDiscLine(0,pos[0],dualMesh); +} + +double Operator_Cylinder::GetCellVolume(const unsigned int pos[3], bool dualMesh) const +{ + return GetEdgeArea(2,pos,dualMesh)*GetEdgeLength(2,pos,dualMesh); +} + +double Operator_Cylinder::GetEdgeArea(int ny, const unsigned int pos[3], bool dualMesh) const +{ + if (ny!=0) + return GetNodeArea(ny,pos,dualMesh); + + return GetEdgeLength(1,pos,!dualMesh) * GetEdgeLength(2,pos,!dualMesh); +} + +double Operator_Cylinder::FitToAlphaRange(double a_coord, bool fullMesh) const +{ + double min = GetDiscLine(1,0); + double max = GetDiscLine(1,GetNumberOfLines(1, fullMesh)-1); + if ((a_coord>=min) && (a_coord<=max)) + return a_coord; + while (a_coordmax) + return a_coord-2*PI; + if (a_coord>min) + return a_coord; + } + while (a_coord>max) + { + a_coord-=2*PI; + if (a_coord=(int)numLines[1]-2) + return pos-(int)numLines[1]+2; + else + return pos; +} + +bool Operator_Cylinder::GetCellCenterMaterialAvgCoord(const int pos[3], double coord[3]) const +{ + if (!CC_closedAlpha || ((pos[1]>=0) && (pos[1]<(int)numLines[1]-2))) + { + return Operator_Multithread::GetCellCenterMaterialAvgCoord(pos, coord); + } + if ((pos[0]<0) || (pos[2]<0)) + return false; + int l_pos[3] = {pos[0], 0, pos[2]}; + l_pos[1] = MapAlphaIndex2Range(pos[1]); + return Operator_Multithread::GetCellCenterMaterialAvgCoord(l_pos, coord); +} + +unsigned int Operator_Cylinder::SnapToMeshLine(int ny, double coord, bool &inside, bool dualMesh, bool fullMesh) const +{ + if (ny==1) + coord=FitToAlphaRange(coord); + return Operator_Multithread::SnapToMeshLine(ny, coord, inside, dualMesh, fullMesh); +} + +int Operator_Cylinder::SnapBox2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh, bool fullMesh, int SnapMethod, bool* bStartIn, bool* bStopIn) const +{ + double a_min = GetDiscLine(1,0); + double a_max = GetDiscLine(1,GetNumberOfLines(1,fullMesh)-1); + + double a_size = stop[1] - start[1]; + double a_center = FitToAlphaRange(0.5*(stop[1]+start[1])); + double a_start = a_center-a_size/2; + double a_stop = a_start + a_size; + if (a_stop>a_max) + a_stop=a_max; + if (a_stopa_max) + a_start=a_max; + if (a_startstart[1]) && (uiStop[1]uiStart[1]) && (uiStop[1]==GetNumberOfLines(1, fullMesh)-1-(int)CC_closedAlpha)) + uiStop[1] = 0; + + return ret; +} + + +Grid_Path Operator_Cylinder::FindPath(double start[], double stop[]) +{ + double l_start[3]; + double l_stop[3]; + + for (int n=0;n<3;++n) + { + l_start[n] = start[n]; + l_stop[n] = stop[n]; + } + + while (fabs(l_stop[1]-l_start[1])>PI) + { + if (l_stop[1]>l_start[1]) + l_stop[1]-=2*PI; + else + l_stop[1]+=2*PI; + } + + double help=0; + if (l_start[1]>l_stop[1]) + { + for (int n=0;n<3;++n) + { + help = l_start[n]; + l_start[n] = l_stop[n]; + l_stop[n] = help; + } + } + + double a_start = FitToAlphaRange(l_start[1]); + double a_stop = FitToAlphaRange(l_stop[1]); + + if (a_stop >= a_start) + { + l_start[1] = a_start; + l_stop[1] = a_stop; + return Operator_Multithread::FindPath(l_start, l_stop); + } + + // if a-stop fitted to disc range is now smaller than a-start, it must step over the a-bounds... + + Grid_Path path; + for (int n=0;n<3;++n) + { + if ((l_start[n]GetDiscLine(n,GetNumberOfLines(n,true)-1)) && (l_stop[n]>GetDiscLine(n,GetNumberOfLines(n,true)-1))) + return path; //upper bound violation + } + + if (g_settings.GetVerboseLevel()>2) + cerr << __func__ << ": A path was leaving the alpha-direction mesh..." << endl; + + // this section comes into play, if the line moves over the angulare mesh-end/start + // we try to have one part of the path on both "ends" of the mesh and stitch them together + + Grid_Path path1; + Grid_Path path2; + + // calculate the intersection of the line with the a-max boundary + double p0[3],p1[3],p2[3]; + for (int n=0;n<3;++n) + { + p0[n] = GetDiscLine(n,0); + p1[n] = p0[n]; + p2[n] = p0[n]; + } + p0[1] = GetDiscLine(1,GetNumberOfLines(1,true)-1-(int)CC_closedAlpha); + p1[1] = p0[1]; + p2[1] = p0[1]; + p1[0] = discLines[0][numLines[0]-1]; + p2[2] = discLines[2][numLines[2]-1]; + + TransformCoordSystem(p0,p0,m_MeshType,CARTESIAN); + TransformCoordSystem(p1,p1,m_MeshType,CARTESIAN); + TransformCoordSystem(p2,p2,m_MeshType,CARTESIAN); + + double c_start[3],c_stop[3]; + TransformCoordSystem(l_start,c_start,m_MeshType,CARTESIAN); + TransformCoordSystem(l_stop,c_stop,m_MeshType,CARTESIAN); + double intersect[3]; + double dist; + int ret = LinePlaneIntersection(p0,p1,p2,c_start,c_stop,intersect,dist); + if (ret<0) + { + cerr << __func__ << ": Error, unable to calculate intersection, this should not happen!" << endl; + return path; // return empty path; + } + + if (ret==0) + { + TransformCoordSystem(intersect,intersect,CARTESIAN,m_MeshType); + intersect[1] = GetDiscLine(1,GetNumberOfLines(1,true)-1-(int)CC_closedAlpha); + l_start[1] = FitToAlphaRange(l_start[1]); + path1 = Operator::FindPath(l_start, intersect); + if (g_settings.GetVerboseLevel()>2) + cerr << __func__ << ": Intersection top: " << intersect[0] << "," << intersect[1] << "," << intersect[2] << endl; + } //otherwise the path was not intersecting the upper a-bound... + + if (CC_closedAlpha==false) + { + for (int n=0;n<3;++n) + { + p0[n] = GetDiscLine(n,0); + p1[n] = p0[n]; + p2[n] = p0[n]; + } + p1[0] = discLines[0][numLines[0]-1]; + p2[2] = discLines[2][numLines[2]-1]; + + TransformCoordSystem(p0,p0,m_MeshType,CARTESIAN); + TransformCoordSystem(p1,p1,m_MeshType,CARTESIAN); + TransformCoordSystem(p2,p2,m_MeshType,CARTESIAN); + + TransformCoordSystem(l_start,c_start,m_MeshType,CARTESIAN); + TransformCoordSystem(l_stop,c_stop,m_MeshType,CARTESIAN); + + ret = LinePlaneIntersection(p0,p1,p2,c_start,c_stop,intersect,dist); + TransformCoordSystem(intersect,intersect,CARTESIAN,m_MeshType); + } + + if (ret==0) + { + intersect[1] = GetDiscLine(1,0); + l_stop[1] = FitToAlphaRange(l_stop[1]); + path2 = Operator::FindPath(intersect, l_stop); + if (g_settings.GetVerboseLevel()>2) + cerr << __func__ << ": Intersection bottom: " << intersect[0] << "," << intersect[1] << "," << intersect[2] << endl; + } + + //combine path + for (size_t t=0; tGetLines(1,alphaLines,alphaNum,true); + + double minmaxA = fabs(alphaLines[alphaNum-1]-alphaLines[0]); + if (fabs(minmaxA-2*PI) < OPERATOR_CYLINDER_CLOSED_ALPHA_THRESHOLD) + { + if (g_settings.GetVerboseLevel()>0) + cout << "Operator_Cylinder::SetupCSXGrid: Alpha is a full 2*PI => closed Cylinder..." << endl; + CC_closedAlpha = true; + grid->SetLine(1,alphaNum-1,2*PI+alphaLines[0]); + grid->AddDiscLine(1,2*PI+alphaLines[1]); + } + else if (minmaxA>2*PI) + { + cerr << "Operator_Cylinder::SetupCSXGrid: Alpha Max-Min must not be larger than 2*PI!!!" << endl; + Reset(); + return false; + } + else + { + CC_closedAlpha=false; + } + + CC_R0_included = false; + if (grid->GetLine(0,0)<0) + { + cerr << "Operator_Cylinder::SetupCSXGrid: r<0 not allowed in Cylinder Coordinates!!!" << endl; + Reset(); + return false; + } + else if (grid->GetLine(0,0)==0.0) + { + if (g_settings.GetVerboseLevel()>0) + cout << "Operator_Cylinder::SetupCSXGrid: r=0 included..." << endl; + CC_R0_included = CC_closedAlpha; //needed for correct ec-calculation, deactivate if closed cylinder is false... --> E_r = 0 anyways + } + +#ifdef MPI_SUPPORT + // Setup an MPI split in alpha direction for a closed cylinder + CC_MPI_Alpha = false; + if ((m_NeighborUp[1]>=0) || (m_NeighborDown[1]>=0)) //check for MPI split in alpha direction + { + double minmaxA = 2*PI;// fabs(m_OrigDiscLines[1][m_OrigNumLines[1]-1]-m_OrigDiscLines[1][0]); + if (fabs(minmaxA-2*PI) < OPERATOR_CYLINDER_CLOSED_ALPHA_THRESHOLD) //check for closed alpha MPI split + { + CC_MPI_Alpha = true; + if (m_OrigDiscLines[0][0]==0) + { + cerr << "Operator_Cylinder::SetupCSXGrid: Error: MPI split in alpha direction for closed cylinder including r==0 is currently not supported! Exit!" << endl; + exit(-2); + } + + if (m_NeighborUp[1]<0) //check if this process is at the alpha-end + { + grid->SetLine(1,alphaNum-1,2*PI+m_OrigDiscLines[1][0]); + grid->AddDiscLine(1,2*PI+m_OrigDiscLines[1][1]); + + SetNeighborUp(1,m_ProcTable[m_ProcTablePos[0]][0][m_ProcTablePos[2]]); + } + + if (m_NeighborDown[1]<0) //check if this process is at the alpha-start + { + SetNeighborDown(1,m_ProcTable[m_ProcTablePos[0]][m_SplitNumber[1]-1][m_ProcTablePos[2]]); + } + + //Note: the process table will not reflect this up/down neighbors necessary for a closed cylinder + } + } +#endif + + if (Operator_Multithread::SetupCSXGrid(grid)==false) + return false; + + if (CC_closedAlpha || CC_R0_included) + { + m_Cyl_Ext = new Operator_Ext_Cylinder(this); + this->AddExtension(m_Cyl_Ext); + } + + return true; +} + +void Operator_Cylinder::ApplyMagneticBC(bool* dirs) +{ + if (dirs==NULL) return; + if (CC_closedAlpha) + { + dirs[2]=0; + dirs[3]=0; //no PMC in alpha directions... + } + if (CC_R0_included) + { + dirs[0]=0; //no PMC in r_min directions... + } + Operator_Multithread::ApplyMagneticBC(dirs); +} + +void Operator_Cylinder::AddExtension(Operator_Extension* op_ext) +{ + if (op_ext->IsCylinderCoordsSave(CC_closedAlpha, CC_R0_included)) + Operator_Multithread::AddExtension(op_ext); + else + { + cerr << "Operator_Cylinder::AddExtension: Warning: Operator extension \"" << op_ext->GetExtensionName() << "\" is not compatible with cylinder-coords!! skipping...!" << endl; + delete op_ext; + } +} diff --git a/openEMS/FDTD/operator_cylinder.h b/openEMS/FDTD/operator_cylinder.h new file mode 100644 index 0000000..152f618 --- /dev/null +++ b/openEMS/FDTD/operator_cylinder.h @@ -0,0 +1,118 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef OPERATOR_CYLINDER_H +#define OPERATOR_CYLINDER_H + +#define OPERATOR_CYLINDER_CLOSED_ALPHA_THRESHOLD 1e-6 + +#include "operator_multithread.h" + +class Operator_Ext_Cylinder; + +//! This class creates an operator for a cylindrical FDTD. +/*! +This class creates an operator for a cylindrical FDTD. No special engine is necessary, +all special cases e.g. a closed alpha mesh or an included r=0 case is treated by an operator/engine extension \sa operator_ext_cylinder. +*/ +class Operator_Cylinder : public Operator_Multithread +{ + friend class Operator_CylinderMultiGrid; + friend class Operator_Ext_Cylinder; + friend class Operator_Ext_LorentzMaterial; +public: + static Operator_Cylinder* New(unsigned int numThreads = 0); + virtual ~Operator_Cylinder(); + + virtual void ApplyMagneticBC(bool* dirs); + + virtual unsigned int GetNumberOfLines(int ny, bool full=false) const; + + //! Get the name for the given direction: 0 -> rho, 1 -> alpha, 2 -> z + virtual string GetDirName(int ny) const; + + //! Get the coordinates for a given node index and component, according to the cylindrical yee-algorithm. Returns true if inside the FDTD domain. + virtual bool GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const; + + //! Get the node width for a given direction \a n and a given mesh posisition \a pos + virtual double GetNodeWidth(int ny, const unsigned int pos[3], bool dualMesh = false) const; + //! Get the node width for a given direction \a n and a given mesh posisition \a pos + virtual double GetNodeWidth(int ny, const int pos[3], bool dualMesh = false) const; + + //! Get the node area for a given direction \a n and a given mesh posisition \a pos + virtual double GetNodeArea(int n, const unsigned int* pos, bool dualMesh=false) const; + //! Get the node area for a given direction \a n and a given mesh posisition \a pos + virtual double GetNodeArea(int ny, const int pos[3], bool dualMesh = false) const; + + //! Get the length of an FDTD edge, including radius corrected alpha-mesh width. + virtual double GetEdgeLength(int ny, const unsigned int pos[3], bool dualMesh = false) const; + + //! Get the volume of an FDTD cell + virtual double GetCellVolume(const unsigned int pos[3], bool dualMesh = false) const; + + //! Get the area around an edge for a given direction \a n and a given mesh posisition \a pos + /*! + This will return the area around an edge with a given direction, measured at the middle of the edge. + In a cartesian mesh this is equal to the NodeArea, may be different in other coordinate systems. + */ + virtual double GetEdgeArea(int ny, const unsigned int pos[3], bool dualMesh = false) const; + + virtual double FitToAlphaRange(double a_coord, bool fullMesh=false) const; + + //! Map a negative or out of range index in alpha direction back into the closed alpha mesh + virtual int MapAlphaIndex2Range(int pos) const; + + virtual bool GetCellCenterMaterialAvgCoord(const int pos[3], double coord[3]) const; + + virtual unsigned int SnapToMeshLine(int ny, double coord, bool &inside, bool dualMesh=false, bool fullMesh=false) const; + + //! Snap a given box to the FDTD mesh + virtual int SnapBox2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh=false, bool fullMesh=false, int SnapMethod=0, bool* bStartIn=NULL, bool* bStopIn=NULL) const; + + virtual int SnapLine2Mesh(const double* start, const double* stop, unsigned int* uiStart, unsigned int* uiStop, bool dualMesh=false, bool fullMesh=false) const; + + bool GetClosedAlpha() const {return CC_closedAlpha;} + bool GetR0Included() const {return CC_R0_included;} + + virtual void AddExtension(Operator_Extension* op_ext); + + virtual Engine* CreateEngine(); + +protected: + Operator_Cylinder(); + virtual void Init(); + + virtual bool SetupCSXGrid(CSRectGrid* grid); + + virtual Grid_Path FindPath(double start[], double stop[]); + + virtual double GetRawDiscDelta(int ny, const int pos) const; + + virtual double GetMaterial(int ny, const double coords[3], int MatType, vector vPrims, bool markAsUsed=true) const; + + virtual int CalcECOperator( DebugFlags debugFlags = None ); + virtual double CalcTimestep(); + bool CC_closedAlpha; + bool CC_R0_included; + Operator_Ext_Cylinder* m_Cyl_Ext; + +#ifdef MPI_SUPPORT + bool CC_MPI_Alpha; +#endif +}; + +#endif // OPERATOR_CYLINDER_H diff --git a/openEMS/FDTD/operator_cylindermultigrid.cpp b/openEMS/FDTD/operator_cylindermultigrid.cpp new file mode 100644 index 0000000..88f9f82 --- /dev/null +++ b/openEMS/FDTD/operator_cylindermultigrid.cpp @@ -0,0 +1,569 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "operator_cylindermultigrid.h" +#include "engine_cylindermultigrid.h" +#include "extensions/operator_ext_cylinder.h" +#include "tools/useful.h" +#include "CSUseful.h" + +Operator_CylinderMultiGrid::Operator_CylinderMultiGrid(vector Split_Radii, unsigned int level) : Operator_Cylinder() +{ + m_Split_Radii = Split_Radii; + m_Split_Rad = m_Split_Radii.back(); + m_Split_Radii.pop_back(); + m_MultiGridLevel = level; +} + +Operator_CylinderMultiGrid::~Operator_CylinderMultiGrid() +{ + Delete(); +} + +Operator_CylinderMultiGrid* Operator_CylinderMultiGrid::New(vector Split_Radii, unsigned int numThreads, unsigned int level) +{ + if ((Split_Radii.size()==0) || (Split_Radii.size()>CYLIDINDERMULTIGRID_LIMIT)) + { + cerr << "Operator_CylinderMultiGrid::New: Warning: Number of multigrids invalid! Split-Number: " << Split_Radii.size() << endl; + return NULL; + } + cout << "Create cylindrical multi grid FDTD operator " << endl; + Operator_CylinderMultiGrid* op = new Operator_CylinderMultiGrid(Split_Radii, level); + op->setNumThreads(numThreads); + op->Init(); + + return op; +} + +Engine* Operator_CylinderMultiGrid::CreateEngine() +{ + m_Engine = Engine_CylinderMultiGrid::New(this,m_numThreads); + return m_Engine; +} + +double Operator_CylinderMultiGrid::GetNumberCells() const +{ + if (numLines) + return (numLines[0]-m_Split_Pos)*(numLines[1])*(numLines[2]) + m_InnerOp->GetNumberCells(); + return 0; +} + +bool Operator_CylinderMultiGrid::SetupCSXGrid(CSRectGrid* grid) +{ + if (Operator_Cylinder::SetupCSXGrid(grid)==false) + return false; + + // make this multigrid use the larger timestep by method 3, since no r==0 singularity can be part of this engine + m_TimeStepVar = 3; + + if ((numLines[1]-CC_closedAlpha)%2 != 1) + { + cerr << "Operator_CylinderMultiGrid::SetupCSXGrid: Error, number of line in alpha direction must be odd... found: " << numLines[1] << endl; + exit(0); + } + + m_Split_Pos = 0; + for (unsigned int n=0; n0) + cout << "Operator_CylinderMultiGrid::SetupCSXGrid: Found mesh split position @" << m_Split_Pos << endl; + m_Split_Rad = discLines[0][n]; + break; + } + } + if ((m_Split_Pos<4) || (m_Split_Pos>numLines[0]-4)) + { + cerr << "Operator_CylinderMultiGrid::SetupCSXGrid: Error, split invalid..." << endl; + return false; + } + return true; +} + +bool Operator_CylinderMultiGrid::SetGeometryCSX(ContinuousStructure* geo) +{ + if (Operator_Cylinder::SetGeometryCSX(geo)==false) + return false; + + CSRectGrid* grid = geo->GetGrid(); + + grid->ClearLines(0); + grid->ClearLines(1); + for (unsigned int n=0; nAddDiscLine(0,discLines[0][n]); + for (unsigned int n=0; nAddDiscLine(1,discLines[1][n]); + + if (m_InnerOp->SetGeometryCSX(CSX)==false) + return false; + + //restore grid to original mesh + grid->ClearLines(0); + grid->ClearLines(1); + for (unsigned int n=0; nAddDiscLine(0,discLines[0][n]); + for (unsigned int n=0; nAddDiscLine(1,discLines[1][n]); + + return true; +} + +void Operator_CylinderMultiGrid::Init() +{ + Operator_Cylinder::Init(); + + if (m_Split_Radii.empty()) + m_InnerOp = Operator_Cylinder::New(m_numThreads); + else + m_InnerOp = Operator_CylinderMultiGrid::New(m_Split_Radii,m_numThreads, m_MultiGridLevel+1); + + for (int n=0;n<2;++n) + { + m_interpol_pos_v_2p[n] = NULL; + f4_interpol_v_2p[n]=NULL; + m_interpol_pos_v_2pp[n] = NULL; + f4_interpol_v_2pp[n]=NULL; + + m_interpol_pos_i_2p[n] = NULL; + f4_interpol_i_2p[n]=NULL; + m_interpol_pos_i_2pp[n] = NULL; + f4_interpol_i_2pp[n]=NULL; + } +} + +bool Operator_CylinderMultiGrid::GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const +{ + bool ret = Operator_Cylinder::GetYeeCoords(ny,pos,coords,dualMesh); + + if (pos[0]<(m_Split_Pos-1)) + ret = false; + + return ret; +} + +#ifdef MPI_SUPPORT +void Operator_CylinderMultiGrid::SetTag(int tag) +{ + m_MyTag = tag; + m_InnerOp->SetTag(tag+1); +} + +void Operator_CylinderMultiGrid::SetNeighborUp(int ny, int id) +{ + if (ny==0) + { + cerr << "Operator_CylinderMultiGrid::SetNeighborUp: Error: MPI segregation in radial direction not supported for a cylindircal multigrid. Exit!"; + MPI_Barrier(MPI_COMM_WORLD); + exit(-1); + } + Operator_Cylinder::SetNeighborUp(ny,id); + m_InnerOp->SetNeighborUp(ny,id); +} + +void Operator_CylinderMultiGrid::SetNeighborDown(int ny, int id) +{ + if (ny==0) + { + cerr << "Operator_CylinderMultiGrid::SetNeighborDown: Error: MPI segregation in radial direction not supported for a cylindircal multigrid. Exit!"; + MPI_Barrier(MPI_COMM_WORLD); + exit(-1); + } + Operator_Cylinder::SetNeighborDown(ny,id); + m_InnerOp->SetNeighborDown(ny,id); +} +#endif + +void Operator_CylinderMultiGrid::CalcStartStopLines(unsigned int &numThreads, vector &start, vector &stop) const +{ + vector jpt = AssignJobs2Threads(numLines[0]- m_Split_Pos + 1, numThreads, true); + + numThreads = jpt.size(); + + start.resize(numThreads); + stop.resize(numThreads); + + start.at(0)= m_Split_Pos-1; + stop.at(0)= jpt.at(0)-1 + m_Split_Pos-1; + + for (unsigned int n=1; n vPrims = this->GetPrimitivesBoundBox(pos[0], pos[1], -1, CSProperties::MATERIAL); + for (pos[2]=0; pos[2]=((int)m_Split_Pos)) + return true; + + int pos_a = MapAlphaIndex2Range(pos[1])/2; + if ((pos_a<0) || (pos_a>=(int)m_InnerOp->numLines[1])) + return false; + coord[1] = m_InnerOp->GetDiscLine(1,pos_a,true); + return true; +} + +int Operator_CylinderMultiGrid::CalcECOperator( DebugFlags debugFlags ) +{ + int retCode=0; + if (dT) + m_InnerOp->SetTimestep(dT); + + //calc inner child first + m_InnerOp->CalcECOperator(); + + dT = m_InnerOp->GetTimestep(); + + retCode = Operator_Cylinder::CalcECOperator( debugFlags ); + if (GetTimestepValid()==false) + { + cerr << "Operator_CylinderMultiGrid::CalcECOperator(): Warning, timestep invalid... resetting..." << endl; + dT = opt_dT; + m_InnerOp->SetTimestep(dT); + m_InnerOp->CalcECOperator(); + retCode = Operator_Cylinder::CalcECOperator( debugFlags ); + } + + SetupInterpolation(); + + //the data storage will only be filled up to m_Split_Pos-1, fill the remaining area here... + FillMissingDataStorage(); + return retCode; +} + +void Operator_CylinderMultiGrid::DumpPEC2File( string filename, unsigned int *range) +{ + if (range!=NULL) + return Operator_Cylinder::DumpPEC2File(filename, range); + + range = new unsigned int[6]; + for (int n=0;n<3;++n) + { + range[2*n] = 0; + range[2*n+1] = numLines[n]-1; + } + range[0] = m_Split_Pos-1; + Operator_Cylinder::DumpPEC2File(filename + "_S" + ConvertInt(m_MultiGridLevel), range); + delete[] range; + range=NULL; + + if (dynamic_cast(m_InnerOp)) + m_InnerOp->DumpPEC2File(filename); + else // base cylindrical grid + m_InnerOp->DumpPEC2File(filename + "_S" + ConvertInt(m_MultiGridLevel+1)); +} + +void Operator_CylinderMultiGrid::SetupInterpolation() +{ + // n==0 --> interpolation in r&z-direction + // n==1 --> interpolation in a-direction + for (int n=0;n<2;++n) + { + delete[] m_interpol_pos_v_2p[n]; + m_interpol_pos_v_2p[n] = new unsigned int[numLines[1]]; + Delete1DArray_v4sf(f4_interpol_v_2p[n]); + f4_interpol_v_2p[n]=Create1DArray_v4sf(numLines[1]); + + delete[] m_interpol_pos_v_2pp[n]; + m_interpol_pos_v_2pp[n] = new unsigned int[numLines[1]]; + Delete1DArray_v4sf(f4_interpol_v_2pp[n]); + f4_interpol_v_2pp[n]=Create1DArray_v4sf(numLines[1]); + + delete[] m_interpol_pos_i_2p[n]; + m_interpol_pos_i_2p[n] = new unsigned int[numLines[1]]; + Delete1DArray_v4sf(f4_interpol_i_2p[n]); + f4_interpol_i_2p[n]=Create1DArray_v4sf(numLines[1]); + + delete[] m_interpol_pos_i_2pp[n]; + m_interpol_pos_i_2pp[n] = new unsigned int[numLines[1]]; + Delete1DArray_v4sf(f4_interpol_i_2pp[n]); + f4_interpol_i_2pp[n]=Create1DArray_v4sf(numLines[1]); + } + + bool isOdd, isEven; + for (unsigned int a_n=0; a_nnumLines[1]-3; + else if ((a_n==0) && !CC_closedAlpha) + m_interpol_pos_i_2pp[0][a_n] = 0; + + //setup some special treatments for not closed alpha mesh + if ((a_n==numLines[1]-2) && !CC_closedAlpha) + m_interpol_pos_i_2pp[0][a_n] = a_n/2 - 1; + if ((a_n==numLines[1]-1) && !CC_closedAlpha) + m_interpol_pos_i_2p[0][a_n] = m_interpol_pos_i_2pp[0][a_n] = a_n/2; + + double dl_p=m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2p[0][a_n],true); + double dl_pp=m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2pp[0][a_n],true); + if ((a_n==0) && CC_closedAlpha) + dl_pp -= 2*PI; + + for (int v=0;v<4;++v) + { + if (m_interpol_pos_i_2p[0][a_n]==m_interpol_pos_i_2pp[0][a_n]) + f4_interpol_i_2p[0][a_n].f[v] = 1.0; + else + { + f4_interpol_i_2p[0][a_n].f[v] = (dl_pp-GetDiscLine(1,a_n,true)) / (dl_pp-dl_p); + f4_interpol_i_2pp[0][a_n].f[v] = (GetDiscLine(1,a_n,true)-dl_p) / (dl_pp-dl_p); + } + } + + /* voltage interpolation position for r,z direction + this sub_grid 2p sub_grid 2pp + 0 <-- 0 0 + 1 <-- 0 1 + 2 <-- 1 1 + 3 <-- 1 2 + 4 <-- 2 2 + 5 <-- 2 3 + ... + */ + m_interpol_pos_v_2p[0][a_n] = a_n/2; + m_interpol_pos_v_2pp[0][a_n] = a_n/2 + isOdd; + + dl_p=m_InnerOp->GetDiscLine(1,m_interpol_pos_v_2p[0][a_n],false); + dl_pp=m_InnerOp->GetDiscLine(1,m_interpol_pos_v_2pp[0][a_n],false); + + for (int v=0;v<4;++v) + { + if (m_interpol_pos_v_2p[0][a_n]==m_interpol_pos_v_2pp[0][a_n]) + f4_interpol_v_2p[0][a_n].f[v] = 1.0; + else + { + f4_interpol_v_2p[0][a_n].f[v] = (dl_pp-GetDiscLine(1,a_n,false)) / (dl_pp-dl_p); + f4_interpol_v_2pp[0][a_n].f[v] = (GetDiscLine(1,a_n,false)-dl_p) / (dl_pp-dl_p); + } + } + + /* current interpolation position for the alpha direction + this sub_grid 2p sub_grid 2pp + 0 <-- 0 0 + 1 <-- 0 1 + 2 <-- 1 1 + 3 <-- 1 2 + 4 <-- 2 2 + 5 <-- 2 3 + ... + */ + m_interpol_pos_i_2p[1][a_n] = a_n/2; + m_interpol_pos_i_2pp[1][a_n] = a_n/2 + isOdd; + + //setup some special treatments for not closed alpha mesh + if ((a_n==1) && !CC_closedAlpha) + m_interpol_pos_i_2p[1][a_n] = 2; + if ((a_n==numLines[1]-2) && !CC_closedAlpha) + m_interpol_pos_i_2pp[1][a_n] = a_n/2 - 1; + + for (int v=0;v<4;++v) + { + if (m_interpol_pos_i_2p[1][a_n]==m_interpol_pos_i_2pp[1][a_n]) + f4_interpol_i_2p[1][a_n].f[v] = GetDiscDelta(1,a_n,true)/m_InnerOp->GetDiscDelta(1,m_interpol_pos_i_2p[1][a_n],true); + else + { + f4_interpol_i_2p[1][a_n].f[v] = (m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2pp[1][a_n],false)-GetDiscLine(1,a_n,false)) / + (m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2pp[1][a_n],false)-m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2p[1][a_n],false)); + f4_interpol_i_2p[1][a_n].f[v] *= GetDiscDelta(1,a_n,true)/m_InnerOp->GetDiscDelta(1,m_interpol_pos_i_2p[1][a_n],true); + + f4_interpol_i_2pp[1][a_n].f[v] = (GetDiscLine(1,a_n,false)-m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2p[1][a_n],false)) / + (m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2pp[1][a_n],false)-m_InnerOp->GetDiscLine(1,m_interpol_pos_i_2p[1][a_n],false)); + f4_interpol_i_2pp[1][a_n].f[v] *= GetDiscDelta(1,a_n,true)/m_InnerOp->GetDiscDelta(1,m_interpol_pos_i_2pp[1][a_n],true); + } + } + + /* voltage interpolation position for the alpha direction + this sub_grid 2p sub_grid 2pp + 0 <-- 0 (-1) 0 + 1 <-- 0 1 + 2 <-- 1 0 + 3 <-- 1 2 + 4 <-- 2 1 + 5 <-- 2 3 + ... + */ + m_interpol_pos_v_2p[1][a_n] = a_n/2; + m_interpol_pos_v_2pp[1][a_n] = a_n/2 + isOdd - isEven; + + if ((a_n==0) && CC_closedAlpha) + m_interpol_pos_v_2pp[1][a_n] = m_InnerOp->numLines[1]-3; + else if ((a_n==0) && !CC_closedAlpha) + m_interpol_pos_v_2pp[1][a_n] = 1; + + //setup some special treatments for not closed alpha mesh + if ((a_n==numLines[1]-2) && !CC_closedAlpha) + m_interpol_pos_v_2pp[1][a_n] = a_n/2 - 1; + if ((a_n==numLines[1]-1) && !CC_closedAlpha) + { + m_interpol_pos_v_2p[1][a_n] = 0; + m_interpol_pos_v_2pp[1][a_n] = 0; + } + + dl_p=m_InnerOp->GetDiscLine(1,m_interpol_pos_v_2p[1][a_n],true); + dl_pp=m_InnerOp->GetDiscLine(1,m_interpol_pos_v_2pp[1][a_n],true); + + for (int v=0;v<4;++v) + { + if (m_interpol_pos_v_2p[1][a_n]==m_interpol_pos_v_2pp[1][a_n]) + f4_interpol_v_2p[1][a_n].f[v] = f4_interpol_v_2pp[1][a_n].f[v] = 0; + else + { + f4_interpol_v_2p[1][a_n].f[v] = (dl_pp-GetDiscLine(1,a_n,true)) / (dl_pp-dl_p); + f4_interpol_v_2p[1][a_n].f[v] *= GetDiscDelta(1,a_n,false)/m_InnerOp->GetDiscDelta(1,m_interpol_pos_v_2p[1][a_n],false); + + f4_interpol_v_2pp[1][a_n].f[v] = (GetDiscLine(1,a_n,true)-dl_p) / (dl_pp-dl_p); + f4_interpol_v_2pp[1][a_n].f[v] *= GetDiscDelta(1,a_n,false)/m_InnerOp->GetDiscDelta(1,m_interpol_pos_v_2pp[1][a_n],false); + } + } + } +} + +void Operator_CylinderMultiGrid::SetExcitationSignal(Excitation* exc) +{ + m_InnerOp->SetExcitationSignal(exc); + Operator_Cylinder::SetExcitationSignal(exc); +} + +void Operator_CylinderMultiGrid::Delete() +{ + delete m_InnerOp; + m_InnerOp=0; + + for (int n=0;n<2;++n) + { + delete[] m_interpol_pos_v_2p[n]; + m_interpol_pos_v_2p[n]=NULL; + Delete1DArray_v4sf(f4_interpol_v_2p[n]); + f4_interpol_v_2p[n]=NULL; + delete[] m_interpol_pos_v_2pp[n]; + m_interpol_pos_v_2pp[n]=NULL; + Delete1DArray_v4sf(f4_interpol_v_2pp[n]); + f4_interpol_v_2pp[n]=NULL; + + delete[] m_interpol_pos_i_2p[n]; + m_interpol_pos_i_2p[n]=NULL; + Delete1DArray_v4sf(f4_interpol_i_2p[n]); + f4_interpol_i_2p[n]=NULL; + delete[] m_interpol_pos_i_2pp[n]; + m_interpol_pos_i_2pp[n]=NULL; + Delete1DArray_v4sf(f4_interpol_i_2pp[n]); + f4_interpol_i_2pp[n]=NULL; + } +} + +void Operator_CylinderMultiGrid::Reset() +{ + Delete(); + Operator_Cylinder::Reset(); +} + +void Operator_CylinderMultiGrid::SetBoundaryCondition(int* BCs) +{ + Operator_Cylinder::SetBoundaryCondition(BCs); + int oldBC = BCs[1]; + BCs[1] = 0; //always PEC in +r-direction + m_InnerOp->SetBoundaryCondition(BCs); + BCs[1] = oldBC; +} + +void Operator_CylinderMultiGrid::AddExtension(Operator_Extension* op_ext) +{ + //check whether extension is save to use in multi-grid + if (op_ext->IsCylindricalMultiGridSave(false)==false) + { + cerr << "Operator_CylinderMultiGrid::AddExtension: Warning: Operator extension \"" << op_ext->GetExtensionName() << "\" is not compatible with cylindrical multi-grids!! skipping...!" << endl; + delete op_ext; + return; + } + + Operator_Cylinder::AddExtension(op_ext); + + // cylinder extension does not need to be cloned, it will be created by each operator of its own... + if (dynamic_cast(op_ext)) + return; + + //check whether extension is save to use in child multi-grid + if (op_ext->IsCylindricalMultiGridSave(true)) + { + Operator_Extension* child_Ext = op_ext->Clone(m_InnerOp); + if (child_Ext==NULL) + { + cerr << "Operator_CylinderMultiGrid::AddExtension: Warning, extension: " << op_ext->GetExtensionName() << " can not be cloned for the child operator. Skipping Extension... " << endl; + return; + } + //give the copy to child + m_InnerOp->AddExtension(child_Ext); + } +} + +void Operator_CylinderMultiGrid::ShowStat() const +{ + m_InnerOp->ShowStat(); + m_InnerOp->ShowExtStat(); + Operator_Cylinder::ShowStat(); +} diff --git a/openEMS/FDTD/operator_cylindermultigrid.h b/openEMS/FDTD/operator_cylindermultigrid.h new file mode 100644 index 0000000..57481f1 --- /dev/null +++ b/openEMS/FDTD/operator_cylindermultigrid.h @@ -0,0 +1,109 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef OPERATOR_CYLINDERMULTIGRID_H +#define OPERATOR_CYLINDERMULTIGRID_H + +#define CYLIDINDERMULTIGRID_LIMIT 20 + +#include "operator_cylinder.h" + +//! This is a cylindrical FDTD operator using a simple multi-grid approach. +/*! + This cylindrical multi-grid operator itself is not calculating any real operator, instead it is hosting two separate "child" operators of type "Operator_Cylinder". + This operator class (or the corresponding engine) will perform the interpolation and connection between these two child-operator/engines. + One of the child operators itself may be another multi-grid operator to allow for a cascaded multi-grid approach. + */ +class Operator_CylinderMultiGrid : public Operator_Cylinder +{ + friend class Engine_CylinderMultiGrid; +public: + static Operator_CylinderMultiGrid* New(vector Split_Radii, unsigned int numThreads = 0, unsigned int level = 0); + virtual ~Operator_CylinderMultiGrid(); + + virtual double GetNumberCells() const; + + virtual Engine* CreateEngine(); + + virtual bool SetGeometryCSX(ContinuousStructure* geo); + + //! Get the coordinates for a given node index and component, according to the cylindrical yee-algorithm. Returns true if inside the FDTD domain. + virtual bool GetYeeCoords(int ny, unsigned int pos[3], double* coords, bool dualMesh) const; + + virtual unsigned int GetSplitPos() const {return m_Split_Pos;} + + virtual void SetBoundaryCondition(int* BCs); + + virtual void AddExtension(Operator_Extension* op_ext); + + //! Get the multi grid level of this operator, e.g. 0 is main grid --> no parent grid + int GetMultiGridLevel() const {return m_MultiGridLevel;} + + Operator_Cylinder* GetInnerOperator() const {return m_InnerOp;} + + virtual void SetExcitationSignal(Excitation* exc); + + virtual void ShowStat() const; + + //! Get the cell center coordinate usable for material averaging (Warning, may not be the yee cell center) + virtual bool GetCellCenterMaterialAvgCoord(const int pos[3], double coord[3]) const; + +#ifdef MPI_SUPPORT + virtual void SetTag(int tag); + virtual void SetNeighborUp(int ny, int id); + virtual void SetNeighborDown(int ny, int id); +#endif + +protected: + Operator_CylinderMultiGrid(vector Split_Radii, unsigned int level); + virtual void Init(); + void Delete(); + virtual void Reset(); + + virtual bool SetupCSXGrid(CSRectGrid* grid); + + virtual int CalcECOperator( DebugFlags debugFlags = None ); + + virtual void DumpPEC2File( string filename, unsigned int *range = NULL ); + + //! The material data storage in the sub-grid area's will not be filled by the base-operator. Check and do this here! + void FillMissingDataStorage(); + + unsigned int m_MultiGridLevel; + double m_Split_Rad; + vector m_Split_Radii; + unsigned int m_Split_Pos; + + Operator_Cylinder* m_InnerOp; + + // sub-grid to base interpolation coefficients + unsigned int* m_interpol_pos_v_2p[2]; + f4vector* f4_interpol_v_2p[2]; + unsigned int* m_interpol_pos_v_2pp[2]; + f4vector* f4_interpol_v_2pp[2]; + + unsigned int* m_interpol_pos_i_2p[2]; + f4vector* f4_interpol_i_2p[2]; + unsigned int* m_interpol_pos_i_2pp[2]; + f4vector* f4_interpol_i_2pp[2]; + + void SetupInterpolation(); + + virtual void CalcStartStopLines(unsigned int &numThreads, vector &start, vector &stop) const; +}; + +#endif // OPERATOR_CYLINDERMULTIGRID_H diff --git a/openEMS/FDTD/operator_mpi.cpp b/openEMS/FDTD/operator_mpi.cpp new file mode 100644 index 0000000..432f5d7 --- /dev/null +++ b/openEMS/FDTD/operator_mpi.cpp @@ -0,0 +1,209 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "operator_mpi.h" +#include "operator_sse_compressed.h" +#include "engine_sse_compressed.h" +#include "engine_mpi.h" +#include "extensions/operator_extension.h" +#include "tools/array_ops.h" +#include "tools/useful.h" +#include "mpi.h" + +Operator_MPI* Operator_MPI::New() +{ + cout << "Create FDTD operator (compressed SSE + MPI)" << endl; + Operator_MPI* op = new Operator_MPI(); + op->Init(); + return op; +} + +Operator_MPI::Operator_MPI() : Operator_SSE_Compressed() +{ + m_NumProc = MPI::COMM_WORLD.Get_size(); + + //enabled only if more than one process is active + m_MPI_Enabled = m_NumProc>1; +} + +Operator_MPI::~Operator_MPI() +{ + Delete(); +} + +double Operator_MPI::CalcTimestep() +{ + double ret = Operator::CalcTimestep(); + + if (!m_MPI_Enabled) + return ret; + + double local_dT = dT; + //find the smallest time-step requestes by all processings + MPI_Reduce(&local_dT, &dT, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD); + //send the smallest time-step to all + MPI_Bcast(&dT, 1, MPI_DOUBLE, 0, MPI_COMM_WORLD); + + return ret; +} + +void Operator_MPI::SetBoundaryCondition(int* BCs) +{ + if (!m_MPI_Enabled) + return Operator_SSE_Compressed::SetBoundaryCondition(BCs); + + //set boundary conditions on MPI interfaces to PEC, ApplyElectricBC will handle proper interface handling... + for (int n=0;n<3;++n) + { + if (m_NeighborUp[n]>=0) + BCs[2*n+1] = 0; + if (m_NeighborDown[n]>=0) + BCs[2*n] = 0; + } + Operator_SSE_Compressed::SetBoundaryCondition(BCs); +} + +Engine* Operator_MPI::CreateEngine() +{ + if (m_MPI_Enabled) + m_Engine = Engine_MPI::New(this); + else + m_Engine = Engine_SSE_Compressed::New(this); + return m_Engine; +} + +void Operator_MPI::SetNeighborUp(int ny, int id) +{ + if ((ny<0) || (ny>2)) + return; + m_NeighborUp[ny]=id; +} + +void Operator_MPI::SetNeighborDown(int ny, int id) +{ + if ((ny<0) || (ny>2)) + return; + m_NeighborDown[ny]=id; +} + +void Operator_MPI::Init() +{ + Operator_SSE_Compressed::Init(); + + m_MyTag = 0; + + for (int i=0;i<3;++i) + { + m_NeighborUp[i]=-1; + m_NeighborDown[i]=-1; + m_OrigDiscLines[i]=NULL; + } + + m_ProcTable = NULL; + m_SplitNumber[0]=0; + m_SplitNumber[1]=0; + m_SplitNumber[2]=0; + + int namelen; + m_NumProc = MPI::COMM_WORLD.Get_size(); + m_MyID = MPI::COMM_WORLD.Get_rank(); + + m_Processor_Name = new char[MPI_MAX_PROCESSOR_NAME]; + MPI::Get_processor_name(m_Processor_Name,namelen); + + if ((m_MPI_Enabled) && (g_settings.GetVerboseLevel()>0)) + cerr << "Operator_MPI::Init(): Running on " << m_Processor_Name << endl; +} + +void Operator_MPI::Delete() +{ + delete[] m_Processor_Name; + m_Processor_Name = NULL; + for (int i=0;i<3;++i) + { + delete[] m_OrigDiscLines[i]; + m_OrigDiscLines[i] = NULL; + } + Delete3DArray(m_ProcTable,m_SplitNumber); + m_ProcTable=NULL; +} + +void Operator_MPI::Reset() +{ + Delete(); + Operator_SSE_Compressed::Reset(); +} + +void Operator_MPI::SetOriginalMesh(CSRectGrid* orig_Mesh) +{ + for (int n=0;n<3;++n) + { + delete[] m_OrigDiscLines[n]; + m_OrigDiscLines[n] = orig_Mesh->GetLines(n,NULL,m_OrigNumLines[n]); + } +} + +unsigned int Operator_MPI::GetNumberOfLines(int ny, bool fullMesh) const +{ + if (fullMesh) + return Operator_SSE_Compressed::GetNumberOfLines(ny,fullMesh); + + if ((!m_MPI_Enabled) || (m_NeighborUp[ny]<0)) + return Operator_SSE_Compressed::GetNumberOfLines(ny,fullMesh); + + return Operator_SSE_Compressed::GetNumberOfLines(ny)-1; +} + +void Operator_MPI::AddExtension(Operator_Extension* op_ext) +{ + if (m_MPI_Enabled==false) + return Operator_SSE_Compressed::AddExtension(op_ext); + + if (op_ext->IsMPISave()) + Operator_SSE_Compressed::AddExtension(op_ext); + else + { + cerr << "Operator_MPI::AddExtension: Warning: Operator extension \"" << op_ext->GetExtensionName() << "\" is not compatible with MPI!! skipping...!" << endl; + delete op_ext; + } +} + + +string Operator_MPI::PrependRank(string name) +{ + stringstream out_name; + if (m_MPI_Enabled) + out_name << "ID" << m_MyID << "_" << name; + else + out_name << name; + return out_name.str(); +} + +void Operator_MPI::DumpOperator2File(string filename) +{ + Operator_SSE_Compressed::DumpOperator2File(PrependRank(filename)); +} + +void Operator_MPI::DumpMaterial2File(string filename) +{ + Operator_SSE_Compressed::DumpMaterial2File(PrependRank(filename)); +} + +void Operator_MPI::DumpPEC2File(string filename , unsigned int *range) +{ + Operator_SSE_Compressed::DumpPEC2File(PrependRank(filename), range); +} diff --git a/openEMS/FDTD/operator_mpi.h b/openEMS/FDTD/operator_mpi.h new file mode 100644 index 0000000..c09616e --- /dev/null +++ b/openEMS/FDTD/operator_mpi.h @@ -0,0 +1,90 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#ifndef OPERATOR_MPI_H +#define OPERATOR_MPI_H + +#include "operator_sse_compressed.h" + +class Operator_MPI : public Operator_SSE_Compressed +{ + friend class Engine_MPI; +public: + //! Create a new operator + static Operator_MPI* New(); + virtual ~Operator_MPI(); + + bool GetMPIEnabled() const {return m_MPI_Enabled;} + + virtual void SetBoundaryCondition(int* BCs); + + virtual Engine* CreateEngine(); + + virtual void SetTag(int tag) {m_MyTag=tag;} + + //! Set the number of splits for a given direction. This also defines the size of the process table. \sa SetProcessTable + virtual void SetSplitNumbers(int ny, unsigned int splits) {m_SplitNumber[ny]=splits;} + //! Set the table containing a list of all MPI rank ID's and there mesh affiliation. \sa SetProcessTablePosition + virtual void SetProcessTable(unsigned int*** procTable) {m_ProcTable=procTable;} + //! Save the position for this rank in the process table. \sa SetProcessTable + virtual void SetProcessTablePosition(int ny, unsigned int pos) {m_ProcTablePos[ny]=pos;} + + virtual void SetNeighborUp(int ny, int id); + virtual void SetNeighborDown(int ny, int id); + + //! Set the lower original mesh position + virtual void SetSplitPos(int ny, unsigned int pos) {m_SplitPos[ny]=pos;} + virtual void SetOriginalMesh(CSRectGrid* orig_Mesh); + + virtual unsigned int GetNumberOfLines(int ny, bool fullMesh=false) const; + + virtual void AddExtension(Operator_Extension* op_ext); + +protected: + Operator_MPI(); + bool m_MPI_Enabled; + virtual void Init(); + void Delete(); + virtual void Reset(); + + virtual double CalcTimestep(); + + unsigned int m_MyID; + unsigned int m_NumProc; + int m_MyTag; + char* m_Processor_Name; + + //the up and down neighbors, -1 if non for the given direction + int m_NeighborUp[3]; + int m_NeighborDown[3]; + + unsigned int m_SplitNumber[3]; + unsigned int m_ProcTablePos[3]; + unsigned int*** m_ProcTable; + + double* m_OrigDiscLines[3]; + unsigned int m_OrigNumLines[3]; + unsigned int m_SplitPos[3]; + + string PrependRank(string name); + + virtual void DumpOperator2File(string filename); + virtual void DumpMaterial2File(string filename); + virtual void DumpPEC2File( string filename, unsigned int *range = NULL ); +}; + +#endif // OPERATOR_MPI_H diff --git a/openEMS/FDTD/operator_multithread.cpp b/openEMS/FDTD/operator_multithread.cpp new file mode 100644 index 0000000..9a602a6 --- /dev/null +++ b/openEMS/FDTD/operator_multithread.cpp @@ -0,0 +1,203 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "operator_multithread.h" +#include "engine_multithread.h" +#include "tools/useful.h" + +Operator_Multithread* Operator_Multithread::New(unsigned int numThreads) +{ + cout << "Create FDTD operator (compressed SSE + multi-threading)" << endl; + Operator_Multithread* op = new Operator_Multithread(); + op->setNumThreads(numThreads); + op->Init(); + return op; +} + +Operator_Multithread::~Operator_Multithread() +{ + Delete(); +} + +void Operator_Multithread::setNumThreads( unsigned int numThreads ) +{ + m_numThreads = numThreads; +} + +Engine* Operator_Multithread::CreateEngine() +{ + m_Engine = Engine_Multithread::New(this,m_numThreads); + return m_Engine; +} + +Operator_Multithread::Operator_Multithread() : OPERATOR_MULTITHREAD_BASE() +{ + m_CalcEC_Start=NULL; + m_CalcEC_Stop=NULL; + + m_CalcPEC_Start=NULL; + m_CalcPEC_Stop=NULL; +} + +void Operator_Multithread::Init() +{ + OPERATOR_MULTITHREAD_BASE::Init(); + + m_CalcEC_Start=NULL; + m_CalcEC_Stop=NULL; + + m_CalcPEC_Start=NULL; + m_CalcPEC_Stop=NULL; +} + +void Operator_Multithread::Delete() +{ + m_thread_group.join_all(); + + delete m_CalcEC_Start; + m_CalcEC_Start=NULL; + delete m_CalcEC_Stop; + m_CalcEC_Stop=NULL; + + delete m_CalcPEC_Start; + m_CalcPEC_Start=NULL; + delete m_CalcPEC_Stop; + m_CalcPEC_Stop=NULL; +} + +void Operator_Multithread::Reset() +{ + Delete(); + OPERATOR_MULTITHREAD_BASE::Reset(); +} + +void Operator_Multithread::CalcStartStopLines(unsigned int &numThreads, vector &start, vector &stop) const +{ + vector jpt = AssignJobs2Threads(numLines[0], numThreads, true); + + numThreads = jpt.size(); + + start.resize(numThreads); + stop.resize(numThreads); + + start.at(0)=0; + stop.at(0)=jpt.at(0)-1; + + for (unsigned int n=1; n m_Start_Lines; + vector m_Stop_Lines; + CalcStartStopLines( m_numThreads, m_Start_Lines, m_Stop_Lines ); + + if (g_settings.GetVerboseLevel()>0) + cout << "Multithreaded operator using " << m_numThreads << " threads." << std::endl; + + m_thread_group.join_all(); + delete m_CalcEC_Start; + m_CalcEC_Start = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + delete m_CalcEC_Stop; + m_CalcEC_Stop = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + + delete m_CalcPEC_Start; + m_CalcPEC_Start = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + delete m_CalcPEC_Stop; + m_CalcPEC_Stop = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + + for (unsigned int n=0; nSetPos(0,0,0); + + m_CalcEC_Start->wait(); + + m_CalcEC_Stop->wait(); + + return true; +} + +bool Operator_Multithread::CalcPEC() +{ + m_Nr_PEC[0]=0; + m_Nr_PEC[1]=0; + m_Nr_PEC[2]=0; + + m_Nr_PEC_thread = new unsigned int[m_numThreads][3]; + + m_CalcPEC_Start->wait(); + + m_CalcPEC_Stop->wait(); + + for (unsigned int t=0; tm_CalcEC_Start->wait(); + m_OpPtr->Calc_EC_Range(m_start,m_stop); + m_OpPtr->m_CalcEC_Stop->wait(); + + //************** calculate EC (Calc_EC) ***********************// + m_OpPtr->m_CalcPEC_Start->wait(); + for (int n=0; n<3; ++n) + m_OpPtr->m_Nr_PEC_thread[m_threadID][n] = 0; + + m_OpPtr->CalcPEC_Range(m_start,m_stop,m_OpPtr->m_Nr_PEC_thread[m_threadID]); + m_OpPtr->m_CalcPEC_Stop->wait(); +} + diff --git a/openEMS/FDTD/operator_multithread.h b/openEMS/FDTD/operator_multithread.h new file mode 100644 index 0000000..65f4748 --- /dev/null +++ b/openEMS/FDTD/operator_multithread.h @@ -0,0 +1,89 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef OPERATOR_MULTITHREAD_H +#define OPERATOR_MULTITHREAD_H + +#include "operator_sse_compressed.h" + +#include + +#ifdef MPI_SUPPORT + #define OPERATOR_MULTITHREAD_BASE Operator_MPI + #include "operator_mpi.h" +#else + #define OPERATOR_MULTITHREAD_BASE Operator_SSE_Compressed +#endif + +class Operator_Multithread : public OPERATOR_MULTITHREAD_BASE +{ + friend class Engine_Multithread; + friend class Operator_Thread; +public: + //! Create a new operator + static Operator_Multithread* New(unsigned int numThreads = 0); + virtual ~Operator_Multithread(); + + virtual void setNumThreads( unsigned int numThreads ); + + virtual Engine* CreateEngine(); + +protected: + Operator_Multithread(); + virtual void Init(); + void Delete(); + virtual void Reset(); + + virtual bool Calc_EC(); //this method is using multi-threading + + unsigned int (*m_Nr_PEC_thread)[3]; //count PEC edges per thread + virtual bool CalcPEC(); //this method is using multi-threading + + virtual int CalcECOperator( DebugFlags debugFlags = None ); + + //Calc_EC barrier + boost::barrier* m_CalcEC_Start; + boost::barrier* m_CalcEC_Stop; + //CalcPEC barrier + boost::barrier* m_CalcPEC_Start; + boost::barrier* m_CalcPEC_Stop; + + boost::thread_group m_thread_group; + unsigned int m_numThreads; // number of worker threads + + //! Calculate the start/stop lines for the multithreading operator and engine. + /*! + It depends on the number of threads and number of lines to simulate. + This method is also used by the multithreading engine! + This method may also reduce the usable number of thread in case of too few lines or otherwise bad utilization. + */ + virtual void CalcStartStopLines(unsigned int &numThreads, vector &start, vector &stop) const; +}; + +class Operator_Thread +{ +public: + Operator_Thread( Operator_Multithread* ptr, unsigned int start, unsigned int stop, unsigned int threadID ); + void operator()(); + +protected: + unsigned int m_start, m_stop, m_threadID; + Operator_Multithread *m_OpPtr; +}; + + +#endif // OPERATOR_MULTITHREAD_H diff --git a/openEMS/FDTD/operator_sse.cpp b/openEMS/FDTD/operator_sse.cpp new file mode 100644 index 0000000..8a1b21b --- /dev/null +++ b/openEMS/FDTD/operator_sse.cpp @@ -0,0 +1,91 @@ +/* +* Copyright (C) 2010 Sebastian Held (Sebastian.Held@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 . +*/ + +#include "engine_sse.h" +#include "operator_sse.h" +#include "tools/array_ops.h" +//#include "processfields.h" + +Operator_sse* Operator_sse::New() +{ + cout << "Create FDTD operator (SSE)" << endl; + Operator_sse* op = new Operator_sse(); + op->Init(); + return op; +} + +Operator_sse::Operator_sse() : Operator() +{ + f4_vv = 0; + f4_vi = 0; + f4_iv = 0; + f4_ii = 0; +} + +Operator_sse::~Operator_sse() +{ + Delete(); +} + +Engine* Operator_sse::CreateEngine() const +{ + //! create a special sse-engine + Engine_sse* eng = Engine_sse::New(this); + return eng; +} + +void Operator_sse::Init() +{ + Operator::Init(); + f4_vv = 0; + f4_vi = 0; + f4_iv = 0; + f4_ii = 0; +} + +void Operator_sse::Delete() +{ + Delete_N_3DArray_v4sf(f4_vv,numLines); + Delete_N_3DArray_v4sf(f4_vi,numLines); + Delete_N_3DArray_v4sf(f4_iv,numLines); + Delete_N_3DArray_v4sf(f4_ii,numLines); + f4_vv = 0; + f4_vi = 0; + f4_iv = 0; + f4_ii = 0; +} + +void Operator_sse::Reset() +{ + Delete(); + Operator::Reset(); +} + + +void Operator_sse::InitOperator() +{ + Delete_N_3DArray_v4sf(f4_vv,numLines); + Delete_N_3DArray_v4sf(f4_vi,numLines); + Delete_N_3DArray_v4sf(f4_iv,numLines); + Delete_N_3DArray_v4sf(f4_ii,numLines); + f4_vv = Create_N_3DArray_v4sf(numLines); + f4_vi = Create_N_3DArray_v4sf(numLines); + f4_iv = Create_N_3DArray_v4sf(numLines); + f4_ii = Create_N_3DArray_v4sf(numLines); + + numVectors = ceil((double)numLines[2]/4.0); +} diff --git a/openEMS/FDTD/operator_sse.h b/openEMS/FDTD/operator_sse.h new file mode 100644 index 0000000..317ea72 --- /dev/null +++ b/openEMS/FDTD/operator_sse.h @@ -0,0 +1,63 @@ +/* +* Copyright (C) 2010 Sebastian Held (Sebastian.Held@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 . +*/ + +#ifndef OPERATOR_SSE_H +#define OPERATOR_SSE_H + +#include "operator.h" +#include "tools/array_ops.h" + +class Operator_sse : public Operator +{ + friend class Engine_Interface_SSE_FDTD; +public: + //! Create a new operator + static Operator_sse* New(); + virtual ~Operator_sse(); + + virtual Engine* CreateEngine() const; + + 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]; } + inline virtual FDTD_FLOAT GetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_ii[n][x][y][z%numVectors].f[z/numVectors]; } + inline virtual FDTD_FLOAT GetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { return f4_iv[n][x][y][z%numVectors].f[z/numVectors]; } + + inline virtual void SetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { f4_vv[n][x][y][z%numVectors].f[z/numVectors] = value; } + inline virtual void SetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { f4_vi[n][x][y][z%numVectors].f[z/numVectors] = value; } + inline virtual void SetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { f4_ii[n][x][y][z%numVectors].f[z/numVectors] = value; } + inline virtual void SetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { f4_iv[n][x][y][z%numVectors].f[z/numVectors] = value; } + +protected: + //! use New() for creating a new Operator + Operator_sse(); + + virtual void Init(); + void Delete(); + virtual void Reset(); + virtual void InitOperator(); + + unsigned int numVectors; + + // engine/post-proc needs access +public: + f4vector**** f4_vv; //calc new voltage from old voltage + f4vector**** f4_vi; //calc new voltage from old current + f4vector**** f4_iv; //calc new current from old current + f4vector**** f4_ii; //calc new current from old voltage +}; + +#endif // OPERATOR_SSE_H diff --git a/openEMS/FDTD/operator_sse_compressed.cpp b/openEMS/FDTD/operator_sse_compressed.cpp new file mode 100644 index 0000000..5214892 --- /dev/null +++ b/openEMS/FDTD/operator_sse_compressed.cpp @@ -0,0 +1,251 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "operator_sse_compressed.h" +#include "engine_sse_compressed.h" +#include "engine_sse.h" +#include "tools/array_ops.h" + +#include +#include + +Operator_SSE_Compressed* Operator_SSE_Compressed::New() +{ + cout << "Create FDTD operator (compressed SSE)" << endl; + Operator_SSE_Compressed* op = new Operator_SSE_Compressed(); + op->Init(); + return op; +} + +Operator_SSE_Compressed::Operator_SSE_Compressed() : Operator_sse() +{ + m_Op_index = NULL; + m_Use_Compression = false; +} + +Operator_SSE_Compressed::~Operator_SSE_Compressed() +{ + Delete(); +} + +Engine* Operator_SSE_Compressed::CreateEngine() const +{ + 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; +} + +int Operator_SSE_Compressed::CalcECOperator( DebugFlags debugFlags ) +{ + int ErrCode = Operator_sse::CalcECOperator( debugFlags ); + m_Use_Compression = false; + m_Use_Compression = CompressOperator(); + + return ErrCode; +} + +void Operator_SSE_Compressed::Init() +{ + Operator_sse::Init(); + m_Use_Compression = false; + m_Op_index = NULL; +} + +void Operator_SSE_Compressed::Delete() +{ + if (m_Op_index) + { + Delete3DArray( m_Op_index, numLines ); + m_Op_index = 0; + } + + m_Use_Compression = false; + for (int n=0; n<3; n++) + { + f4_vv_Compressed[n].clear(); + f4_vi_Compressed[n].clear(); + f4_iv_Compressed[n].clear(); + f4_ii_Compressed[n].clear(); + } +} + +void Operator_SSE_Compressed::Reset() +{ + Delete(); + Operator_sse::Reset(); +} + +void Operator_SSE_Compressed::InitOperator() +{ + //cleanup compression + m_Use_Compression = false; + for (int n=0; n<3; n++) + { + f4_vv_Compressed[n].clear(); + f4_vi_Compressed[n].clear(); + f4_iv_Compressed[n].clear(); + f4_ii_Compressed[n].clear(); + } + + Operator_sse::InitOperator(); + m_Op_index = Create3DArray( numLines ); +} + +void Operator_SSE_Compressed::ShowStat() const +{ + Operator_sse::ShowStat(); + + cout << "SSE compression enabled\t: " << (m_Use_Compression?"yes":"no") << endl; + cout << "Unique SSE operators\t: " << f4_vv_Compressed->size() << endl; + cout << "-----------------------------------" << endl; +} + +bool Operator_SSE_Compressed::CompressOperator() +{ + if (g_settings.GetVerboseLevel()>0) + cout << "Compressing the FDTD operator... this may take a while..." << endl; + + map lookUpMap; + + unsigned int pos[3]; + for (pos[0]=0; pos[0]::iterator it; + it = lookUpMap.find(c); + if (it == lookUpMap.end()) + { + // not found -> insert + unsigned int index = f4_vv_Compressed[0].size(); + for (int n=0; n<3; n++) + { + f4_vv_Compressed[n].push_back( vv[n] ); + f4_vi_Compressed[n].push_back( vi[n] ); + f4_iv_Compressed[n].push_back( iv[n] ); + f4_ii_Compressed[n].push_back( ii[n] ); + } + lookUpMap[c] = index; + m_Op_index[pos[0]][pos[1]][pos[2]] = index; + } + else + { + // this operator is already in the list + unsigned int index = (*it).second; + m_Op_index[pos[0]][pos[1]][pos[2]] = index; + } + } + } + } + + Delete_N_3DArray_v4sf(f4_vv,numLines); + Delete_N_3DArray_v4sf(f4_vi,numLines); + Delete_N_3DArray_v4sf(f4_iv,numLines); + Delete_N_3DArray_v4sf(f4_ii,numLines); + f4_vv = 0; + f4_vi = 0; + f4_iv = 0; + f4_ii = 0; + + return true; +} + + + + +// ---------------------------------------------------------------------------- + +SSE_coeff::SSE_coeff( f4vector vv[3], f4vector vi[3], f4vector iv[3], f4vector ii[3] ) +{ + for (int n=0; n<3; n++) + { + m_vv[n] = vv[n]; + m_vi[n] = vi[n]; + m_iv[n] = iv[n]; + m_ii[n] = ii[n]; + } +} + +bool SSE_coeff::operator==( const SSE_coeff& other ) const +{ + for (int n=0; n<3; n++) + { + if (memcmp( &(m_vv[n]), &(other.m_vv[n]), sizeof(f4vector) ) != 0) return false; + if (memcmp( &(m_vi[n]), &(other.m_vi[n]), sizeof(f4vector) ) != 0) return false; + if (memcmp( &(m_iv[n]), &(other.m_iv[n]), sizeof(f4vector) ) != 0) return false; + if (memcmp( &(m_ii[n]), &(other.m_ii[n]), sizeof(f4vector) ) != 0) return false; + } + return true; +} +bool SSE_coeff::operator!=( const SSE_coeff& other ) const +{ + return !(*this == other); +} +bool SSE_coeff::operator<( const SSE_coeff& other ) const +{ + for (int n=0; n<3; n++) + { + for (int c=0; c<4; c++) + { + if (m_vv[n].f[c] > other.m_vv[n].f[c]) return false; + if (m_vv[n].f[c] < other.m_vv[n].f[c]) return true; + if (m_vi[n].f[c] > other.m_vi[n].f[c]) return false; + if (m_vi[n].f[c] < other.m_vi[n].f[c]) return true; + if (m_iv[n].f[c] > other.m_iv[n].f[c]) return false; + if (m_iv[n].f[c] < other.m_iv[n].f[c]) return true; + if (m_ii[n].f[c] > other.m_ii[n].f[c]) return false; + if (m_ii[n].f[c] < other.m_ii[n].f[c]) return true; + } + } + return false; +} + +void SSE_coeff::print( ostream& stream ) const +{ + stream << "SSE_coeff: (" << endl; + for (int n=0; n<3; n++) + { + stream << "n=" << n << ":" << endl; + stream << "vv="; + for (int c=0; c<4; c++) + stream << m_vv[n].f[c] << " "; + stream << endl << "vi="; + for (int c=0; c<4; c++) + stream << m_vi[n].f[c] << " "; + stream << endl << "iv="; + for (int c=0; c<4; c++) + stream << m_iv[n].f[c] << " "; + stream << endl << "ii="; + for (int c=0; c<4; c++) + stream << m_ii[n].f[c] << " "; + stream << endl; + } + stream << ")" << endl; +} diff --git a/openEMS/FDTD/operator_sse_compressed.h b/openEMS/FDTD/operator_sse_compressed.h new file mode 100644 index 0000000..5d3454f --- /dev/null +++ b/openEMS/FDTD/operator_sse_compressed.h @@ -0,0 +1,84 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef OPERATOR_SSE_COMPRESSED_H +#define OPERATOR_SSE_COMPRESSED_H + +#include "operator_sse.h" +#include "tools/aligned_allocator.h" + +class SSE_coeff +{ +public: + SSE_coeff( f4vector vv[3], f4vector vi[3], f4vector iv[3], f4vector ii[3] ); + bool operator==( const SSE_coeff& ) const; + bool operator!=( const SSE_coeff& ) const; + bool operator<( const SSE_coeff& ) const; + void print( ostream& stream ) const; +protected: + f4vector m_vv[3]; + f4vector m_vi[3]; + f4vector m_iv[3]; + f4vector m_ii[3]; +}; + +class Operator_SSE_Compressed : public Operator_sse +{ +public: + //! Create a new operator + static Operator_SSE_Compressed* New(); + virtual ~Operator_SSE_Compressed(); + + virtual Engine* CreateEngine() const; + + 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);} + inline virtual FDTD_FLOAT GetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { if (m_Use_Compression) return f4_ii_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors]; else return Operator_sse::GetII(n,x,y,z);} + inline virtual FDTD_FLOAT GetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z ) const { if (m_Use_Compression) return f4_iv_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors]; else return Operator_sse::GetIV(n,x,y,z);} + + inline virtual void SetVV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { if (m_Use_Compression) f4_vv_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors] = value; else Operator_sse::SetVV(n,x,y,z,value);} + inline virtual void SetVI( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { if (m_Use_Compression) f4_vi_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors] = value; else Operator_sse::SetVI(n,x,y,z,value);} + inline virtual void SetII( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { if (m_Use_Compression) f4_ii_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors] = value; else Operator_sse::SetII(n,x,y,z,value);} + inline virtual void SetIV( unsigned int n, unsigned int x, unsigned int y, unsigned int z, FDTD_FLOAT value ) { if (m_Use_Compression) f4_iv_Compressed[n][m_Op_index[x][y][z%numVectors]].f[z/numVectors] = value; else Operator_sse::SetIV(n,x,y,z,value);} + + virtual void ShowStat() const; + + bool CompressOperator(); + +protected: + Operator_SSE_Compressed(); + + bool m_Use_Compression; + + virtual void Init(); + void Delete(); + virtual void Reset(); + virtual void InitOperator(); + + virtual int CalcECOperator( DebugFlags debugFlags = None ); + + // engine needs access +public: + unsigned int*** m_Op_index; + vector > f4_vv_Compressed[3]; //!< coefficient: calc new voltage from old voltage + vector > f4_vi_Compressed[3]; //!< coefficient: calc new voltage from old current + vector > f4_iv_Compressed[3]; //!< coefficient: calc new current from old voltage + vector > f4_ii_Compressed[3]; //!< coefficient: calc new current from old current + +}; + +#endif // OPERATOR_SSE_Compressed_H diff --git a/openEMS/INSTALL b/openEMS/INSTALL new file mode 100644 index 0000000..6678190 --- /dev/null +++ b/openEMS/INSTALL @@ -0,0 +1,27 @@ +Install instructions for openEMS: +--------------------------------------------- + +1) Prerequirements: + openEMS relies on a number of libraries: + - CSXCAD (http://openEMS.de) + - fparser (http://warp.povusers.org/FunctionParser/) + - tinyxml (http://www.grinninglizard.com/tinyxml/) + - hdf5 (http://www.hdfgroup.org/HDF5/) + - vtk (http://www.vtk.org/) + - boost (http://www.boost.org/) + - cgal (http://www.cgal.org/) + - zlib (http://www.zlib.net/) + +2) Build: + - change directory to openEMS + - build: + mkdir build + cd build + cmake .. -DCMAKE_INSTALL_PREFIX= -DFPARSER_ROOT_DIR= -DCSXCAD_ROOT_DIR= + make + make install (may require root) + + Note: + - all path informations may be stored in a localConfig.cmake + - the default "prefix" is /usr/local + diff --git a/openEMS/NEWS b/openEMS/NEWS new file mode 100644 index 0000000..769a73b --- /dev/null +++ b/openEMS/NEWS @@ -0,0 +1,40 @@ +Summary of most noticeable changes for version 0.0.31: +----------------------------------------------------- + - nf2ff: calculate circular polarization + - improvements to calcPort + - allow 1D and 2D lumped ports + - improvements to SAR calculations + - curve primitives and port fixes & improvements + - FDTD operator now supports different material averaging methods + - support for full multi-polar Lorentz/Drude/Debye dispersive material types + - new ports for waveguides (rectangular and circular waveguides) + - improved PEC debugging + - improvements/simplifications in plotting far-fields (thanks to Stefan) + - new tutorials and examples + - many fixes and updates + +Summary of most noticeable changes for version 0.0.30: +----------------------------------------------------- + - meshing improved with new detect edges and new smoothing capabilities + - new calcPort function for simplified port analysis + - cylindrical mesh improvement by considering 360° rotation symmetry + - support for harminv on all platforms + - update to auto-regressive model for voltage/current probes + - new SAR calculation options, incl. 1g/10g averaging + - support for a new primitive: polyhedron + - CAD import: STL/PLY surface solids supported (matlab: ImportSTL / ImportPLY) + - CAD export: STL/PLY export (using AppCSXCAD) + - lot of minor fixes and updates + +Summary of most noticeable changes for version 0.0.29: +----------------------------------------------------- + - Cylindrical sub-grids now fully support alpha-graded meshes + - Property Electrode has been renamed to Excitation + This doesn't have any effect on the Matlab/Octave interface, + but old *.xml files cannot be run with a current openEMS/CSXCAD version. + - Overall memory usage reduced during pre-processing + - New excitation: Total-field/scattered field (TFSF) + - New tutorial on radar cross section on a metallic sphere using the TFSF excitation + - official support for 64-bit windows version + - check for engine extensions MPI compatibility + - CSXCAD: support for new CSXGeomPlot export options (see help for more infos) diff --git a/openEMS/README b/openEMS/README new file mode 100644 index 0000000..fdfd137 --- /dev/null +++ b/openEMS/README @@ -0,0 +1,19 @@ +* +* openEMS - a free and open electromagnetic field solver +* +* Copyright (C) 2010-2015 Thorsten Liebig +* + +openEMS is licensed under the terms of the GPLv3, see . + + +Website: http://openems.de +Forum: http://openems.de/forum/ +Tutorials: http://openems.de/index.php/Tutorials + + +To use openEMS from Matlab or Octave, you need to include the /matlab folder in the respective environment: +> addpath( '/matlab' ); + +To verify the correct installation follow the instructions at: +http://openems.de/index.php/Tutorial:_First_Steps diff --git a/openEMS/TESTSUITE/combinedtests/Coax.m b/openEMS/TESTSUITE/combinedtests/Coax.m new file mode 100644 index 0000000..18ed5ab --- /dev/null +++ b/openEMS/TESTSUITE/combinedtests/Coax.m @@ -0,0 +1,158 @@ +function pass = Coax( openEMS_options, options ) + +physical_constants; + + +ENABLE_PLOTS = 1; +CLEANUP = 1; % if enabled and result is PASS, remove simulation folder +STOP_IF_FAILED = 1; % if enabled and result is FAILED, stop with error +SILENT = 0; % 0=show openEMS output + +if nargin < 1 + openEMS_options = ''; +end +if nargin < 2 + options = ''; +end +if any(strcmp( options, 'run_testsuite' )) + ENABLE_PLOTS = 0; + STOP_IF_FAILED = 0; + SILENT = 1; +end + +% LIMITS +upper_error = 0.03; % max +3% +lower_error = 0.01; % max -1% + +% structure +length = 1000; +coax_rad_i = 100; +coax_rad_ai = 230; +coax_rad_aa = 240; +mesh_res = [5 5 5]; +f_start = 0; +f_stop = 1e9; + +Sim_Path = 'tmp_Coax'; +Sim_CSX = 'coax.xml'; + +[status,message,messageid]=rmdir(Sim_Path,'s'); +[status,message,messageid]=mkdir(Sim_Path); + +%setup FDTD parameter +FDTD = InitFDTD(5000,1e-6); +FDTD = SetGaussExcite(FDTD,0,f_stop); +FDTD = SetBoundaryCond(FDTD,{'PEC','PEC','PEC','PEC','PEC','PML_8'}); + +%setup CSXCAD geometry +CSX = InitCSX(); +mesh.x = -2.5*mesh_res(1)-coax_rad_aa : mesh_res(1) : coax_rad_aa+2.5*mesh_res(1); +mesh.y = mesh.x; +mesh.z = 0 : mesh_res(3) : length; +mesh.z = linspace(0,length,numel(mesh.z)); +CSX = DefineRectGrid(CSX, 1e-3,mesh); + +% create a perfect electric conductor +CSX = AddMetal(CSX,'PEC'); + +%%% coax +start = [0, 0 , 0];stop = [0, 0 , length]; +CSX = AddCylinder(CSX,'PEC',1 ,start,stop,coax_rad_i); % inner conductor +CSX = AddCylindricalShell(CSX,'PEC',0 ,start,stop,0.5*(coax_rad_aa+coax_rad_ai),(coax_rad_aa-coax_rad_ai)); % outer conductor + +%%% add excitation +start(3) = 0; stop(3)=mesh_res(1)/2; +CSX = AddExcitation(CSX,'excite',0,[1 1 0]); +weight{1} = '(x)/(x*x+y*y)'; +weight{2} = 'y/pow(rho,2)'; +weight{3} = '0'; +CSX = SetExcitationWeight(CSX, 'excite', weight ); +CSX = AddCylindricalShell(CSX,'excite',0 ,start,stop,0.5*(coax_rad_i+coax_rad_ai),(coax_rad_ai-coax_rad_i)); + +% %dump +% CSX = AddDump(CSX,'Et_',0,2); +% start = [mesh.x(1) , 0 , mesh.z(1)]; +% stop = [mesh.x(end) , 0 , mesh.z(end)]; +% CSX = AddBox(CSX,'Et_',0 , start,stop); +% +% CSX = AddDump(CSX,'Ht_',1,2); +% CSX = AddBox(CSX,'Ht_',0,start,stop); + +%voltage calc +CSX = AddProbe(CSX,'ut1',0); +start = [ coax_rad_i 0 length/2 ];stop = [ coax_rad_ai 0 length/2 ]; +CSX = AddBox(CSX,'ut1', 0 ,start,stop); + +%current calc +CSX = AddProbe(CSX,'it1',1); +% mid = 0.5*(coax_rad_i+coax_rad_ai); +mid = coax_rad_i+3*mesh_res(1); +start = [ -mid -mid length/2 ];stop = [ mid mid length/2 ]; +CSX = AddBox(CSX,'it1', 0 ,start,stop); + +%Write openEMS compatible xml-file +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + +% show structure +% CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + +% run openEMS +folder = fileparts( mfilename('fullpath') ); +Settings.LogFile = [folder '/' Sim_Path '/openEMS.log']; +Settings.Silent = SILENT; +RunOpenEMS( Sim_Path, Sim_CSX, openEMS_options, Settings ); +UI = ReadUI( {[Sim_Path '/ut1'], [Sim_Path '/it1']} ); + + +% +% analysis +% + +f = UI.FD{2}.f; +u = UI.FD{1}.val; +i = UI.FD{2}.val; + +f_idx_start = interp1( f, 1:numel(f), f_start, 'nearest' ); +f_idx_stop = interp1( f, 1:numel(f), f_stop, 'nearest' ); +f = f(f_idx_start:f_idx_stop); +u = u(f_idx_start:f_idx_stop); +i = i(f_idx_start:f_idx_stop); + +Z = abs(u./i); + +% analytic formular for characteristic impedance +Z0 = sqrt(MUE0/EPS0) * log(coax_rad_ai/coax_rad_i) / (2*pi); +upper_limit = Z0 * (1+upper_error); +lower_limit = Z0 * (1-lower_error); + +if ENABLE_PLOTS + upper = upper_limit * ones(1,size(Z,2)); + lower = lower_limit * ones(1,size(Z,2)); + Z0_plot = Z0 * ones(1,size(Z,2)); + figure + plot(f/1e9,[Z;upper;lower]) + hold on + plot(f/1e9,Z0_plot,'m-.','LineWidth',2) + hold off + xlabel('Frequency (GHz)') + ylabel('Impedance (Ohm)') + legend( {'sim', 'upper limit', 'lower limit', 'theoretical'} ); +end + +pass = check_limits( Z, upper_limit, lower_limit ); +if pass + disp( 'combinedtests/Coax.m (characteristic impedance): pass' ); +else + disp( 'combinedtests/Coax.m (characteristic impedance): * FAILED *' ); +end + + + + +if pass && CLEANUP + rmdir( Sim_Path, 's' ); +end +if ~pass && STOP_IF_FAILED + error 'test failed'; +end + diff --git a/openEMS/TESTSUITE/combinedtests/README b/openEMS/TESTSUITE/combinedtests/README new file mode 100644 index 0000000..cc29c5b --- /dev/null +++ b/openEMS/TESTSUITE/combinedtests/README @@ -0,0 +1,3 @@ +# +# These scripts test the full simulator (not single features) +# \ No newline at end of file diff --git a/openEMS/TESTSUITE/combinedtests/cavity.m b/openEMS/TESTSUITE/combinedtests/cavity.m new file mode 100644 index 0000000..4123a81 --- /dev/null +++ b/openEMS/TESTSUITE/combinedtests/cavity.m @@ -0,0 +1,229 @@ +function pass = cavity( openEMS_options, options ) + +physical_constants; + + +ENABLE_PLOTS = 1; +CLEANUP = 1; % if enabled and result is PASS, remove simulation folder +STOP_IF_FAILED = 1; % if enabled and result is FAILED, stop with error +SILENT = 0; % 0=show openEMS output + +if nargin < 1 + openEMS_options = ''; +end +if nargin < 2 + options = ''; +end +if any(strcmp( options, 'run_testsuite' )) + ENABLE_PLOTS = 0; + STOP_IF_FAILED = 0; + SILENT = 1; +end + +% LIMITS - inside +lower_rel_limit = 1.3e-3; % -0.13% +upper_rel_limit = 1.3e-3; % +0.13% +lower_rel_limit_TM = 2.5e-3; % -0.25% +upper_rel_limit_TM = 0; % +0% +min_rel_amplitude = 0.6; % 60% +min_rel_amplitude_TM = 0.27; % 27% + +% LIMITS - outside +outer_rel_limit = 0.02; +max_rel_amplitude = 0.17; + + +% structure +a = 5e-2; +b = 2e-2; +d = 6e-2; +if ~((b f2, f2_idx = f2_idx - 1; end + + if strcmp( type, 'inside' ) + if max( val(f1_idx:f2_idx) ) < max1 * rel_amplitude + pass = false; + return + end + elseif strcmp( type, 'outside' ) + if max( val(f1_idx:f2_idx) ) > max1 * rel_amplitude + pass = false; + return + end + else + error 'unsupported operation' + end +end diff --git a/openEMS/TESTSUITE/helperscripts/check_limits.m b/openEMS/TESTSUITE/helperscripts/check_limits.m new file mode 100644 index 0000000..c1cba3d --- /dev/null +++ b/openEMS/TESTSUITE/helperscripts/check_limits.m @@ -0,0 +1,22 @@ +function pass = check_limits( Z, upper_limit, lower_limit ) + +% make row vector +if size(Z,1) ~= 1 + Z = Z.'; +end + +if numel(upper_limit) == 1 + upper_limit = upper_limit * ones(1,size(Z,2)); +end +if numel(lower_limit) == 1 + lower_limit = lower_limit * ones(1,size(Z,2)); +end + + +pass = 1; +if any( Z > upper_limit ) + pass = 0; +end +if any( Z < lower_limit ) + pass = 0; +end diff --git a/openEMS/TESTSUITE/probes/fieldprobes.m b/openEMS/TESTSUITE/probes/fieldprobes.m new file mode 100644 index 0000000..edf7ed2 --- /dev/null +++ b/openEMS/TESTSUITE/probes/fieldprobes.m @@ -0,0 +1,324 @@ +function pass = fieldprobes( openEMS_options, options ) +% +% infinitesimal dipole in free-space +% +% E/H-field probes are compared to hdf5 field dumps +% + +pass = 1; + +physical_constants; + + +ENABLE_PLOTS = 1; +CLEANUP = 1; % if enabled and result is PASS, remove simulation folder +STOP_IF_FAILED = 1; % if enabled and result is FAILED, stop with error +VERBOSE = 1; +SILENT = 0; % 0=show openEMS output + +if nargin < 1 + openEMS_options = ''; +end +if nargin < 2 + options = ''; +end +if any(strcmp( options, 'run_testsuite' )) + ENABLE_PLOTS = 0; + STOP_IF_FAILED = 0; + SILENT = 1; + VERBOSE = 0; +end + +% LIMITS +limit_max_time_diff = 1e-13; +limit_max_amp_diff = 1e-7; %relative amplitude difference +limit_min_e_amp = 5e-3; +limit_min_h_amp = 1e-7; + + +% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +drawingunit = 1e-6; % specify everything in um +Sim_Path = 'tmp_fieldprobes'; +Sim_CSX = 'tmp.xml'; + +f_max = 1e9; +lambda = c0/f_max /drawingunit; + +% setup geometry values +dipole_length = lambda/50; + + +% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +mesh.x = -dipole_length*20:dipole_length/2:dipole_length*20; +mesh.y = -dipole_length*20:dipole_length/2:dipole_length*20; +mesh.z = -dipole_length*20:dipole_length/2:dipole_length*20; +CSX = DefineRectGrid( CSX, drawingunit, mesh ); + +% excitation +CSX = AddExcitation( CSX, 'infDipole', 1, [0 0 1] ); +start = [0, 0, -dipole_length/2]; +stop = [0, 0, +dipole_length/2]; +CSX = AddBox( CSX, 'infDipole', 1, start, stop ); + +% NFFF contour +s1 = [-4.5, -4.5, -4.5] * dipole_length/2; +s2 = [ 4.5, 4.5, 4.5] * dipole_length/2; +CSX = AddBox( AddDump(CSX,'Et_xn','DumpType',0,'DumpMode',0,'FileType',1), 'Et_xn', 0, s1, [s1(1) s2(2) s2(3)] ); +CSX = AddBox( AddDump(CSX,'Et_xp','DumpType',0,'DumpMode',0,'FileType',1), 'Et_xp', 0, [s2(1) s1(2) s1(3)], s2 ); +CSX = AddBox( AddDump(CSX,'Et_yn','DumpType',0,'DumpMode',0,'FileType',1), 'Et_yn', 0, s1, [s2(1) s1(2) s2(3)] ); +CSX = AddBox( AddDump(CSX,'Et_yp','DumpType',0,'DumpMode',0,'FileType',1), 'Et_yp', 0, [s1(1) s2(2) s1(3)], s2 ); +CSX = AddBox( AddDump(CSX,'Et_zn','DumpType',0,'DumpMode',0,'FileType',1), 'Et_zn', 0, s1, [s2(1) s2(2) s1(3)] ); +CSX = AddBox( AddDump(CSX,'Et_zp','DumpType',0,'DumpMode',0,'FileType',1), 'Et_zp', 0, [s1(1) s1(2) s2(3)], s2 ); +CSX = AddBox( AddDump(CSX,'Ht_xn','DumpType',1,'DumpMode',0,'FileType',1), 'Ht_xn', 0, s1, [s1(1) s2(2) s2(3)] ); +CSX = AddBox( AddDump(CSX,'Ht_xp','DumpType',1,'DumpMode',0,'FileType',1), 'Ht_xp', 0, [s2(1) s1(2) s1(3)], s2 ); +CSX = AddBox( AddDump(CSX,'Ht_yn','DumpType',1,'DumpMode',0,'FileType',1), 'Ht_yn', 0, s1, [s2(1) s1(2) s2(3)] ); +CSX = AddBox( AddDump(CSX,'Ht_yp','DumpType',1,'DumpMode',0,'FileType',1), 'Ht_yp', 0, [s1(1) s2(2) s1(3)], s2 ); +CSX = AddBox( AddDump(CSX,'Ht_zn','DumpType',1,'DumpMode',0,'FileType',1), 'Ht_zn', 0, s1, [s2(1) s2(2) s1(3)] ); +CSX = AddBox( AddDump(CSX,'Ht_zp','DumpType',1,'DumpMode',0,'FileType',1), 'Ht_zp', 0, [s1(1) s1(2) s2(3)], s2 ); + +% E-field probes +coords{1} = [s1(1) 0 0]; +CSX = AddPoint( AddProbe(CSX,'et1',2), 'et1', 0, coords{1} ); +coords{2} = [s2(1) 0 0]; +CSX = AddPoint( AddProbe(CSX,'et2',2), 'et2', 0, coords{2} ); +coords{3} = [0 s1(2) 0]; +CSX = AddPoint( AddProbe(CSX,'et3',2), 'et3', 0, coords{3} ); +coords{4} = [0 s2(2) 0]; +CSX = AddPoint( AddProbe(CSX,'et4',2), 'et4', 0, coords{4} ); +coords{5} = [0 0 s1(3)]; +CSX = AddPoint( AddProbe(CSX,'et5',2), 'et5', 0, coords{5} ); +coords{6} = [0 0 s2(3)]; +CSX = AddPoint( AddProbe(CSX,'et6',2), 'et6', 0, coords{6} ); + +% H-field probes +CSX = AddPoint( AddProbe(CSX,'ht1',3), 'ht1', 0, [s1(1) 0 0] ); +CSX = AddPoint( AddProbe(CSX,'ht2',3), 'ht2', 0, [s2(1) 0 0] ); +CSX = AddPoint( AddProbe(CSX,'ht3',3), 'ht3', 0, [0 s1(2) 0] ); +CSX = AddPoint( AddProbe(CSX,'ht4',3), 'ht4', 0, [0 s2(2) 0] ); +CSX = AddPoint( AddProbe(CSX,'ht5',3), 'ht5', 0, [0 0 s1(3)] ); +CSX = AddPoint( AddProbe(CSX,'ht6',3), 'ht6', 0, [0 0 s2(3)] ); + + + +% setup FDTD parameters & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%% +max_timesteps = 10000; +min_decrement = 1e-6; +FDTD = InitFDTD( max_timesteps, min_decrement,'OverSampling',10 ); +FDTD = SetGaussExcite( FDTD, 0, f_max ); +BC = [2 2 2 2 2 2]; +FDTD = SetBoundaryCond( FDTD, BC ); + +% Write openEMS compatible xml-file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +[~,~,~] = rmdir(Sim_Path,'s'); +[~,~,~] = mkdir(Sim_Path); +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + +% run openEMS +folder = fileparts( mfilename('fullpath') ); +Settings.LogFile = [folder '/' Sim_Path '/openEMS.log']; +Settings.Silent = SILENT; +RunOpenEMS( Sim_Path, Sim_CSX, openEMS_options, Settings ); + + +%% POSTPROCESS +filenames_E = {'Et_xn.h5','Et_xp.h5','Et_yn.h5','Et_yp.h5','Et_zn.h5','Et_zp.h5'}; +filenames_H = {'Ht_xn.h5','Ht_xp.h5','Ht_yn.h5','Ht_yp.h5','Ht_zn.h5','Ht_zp.h5'}; + +for n=1:numel(filenames_E) + Et{n} = ReadHDF5FieldData( [Sim_Path '/' filenames_E{n}] ); + E_mesh{n} = ReadHDF5Mesh( [Sim_Path '/' filenames_E{n}] ); + Ht{n} = ReadHDF5FieldData( [Sim_Path '/' filenames_H{n}] ); + H_mesh{n} = ReadHDF5Mesh( [Sim_Path '/' filenames_H{n}] ); + Et_probe{n} = load( [Sim_Path '/et' num2str(n)] ); + Ht_probe{n} = load( [Sim_Path '/ht' num2str(n)] ); +end + +if ENABLE_PLOTS + close all +end + +% +% E-fields +% +if VERBOSE, disp( 'extracting field components from field dumps...' ); end +for n=1:6 + if numel(E_mesh{n}.lines{1}) > 1 + x_idx = interp1( E_mesh{n}.lines{1}, 1:numel(E_mesh{n}.lines{1}), coords{n}(1), 'nearest' ); + else + x_idx = 1; + end + if numel(E_mesh{n}.lines{2}) > 1 + y_idx = interp1( E_mesh{n}.lines{2}, 1:numel(E_mesh{n}.lines{2}), coords{n}(2), 'nearest' ); + else + y_idx = 1; + end + if numel(E_mesh{n}.lines{3}) > 1 + z_idx = interp1( E_mesh{n}.lines{3}, 1:numel(E_mesh{n}.lines{3}), coords{n}(3), 'nearest' ); + else + z_idx = 1; + end + + if VERBOSE + disp( ['n=' num2str(n) ' coords: (' num2str(E_mesh{n}.lines{1}(x_idx)) ','... + num2str(E_mesh{n}.lines{2}(y_idx)) ','... + num2str(E_mesh{n}.lines{3}(z_idx)) ') m indices: ('... + num2str(x_idx) ',' num2str(y_idx) ',' num2str(z_idx) ')'] ); + end + + field_x = zeros(numel(Et{n}.TD.values),1); + field_y = zeros(numel(Et{n}.TD.values),1); + field_z = zeros(numel(Et{n}.TD.values),1); + for t=1:numel(Et{n}.TD.values) + field_x(t) = squeeze(Et{n}.TD.values{t}(x_idx,y_idx,z_idx,1)); + field_y(t) = squeeze(Et{n}.TD.values{t}(x_idx,y_idx,z_idx,2)); + field_z(t) = squeeze(Et{n}.TD.values{t}(x_idx,y_idx,z_idx,3)); + end + field_t = reshape( Et{n}.TD.time, [], 1 ); + + % check vector length + if numel(field_x) ~= size(Et_probe{n},1) + pass = 0; + disp( 'probes/fieldprobes.m (vector length): * FAILED *' ); + break + end + + % check absolute simulation time + if any(abs(field_t - Et_probe{n}(:,1)) > limit_max_time_diff) + pass = 0; + disp( 'probes/fieldprobes.m (time inconsistant): * FAILED *' ); + break + end + + if ENABLE_PLOTS + figure + subplot(2,3,1); + plot( field_t, [field_x Et_probe{n}(:,2)] ); + subplot(2,3,2); + plot( field_t, [field_y Et_probe{n}(:,3)] ); + subplot(2,3,3); + plot( field_t, [field_z Et_probe{n}(:,4)] ); + subplot(2,3,4); + plot( field_t, (field_x - Et_probe{n}(:,2))./field_x ); + subplot(2,3,5); + plot( field_t, (field_y - Et_probe{n}(:,3))./field_y ); + subplot(2,3,6); + plot( field_t, (field_z - Et_probe{n}(:,4))./field_z ); + end + + % difference + if any( abs( (field_x - Et_probe{n}(:,2))./field_x) > limit_max_amp_diff ) || ... + any( abs( (field_y - Et_probe{n}(:,3))./field_y) > limit_max_amp_diff ) || ... + any( abs( (field_z - Et_probe{n}(:,4))./field_z) > limit_max_amp_diff ) + pass = 0; + disp( 'probes/fieldprobes.m (amplitudes differ too much): * FAILED *' ); + break + end + + % check absolute field strength of z component + if max(abs(field_z)) < limit_min_e_amp + pass = 0; + disp( 'probes/fieldprobes.m (amplitude of z-component too small): * FAILED *' ); + break + end +end + +% +% H-fields +% +if VERBOSE, disp( 'extracting field components from field dumps...' ); end +for n=1:6 + if numel(H_mesh{n}.lines{1}) > 1 + x_idx = interp1( H_mesh{n}.lines{1}, 1:numel(H_mesh{n}.lines{1}), coords{n}(1), 'nearest' ); + else + x_idx = 1; + end + if numel(E_mesh{n}.lines{2}) > 1 + y_idx = interp1( H_mesh{n}.lines{2}, 1:numel(H_mesh{n}.lines{2}), coords{n}(2), 'nearest' ); + else + y_idx = 1; + end + if numel(E_mesh{n}.lines{3}) > 1 + z_idx = interp1( H_mesh{n}.lines{3}, 1:numel(H_mesh{n}.lines{3}), coords{n}(3), 'nearest' ); + else + z_idx = 1; + end + + if VERBOSE + disp( ['n=' num2str(n) ' coords: (' num2str(E_mesh{n}.lines{1}(x_idx)) ','... + num2str(E_mesh{n}.lines{2}(y_idx)) ','... + num2str(E_mesh{n}.lines{3}(z_idx)) ') m indices: ('... + num2str(x_idx) ',' num2str(y_idx) ',' num2str(z_idx) ')'] ); + end + + field_x = zeros(numel(Ht{n}.TD.values),1); + field_y = zeros(numel(Ht{n}.TD.values),1); + field_z = zeros(numel(Ht{n}.TD.values),1); + for t=1:numel(Ht{n}.TD.values) + field_x(t) = squeeze(Ht{n}.TD.values{t}(x_idx,y_idx,z_idx,1)); + field_y(t) = squeeze(Ht{n}.TD.values{t}(x_idx,y_idx,z_idx,2)); + field_z(t) = squeeze(Ht{n}.TD.values{t}(x_idx,y_idx,z_idx,3)); + end + field_t = reshape( Ht{n}.TD.time, [], 1 ); + + % check vector length + if numel(field_x) ~= size(Ht_probe{n},1) + pass = 0; + disp( 'probes/fieldprobes.m (vector length): * FAILED *' ); + break + end + + % check absolute simulation time + if any(abs(field_t - Ht_probe{n}(:,1)) > limit_max_time_diff) + pass = 0; + disp( 'probes/fieldprobes.m (time inconsistant): * FAILED *' ); + break + end + + if ENABLE_PLOTS + figure + subplot(2,3,1); + plot( field_t, [field_x Ht_probe{n}(:,2)] ); + subplot(2,3,2); + plot( field_t, [field_y Ht_probe{n}(:,3)] ); + subplot(2,3,3); + plot( field_t, [field_z Ht_probe{n}(:,4)] ); + subplot(2,3,4); + plot( field_t, (field_x - Ht_probe{n}(:,2))./field_x ); + subplot(2,3,5); + plot( field_t, (field_y - Ht_probe{n}(:,3))./field_y ); + subplot(2,3,6); + plot( field_t, (field_z - Ht_probe{n}(:,4))./field_z ); + end + + % difference + if any( abs( (field_x - Ht_probe{n}(:,2))./field_x) > limit_max_amp_diff ) || ... + any( abs( (field_y - Ht_probe{n}(:,3))./field_y) > limit_max_amp_diff ) || ... + any( abs( (field_z - Ht_probe{n}(:,4))./field_z) > limit_max_amp_diff ) + pass = 0; + disp( 'probes/fieldprobes.m (amplitudes differ too much): * FAILED *' ); + break + end + + % check absolute field strength of z component + if (max(abs(field_x)) < limit_min_h_amp) || (max(abs(field_y)) < limit_min_h_amp) + pass = 0; + disp( 'probes/fieldprobes.m (amplitude of x- or y-component too small): * FAILED *' ); + break + end +end + + + + +if pass + disp( 'probes/fieldprobes.m: pass' ); +end + + +if pass && CLEANUP + rmdir( Sim_Path, 's' ); +end +if ~pass && STOP_IF_FAILED + error 'test failed'; +end diff --git a/openEMS/TESTSUITE/run_testsuite.m b/openEMS/TESTSUITE/run_testsuite.m new file mode 100644 index 0000000..9f1707b --- /dev/null +++ b/openEMS/TESTSUITE/run_testsuite.m @@ -0,0 +1,58 @@ +% +% run the testsuite +% + +clc +clear +close all +drawnow + +if isOctave + confirm_recursive_rmdir(0); + page_screen_output(0); % do not buffer output + page_output_immediately(1); % do not buffer output +end + +folder = fileparts( mfilename( 'fullpath' ) ); +cd( folder ); +addpath( [folder filesep 'helperscripts'] ); + +% openEMS options +options = {'--engine=multithreaded', '--engine=sse-compressed', '--engine=sse', '--engine=basic'}; + +for o=1:numel(options) + + disp( [datestr(now) ' *** TESTSUITE started (options: ' options{o} ')'] ); + + % now list the tests + folders = dir(); + for f=1:numel(folders) + if folders(f).isdir + if strcmp(folders(f).name,'.') || strcmp(folders(f).name,'..') + continue + end + if strcmp(folders(f).name,'helperscripts') + continue + end + oldpwd = pwd; + cd( folders(f).name ); + scripts = dir('*.m'); + for s=1:numel(scripts) + if ~scripts(s).isdir + % execute function + disp( [datestr(now) ' executing: ' folders(f).name '/' scripts(s).name] ); + [~,fname] = fileparts( scripts(s).name ); + if isOctave + fflush(1); % flush stdout + end + pass = feval( fname, options{o}, 'run_testsuite' ); + end + end + cd(oldpwd); + end + end +end + +disp( '***' ); +disp( ['*** ' datestr(now) ' ALL TESTS DONE'] ); +disp( '***' ); diff --git a/openEMS/TODO b/openEMS/TODO new file mode 100644 index 0000000..a6e6d2c --- /dev/null +++ b/openEMS/TODO @@ -0,0 +1,14 @@ +#this is a todo/wish/feature-request/outlook list for the openEMS project +#priorities: todo (highest) --> outlook (lowest) + +todo / mandatory for v0.1.0: +- more examples and lots of testing... +- improvments and testing for MPI engine + +wishes: +- location dependend excitation given by a file (e.g. mode-profile simulated with comsol) +- more import filter (e.g. gerber import) + +outlook: +- incorporate a static FD-solver into openEMS +- include other EM-solver (e.g. FEM, FDFD, TLM) diff --git a/openEMS/astyle.sh b/openEMS/astyle.sh new file mode 100755 index 0000000..2c8bd41 --- /dev/null +++ b/openEMS/astyle.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +find . -type f -name \*.cpp -exec astyle --style=allman --indent=tab --indent-cases {} \; +find . -type f -name \*.h -exec astyle --style=allman --indent=tab --keep-one-line-blocks --indent-cases {} \; diff --git a/openEMS/cmake/Modules/FindTinyXML.cmake b/openEMS/cmake/Modules/FindTinyXML.cmake new file mode 100644 index 0000000..aabb323 --- /dev/null +++ b/openEMS/cmake/Modules/FindTinyXML.cmake @@ -0,0 +1,74 @@ +################################################################################################## +# +# CMake script for finding TinyXML. +# +# Input variables: +# +# - TinyXML_ROOT_DIR (optional): When specified, header files and libraries will be searched for in +# ${TinyXML_ROOT_DIR}/include +# ${TinyXML_ROOT_DIR}/libs +# respectively, and the default CMake search order will be ignored. When unspecified, the default +# CMake search order is used. +# This variable can be specified either as a CMake or environment variable. If both are set, +# preference is given to the CMake variable. +# Use this variable for finding packages installed in a nonstandard location, or for enforcing +# that one of multiple package installations is picked up. +# +# +# Cache variables (not intended to be used in CMakeLists.txt files) +# +# - TinyXML_INCLUDE_DIR: Absolute path to package headers. +# - TinyXML_LIBRARY: Absolute path to library. +# +# +# Output variables: +# +# - TinyXML_FOUND: Boolean that indicates if the package was found +# - TinyXML_INCLUDE_DIRS: Paths to the necessary header files +# - TinyXML_LIBRARIES: Package libraries +# +# +# Example usage: +# +# find_package(TinyXML) +# if(NOT TinyXML_FOUND) +# # Error handling +# endif() +# ... +# include_directories(${TinyXML_INCLUDE_DIRS} ...) +# ... +# target_link_libraries(my_target ${TinyXML_LIBRARIES}) +# +################################################################################################## + +# Get package location hint from environment variable (if any) +if(NOT TinyXML_ROOT_DIR AND DEFINED ENV{TinyXML_ROOT_DIR}) + set(TinyXML_ROOT_DIR "$ENV{TinyXML_ROOT_DIR}" CACHE PATH + "TinyXML base directory location (optional, used for nonstandard installation paths)") +endif() + +# Search path for nonstandard package locations +if(TinyXML_ROOT_DIR) + set(TinyXML_INCLUDE_PATH PATHS "${TinyXML_ROOT_DIR}/include" NO_DEFAULT_PATH) + set(TinyXML_LIBRARY_PATH PATHS "${TinyXML_ROOT_DIR}/lib" NO_DEFAULT_PATH) +endif() + +# Find headers and libraries +find_path(TinyXML_INCLUDE_DIR NAMES tinyxml.h PATH_SUFFIXES "tinyxml" ${TinyXML_INCLUDE_PATH}) +find_library(TinyXML_LIBRARY NAMES tinyxml PATH_SUFFIXES "tinyxml" ${TinyXML_LIBRARY_PATH}) + +mark_as_advanced(TinyXML_INCLUDE_DIR + TinyXML_LIBRARY) + +# Output variables generation +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(TinyXML DEFAULT_MSG TinyXML_LIBRARY + TinyXML_INCLUDE_DIR) + +set(TinyXML_FOUND ${TINYXML_FOUND}) # Enforce case-correctness: Set appropriately cased variable... +unset(TINYXML_FOUND) # ...and unset uppercase variable generated by find_package_handle_standard_args + +if(TinyXML_FOUND) + set(TinyXML_INCLUDE_DIRS ${TinyXML_INCLUDE_DIR}) + set(TinyXML_LIBRARIES ${TinyXML_LIBRARY}) +endif() diff --git a/openEMS/known_bugs b/openEMS/known_bugs new file mode 100644 index 0000000..944b1a2 --- /dev/null +++ b/openEMS/known_bugs @@ -0,0 +1 @@ +#known bugs list diff --git a/openEMS/known_problems b/openEMS/known_problems new file mode 100644 index 0000000..0257b1b --- /dev/null +++ b/openEMS/known_problems @@ -0,0 +1,4 @@ +#known problems that also might be bugs + +11-03-2010 +example Coaxial_Cartesian: field distribution with PEC != kappa very large, staircasing problem?? diff --git a/openEMS/linux/CalcNF2FF.m.patch b/openEMS/linux/CalcNF2FF.m.patch new file mode 100644 index 0000000..ae091af --- /dev/null +++ b/openEMS/linux/CalcNF2FF.m.patch @@ -0,0 +1,14 @@ +diff --git a/matlab/CalcNF2FF.m b/matlab/CalcNF2FF.m +index 35c11c7..1638110 100644 +--- a/matlab/CalcNF2FF.m ++++ b/matlab/CalcNF2FF.m +@@ -83,7 +83,8 @@ cd(Sim_Path); + try + if isunix + % remove LD_LIBRARY_PATH set by matlab +- system(['export LD_LIBRARY_PATH=; ' openEMS_Path 'nf2ff/nf2ff ' filename '.xml']); ++ % this is a packaged openEMS; nf2ff is found within PATH ++ system(['LD_LIBRARY_PATH=; nf2ff ' filename '.xml']); + else + system([openEMS_Path 'nf2ff.exe ' filename '.xml']); + end diff --git a/openEMS/linux/README.patch b/openEMS/linux/README.patch new file mode 100644 index 0000000..e005adb --- /dev/null +++ b/openEMS/linux/README.patch @@ -0,0 +1,15 @@ +diff --git a/README b/README +index 1962055..ae6df82 100644 +--- a/README ++++ b/README +@@ -10,8 +10,8 @@ Forum: http://openems.de/forum/ + Tutorials: http://openems.de/index.php/Tutorials + + +-To use openEMS from Matlab or Octave, you need to include the /matlab folder in the respective environment: +-> addpath( '/matlab' ); ++To use openEMS from Matlab or Octave, you need to include the /usr/share/openEMS/matlab folder in the respective environment: ++> addpath( '/usr/share/openEMS/matlab' ); + + To verify the correct installation follow the instructions at: + http://openems.de/index.php/Tutorial:_First_Steps diff --git a/openEMS/linux/debian.changelog b/openEMS/linux/debian.changelog new file mode 100644 index 0000000..755d0f4 --- /dev/null +++ b/openEMS/linux/debian.changelog @@ -0,0 +1,27 @@ +openems (0.0.28-2) stable; urgency=low + * display correct version + -- Sebastian Held Sun, 24 Jun 2012 14:17:00 +0200 +openems (0.0.28-1) stable; urgency=low + * New upstream release + -- Sebastian Held Sun, 17 Jun 2012 23:28:29 +0200 +openems (0.0.27-1) stable; urgency=low + * New upstream release + -- Sebastian Held Thu, 1 Mar 2012 22:37:38 +0100 +openems (0.0.26-1) stable; urgency=low + * New upstream release + -- Sebastian Held Sat, 21 Jan 2012 12:32:38 +0100 +openems (0.0.25-5) stable; urgency=low + * added README + -- Sebastian Held Thu, 29 Dec 2011 20:35:38 +0100 +openems (0.0.25-4) stable; urgency=low + * Upstream fixes + -- Sebastian Held Sun, 25 Dec 2011 21:23:38 +0100 +openems (0.0.25-3) stable; urgency=low + * Changed dependancy on boost to enable build on oneiric + -- Sebastian Held Sun, 18 Dec 2011 21:39:38 +0100 +openems (0.0.25-2) stable; urgency=low + * New upstream release + -- Sebastian Held Sun, 4 Dec 2011 17:19:38 +0100 +openems (0.0.24-1) stable; urgency=low + * Initial Release + -- Sebastian Held Thu, 8 Oct 2011 8:30:38 +0200 diff --git a/openEMS/linux/debian.control b/openEMS/linux/debian.control new file mode 100644 index 0000000..43f9441 --- /dev/null +++ b/openEMS/linux/debian.control @@ -0,0 +1,12 @@ +Source: openems +Section: contrib/science +Priority: optional +Maintainer: Sebastian Held +Build-Depends: debhelper (>=7.0.50~), qt4-qmake, libfparser4, libhdf5-serial-dev, libtinyxml-dev, csxcad-dev (>= 0.2.4), libopenmpi-dev, libvtk5-qt4-dev, libboost-all-dev + +Package: openems +Architecture: any +Depends: ${shlibs:Depends} +Recommends: octave3.2, paraview +Description: Free and Open Electromagnetic Field Solver + OpenEMS is a free and open-source electromagnetic field solver using the (EC-)FDTD method. diff --git a/openEMS/linux/debian.docs b/openEMS/linux/debian.docs new file mode 100644 index 0000000..2e3abae --- /dev/null +++ b/openEMS/linux/debian.docs @@ -0,0 +1,2 @@ +COPYING +README diff --git a/openEMS/linux/debian.rules b/openEMS/linux/debian.rules new file mode 100644 index 0000000..a3edec1 --- /dev/null +++ b/openEMS/linux/debian.rules @@ -0,0 +1,90 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatibility version to use. +export DH_COMPAT=4 + +CFLAGS = -g -msse +ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) +CFLAGS += -O0 +else +CFLAGS += -O2 +endif + +build: build-stamp +build-stamp: + dh_testdir + + # Add here commands to compile the package. + qmake-qt4 QMAKE_CFLAGS="$$CFLAGS" QMAKE_CXXFLAGS="$$CFLAGS" CONFIG+=packaging openEMS.pro + make + cd nf2ff && qmake-qt4 QMAKE_CFLAGS="$$CFLAGS" QMAKE_CXXFLAGS="$$CFLAGS" CONFIG+=packaging nf2ff.pro + make -C nf2ff + # --- end custom part for compiling + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + + # Add here commands to clean up after the build process. + make clean || true + make -C nf2ff clean || true + # --- end custom part for cleaning up + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # Add here commands to install the package + # The DESTDIR Has To Be Exactly /usr/src/packages/BUILD/debian/ + make install INSTALL_ROOT=/usr/src/packages/BUILD/debian/openems + make -C nf2ff install INSTALL_ROOT=/usr/src/packages/BUILD/debian/openems + # --- end custom part for installing + +# Build architecture-independent files here. +binary-indep: build install + # We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot +# dh_installdebconf + dh_installdocs + dh_installexamples + dh_installmenu +# dh_installlogrotate +# dh_installemacsen +# dh_installpam +# dh_installmime +# dh_installinit + dh_installcron + dh_installman + dh_installinfo +# dh_undocumented + dh_installchangelogs + dh_link + dh_strip + dh_compress + dh_fixperms +# dh_makeshlibs + dh_installdeb +# dh_perl + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/openEMS/linux/debian.series b/openEMS/linux/debian.series new file mode 100644 index 0000000..61ef578 --- /dev/null +++ b/openEMS/linux/debian.series @@ -0,0 +1,3 @@ +invoke_openEMS.m.patch -p1 +README.patch -p1 +CalcNF2FF.m.patch -p1 diff --git a/openEMS/linux/fedora17.diff b/openEMS/linux/fedora17.diff new file mode 100644 index 0000000..12b1b41 --- /dev/null +++ b/openEMS/linux/fedora17.diff @@ -0,0 +1,13 @@ +diff --git a/openEMS.pro b/openEMS.pro +index 97b0632..b9c3cf7 100644 +--- a/openEMS.pro ++++ b/openEMS.pro +@@ -68,7 +68,7 @@ win32 { + /usr/include/vtk-5.10 \ + /usr/include/vtk + INCLUDEPATH += /usr/include/CSXCAD +- LIBS += -lvtkCommon \ ++ LIBS += -L/usr/lib/vtk -L/usr/lib64/vtk -lvtkCommon \ + -lvtkIO \ + -lvtksys \ + -lvtkFiltering diff --git a/openEMS/linux/invoke_openEMS.m.patch b/openEMS/linux/invoke_openEMS.m.patch new file mode 100644 index 0000000..cbd3073 --- /dev/null +++ b/openEMS/linux/invoke_openEMS.m.patch @@ -0,0 +1,15 @@ +diff --git a/matlab/private/invoke_openEMS.m b/matlab/private/invoke_openEMS.m +index ce3ac53..d64771d 100644 +--- a/matlab/private/invoke_openEMS.m ++++ b/matlab/private/invoke_openEMS.m +@@ -32,7 +32,9 @@ end + filename = mfilename('fullpath'); + dir = fileparts( filename ); + openEMS_Path = [dir filesep '../..' filesep]; +- ++ ++openEMS_Path = ''; % this is a packaged openEMS installation; openEMS.sh is found in $PATH ++ + if isunix + openEMS_Path = [openEMS_Path 'openEMS.sh']; + else diff --git a/openEMS/linux/openEMS.dsc b/openEMS/linux/openEMS.dsc new file mode 100644 index 0000000..b50da0e --- /dev/null +++ b/openEMS/linux/openEMS.dsc @@ -0,0 +1,9 @@ +Format: 1.0 +Source: openems +Version: 0.0.28-2 +Binary: openems +Maintainer: Thorsten Liebig , Sebastian Held +Homepage: http://www.openems.de +Architecture: any +Build-Depends: debhelper (>= 5.0.0), qt4-qmake, libfparser4, libhdf5-serial-dev, libtinyxml-dev, csxcad-dev (>= 0.3.0-2), libopenmpi-dev, libvtk5-qt4-dev, libboost-all-dev +DEBTRANSFORM-TAR: openEMS-0.0.28.tar.bz2 diff --git a/openEMS/linux/openEMS.spec b/openEMS/linux/openEMS.spec new file mode 100644 index 0000000..f7b0b18 --- /dev/null +++ b/openEMS/linux/openEMS.spec @@ -0,0 +1,113 @@ +# +# spec file for package [spectemplate] +# +# Copyright (c) 2010 SUSE LINUX Products GmbH, Nuernberg, Germany. +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.opensuse.org/ +# + +# norootforbuild + +Name: openEMS +Version: 0.0.28 +Release: 3 +Summary: Free and Open Electromagnetic Field Solver +Group: Productivity/Scientific/Physics +License: GPLv3 +URL: http://www.openems.de +Source0: %{name}-%{version}.tar.bz2 +Patch0: invoke_openEMS.m.patch +Patch1: README.patch +Patch2: CalcNF2FF.m.patch +Patch3: fedora17.diff +BuildRoot: %_tmppath/%name-%version-build + +# libqt4-devel is needed only to provide qmake (the Qt-libraries are not used) +# libfparser4-devel contains a static library => no runtime requirement +BuildRequires: libqt4-devel gcc-c++ libfparser4-devel hdf5-devel tinyxml-devel CSXCAD-devel openmpi-devel vtk-devel boost-devel +Requires: CSXCAD + +# determine qt4 qmake executable +%if 0%{?fedora} + %global qmake qmake-qt4 +%else + %global qmake qmake +%endif + + + +%description +OpenEMS is a free and open-source electromagnetic field solver using the (EC-)FDTD method. + + +%prep +%setup -q +%patch0 -p1 +#%if 0%{?fedora} +#%patch1 -p1 +#%endif +%patch1 -p1 +%patch2 -p1 +%if 0%{?fedora} >= 17 +%patch3 -p1 +%endif + +%build +ADDFLAGS="-msse" # enable at least the SSE command set (no SSE makes no sense -- way too slow) +%qmake QMAKE_CFLAGS="%optflags $ADDFLAGS" QMAKE_CXXFLAGS="%optflags $ADDFLAGS" LIB_SUFFIX="$(echo %_lib | cut -b4-)" CONFIG+=packaging openEMS.pro +make %{?_smp_mflags} +cd nf2ff +%qmake QMAKE_CFLAGS="%optflags $ADDFLAGS" QMAKE_CXXFLAGS="%optflags $ADDFLAGS" LIB_SUFFIX="$(echo %_lib | cut -b4-)" CONFIG+=packaging nf2ff.pro +make %{?_smp_mflags} +cd .. + +%install +make INSTALL_ROOT=%{buildroot} install +cd nf2ff +make INSTALL_ROOT=%{buildroot} install +cd .. +find %{buildroot} -name '*.la' -exec rm -f {} ';' + + +%clean +rm -rf %{buildroot} + + +%files +%defattr(-,root,root) +%doc README COPYING TODO known_bugs known_problems +/usr/share/%{name} +/usr/bin/openEMS* +/usr/bin/nf2ff + + +%changelog +* Sat Jun 23 2012 Sebastian Held - 0.0.28-3 +- display correct version +* Mon Jun 18 2012 Sebastian Held - 0.0.28-2 +- Fedora 17 build fixes +* Sun Jun 17 2012 Sebastian Held - 0.0.28-1 +- new upstream version +* Thu Mar 1 2012 Sebastian Held - 0.0.27-1 +- new upstream version +* Sat Jan 21 2012 Sebastian Held - 0.0.26-1 +- new upstream version +* Mon Jan 9 2012 Sebastian Held - 0.0.25-4 +- added runtime dep on CSXCAD +* Thu Dec 29 2011 Sebastian Held - 0.0.25-3 +- added README +* Sun Dec 25 2011 Sebastian Held - 0.0.25-2 +- Fedora 16 build fix and upstream fixes +* Sun Dec 4 2011 Sebastian Held - 0.0.25-1 +- new upstream version +* Mon Oct 3 2011 Sebastian Held - 0.0.24-1 +- initial version diff --git a/openEMS/main.cpp b/openEMS/main.cpp new file mode 100644 index 0000000..8a8000f --- /dev/null +++ b/openEMS/main.cpp @@ -0,0 +1,85 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include +#include +#include +#include +#include + +#ifdef MPI_SUPPORT +#include "mpi.h" +#include "FDTD/openems_fdtd_mpi.h" +#else +#include "openems.h" +#endif + +#include "tools/global.h" + +#ifndef GIT_VERSION +#define GIT_VERSION "unknown:compiled@" __DATE__ +#endif + +using namespace std; + +int main(int argc, char *argv[]) +{ +#ifdef MPI_SUPPORT + //init MPI + MPI::Init(argc,argv); + openEMS_FDTD_MPI FDTD(false); +#else + openEMS FDTD; +#endif + +#ifdef MPI_SUPPORT + openEMS_FDTD_MPI::WelcomeScreen(); +#else + openEMS::WelcomeScreen(); +#endif + + if (argc<=1) + { + openEMS::showUsage(); + exit(-1); + } + + if (argc>=3) + { + for (int n=2; n) +% +% apply autoregressive signal model to improve dft results +% +% t : time vector +% val : time domain values +% freq : frequency vector for dft +% +% optional +% nu : AR order (default 40) +% mu : number of timesteps to train the model (default 3*nu) +% expand_factor : increase signal length by this factor (default 5) +% +% return values: +% val_ar: AR estimated time signal +% t_ar: time vector +% f_val_ar: FD transformed AR estimated signal +% EC: error code +% 0 --> no error +% 1 --> input error: t and val mismatch +% 2 --> input error: mu has to be larger than 2*nu +% 3 --> inout error: expand_factor has to be larger than 1 +% 10 --> AR error: signal is to short for AR estimate --> decrease AR order +% 11 --> AR error: estimated signal appears to be unstable --> use a different mu +% +% openEMS matlab interface +% ----------------------- +% Author: Thorsten Liebig, 2011 +% +% See also ReadUI, DFT_time2freq + +EC = 0; +val_ar = []; +t_ar = []; +f_val_ar = []; + + +if numel(t) ~= numel(val) + if (nargout<4) + error 'numel(t) ~= numel(val)' + else + EC = 1; + return + end +end + +if (nargin<4) + nu = 40; +end +if (nargin<5) + mu = 3*nu; +end +if (nargin<6) + expand_factor=5; +end + +if (mu<=2*nu) + if (nargout<4) + error 'mu has to be larger than 2*nu' + else + EC = 2; + return + end +end + +if (expand_factor<=1) + if (nargout<4) + error 'expand_factor has to be larger than 1' + else + EC = 3; + return + end +end + +dt = t(2)-t(1); + +M = numel(t); + +if (M<0.6*mu) + if (nargout<4) + error 'signal is to short for AR estimate --> decrease AR order' + else + EC = 10; + return + end +end + +for n=1:mu-nu + b(n) = val(end-n+1); + for m=1:nu + A(n,m)=val(end-n+1-m); + end +end + +a = ((A'*A)\A')*b'; + +val_ar = val; +t_ar = t; +for k=M:expand_factor*M + val_ar(k) = 0; + t_ar(k) = t_ar(k-1)+dt; + val_ar(k) = sum(a.*val_ar(k-(1:nu))'); +end + +if (max(val_ar(M:end)) > max(val)) + if (nargout<4) + error 'estimated signal appears to be unstable --> use a different mu' + else + EC = 11; + return + end +end + +f_val_ar = DFT_time2freq(t_ar, val_ar, freq); diff --git a/openEMS/matlab/Add2Queue.m b/openEMS/matlab/Add2Queue.m new file mode 100644 index 0000000..a80bdc9 --- /dev/null +++ b/openEMS/matlab/Add2Queue.m @@ -0,0 +1,48 @@ +function [queue] = Add2Queue(queue,func_name, func_args, varargin) +% function [queue] = Add2Queue(queue,func_name, func_args, varargin) +% +% Use this function to add a funtion to the queue. +% +% For more details see: InitQueue +% +% See also: InitQueue, FinishQueue, ResultsQueue, RunOpenEMS +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +if isfield(queue,'jobs') + jobnum = numel(queue.jobs)+1; +else + jobnum = 1; +end + +running = numel(queue.jobs_finished) - sum(queue.jobs_finished); + +while (running>=queue.maxThreads) + [queue running] = CheckQueue(queue); +end + + +if (queue.verbose>=1) + disp(['Add2Queue: Job #' num2str(jobnum) ' starting...']); +end + +queue.jobs_finished(jobnum) = 0; + +queue.jobs{jobnum}.argsfile = [tempname '.mat']; +save(queue.jobs{jobnum}.argsfile,'func_args'); + +queue.jobs{jobnum}.nargout = nargout(func_name); +queue.jobs{jobnum}.outargsfile = [tempname '.mat']; + +queue.jobs{jobnum}.command = [queue.bin queue.bin_options ' "load(''' queue.jobs{jobnum}.argsfile ''');' ... + queue.DependPath ... + 'err=[];' ... + 'try;' ... + '[outargs{1:' num2str(queue.jobs{jobnum}.nargout) '}]=' func_name '(func_args{:});' ... + 'catch err;outargs=0;end;' ... + 'save(''-V7'',''' queue.jobs{jobnum}.outargsfile ''',''outargs'',''err'');' ... + 'exit;"']; + +[queue.jobs{jobnum}.pid, queue.jobs{jobnum}.filenames] = queue_addProcess( queue.jobs{jobnum}.command ); diff --git a/openEMS/matlab/AddCPWPort.m b/openEMS/matlab/AddCPWPort.m new file mode 100644 index 0000000..ba4fc4a --- /dev/null +++ b/openEMS/matlab/AddCPWPort.m @@ -0,0 +1,285 @@ +function [CSX,port] = AddCPWPort( CSX, prio, portnr, materialname, start, stop, gap_width, dir, evec, varargin ) +% [CSX,port] = AddCPWPort( CSX, prio, portnr, materialname, start, stop, gap_width, dir, evec, varargin ) +% +% CSX: CSX-object created by InitCSX() +% prio: priority for excitation and probe boxes +% portnr: (integer) number of the port +% materialname: property for the CPW (created by AddMetal()) +% start: 3D start rowvector for port definition +% stop: 3D end rowvector for port definition +% gap_width: width of the CPW gap (left and right) +% dir: direction of wave propagation (choices: 0, 1, 2 or 'x','y','z') +% evec: excitation vector, which defines the direction of the e-field (must be the same as used in AddExcitation()) +% +% variable input: +% varargin: optional additional excitations options, see also AddExcitation +% 'ExcitePort' true/false to make the port an active feeding port (default +% is false) +% 'FeedShift' shift to port from start by a given distance in drawing +% units. Default is 0. Only active if 'ExcitePort' is set! +% 'Feed_R' Specifiy a lumped port resistance. Default is no lumped +% port resistance --> port has to end in an ABC. +% 'MeasPlaneShift' Shift the measurement plane from start t a given distance +% in drawing units. Default is the middle of start/stop. +% 'PortNamePrefix' a prefix to the port name +% +% Important: The mesh has to be already set and defined by DefineRectGrid! +% +% example: +% CSX = AddMetal( CSX, 'metal' ); %create a PEC called 'metal' +% start = [0 -width/2 0]; +% stop = [length +width/2 0]; +% [CSX,port] = AddCPWPort( CSX, 0, 1, 'metal', start, stop, gap_width, 'x', ... +% [0 0 -1], 'ExcitePort', true, 'Feed_R', 50 ) +% Explanation: +% - this defines a stripline in x-direction (dir='x') +% --> the wave travels along the x-direction +% - with an e-field excitation in -z-direction (evec=[0 0 -1]) +% - the excitation is active and placed at x=start(1) ('ExcitePort', true) +% - a 50 Ohm lumped port resistance is placed at x=start(1) ('Feed_R', 50) +% - the width-direction is determined by the cross product of the +% direction of propagtion (dir='x') and the excitation vector +% (evec=[0 0 -1]), in this case it is the y-direction +% - the stripline-metal is created in a xy-plane at a height at z=start(3) +% --> The upper and lower reference plane (ground) must be defined by +% the user +% +% Thorsten Liebig (c) 2014 +% +% See also InitCSX DefineRectGrid AddMetal AddMaterial AddExcitation calcPort + +%% validate arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%check mesh +if ~isfield(CSX,'RectilinearGrid') + error 'mesh needs to be defined! Use DefineRectGrid() first!'; +end +if (~isfield(CSX.RectilinearGrid,'XLines') || ~isfield(CSX.RectilinearGrid,'YLines') || ~isfield(CSX.RectilinearGrid,'ZLines')) + error 'mesh needs to be defined! Use DefineRectGrid() first!'; +end + +% check dir +dir = DirChar2Int(dir); + +% check evec +if ~(evec(1) == evec(2) == 0) && ~(evec(1) == evec(3) == 0) && ~(evec(2) == evec(3) == 0) || (sum(evec) == 0) + error 'evec must have exactly one component ~= 0' +end +evec0 = evec ./ sum(evec); % evec0 is a unit vector + +%set defaults +feed_shift = 0; +feed_R = inf; %(default is open, no resitance) +excite = false; +measplanepos = nan; +PortNamePrefix = ''; + +excite_args = {}; + +%% read optional arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'FeedShift')==1); + feed_shift = varargin{n+1}; + if (numel(feed_shift)>1) + error 'FeedShift must be a scalar value' + end + elseif (strcmp(varargin{n},'Feed_R')==1); + feed_R = varargin{n+1}; + if (numel(feed_shift)>1) + error 'Feed_R must be a scalar value' + end + elseif (strcmp(varargin{n},'MeasPlaneShift')==1); + measplanepos = varargin{n+1}; + if (numel(feed_shift)>1) + error 'MeasPlaneShift must be a scalar value' + end + elseif (strcmp(varargin{n},'ExcitePort')==1); + if ischar(varargin{n+1}) + warning('CSXCAD:AddCPWPort','depreceated: a string as excite option is no longer supported and will be removed in the future, please use true or false'); + if ~isempty(excite) + excite = true; + else + excite = false; + end + else + excite = varargin{n+1}; + end + elseif (strcmpi(varargin{n},'PortNamePrefix')) + PortNamePrefix = varargin{n+1}; + else + excite_args{end+1} = varargin{n}; + excite_args{end+1} = varargin{n+1}; + end +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% normalize start and stop +nstart = min( [start;stop] ); +nstop = max( [start;stop] ); + +% determine index (1, 2 or 3) of propagation (length of CPW) +idx_prop = dir + 1; + +% determine index (1, 2 or 3) of width of CPW +dir = [0 0 0]; +dir(idx_prop) = 1; +idx_height = abs(cross(dir,evec0)) * [1;2;3]; + +% determine index (1, 2 or 3) of height +idx_width = abs(evec0) * [1;2;3]; + + +if (start(idx_height)~=stop(idx_height)) + error('openEMS:AddCPWPort','start/stop in height direction must be equal'); +end + +% direction of propagation +if stop(idx_prop)-start(idx_prop) > 0 + direction = +1; +else + direction = -1; +end + +% create the metal/material for the CPW +SL_start = start; +SL_stop = stop; +CSX = AddBox( CSX, materialname, prio, SL_start, SL_stop ); + +if isnan(measplanepos) + measplanepos = (nstart(idx_prop)+nstop(idx_prop))/2; +else + measplanepos = start(idx_prop)+direction*measplanepos; +end + +% calculate position of the voltage probes +mesh{1} = sort(CSX.RectilinearGrid.XLines); +mesh{2} = sort(CSX.RectilinearGrid.YLines); +mesh{3} = sort(CSX.RectilinearGrid.ZLines); +meshlines = interp1( mesh{idx_prop}, 1:numel(mesh{idx_prop}), measplanepos, 'nearest' ); +meshlines = mesh{idx_prop}(meshlines-1:meshlines+1); % get three lines (approx. at center) +if direction == -1 + meshlines = fliplr(meshlines); +end +SL_w2 = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), (nstart(idx_width)+nstop(idx_width))/2, 'nearest' ); +SL_w2 = mesh{idx_width}(SL_w2); % get e-line at center of CPW (SL_width/2) +v1_start(idx_prop) = meshlines(1); +v1_start(idx_width) = (nstart(idx_width)+nstop(idx_width))/2; +v1_start(idx_height) = start(idx_height); +v1_stop = v1_start; +v2_start = v1_start; +v2_stop = v1_stop; +v2_start(idx_prop) = meshlines(2); +v2_stop(idx_prop) = meshlines(2); +v3_start = v2_start; +v3_stop = v2_stop; +v3_start(idx_prop) = meshlines(3); +v3_stop(idx_prop) = meshlines(3); + +width_add_start = [0 0 0]; +width_add_stop = [0 0 0]; +width_add_start(idx_width) = (nstop(idx_width)-nstart(idx_width))/2; +width_add_stop(idx_width) = (nstop(idx_width)-nstart(idx_width))/2+gap_width; + +weight = 0.5; +% create the voltage-probes +port.U_filename{1,1} = [PortNamePrefix 'port_ut' num2str(portnr) 'A1']; +CSX = AddProbe( CSX, port.U_filename{1,1}, 0, 'weight', -1*weight ); +CSX = AddBox( CSX, port.U_filename{1,1}, prio, v1_start-width_add_start, v1_stop-width_add_stop); + +port.U_filename{1,2} = [PortNamePrefix 'port_ut' num2str(portnr) 'A2']; +CSX = AddProbe( CSX, port.U_filename{1,2}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{1,2}, prio, v1_start+width_add_start, v1_stop+width_add_stop); + + +port.U_filename{2,1} = [PortNamePrefix 'port_ut' num2str(portnr) 'B1']; +CSX = AddProbe( CSX, port.U_filename{2,1}, 0, 'weight', -1*weight ); +CSX = AddBox( CSX, port.U_filename{2,1}, prio, v2_start-width_add_start, v2_stop-width_add_stop ); + +port.U_filename{2,2} = [PortNamePrefix 'port_ut' num2str(portnr) 'B2']; +CSX = AddProbe( CSX, port.U_filename{2,2}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{2,2}, prio, v2_start+width_add_start, v2_stop+width_add_stop ); + + +port.U_filename{3,1} = [PortNamePrefix 'port_ut' num2str(portnr) 'C1']; +CSX = AddProbe( CSX, port.U_filename{3,1}, 0, 'weight', -1*weight ); +CSX = AddBox( CSX, port.U_filename{3,1}, prio, v3_start-width_add_start, v3_stop-width_add_stop ); + +port.U_filename{3,2} = [PortNamePrefix 'port_ut' num2str(portnr) 'C2']; +CSX = AddProbe( CSX, port.U_filename{3,2}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{3,2}, prio, v3_start+width_add_start, v3_stop+width_add_stop ); + +% calculate position of the current probes +idx = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), nstart(idx_width), 'nearest' ); +i1_start(idx_width) = mesh{idx_width}(idx) - diff(mesh{idx_width}(idx-1:idx))/2; +idx = interp1( mesh{idx_height}, 1:numel(mesh{idx_height}), start(idx_height), 'nearest' ); +i1_start(idx_height) = mesh{idx_height}(idx-1) - diff(mesh{idx_height}(idx-2:idx-1))/2; +i1_stop(idx_height) = mesh{idx_height}(idx+1) + diff(mesh{idx_height}(idx+1:idx+2))/2; +i1_start(idx_prop) = sum(meshlines(1:2))/2; +i1_stop(idx_prop) = i1_start(idx_prop); +idx = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), nstop(idx_width), 'nearest' ); +i1_stop(idx_width) = mesh{idx_width}(idx) + diff(mesh{idx_width}(idx:idx+1))/2; +i2_start = i1_start; +i2_stop = i1_stop; +i2_start(idx_prop) = sum(meshlines(2:3))/2; +i2_stop(idx_prop) = i2_start(idx_prop); + +% create the curr-probes +weight = direction; +port.I_filename{1} = [PortNamePrefix 'port_it' num2str(portnr) 'A']; +CSX = AddProbe( CSX, port.I_filename{1}, 1, 'weight', weight ); +CSX = AddBox( CSX, port.I_filename{1}, prio, i1_start, i1_stop ); +port.I_filename{2} = [PortNamePrefix 'port_it' num2str(portnr) 'B']; +CSX = AddProbe( CSX, port.I_filename{2}, 1,'weight', weight ); +CSX = AddBox( CSX, port.I_filename{2}, prio, i2_start, i2_stop ); + +% create port structure +port.LengthScale = 1; +if ((CSX.ATTRIBUTE.CoordSystem==1) && (idx_prop==2)) + port.LengthScale = SL_stop(idx_height); +end +port.nr = portnr; +port.type = 'CPW'; +port.drawingunit = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit; +port.v_delta = diff(meshlines)*port.LengthScale; +port.i_delta = diff( meshlines(1:end-1) + diff(meshlines)/2 )*port.LengthScale; +port.direction = direction; +port.excite = 0; +port.measplanepos = abs(v2_start(idx_prop) - start(idx_prop))*port.LengthScale; +% port + +% create excitation (if enabled) and port resistance +meshline = interp1( mesh{idx_prop}, 1:numel(mesh{idx_prop}), start(idx_prop) + feed_shift*direction, 'nearest' ); +ex_start(idx_prop) = mesh{idx_prop}(meshline) ; +ex_start(idx_width) = (nstart(idx_width)+nstop(idx_width))/2; +ex_start(idx_height) = nstart(idx_height); +ex_stop(idx_prop) = ex_start(idx_prop); +ex_stop(idx_width) = (nstart(idx_width)+nstop(idx_width))/2; +ex_stop(idx_height) = nstop(idx_height); + +port.excite = 0; +if excite + port.excite = 1; + CSX = AddExcitation( CSX, [PortNamePrefix 'port_excite_1_' num2str(portnr)], 0, evec, excite_args{:} ); + CSX = AddBox( CSX, [PortNamePrefix 'port_excite_1_' num2str(portnr)], prio, ex_start-width_add_start, ex_stop-width_add_stop ); + CSX = AddExcitation( CSX, [PortNamePrefix 'port_excite_2_' num2str(portnr)], 0, -evec, excite_args{:} ); + CSX = AddBox( CSX, [PortNamePrefix 'port_excite_2_' num2str(portnr)], prio, ex_start+width_add_start, ex_stop+width_add_stop ); +end + +%% CPW resitance at start of CPW line +ex_start(idx_prop) = start(idx_prop); +ex_stop(idx_prop) = ex_start(idx_prop); + +if (feed_R > 0) && ~isinf(feed_R) + CSX = AddLumpedElement( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], idx_width-1, 'R', 2*feed_R ); + CSX = AddBox( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], prio, ex_start-width_add_start, ex_stop-width_add_stop ); + CSX = AddBox( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], prio, ex_start+width_add_start, ex_stop+width_add_stop ); +elseif isinf(feed_R) + % do nothing --> open port +elseif feed_R == 0 + %port "resistance" as metal + CSX = AddBox( CSX, materialname, prio, ex_start-width_add_start, ex_stop-width_add_stop ); + CSX = AddBox( CSX, materialname, prio, ex_start+width_add_start, ex_stop+width_add_stop ); +else + error('openEMS:AddCPWPort','CPW port with resitance <= 0 it not possible'); +end +end diff --git a/openEMS/matlab/AddCircWaveGuidePort.m b/openEMS/matlab/AddCircWaveGuidePort.m new file mode 100644 index 0000000..2d2e7ff --- /dev/null +++ b/openEMS/matlab/AddCircWaveGuidePort.m @@ -0,0 +1,109 @@ +function [CSX,port] = AddCircWaveGuidePort( CSX, prio, portnr, start, stop, radius, mode_name, pol_ang, exc_amp, varargin ) +% function [CSX,port] = AddCircWaveGuidePort( CSX, prio, portnr, start, stop, radius, mode_name, pol_ang, exc_amp, varargin ) +% +% Create a circular waveguide port, including an optional excitation and probes +% +% Note: - The excitation will be located at the start position in the given direction +% - The voltage and current probes at the stop position in the given direction +% +% input: +% CSX: complete CSX structure (must contain a mesh) +% prio: priority of primitives +% start: start coordinates of waveguide port box +% stop: stop coordinates of waveguide port box +% radius: circular waveguide radius (in meter) +% mode_name: mode name, e.g. 'TE11' or 'TM21' +% pol_ang: polarization angle (e.g. 0 = horizontal, pi/2 = vertical) +% exc_amp: excitation amplitude (set 0 to be passive) +% +% optional (key/values): +% varargin: optional additional excitations options, see also AddExcitation +% 'PortNamePrefix': a prefix to the port name +% +% output: +% CSX: modified CSX structure +% port: port structure to use with calcPort +% +% example: +% % create a TE11 circular waveguide mode, using cylindircal coordinates +% start=[mesh.r(1) mesh.a(1) 0 ]; +% stop =[mesh.r(end) mesh.a(end) 100]; +% [CSX,port] = AddCircWaveGuidePort( CSX, 99, 1, start, stop, 320e-3, 'TE11', 0, 1); +% +% openEMS matlab interface +% ----------------------- +% (c) 2013 Thorsten Liebig (thorsten.liebig@gmx.de) +% +% See also InitCSX, AddExcitation, calcWGPort, calcPort + +if (~strcmpi(mode_name(1:2),'TE')) + error 'currently only TE type modes are supported' +end + +if (nargin<9) + exc_amp = 0; +end +if (nargin<8) + pol_ang = 0; +end + +pnm = 0; +n = str2double(mode_name(3)); +m = str2double(mode_name(4)); + +% values by David M. Pozar, Microwave Engineering, third edition +if ((n==0) && (m==1)) + pnm = 3.832; +elseif ((n==1) && (m==1)) + pnm = 1.841; +elseif ((n==2) && (m==1)) + pnm = 3.054; +elseif ((n==0) && (m==2)) + pnm = 7.016; +elseif ((n==1) && (m==2)) + pnm = 5.331; +elseif ((n==2) && (m==2)) + pnm = 6.706; +elseif ((n==0) && (m==3)) + pnm = 10.174; +elseif ((n==1) && (m==3)) + pnm = 8.536; +elseif ((n==2) && (m==3)) + pnm = 9.970; +else + error 'invalid TE_nm mode' +end + +if ~isfield(CSX,'RectilinearGrid') + error 'mesh needs to be defined! Use DefineRectGrid() first!'; +end + +unit = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit; +kc = pnm/radius; +kc_draw = kc*unit; + +angle = ['a-' num2str(pol_ang)]; +% functions by David M. Pozar, Microwave Engineering, third edition +% electric field mode profile +func_Er = [ num2str(-1/kc_draw^2,15) '/rho*cos(' angle ')*j1(' num2str(kc_draw,15) '*rho)']; +func_Ea = [ num2str(1/kc_draw,15) '*sin(' angle ')*0.5*(j0(' num2str(kc_draw,15) '*rho)-jn(2,' num2str(kc_draw,15) '*rho))']; + +% magnetic field mode profile +func_Hr = [ num2str(-1/kc_draw,15) '*sin(' angle ')*0.5*(j0(' num2str(kc_draw,15) '*rho)-jn(2,' num2str(kc_draw,15) '*rho))']; +func_Ha = [ num2str(-1/kc_draw^2,15) '/rho*cos(' angle ')*j1(' num2str(kc_draw,15) '*rho)']; + +if (CSX.ATTRIBUTE.CoordSystem==1) + func_E = {func_Er, func_Ea, 0}; + func_H = {func_Hr, func_Ha, 0}; +else + func_Ex = ['(' func_Er '*cos(a) - ' func_Ea '*sin(a) ) * (rho<' num2str(radius/unit) ')']; + func_Ey = ['(' func_Er '*sin(a) + ' func_Ea '*cos(a) ) * (rho<' num2str(radius/unit) ')']; + func_E = {func_Ex, func_Ey, 0}; + + func_Hx = ['(' func_Hr '*cos(a) - ' func_Ha '*sin(a) ) * (rho<' num2str(radius/unit) ')']; + func_Hy = ['(' func_Hr '*sin(a) + ' func_Ha '*cos(a) ) * (rho<' num2str(radius/unit) ')']; + func_H = {func_Hx, func_Hy, 0}; +end + +[CSX,port] = AddWaveGuidePort( CSX, prio, portnr, start, stop, 2, func_E, func_H, kc, exc_amp, varargin{:} ); + diff --git a/openEMS/matlab/AddCoaxialPort.m b/openEMS/matlab/AddCoaxialPort.m new file mode 100644 index 0000000..45c0d2b --- /dev/null +++ b/openEMS/matlab/AddCoaxialPort.m @@ -0,0 +1,232 @@ +function [CSX,port] = AddCoaxialPort( CSX, prio, portnr, pec_name, materialname, start, stop, dir, r_i, r_o, r_os, varargin ) +% function [CSX,port] = AddCoaxialPort( CSX, prio, portnr, pec_name, materialname, start, stop, dir, r_i, r_o, r_os, varargin ) +% +% CSX: CSX-object created by InitCSX() +% prio: priority for excitation and probe boxes +% portnr: (integer) number of the port +% pec_name: metal property for coaxial inner/outer conductor (created by AddMetal()) +% materialname: substrate property for coaxial line (created by AddMaterial()) +% Note: this may be empty for an "air filled" coaxial line +% start: 3D start rowvector for coaxial cable axis +% stop: 3D end rowvector for coaxial cable axis +% dir: direction of wave propagation (choices: 0, 1, 2 or 'x','y','z') +% r_i: inner coaxial radius (in drawing unit) +% r_o: outer coaxial radius (in drawing unit) +% r_os: outer shell coaxial radius (in drawing unit) +% +% variable input: +% varargin: optional additional excitations options, see also AddExcitation +% 'ExciteAmp' excitation amplitude of transversal electric field profile, +% set to 0 (default) for a passive port +% 'FeedShift' shift to port from start by a given distance in drawing +% units. Default is 0. Only active if 'ExciteAmp' is set! +% 'Feed_R' Specifiy a lumped port resistance. Default is no lumped +% port resistance --> port has to end in an ABC. +% 'MeasPlaneShift' Shift the measurement plane from start t a given distance +% in drawing units. Default is the middle of start/stop. +% 'PortNamePrefix' a prefix to the port name +% +% the mesh must be already initialized +% +% example: +% +% openEMS matlab interface +% ----------------------- +% Thorsten Liebig (c) 2013 +% +% See also InitCSX AddMetal AddMaterial AddExcitation calcPort + +%% validate arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%check mesh +if ~isfield(CSX,'RectilinearGrid') + error 'mesh needs to be defined! Use DefineRectGrid() first!'; +end +if (~isfield(CSX.RectilinearGrid,'XLines') || ~isfield(CSX.RectilinearGrid,'YLines') || ~isfield(CSX.RectilinearGrid,'ZLines')) + error 'mesh needs to be defined! Use DefineRectGrid() first!'; +end + +% check dir +dir = DirChar2Int(dir); + +%set defaults +feed_shift = 0; +feed_R = inf; %(default is open, no resitance) +excite_amp = 0; +measplanepos = nan; +PortNamePrefix = ''; + +excite_args = {}; + +%% read optional arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'FeedShift')==1); + feed_shift = varargin{n+1}; + if (numel(feed_shift)>1) + error 'FeedShift must be a scalar value' + end + elseif (strcmp(varargin{n},'Feed_R')==1); + feed_R = varargin{n+1}; + if (numel(feed_shift)>1) + error 'Feed_R must be a scalar value' + end + elseif (strcmp(varargin{n},'MeasPlaneShift')==1); + measplanepos = varargin{n+1}; + if (numel(feed_shift)>1) + error 'MeasPlaneShift must be a scalar value' + end + elseif (strcmp(varargin{n},'ExciteAmp')==1); + excite_amp = varargin{n+1}; + elseif (strcmpi(varargin{n},'PortNamePrefix')) + PortNamePrefix = varargin{n+1}; + else + excite_args{end+1} = varargin{n}; + excite_args{end+1} = varargin{n+1}; + end +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% determine index (1, 2 or 3) of propagation (length of MSL) +idx_prop_n = dir + 1; +idx_prop_nP = mod((dir+1),3)+1; +idx_prop_nPP = mod((dir+2),3)+1; + +% direction of propagation +if stop(idx_prop_n)-start(idx_prop_n) > 0 + direction = +1; +else + direction = -1; +end + +% create the metal for the coaxial line +CSX = AddCylinder( CSX, pec_name, prio, start, stop, r_i ); +CSX = AddCylindricalShell( CSX, pec_name, prio, start, stop, 0.5*(r_o+r_os), r_os-r_o ); + +% create the material filling for the coaxial line +if (~isempty(materialname)) + CSX = AddCylindricalShell( CSX, materialname, prio-1, start, stop, 0.5*(r_o+r_i), r_o-r_i ); +end + +if isnan(measplanepos) + measplanepos = (start(idx_prop_n)+stop(idx_prop_n))/2; +else + measplanepos = start(idx_prop_n)+direction*measplanepos; +end + +% calculate position of the voltage probes +mesh{1} = sort(unique(CSX.RectilinearGrid.XLines)); +mesh{2} = sort(unique(CSX.RectilinearGrid.YLines)); +mesh{3} = sort(unique(CSX.RectilinearGrid.ZLines)); +meshlines = interp1( mesh{idx_prop_n}, 1:numel(mesh{idx_prop_n}), measplanepos, 'nearest' ); +meshlines = mesh{idx_prop_n}(meshlines-1:meshlines+1); % get three lines (approx. at center) +if direction == -1 + meshlines = fliplr(meshlines); +end +v1_start(idx_prop_n) = meshlines(1); +v1_start(idx_prop_nP) = start(idx_prop_nP)+r_i; +v1_start(idx_prop_nPP) = start(idx_prop_nPP); +v1_stop = v1_start; +v1_stop(idx_prop_nP) = start(idx_prop_nP)+r_o; +v2_start = v1_start; +v2_stop = v1_stop; +v2_start(idx_prop_n) = meshlines(2); +v2_stop(idx_prop_n) = meshlines(2); +v3_start = v2_start; +v3_stop = v2_stop; +v3_start(idx_prop_n) = meshlines(3); +v3_stop(idx_prop_n) = meshlines(3); + +% calculate position of the current probes +i1_start(idx_prop_n) = 0.5*(meshlines(1)+meshlines(2)); +i1_start(idx_prop_nP) = start(idx_prop_nP)-r_i-0.1*(r_o-r_i); +i1_start(idx_prop_nPP) = start(idx_prop_nPP)-r_i-0.1*(r_o-r_i); +i1_stop = i1_start; +i1_stop(idx_prop_nP) = start(idx_prop_nP)+r_i+0.1*(r_o-r_i); +i1_stop(idx_prop_nPP) = start(idx_prop_nPP)+r_i+0.1*(r_o-r_i); + +i2_start = i1_start; +i2_stop = i1_stop; +i2_start(idx_prop_n) = 0.5*(meshlines(2)+meshlines(3)); +i2_stop(idx_prop_n) = 0.5*(meshlines(2)+meshlines(3)); + +% create the probes +port.U_filename{1} = [PortNamePrefix 'port_ut' num2str(portnr) 'A']; +weight = 1; +CSX = AddProbe( CSX, port.U_filename{1}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{1}, prio, v1_start, v1_stop ); +port.U_filename{2} = [PortNamePrefix 'port_ut' num2str(portnr) 'B']; +CSX = AddProbe( CSX, port.U_filename{2}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{2}, prio, v2_start, v2_stop ); +port.U_filename{3} = [PortNamePrefix 'port_ut' num2str(portnr) 'C']; +CSX = AddProbe( CSX, port.U_filename{3}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{3}, prio, v3_start, v3_stop ); + +weight = direction; +port.I_filename{1} = [PortNamePrefix 'port_it' num2str(portnr) 'A']; +CSX = AddProbe( CSX, port.I_filename{1}, 1, 'weight', weight ); +CSX = AddBox( CSX, port.I_filename{1}, prio, i1_start, i1_stop ); +port.I_filename{2} = [PortNamePrefix 'port_it' num2str(portnr) 'B']; +CSX = AddProbe( CSX, port.I_filename{2}, 1,'weight', weight ); +CSX = AddBox( CSX, port.I_filename{2}, prio, i2_start, i2_stop ); + +% create port structure +port.LengthScale = 1; +port.nr = portnr; +port.type = 'Coaxial'; +port.drawingunit = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit; +port.v_delta = diff(meshlines)*port.LengthScale; +port.i_delta = diff( meshlines(1:end-1) + diff(meshlines)/2 )*port.LengthScale; +port.direction = direction; +port.excite = 0; +port.measplanepos = abs(v2_start(idx_prop_n) - start(idx_prop_n))*port.LengthScale; + +port.r_i = r_i; +port.r_o = r_o; + +% create excitation (if enabled) and port resistance +meshline = interp1( mesh{idx_prop_n}, 1:numel(mesh{idx_prop_n}), start(idx_prop_n) + feed_shift*direction, 'nearest' ); +min_cell_prop = min(diff(mesh{idx_prop_n})); +ex_start = start; +ex_start(idx_prop_n) = mesh{idx_prop_n}(meshline) - 0.01*min_cell_prop; +ex_stop = ex_start; +ex_stop(idx_prop_n) = mesh{idx_prop_n}(meshline) + 0.01*min_cell_prop; + +port.excite = 0; +if (excite_amp~=0) + dir_names={'x','y','z'}; + nameX = ['(' dir_names{idx_prop_nP} '-' num2str(start(idx_prop_nP)) ')']; + nameY = ['(' dir_names{idx_prop_nPP} '-' num2str(start(idx_prop_nPP)) ')']; + + func_Ex = [ nameX '/(' nameX '*' nameX '+' nameY '*' nameY ') * (sqrt(' nameX '*' nameX '+' nameY '*' nameY ')<' num2str(r_o) ') * (sqrt(' nameX '*' nameX '+' nameY '*' nameY ')>' num2str(r_i) ')']; + func_Ey = [ nameY '/(' nameX '*' nameX '+' nameY '*' nameY ') * (sqrt(' nameX '*' nameX '+' nameY '*' nameY ')<' num2str(r_o) ') * (sqrt(' nameX '*' nameX '+' nameY '*' nameY ')>' num2str(r_i) ')']; + + func_E{idx_prop_n} = 0; + func_E{idx_prop_nP} = func_Ex; + func_E{idx_prop_nPP} = func_Ey; + + port.excite = 1; + evec = [1 1 1]; + evec(idx_prop_n) = 0; + + CSX = AddExcitation( CSX, [PortNamePrefix 'port_excite_' num2str(portnr)], 0, evec, excite_args{:} ); + CSX = SetExcitationWeight(CSX, [PortNamePrefix 'port_excite_' num2str(portnr)], func_E ); + CSX = AddCylindricalShell(CSX,[PortNamePrefix 'port_excite_' num2str(portnr)],0 ,ex_start,ex_stop,0.5*(r_i+r_o),(r_o-r_i)); +end + +%% resitance at start of coaxial line +ex_start = start; +ex_stop = stop; +ex_stop(idx_prop_n) = ex_start(idx_prop_n); + +if (feed_R > 0) && ~isinf(feed_R) + error 'feed_R not yet implemented' +elseif isinf(feed_R) + % do nothing --> open port +elseif feed_R == 0 + %port "resistance" as metal + CSX = AddBox( CSX, pec_name, prio, ex_start, ex_stop ); + CSX = AddCylindricalShell(CSX, pec_name, prio ,ex_start, ex_stop, 0.5*(r_i+r_o),(r_o-r_i)); +else + error('openEMS:AddMSLPort','MSL port with resitance <= 0 it not possible'); +end +end diff --git a/openEMS/matlab/AddCurvePort.m b/openEMS/matlab/AddCurvePort.m new file mode 100644 index 0000000..6ea99aa --- /dev/null +++ b/openEMS/matlab/AddCurvePort.m @@ -0,0 +1,182 @@ +function [CSX,port] = AddCurvePort( CSX, prio, portnr, R, start, stop, excite, varargin ) +%[CSX,port] = AddCurvePort( CSX, prio, portnr, R, start, stop [, excite, varargin] ) +% +% Creates a curve port (1-dimensional). +% The mesh must already be initialized. +% +% input: +% CSX: CSX-object created by InitCSX() +% prio: priority for excitation, metal, sheet and probe boxes +% portnr: (integer) number of the port +% R: internal resistance of the port +% start: 3D start rowvector for port definition +% stop: 3D end rowvector for port definition +% excite (optional): if true, the port will be switched on (see AddExcitation()) +% Note: for legacy support a string will be accepted +% optional (key/values): +% varargin: optional additional excitations options, see also AddExcitation +% 'PortNamePrefix': a prefix to the port name +% +% output: +% CSX: +% port: +% +% example: +% start = [0 0 0]; stop = [0 0 12]; +% this defines a lumped port in z-direction +% the excitation/probe is placed between start(1) and stop(1) +% +% (C) 2010 Sebastian Held +% See also InitCSX AddExcitation + +port.type='Lumped'; +port.nr=portnr; + +PortNamePrefix = ''; + +varargin_tmp = varargin; +for n=1:2:numel(varargin_tmp) + if strcmpi('PortNamePrefix',varargin_tmp{n}) + PortNamePrefix = varargin_tmp{n+1}; + varargin([n n+1]) = []; + end +end + +% make row vector +start = reshape( start, 1, [] ); +stop = reshape( stop , 1, [] ); + +% get grid +mesh{1} = sort(unique(CSX.RectilinearGrid.XLines)); +mesh{2} = sort(unique(CSX.RectilinearGrid.YLines)); +mesh{3} = sort(unique(CSX.RectilinearGrid.ZLines)); +unit = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit; + +% find port direction +dir = abs(stop - start); +[dummy,dir] = max(dir); + +% other directions +dir1 = mod(dir,3)+1; +dir2 = mod(dir+1,3)+1; + +% normalize start and stop +if start(dir) < stop(dir) + nstart = start; + nstop = stop; +else + nstart = stop; + nstop = start; +end + +% snap to grid +start_idx = zeros(1,3); +stop_idx = zeros(1,3); +for n=1:3 + start_idx(n) = interp1( mesh{n}, 1:numel(mesh{n}), nstart(n), 'nearest' ); + stop_idx(n) = interp1( mesh{n}, 1:numel(mesh{n}), nstop(n), 'nearest' ); +end + +% calculate position +port_start_idx = start_idx; +port_stop_idx = stop_idx; +if abs(start_idx(dir) - stop_idx(dir)) ~= 1 + % calc port position + idx = interp1( mesh{dir}, 1:numel(mesh{dir}), (nstart(dir)+nstop(dir))/2, 'nearest' ); + idx1 = interp1( mesh{dir1}, 1:numel(mesh{dir1}), (nstart(dir1)+nstop(dir1))/2, 'nearest' ); + idx2 = interp1( mesh{dir2}, 1:numel(mesh{dir2}), (nstart(dir2)+nstop(dir2))/2, 'nearest' ); + port_start_idx(dir) = idx; + port_start_idx(dir1) = idx1; + port_start_idx(dir2) = idx2; + port_stop_idx(dir) = idx+1; + port_stop_idx(dir1) = idx1; + port_stop_idx(dir2) = idx2; + metalname = [PortNamePrefix 'port' num2str(portnr) '_PEC']; + CSX = AddMetal( CSX, metalname ); + CSX = AddCurve( CSX, metalname, prio, [nstart.' [mesh{1}(port_start_idx(1));mesh{2}(port_start_idx(2));mesh{3}(port_start_idx(3))]] ); + CSX = AddCurve( CSX, metalname, prio, [nstop.' [mesh{1}(port_stop_idx(1));mesh{2}(port_stop_idx(2));mesh{3}(port_stop_idx(3))]] ); +end + +% calculate position of resistive material +delta1_n = mesh{dir1}(port_start_idx(dir1)) - mesh{dir1}(port_start_idx(dir1)-1); +delta1_p = mesh{dir1}(port_start_idx(dir1)+1) - mesh{dir1}(port_start_idx(dir1)); +delta2_n = mesh{dir2}(port_start_idx(dir2)) - mesh{dir2}(port_start_idx(dir2)-1); +delta2_p = mesh{dir2}(port_start_idx(dir2)+1) - mesh{dir2}(port_start_idx(dir2)); +m_start = zeros(1,3); +m_stop = zeros(1,3); +for n=1:3 + m_start(n) = mesh{n}(port_start_idx(n)); + m_stop(n) = mesh{n}(port_stop_idx(n)); +end +m_start(dir1) = m_start(dir1) - delta1_n/2; +m_stop(dir1) = m_stop(dir1) + delta1_p/2; +m_start(dir2) = m_start(dir2) - delta2_n/2; +m_stop(dir2) = m_stop(dir2) + delta2_p/2; + +% calculate position of the voltage probe & excitation +v_start = [mesh{1}(port_start_idx(1)), mesh{2}(port_start_idx(2)), mesh{3}(port_start_idx(3))]; +v_stop = [mesh{1}(port_stop_idx(1)), mesh{2}(port_stop_idx(2)), mesh{3}(port_stop_idx(3))]; + +% calculate position of the current probe +i_start = m_start; +i_stop = m_stop; +i_start(dir) = (i_start(dir)+i_stop(dir))/2; +i_stop(dir) = i_start(dir); + +% create the probes +port.U_filename = [PortNamePrefix 'port_ut' num2str(portnr)]; +weight = -1; +CSX = AddProbe( CSX, port.U_filename, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename, prio, v_start, v_stop ); +port.I_filename = [PortNamePrefix 'port_it' num2str(portnr)]; +weight = 1; +CSX = AddProbe( CSX, port.I_filename, 1, 'weight', weight ); +CSX = AddBox( CSX, port.I_filename, prio, i_start, i_stop ); + +% create port structure +port.drawingunit = unit; +% port.start = start; +% port.stop = stop; +% port.v_start = v_start; +% port.v_stop = v_stop; +% port.i_start = i_start; +% port.i_stop = i_stop; +% port.dir = dir; +% port.direction = direction; +% port.idx_cal = idx_cal; +% port.idx1 = idx1; +% port.idx1 = idx1; + +if (nargin < 7) + excite = false; +end + +% legacy support, will be removed at some point +if ischar(excite) + warning('CSXCAD:AddCurvePort','depreceated: a string as excite option is no longer supported and will be removed in the future, please use true or false'); + if ~isempty(excite) + excite = true; + else + excite = false; + end +end + +port.excite = excite; + +% create excitation +if (excite) + % excitation of this port is enabled + port.excite = 1; + e_start = v_start; + e_stop = v_stop; + CSX = AddExcitation( CSX, [PortNamePrefix 'port_excite_' num2str(portnr)], 0, start_idx ~= stop_idx, varargin{:}); + CSX = AddBox( CSX, [PortNamePrefix 'port_excite_' num2str(portnr)], prio, e_start, e_stop ); +end + +port.Feed_R = R; +if (R>0 && (~isinf(R))) + CSX = AddLumpedElement( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], dir-1, 'R', R); + CSX = AddBox( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], prio, v_start, v_stop ); +elseif (R==0) + CSX = AddBox(CSX,metalname, prio, v_start, v_stop); +end \ No newline at end of file diff --git a/openEMS/matlab/AddLumpedPort.m b/openEMS/matlab/AddLumpedPort.m new file mode 100644 index 0000000..ad6d5fa --- /dev/null +++ b/openEMS/matlab/AddLumpedPort.m @@ -0,0 +1,129 @@ +function [CSX, port] = AddLumpedPort( CSX, prio, portnr, R, start, stop, dir, excite, varargin ) +% [CSX, port] = AddLumpedPort( CSX, prio, portnr, R, start, stop, dir, excite, varargin ) +% +% Add a lumped port as an excitation. +% +% A lumped port consists of an excitation, a lumped resistor, a voltage and +% current probe. +% +% CSX: CSX-object created by InitCSX() +% prio: priority for substrate and probe boxes +% portnr: (integer) number of the port +% R: internal resistance of the port (lumped element) +% start: 3D start rowvector for port definition +% stop: 3D end rowvector for port definition +% dir: direction/amplitude of port (e.g.: [1 0 0], [0 1 0] or [0 0 1]) +% excite (optional): if true, the port will be switched on (see AddExcitation()) +% Note: for legacy support a string will be accepted +% V_Probe_Weight: additional weigth for the voltage probes +% I_Probe_Weight: additional weigth for the current probes +% optional (key/values): +% 'PortNamePrefix': an prefix to the port name +% varargin (optional): additional excitations options, see also AddExcitation +% +% example: +% start = [0 -width/2 0]; +% stop = [0 width/2 height]; +% [CSX] = AddLumpedPort(CSX, 5 ,1 , 50, start, stop, [0 0 1], true); +% %this defines an active lumped port in z-direction with a 50 Ohm port impedence +% +% openEMS matlab interface +% ----------------------- +% Sebastian Held +% Jun 1 2010 +% Thorsten Liebig +% Jul 13 2011 +% +% See also InitCSX AddExcitation + +% check dir + +port.type='Lumped'; +port.nr=portnr; + +V_Probe_Weight = 1; +I_Probe_Weight = 1; + +if (dir(1)~=0) && (dir(2) == 0) && (dir(3)==0) + n_dir = 1; +elseif (dir(1)==0) && (dir(2) ~= 0) && (dir(3)==0) + n_dir = 2; +elseif (dir(1)==0) && (dir(2) == 0) && (dir(3)~=0) + n_dir = 3; +else + error 'dir must have exactly one component ~= 0' +end + +PortNamePrefix = ''; + +varargin_tmp = varargin; +for n=1:2:numel(varargin_tmp) + if strcmpi('PortNamePrefix',varargin_tmp{n}) + PortNamePrefix = varargin_tmp{n+1}; + varargin([n n+1]) = []; + elseif strcmpi('V_Probe_Weight',varargin_tmp{n}) + V_Probe_Weight = varargin_tmp{n+1}; + elseif strcmpi('I_Probe_Weight',varargin_tmp{n}) + I_Probe_Weight = varargin_tmp{n+1}; + end +end + +if (stop(n_dir)==start(n_dir)) + error 'start/stop in excitation direction in must not be equal' +end + +if (stop(n_dir)-start(n_dir)) > 0 + direction = +1; +else + direction = -1; +end +port.direction = direction; + +port.Feed_R = R; +if (R>0 && (~isinf(R))) + CSX = AddLumpedElement(CSX,[PortNamePrefix 'port_resist_' int2str(portnr)], n_dir-1, 'Caps', 1, 'R', R); + CSX = AddBox(CSX,[PortNamePrefix 'port_resist_' int2str(portnr)], prio, start, stop); +elseif (R<=0) + CSX = AddMetal(CSX,[PortNamePrefix 'port_resist_' int2str(portnr)]); + CSX = AddBox(CSX,[PortNamePrefix 'port_resist_' int2str(portnr)], prio, start, stop); +end + +if (nargin < 8) + excite = false; +end + +% legacy support, will be removed at some point +if ischar(excite) + warning('CSXCAD:AddLumpedPort','depreceated: a string as excite option is no longer supported and will be removed in the future, please use true or false'); + if ~isempty(excite) + excite = true; + else + excite = false; + end +end + +port.excite = excite; +% create excitation +if (excite) + CSX = AddExcitation( CSX, [PortNamePrefix 'port_excite_' num2str(portnr)], 0, -dir*direction, varargin{:}); + CSX = AddBox( CSX, [PortNamePrefix 'port_excite_' num2str(portnr)], prio, start, stop ); +end + +u_start = 0.5*(start + stop); +u_stop = 0.5*(start + stop); +u_start(n_dir) = start(n_dir); +u_stop(n_dir) = stop(n_dir); + +port.U_filename = [PortNamePrefix 'port_ut' int2str(portnr)]; +CSX = AddProbe(CSX, port.U_filename, 0, 'weight', -direction*V_Probe_Weight); +CSX = AddBox(CSX, port.U_filename, prio, u_start, u_stop); + +i_start = start; +i_stop = stop; +i_start(n_dir) = 0.5*(start(n_dir)+stop(n_dir)); +i_stop(n_dir) = 0.5*(start(n_dir)+stop(n_dir)); + +port.I_filename = [PortNamePrefix 'port_it' int2str(portnr)]; +CSX = AddProbe(CSX, port.I_filename, 1, 'weight', direction*I_Probe_Weight, 'NormDir', n_dir-1); +CSX = AddBox(CSX, port.I_filename, prio, i_start, i_stop); + diff --git a/openEMS/matlab/AddMRStub.m b/openEMS/matlab/AddMRStub.m new file mode 100644 index 0000000..432fa6a --- /dev/null +++ b/openEMS/matlab/AddMRStub.m @@ -0,0 +1,73 @@ +function CSX = AddMRStub( CSX, materialname, prio, MSL_width, len, alpha, resolution, orientation, normVector, position ) +% CSX = AddMRStub( CSX, materialname, prio, MSL_width, len, alpha, +% resolution, orientation, normVector, position ) +% +% Microstrip Radial Stub +% +% CSX: CSX-object created by InitCSX() +% materialname: property for the MSL (created by AddMetal() or AddMaterial()) +% prio: priority +% MSL_width: width of the MSL to connect the stub to +% len: length of the radial stub +% alpha: angle subtended by the radial stub (degrees) +% resolution: discrete angle spacing (degrees) +% orientation: angle of main direction of the radial stub (degrees) +% normVector: normal vector of the stub +% position: position of the end of the MSL +% +% This radial stub definition is equivalent to the one Agilent ADS uses. +% +% example: +% CSX = AddMRStub( CSX, 'PEC', 10, 1000, 5900, 30, 1, -90, [0 0 1], [0 -10000 254] ); +% +% +% Sebastian Held +% Jun 1 2010 +% +% See also InitCSX AddMetal AddMaterial + +% check normVector +if ~(normVector(1) == normVector(2) == 0) && ... + ~(normVector(1) == normVector(3) == 0) && ... + ~(normVector(2) == normVector(3) == 0) || (sum(normVector) == 0) + error 'normVector must have exactly one component ~= 0' +end +normVector = normVector ./ sum(normVector); % normVector is now a unit vector + +% convert angles to radians +alpha_rad = alpha/180*pi; +orientation_rad = orientation/180*pi; +resolution_rad = resolution/180*pi; + +% +% build stub at origin (0,0,0) and translate/rotate it later +% + +D = 0.5 * MSL_width / sin(alpha_rad/2); +R = cos(alpha_rad/2) * D; + +% point at the center of the MSL +p(1,1) = 0; +p(2,1) = -MSL_width/2; +p(1,2) = 0; +p(2,2) = MSL_width/2; + +for a = alpha_rad/2 : -resolution_rad : -alpha_rad/2 + p(1,end+1) = cos(a) * (D+len) - R; + p(2,end) = sin(a) * (D+len); +end + +% rotate +rot = [cos(-orientation_rad), -sin(-orientation_rad); sin(-orientation_rad), cos(-orientation_rad)]; +p = (p.' * rot).'; + +% translate +idx_elevation = [1 2 3]; +idx_elevation = idx_elevation(normVector>0); +dim1 = mod( idx_elevation, 3 ) + 1; +dim2 = mod( idx_elevation+1, 3 ) + 1; +p(1,:) = p(1,:) + position(dim1); +p(2,:) = p(2,:) + position(dim2); + +elevation = position(idx_elevation); +CSX = AddPolygon( CSX, materialname, prio, normVector, elevation, p ); diff --git a/openEMS/matlab/AddMSLPort.m b/openEMS/matlab/AddMSLPort.m new file mode 100644 index 0000000..462db14 --- /dev/null +++ b/openEMS/matlab/AddMSLPort.m @@ -0,0 +1,265 @@ +function [CSX,port] = AddMSLPort( CSX, prio, portnr, materialname, start, stop, dir, evec, varargin ) +% [CSX,port] = AddMSLPort( CSX, prio, portnr, materialname, start, stop, dir, evec, varargin ) +% +% CSX: CSX-object created by InitCSX() +% prio: priority for excitation and probe boxes +% portnr: (integer) number of the port +% materialname: property for the MSL (created by AddMetal()) +% start: 3D start rowvector for port definition +% stop: 3D end rowvector for port definition +% dir: direction of wave propagation (choices: 0, 1, 2 or 'x','y','z') +% evec: excitation vector, which defines the direction of the e-field (must be the same as used in AddExcitation()) +% +% variable input: +% varargin: optional additional excitations options, see also AddExcitation +% 'ExcitePort' true/false to make the port an active feeding port (default +% is false) +% 'FeedShift' shift to port from start by a given distance in drawing +% units. Default is 0. Only active if 'ExcitePort' is set! +% 'Feed_R' Specifiy a lumped port resistance. Default is no lumped +% port resistance --> port has to end in an ABC. +% 'MeasPlaneShift' Shift the measurement plane from start t a given distance +% in drawing units. Default is the middle of start/stop. +% 'PortNamePrefix' a prefix to the port name +% +% Important: The mesh has to be already set and defined by DefineRectGrid! +% +% example: +% CSX = AddMetal( CSX, 'metal' ); %create a PEC called 'metal' +% start = [0 -width/2 height]; +% stop = [length +width/2 0 ]; +% [CSX,port] = AddMSLPort( CSX, 0, 1, 'metal', start, stop, 'x', [0 0 -1], ... +% 'ExcitePort', true, 'Feed_R', 50 ) +% Explanation: +% - this defines a MSL in x-direction (dir='x') +% --> the wave travels along the x-direction +% - with an e-field excitation in -z-direction (evec=[0 0 -1]) +% - the excitation is active and placed at x=start(1) ('ExcitePort', true) +% - a 50 Ohm lumped port resistance is placed at x=start(1) ('Feed_R', 50) +% - the width-direction is determined by the cross product of the +% direction of propagtion (dir='x') and the excitation vector +% (evec=[0 0 -1]), in this case it is the y-direction +% - the MSL-metal is created in a xy-plane at a height at z=start(3) +% --> It is important to define the MSL height in the start coordinate! +% - the ground (xy-plane, not defined by the port) is assumed at z=stop(3) +% --> The reference plane (ground) is defined in the stop coordinate! +% +% Sebastian Held May 13 2010 +% Thorsten Liebig (c) 2011-2013 +% +% See also InitCSX DefineRectGrid AddMetal AddMaterial AddExcitation calcPort + +%% validate arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%check mesh +if ~isfield(CSX,'RectilinearGrid') + error 'mesh needs to be defined! Use DefineRectGrid() first!'; +end +if (~isfield(CSX.RectilinearGrid,'XLines') || ~isfield(CSX.RectilinearGrid,'YLines') || ~isfield(CSX.RectilinearGrid,'ZLines')) + error 'mesh needs to be defined! Use DefineRectGrid() first!'; +end + +% check dir +dir = DirChar2Int(dir); + +% check evec +if ~(evec(1) == evec(2) == 0) && ~(evec(1) == evec(3) == 0) && ~(evec(2) == evec(3) == 0) || (sum(evec) == 0) + error 'evec must have exactly one component ~= 0' +end +evec0 = evec ./ sum(evec); % evec0 is a unit vector + +%set defaults +feed_shift = 0; +feed_R = inf; %(default is open, no resitance) +excite = false; +measplanepos = nan; +PortNamePrefix = ''; + +excite_args = {}; + +%% read optional arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'FeedShift')==1); + feed_shift = varargin{n+1}; + if (numel(feed_shift)>1) + error 'FeedShift must be a scalar value' + end + elseif (strcmp(varargin{n},'Feed_R')==1); + feed_R = varargin{n+1}; + if (numel(feed_shift)>1) + error 'Feed_R must be a scalar value' + end + elseif (strcmp(varargin{n},'MeasPlaneShift')==1); + measplanepos = varargin{n+1}; + if (numel(feed_shift)>1) + error 'MeasPlaneShift must be a scalar value' + end + elseif (strcmp(varargin{n},'ExcitePort')==1); + if ischar(varargin{n+1}) + warning('CSXCAD:AddMSLPort','depreceated: a string as excite option is no longer supported and will be removed in the future, please use true or false'); + if ~isempty(excite) + excite = true; + else + excite = false; + end + else + excite = varargin{n+1}; + end + elseif (strcmpi(varargin{n},'PortNamePrefix')) + PortNamePrefix = varargin{n+1}; + else + excite_args{end+1} = varargin{n}; + excite_args{end+1} = varargin{n+1}; + end +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% normalize start and stop +nstart = min( [start;stop] ); +nstop = max( [start;stop] ); + +% determine index (1, 2 or 3) of propagation (length of MSL) +idx_prop = dir + 1; + +% determine index (1, 2 or 3) of width of MSL +dir = [0 0 0]; +dir(idx_prop) = 1; +idx_width = abs(cross(dir,evec0)) * [1;2;3]; + +% determine index (1, 2 or 3) of height +idx_height = abs(evec0) * [1;2;3]; + +% direction of propagation +if stop(idx_prop)-start(idx_prop) > 0 + direction = +1; +else + direction = -1; +end + +% direction of propagation +if stop(idx_height)-start(idx_height) > 0 + upsidedown = +1; +else + upsidedown = -1; +end + +% create the metal/material for the MSL +MSL_start = start; +MSL_stop = stop; +MSL_stop(idx_height) = MSL_start(idx_height); +CSX = AddBox( CSX, materialname, prio, MSL_start, MSL_stop ); + +if isnan(measplanepos) + measplanepos = (nstart(idx_prop)+nstop(idx_prop))/2; +else + measplanepos = start(idx_prop)+direction*measplanepos; +end + +% calculate position of the voltage probes +mesh{1} = sort(CSX.RectilinearGrid.XLines); +mesh{2} = sort(CSX.RectilinearGrid.YLines); +mesh{3} = sort(CSX.RectilinearGrid.ZLines); +meshlines = interp1( mesh{idx_prop}, 1:numel(mesh{idx_prop}), measplanepos, 'nearest' ); +meshlines = mesh{idx_prop}(meshlines-1:meshlines+1); % get three lines (approx. at center) +if direction == -1 + meshlines = fliplr(meshlines); +end +MSL_w2 = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), (nstart(idx_width)+nstop(idx_width))/2, 'nearest' ); +MSL_w2 = mesh{idx_width}(MSL_w2); % get e-line at center of MSL (MSL_width/2) +v1_start(idx_prop) = meshlines(1); +v1_start(idx_width) = MSL_w2; +v1_start(idx_height) = start(idx_height); +v1_stop = v1_start; +v1_stop(idx_height) = stop(idx_height); +v2_start = v1_start; +v2_stop = v1_stop; +v2_start(idx_prop) = meshlines(2); +v2_stop(idx_prop) = meshlines(2); +v3_start = v2_start; +v3_stop = v2_stop; +v3_start(idx_prop) = meshlines(3); +v3_stop(idx_prop) = meshlines(3); + +% calculate position of the current probes +idx = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), nstart(idx_width), 'nearest' ); +i1_start(idx_width) = mesh{idx_width}(idx) - diff(mesh{idx_width}(idx-1:idx))/2; +idx = interp1( mesh{idx_height}, 1:numel(mesh{idx_height}), start(idx_height), 'nearest' ); +i1_start(idx_height) = mesh{idx_height}(idx-1) - diff(mesh{idx_height}(idx-2:idx-1))/2; +i1_stop(idx_height) = mesh{idx_height}(idx+1) + diff(mesh{idx_height}(idx+1:idx+2))/2; +i1_start(idx_prop) = sum(meshlines(1:2))/2; +i1_stop(idx_prop) = i1_start(idx_prop); +idx = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), nstop(idx_width), 'nearest' ); +i1_stop(idx_width) = mesh{idx_width}(idx) + diff(mesh{idx_width}(idx:idx+1))/2; +i2_start = i1_start; +i2_stop = i1_stop; +i2_start(idx_prop) = sum(meshlines(2:3))/2; +i2_stop(idx_prop) = i2_start(idx_prop); + +% create the probes +port.U_filename{1} = [PortNamePrefix 'port_ut' num2str(portnr) 'A']; +% weight = sign(stop(idx_height)-start(idx_height)) +weight = upsidedown; +CSX = AddProbe( CSX, port.U_filename{1}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{1}, prio, v1_start, v1_stop ); +port.U_filename{2} = [PortNamePrefix 'port_ut' num2str(portnr) 'B']; +CSX = AddProbe( CSX, port.U_filename{2}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{2}, prio, v2_start, v2_stop ); +port.U_filename{3} = [PortNamePrefix 'port_ut' num2str(portnr) 'C']; +CSX = AddProbe( CSX, port.U_filename{3}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{3}, prio, v3_start, v3_stop ); + +weight = direction; +port.I_filename{1} = [PortNamePrefix 'port_it' num2str(portnr) 'A']; +CSX = AddProbe( CSX, port.I_filename{1}, 1, 'weight', weight ); +CSX = AddBox( CSX, port.I_filename{1}, prio, i1_start, i1_stop ); +port.I_filename{2} = [PortNamePrefix 'port_it' num2str(portnr) 'B']; +CSX = AddProbe( CSX, port.I_filename{2}, 1,'weight', weight ); +CSX = AddBox( CSX, port.I_filename{2}, prio, i2_start, i2_stop ); + +% create port structure +port.LengthScale = 1; +if ((CSX.ATTRIBUTE.CoordSystem==1) && (idx_prop==2)) + port.LengthScale = MSL_stop(idx_height); +end +port.nr = portnr; +port.type = 'MSL'; +port.drawingunit = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit; +port.v_delta = diff(meshlines)*port.LengthScale; +port.i_delta = diff( meshlines(1:end-1) + diff(meshlines)/2 )*port.LengthScale; +port.direction = direction; +port.excite = 0; +port.measplanepos = abs(v2_start(idx_prop) - start(idx_prop))*port.LengthScale; +% port + +% create excitation (if enabled) and port resistance +meshline = interp1( mesh{idx_prop}, 1:numel(mesh{idx_prop}), start(idx_prop) + feed_shift*direction, 'nearest' ); +ex_start(idx_prop) = mesh{idx_prop}(meshline) ; +ex_start(idx_width) = nstart(idx_width); +ex_start(idx_height) = nstart(idx_height); +ex_stop(idx_prop) = ex_start(idx_prop); +ex_stop(idx_width) = nstop(idx_width); +ex_stop(idx_height) = nstop(idx_height); + +port.excite = 0; +if excite + port.excite = 1; + CSX = AddExcitation( CSX, [PortNamePrefix 'port_excite_' num2str(portnr)], 0, evec, excite_args{:} ); + CSX = AddBox( CSX, [PortNamePrefix 'port_excite_' num2str(portnr)], prio, ex_start, ex_stop ); +end + +%% MSL resitance at start of MSL line +ex_start(idx_prop) = start(idx_prop); +ex_stop(idx_prop) = ex_start(idx_prop); + +if (feed_R > 0) && ~isinf(feed_R) + CSX = AddLumpedElement( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], idx_height-1, 'R', feed_R ); + CSX = AddBox( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], prio, ex_start, ex_stop ); +elseif isinf(feed_R) + % do nothing --> open port +elseif feed_R == 0 + %port "resistance" as metal + CSX = AddBox( CSX, materialname, prio, ex_start, ex_stop ); +else + error('openEMS:AddMSLPort','MSL port with resitance <= 0 it not possible'); +end +end diff --git a/openEMS/matlab/AddPML.m b/openEMS/matlab/AddPML.m new file mode 100644 index 0000000..4e7ba80 --- /dev/null +++ b/openEMS/matlab/AddPML.m @@ -0,0 +1,92 @@ +function mesh = AddPML( mesh, numcells, CoordSystem ) +% mesh = AddPML( mesh, numcells, ) +% +% Adds equidistant cells to the specified directions of the simulation +% area. This is used to put a PML (perfectly matched layer) absorber there. +% Remember: this function only adds space for the PML, the boundary +% conditions need to be set correctly to really add PML material. +% +% The mesh is sorted and duplicate lines are removed. +% +% input: +% mesh: mesh structure +% numcells: 1x6 vector (xmin,xmax,ymin,ymax,zmin,zmax) with number of +% cells to add to this direction +% CoordSystem (optional): set to 1 in case of cylindrical mesh using +% mesh.r, mesh.a and mesh.z +% +% output: +% mesh: new mesh with the added lines +% +% example: +% % some fixed mesh lines +% mesh.x = [-100 0 100]; +% mesh.y = [-100 0 100]; +% mesh.z = [0 500]; +% mesh = DetectEdges(CSX, mesh); %detect edges +% mesh = SmoothMesh(mesh, c0/fmax/20/unit); % smooth the mesh +% +% mesh = AddPML(mesh, 8); % add 8 lines to all directions +% % or +% mesh = AddPML(mesh, [0 0 0 0 8 8]); % add 8 lines in both z-directions +% +% See also DefineRectGrid, SmoothMesh, DetectEdges +% +% openEMS matlab interface +% ----------------------- +% Sebastian Held + +% check +error( nargchk(2,3,nargin) ); + +if (numel(numcells)==1) + numcells = ones(6,1)*numcells; +end + +numcells = reshape( numcells, 1, [] ); +if numel(numcells) ~= 6 + error( 'argument numcells needs to have exactly 6 elements' ); +end + +if (nargin<3) + CoordSystem = 0; +end + +dir_names = 'xyz'; +if (CoordSystem==1) + dir_names = 'raz'; +end + +mesh.(dir_names(1)) = unique(sort(mesh.(dir_names(1)))); +mesh.(dir_names(2)) = unique(sort(mesh.(dir_names(2)))); +mesh.(dir_names(3)) = unique(sort(mesh.(dir_names(3)))); + +% xmin +delta = mesh.(dir_names(1))(2) - mesh.(dir_names(1))(1); +start = mesh.(dir_names(1))(1) - numcells(1)*delta; +mesh.(dir_names(1)) = [start:delta:(mesh.(dir_names(1))(1)-delta), mesh.(dir_names(1))]; + +% xmax +delta = mesh.(dir_names(1))(end) - mesh.(dir_names(1))(end-1); +stop = mesh.(dir_names(1))(end) + numcells(2)*delta; +mesh.(dir_names(1)) = [mesh.(dir_names(1)), (mesh.(dir_names(1))(end)+delta):delta:stop]; + +% ymin +delta = mesh.(dir_names(2))(2) - mesh.(dir_names(2))(1); +start = mesh.(dir_names(2))(1) - numcells(3)*delta; +mesh.(dir_names(2)) = [start:delta:(mesh.(dir_names(2))(1)-delta), mesh.(dir_names(2))]; + +% ymax +delta = mesh.(dir_names(2))(end) - mesh.(dir_names(2))(end-1); +stop = mesh.(dir_names(2))(end) + numcells(4)*delta; +mesh.(dir_names(2)) = [mesh.(dir_names(2)), (mesh.(dir_names(2))(end)+delta):delta:stop]; + +% zmin +delta = mesh.(dir_names(3))(2) - mesh.(dir_names(3))(1); +start = mesh.(dir_names(3))(1) - numcells(5)*delta; +mesh.(dir_names(3)) = [start:delta:(mesh.(dir_names(3))(1)-delta), mesh.(dir_names(3))]; + +% zmax +delta = mesh.(dir_names(3))(end) - mesh.(dir_names(3))(end-1); +stop = mesh.(dir_names(3))(end) + numcells(6)*delta; +mesh.(dir_names(3)) = [mesh.(dir_names(3)), (mesh.(dir_names(3))(end)+delta):delta:stop]; diff --git a/openEMS/matlab/AddRectWaveGuidePort.m b/openEMS/matlab/AddRectWaveGuidePort.m new file mode 100644 index 0000000..8233f77 --- /dev/null +++ b/openEMS/matlab/AddRectWaveGuidePort.m @@ -0,0 +1,92 @@ +function [CSX,port] = AddRectWaveGuidePort( CSX, prio, portnr, start, stop, dir, a, b, mode_name, exc_amp, varargin ) +% function [CSX,port] = AddRectWaveGuidePort( CSX, prio, portnr, start, stop, dir, a, b, mode_name, exc_amp, varargin ) +% +% Create a rectangular waveguide port, including an optional excitation and probes +% +% Note: - The excitation will be located at the start position in the given direction +% - The voltage and current probes at the stop position in the given direction +% +% input: +% CSX: complete CSX structure (must contain a mesh) +% prio: priority of primitives +% start: start coordinates of waveguide port box +% stop: stop coordinates of waveguide port box +% dir: direction of port (0/1/2 or 'x'/'y'/'z'-direction) +% a,b: rectangular waveguide width and height (in meter) +% mode_name: mode name, e.g. 'TE11' or 'TM21' +% exc_amp: excitation amplitude (set 0 to be passive) +% +% optional (key/values): +% varargin: optional additional excitations options, see also AddExcitation +% 'PortNamePrefix': a prefix to the port name +% +% output: +% CSX: modified CSX structure +% port: port structure to use with calcPort +% +% example: +% % create a TE10 circular waveguide mode, using cylindircal coordinates +% start=[mesh.r(1) mesh.a(1) 0 ]; +% stop =[mesh.r(end) mesh.a(end) 100]; +% [CSX,port] = AddCircWaveGuidePort( CSX, 99, 1, start, stop, 320e-3, 'TE11', 0, 1); +% +% openEMS matlab interface +% ----------------------- +% (c) 2013 Thorsten Liebig (thorsten.liebig@gmx.de) +% +% See also InitCSX, AddExcitation, calcWGPort, calcPort + +if (~strcmpi(mode_name(1:2),'TE')) + error 'currently only TE type modes are supported' +end + +if (nargin<10) + exc_amp = 0; +end + +m = str2double(mode_name(3)); +n = str2double(mode_name(4)); + +% values by David M. Pozar, Microwave Engineering, third edition +kc = sqrt((m*pi/a)^2 + (n*pi/b)^2); + +if ~isfield(CSX,'RectilinearGrid') + error 'mesh needs to be defined! Use DefineRectGrid() first!'; + if (~isfield(CSX.RectilinearGrid,'XLines') || ~isfield(CSX.RectilinearGrid,'YLines') || ~isfield(CSX.RectilinearGrid,'ZLines')) + error 'mesh needs to be defined! Use DefineRectGrid() first!'; + end +end + +unit = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit; + +dir = DirChar2Int(dir); +dir_names={'x','y','z'}; + +dirP = mod((dir+1),3)+1; +dirPP = mod((dir+2),3)+1; +nameX = ['(' dir_names{dirP} '-' num2str(start(dirP)) ')']; +nameY = ['(' dir_names{dirPP} '-' num2str(start(dirPP)) ')']; + +%convert a&b to drawing units +a = a/unit; +b = b/unit; +% functions by David M. Pozar, Microwave Engineering, third edition +% electric field mode profile +func_Ex = [num2str( n/b) '*cos(' num2str(m*pi/a) '*' nameX ')*sin(' num2str(n*pi/b) '*' nameY ')']; +func_Ey = [num2str(-m/a) '*sin(' num2str(m*pi/a) '*' nameX ')*cos(' num2str(n*pi/b) '*' nameY ')']; + +% magnetic field mode profile +func_Hx = [num2str(m/a) '*sin(' num2str(m*pi/a) '*' nameX ')*cos(' num2str(n*pi/b) '*' nameY ')']; +func_Hy = [num2str(n/b) '*cos(' num2str(m*pi/a) '*' nameX ')*sin(' num2str(n*pi/b) '*' nameY ')']; + + +func_E{dir+1} = 0; +func_E{dirP} = func_Ex; +func_E{dirPP} = func_Ey; + +func_H{dir+1} = 0; +func_H{dirP} = func_Hx; +func_H{dirPP} = func_Hy; + +[CSX,port] = AddWaveGuidePort( CSX, prio, portnr, start, stop, dir, func_E, func_H, kc, exc_amp, varargin{:} ); + diff --git a/openEMS/matlab/AddStripLinePort.m b/openEMS/matlab/AddStripLinePort.m new file mode 100644 index 0000000..70dd065 --- /dev/null +++ b/openEMS/matlab/AddStripLinePort.m @@ -0,0 +1,283 @@ +function [CSX,port] = AddStripLinePort( CSX, prio, portnr, materialname, start, stop, height, dir, evec, varargin ) +% [CSX,port] = AddStripLinePort( CSX, prio, portnr, materialname, start, stop, height, dir, evec, varargin ) +% +% CSX: CSX-object created by InitCSX() +% prio: priority for excitation and probe boxes +% portnr: (integer) number of the port +% materialname: property for the MSL (created by AddMetal()) +% start: 3D start rowvector for port definition +% stop: 3D end rowvector for port definition +% height: height of the stripline (top and bottom) +% dir: direction of wave propagation (choices: 0, 1, 2 or 'x','y','z') +% evec: excitation vector, which defines the direction of the e-field (must be the same as used in AddExcitation()) +% +% variable input: +% varargin: optional additional excitations options, see also AddExcitation +% 'ExcitePort' true/false to make the port an active feeding port (default +% is false) +% 'FeedShift' shift to port from start by a given distance in drawing +% units. Default is 0. Only active if 'ExcitePort' is set! +% 'Feed_R' Specifiy a lumped port resistance. Default is no lumped +% port resistance --> port has to end in an ABC. +% 'MeasPlaneShift' Shift the measurement plane from start t a given distance +% in drawing units. Default is the middle of start/stop. +% 'PortNamePrefix' a prefix to the port name +% +% Important: The mesh has to be already set and defined by DefineRectGrid! +% +% example: +% CSX = AddMetal( CSX, 'metal' ); %create a PEC called 'metal' +% start = [0 -width/2 0]; +% stop = [length +width/2 0]; +% [CSX,port] = AddStripLinePort( CSX, 0, 1, 'metal', start, stop, height, 'x', ... +% [0 0 -1], 'ExcitePort', true, 'Feed_R', 50 ) +% Explanation: +% - this defines a stripline in x-direction (dir='x') +% --> the wave travels along the x-direction +% - with an e-field excitation in -z-direction (evec=[0 0 -1]) +% - the excitation is active and placed at x=start(1) ('ExcitePort', true) +% - a 50 Ohm lumped port resistance is placed at x=start(1) ('Feed_R', 50) +% - the width-direction is determined by the cross product of the +% direction of propagtion (dir='x') and the excitation vector +% (evec=[0 0 -1]), in this case it is the y-direction +% - the stripline-metal is created in a xy-plane at a height at z=start(3) +% --> The upper and lower reference plane (ground) must be defined by +% the user +% +% Thorsten Liebig (c) 2013 +% +% See also InitCSX DefineRectGrid AddMetal AddMaterial AddExcitation calcPort + +%% validate arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%check mesh +if ~isfield(CSX,'RectilinearGrid') + error 'mesh needs to be defined! Use DefineRectGrid() first!'; +end +if (~isfield(CSX.RectilinearGrid,'XLines') || ~isfield(CSX.RectilinearGrid,'YLines') || ~isfield(CSX.RectilinearGrid,'ZLines')) + error 'mesh needs to be defined! Use DefineRectGrid() first!'; +end + +% check dir +dir = DirChar2Int(dir); + +% check evec +if ~(evec(1) == evec(2) == 0) && ~(evec(1) == evec(3) == 0) && ~(evec(2) == evec(3) == 0) || (sum(evec) == 0) + error 'evec must have exactly one component ~= 0' +end +evec0 = evec ./ sum(evec); % evec0 is a unit vector + +%set defaults +feed_shift = 0; +feed_R = inf; %(default is open, no resitance) +excite = false; +measplanepos = nan; +PortNamePrefix = ''; + +excite_args = {}; + +%% read optional arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'FeedShift')==1); + feed_shift = varargin{n+1}; + if (numel(feed_shift)>1) + error 'FeedShift must be a scalar value' + end + elseif (strcmp(varargin{n},'Feed_R')==1); + feed_R = varargin{n+1}; + if (numel(feed_shift)>1) + error 'Feed_R must be a scalar value' + end + elseif (strcmp(varargin{n},'MeasPlaneShift')==1); + measplanepos = varargin{n+1}; + if (numel(feed_shift)>1) + error 'MeasPlaneShift must be a scalar value' + end + elseif (strcmp(varargin{n},'ExcitePort')==1); + if ischar(varargin{n+1}) + warning('CSXCAD:AddMSLPort','depreceated: a string as excite option is no longer supported and will be removed in the future, please use true or false'); + if ~isempty(excite) + excite = true; + else + excite = false; + end + else + excite = varargin{n+1}; + end + elseif (strcmpi(varargin{n},'PortNamePrefix')) + PortNamePrefix = varargin{n+1}; + else + excite_args{end+1} = varargin{n}; + excite_args{end+1} = varargin{n+1}; + end +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% normalize start and stop +nstart = min( [start;stop] ); +nstop = max( [start;stop] ); + +% determine index (1, 2 or 3) of propagation (length of MSL) +idx_prop = dir + 1; + +% determine index (1, 2 or 3) of width of MSL +dir = [0 0 0]; +dir(idx_prop) = 1; +idx_width = abs(cross(dir,evec0)) * [1;2;3]; + +% determine index (1, 2 or 3) of height +idx_height = abs(evec0) * [1;2;3]; + +if (start(idx_height)~=stop(idx_height)) + error('openEMS:AddStripLinePort','start/stop in height direction must be equal'); +end + +% direction of propagation +if stop(idx_prop)-start(idx_prop) > 0 + direction = +1; +else + direction = -1; +end + +% create the metal/material for the MSL +SL_start = start; +SL_stop = stop; +CSX = AddBox( CSX, materialname, prio, SL_start, SL_stop ); + +if isnan(measplanepos) + measplanepos = (nstart(idx_prop)+nstop(idx_prop))/2; +else + measplanepos = start(idx_prop)+direction*measplanepos; +end + +% calculate position of the voltage probes +mesh{1} = sort(CSX.RectilinearGrid.XLines); +mesh{2} = sort(CSX.RectilinearGrid.YLines); +mesh{3} = sort(CSX.RectilinearGrid.ZLines); +meshlines = interp1( mesh{idx_prop}, 1:numel(mesh{idx_prop}), measplanepos, 'nearest' ); +meshlines = mesh{idx_prop}(meshlines-1:meshlines+1); % get three lines (approx. at center) +if direction == -1 + meshlines = fliplr(meshlines); +end +SL_w2 = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), (nstart(idx_width)+nstop(idx_width))/2, 'nearest' ); +SL_w2 = mesh{idx_width}(SL_w2); % get e-line at center of MSL (SL_width/2) +v1_start(idx_prop) = meshlines(1); +v1_start(idx_width) = SL_w2; +v1_start(idx_height) = start(idx_height); +v1_stop = v1_start; +v1_stop(idx_height) = v1_start(idx_height); +v2_start = v1_start; +v2_stop = v1_stop; +v2_start(idx_prop) = meshlines(2); +v2_stop(idx_prop) = meshlines(2); +v3_start = v2_start; +v3_stop = v2_stop; +v3_start(idx_prop) = meshlines(3); +v3_stop(idx_prop) = meshlines(3); + +height_vector = [0 0 0]; +height_vector(idx_height) = height; + +weight = 0.5; +% create the voltage-probes +port.U_filename{1,1} = [PortNamePrefix 'port_ut' num2str(portnr) 'A1']; +CSX = AddProbe( CSX, port.U_filename{1,1}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{1,1}, prio, v1_start, v1_stop+height_vector); + +port.U_filename{1,2} = [PortNamePrefix 'port_ut' num2str(portnr) 'A2']; +CSX = AddProbe( CSX, port.U_filename{1,2}, 0, 'weight', -1*weight ); +CSX = AddBox( CSX, port.U_filename{1,2}, prio, v1_start, v1_stop-height_vector); + + +port.U_filename{2,1} = [PortNamePrefix 'port_ut' num2str(portnr) 'B1']; +CSX = AddProbe( CSX, port.U_filename{2,1}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{2,1}, prio, v2_start, v2_stop+height_vector ); + +port.U_filename{2,2} = [PortNamePrefix 'port_ut' num2str(portnr) 'B2']; +CSX = AddProbe( CSX, port.U_filename{2,2}, 0, 'weight', -1*weight ); +CSX = AddBox( CSX, port.U_filename{2,2}, prio, v2_start, v2_stop-height_vector ); + + +port.U_filename{3,1} = [PortNamePrefix 'port_ut' num2str(portnr) 'C1']; +CSX = AddProbe( CSX, port.U_filename{3,1}, 0, 'weight', weight ); +CSX = AddBox( CSX, port.U_filename{3,1}, prio, v3_start, v3_stop+height_vector ); + +port.U_filename{3,2} = [PortNamePrefix 'port_ut' num2str(portnr) 'C2']; +CSX = AddProbe( CSX, port.U_filename{3,2}, 0, 'weight', -1*weight ); +CSX = AddBox( CSX, port.U_filename{3,2}, prio, v3_start, v3_stop-height_vector ); + +% calculate position of the current probes +idx = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), nstart(idx_width), 'nearest' ); +i1_start(idx_width) = mesh{idx_width}(idx) - diff(mesh{idx_width}(idx-1:idx))/2; +idx = interp1( mesh{idx_height}, 1:numel(mesh{idx_height}), start(idx_height), 'nearest' ); +i1_start(idx_height) = mesh{idx_height}(idx-1) - diff(mesh{idx_height}(idx-2:idx-1))/2; +i1_stop(idx_height) = mesh{idx_height}(idx+1) + diff(mesh{idx_height}(idx+1:idx+2))/2; +i1_start(idx_prop) = sum(meshlines(1:2))/2; +i1_stop(idx_prop) = i1_start(idx_prop); +idx = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), nstop(idx_width), 'nearest' ); +i1_stop(idx_width) = mesh{idx_width}(idx) + diff(mesh{idx_width}(idx:idx+1))/2; +i2_start = i1_start; +i2_stop = i1_stop; +i2_start(idx_prop) = sum(meshlines(2:3))/2; +i2_stop(idx_prop) = i2_start(idx_prop); + +% create the curr-probes +weight = direction; +port.I_filename{1} = [PortNamePrefix 'port_it' num2str(portnr) 'A']; +CSX = AddProbe( CSX, port.I_filename{1}, 1, 'weight', weight ); +CSX = AddBox( CSX, port.I_filename{1}, prio, i1_start, i1_stop ); +port.I_filename{2} = [PortNamePrefix 'port_it' num2str(portnr) 'B']; +CSX = AddProbe( CSX, port.I_filename{2}, 1,'weight', weight ); +CSX = AddBox( CSX, port.I_filename{2}, prio, i2_start, i2_stop ); + +% create port structure +port.LengthScale = 1; +if ((CSX.ATTRIBUTE.CoordSystem==1) && (idx_prop==2)) + port.LengthScale = SL_stop(idx_height); +end +port.nr = portnr; +port.type = 'StripLine'; +port.drawingunit = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit; +port.v_delta = diff(meshlines)*port.LengthScale; +port.i_delta = diff( meshlines(1:end-1) + diff(meshlines)/2 )*port.LengthScale; +port.direction = direction; +port.excite = 0; +port.measplanepos = abs(v2_start(idx_prop) - start(idx_prop))*port.LengthScale; +% port + +% create excitation (if enabled) and port resistance +meshline = interp1( mesh{idx_prop}, 1:numel(mesh{idx_prop}), start(idx_prop) + feed_shift*direction, 'nearest' ); +ex_start(idx_prop) = mesh{idx_prop}(meshline) ; +ex_start(idx_width) = nstart(idx_width); +ex_start(idx_height) = nstart(idx_height); +ex_stop(idx_prop) = ex_start(idx_prop); +ex_stop(idx_width) = nstop(idx_width); +ex_stop(idx_height) = nstop(idx_height); + +port.excite = 0; +if excite + port.excite = 1; + CSX = AddExcitation( CSX, [PortNamePrefix 'port_excite_1_' num2str(portnr)], 0, evec, excite_args{:} ); + CSX = AddBox( CSX, [PortNamePrefix 'port_excite_1_' num2str(portnr)], prio, ex_start, ex_stop+height_vector ); + CSX = AddExcitation( CSX, [PortNamePrefix 'port_excite_2_' num2str(portnr)], 0, -evec, excite_args{:} ); + CSX = AddBox( CSX, [PortNamePrefix 'port_excite_2_' num2str(portnr)], prio, ex_start, ex_stop-height_vector ); +end + +%% MSL resitance at start of MSL line +ex_start(idx_prop) = start(idx_prop); +ex_stop(idx_prop) = ex_start(idx_prop); + +if (feed_R > 0) && ~isinf(feed_R) + CSX = AddLumpedElement( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], idx_height-1, 'R', 2*feed_R ); + CSX = AddBox( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], prio, ex_start, ex_stop+height_vector ); + CSX = AddBox( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], prio, ex_start, ex_stop-height_vector ); +elseif isinf(feed_R) + % do nothing --> open port +elseif feed_R == 0 + %port "resistance" as metal + CSX = AddBox( CSX, materialname, prio, ex_start, ex_stop+height_vector ); + CSX = AddBox( CSX, materialname, prio, ex_start, ex_stop-height_vector ); +else + error('openEMS:AddMSLPort','MSL port with resitance <= 0 it not possible'); +end +end diff --git a/openEMS/matlab/AddWaveGuidePort.m b/openEMS/matlab/AddWaveGuidePort.m new file mode 100644 index 0000000..1a17db2 --- /dev/null +++ b/openEMS/matlab/AddWaveGuidePort.m @@ -0,0 +1,119 @@ +function [CSX,port] = AddWaveGuidePort( CSX, prio, portnr, start, stop, dir, E_WG_func, H_WG_func, kc, exc_amp, varargin ) +% function [CSX,port] = AddWaveGuidePort( CSX, prio, portnr, start, stop, dir, E_WG_func, H_WG_func, kc, exc_amp, varargin ) +% +% Create a waveguide port, including an optional excitation and probes +% +% Note: - The excitation will be located at the start position in the given direction +% - The voltage and current probes at the stop position in the given direction +% +% parameter: +% CSX: complete CSX structure (must contain a mesh) +% prio: priority of primitives +% start: start coordinates of waveguide port box +% stop: stop coordinates of waveguide port box +% dir: direction of port (0/1/2 or 'x'/'y'/'z'-direction) +% E_WG_func: electric field mode profile function as a string +% H_WG_func: magnetic field mode profile function as a string +% kc: cutoff wavenumber (defined by the waveguide dimensions) +% exc_amp: excitation amplitude (set 0 to be passive) +% +% optional (key/values): +% varargin: optional additional excitations options, see also AddExcitation +% 'PortNamePrefix': a prefix to the port name +% +% output: +% CSX: modified CSX structure +% port: port structure to use with calcPort +% +% example: +% % create a TE11 circular waveguide mode, using cylindircal coordinates +% p11 = 1.841; +% kc = p11 / radius; % cutoff wavenumber with radius in meter +% kc_draw = kc*unit; % cutoff wavenumber in drawing units +% +% % electric field mode profile +% func_E{1} = [ num2str(-1/kc_draw^2,15) '/rho*cos(a)*j1(' num2str(kc_draw,15) '*rho)']; +% func_E{2} = [ num2str(1/kc_draw,15) '*sin(a)*0.5*(j0(' num2str(kc_draw,15) '*rho)-jn(2,' num2str(kc_draw,15) '*rho))']; +% func_E{3} = 0; +% +% % magnetic field mode profile +% func_H{1} = [ '-1*' num2str(1/kc_draw,15) '*sin(a)*0.5*(j0(' num2str(kc_draw,15) '*rho)-jn(2,' num2str(kc_draw,15) '*rho))']; +% func_H{2} = [ num2str(-1/kc_draw^2,15) '/rho*cos(a)*j1(' num2str(kc_draw,15) '*rho)']; +% func_H{3} = 0; +% +% start=[mesh.r(1) mesh.a(1) 0 ]; +% stop =[mesh.r(end) mesh.a(end) 100]; +% [CSX, port{1}] = AddWaveGuidePort(CSX, 0, 1, start, stop, 2, func_E, func_H, kc, 1); +% +% openEMS matlab interface +% ----------------------- +% (c) 2013 Thorsten Liebig (thorsten.liebig@gmx.de) +% +% See also InitCSX, AddExcitation, calcWGPort, calcPort + +%check mesh +if ~isfield(CSX,'RectilinearGrid') + error 'mesh needs to be defined! Use DefineRectGrid() first!'; +end + +dir = DirChar2Int(dir); + +port.type='WaveGuide'; +port.nr=portnr; +port.kc = kc; +port.dir = dir; +port.drawingunit = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit; + +PortNamePrefix = ''; + +varargin_tmp = varargin; +for n=1:2:numel(varargin_tmp) + if strcmpi('PortNamePrefix',varargin_tmp{n}) + PortNamePrefix = varargin_tmp{n+1}; + varargin([n n+1]) = []; + end +end + +% matlab adressing +dir = dir + 1; +dir_sign = sign(stop(dir) - start(dir)); +if (dir_sign==0) + dir_sign = 1; +end + +port.direction = dir_sign; + +E_WG_func{dir} = 0; +H_WG_func{dir} = 0; + +port.excite = 0; +if (exc_amp~=0) + if (start(dir)==stop(dir)) + error 'if waveguide port is to be excited, the length in propagation direction must not be zero' + end + e_start = start; + e_stop = stop; + e_stop(dir) = e_start(dir); + port.excite = 1; + port.excitepos = e_start(dir); + e_vec = [1 1 1]*exc_amp; + e_vec(dir) = 0; + exc_name = [PortNamePrefix 'port_excite_' num2str(portnr)]; + CSX = AddExcitation( CSX, exc_name, 0, e_vec, varargin{:}); + CSX = SetExcitationWeight(CSX, exc_name, E_WG_func ); + CSX = AddBox( CSX, exc_name, prio, e_start, e_stop); +end + +% voltage/current planes +m_start = start; +m_stop = stop; +m_start(dir) = stop(dir); + +port.measplanepos = m_start(dir); +port.U_filename = [PortNamePrefix 'port_ut' int2str(portnr)]; +CSX = AddProbe(CSX, port.U_filename, 10, 'ModeFunction', E_WG_func); +CSX = AddBox(CSX, port.U_filename, 0 ,m_start, m_stop); + +port.I_filename = [PortNamePrefix 'port_it' int2str(portnr)]; +CSX = AddProbe(CSX, port.I_filename, 11, 'ModeFunction', H_WG_func, 'weight', dir_sign); +CSX = AddBox(CSX, port.I_filename, 0 ,m_start, m_stop); diff --git a/openEMS/matlab/AnalyzeNF2FF.m b/openEMS/matlab/AnalyzeNF2FF.m new file mode 100644 index 0000000..bc88b72 --- /dev/null +++ b/openEMS/matlab/AnalyzeNF2FF.m @@ -0,0 +1,231 @@ +function [E_theta,E_phi,Prad,Dmax] = AnalyzeNF2FF( Sim_Path, nf2ff, f, theta, phi, r ) +% [E_theta,E_phi,Prad,Dmax] = AnalyzeNF2FF( Sim_Path, filenames_E, filenames_H, f, theta, phi, r ) +% +% calculates the farfield via a near field to far field transformation +% +% input: +% Sim_Path: simulation directory +% nf2ff: structure on filenames etc. as created by CreateNF2FFBox +% f: frequency (Hz) for far field calculation +% theta: (degrees) vector of discrete theta values to calculate the far field for +% phi: (degrees) vector of discrete phi values to calculate the far field for +% r: (optional) Radius (m) at which the E-fields are calculated (default: 1 m) +% +% output: +% E_theta: E_theta(theta,phi); theta component of the electric field strength at radius r +% E_phi: E_phi(theta,phi); phi component of the electric field strength at radius r +% Prad: time averaged radiated power +% Dmax: maximum directivity +% +% example: +% see examples/NF2FF/infDipol.m +% +% See also CreateNF2FFBox +% +% (C) 2010 Sebastian Held +% (C) 2011 Thorsten Liebig + +% check arguments +error( nargchk(6,6,nargin) ); +if ~isscalar(f) + error 'Currently only one frequency is supported. Call this function multiple times.' +end + +warning('openEMS:AnalyzeNF2FF','This function is deprecated, use CalcNF2FF instead'); + +filenames_E = nf2ff.filenames_E; +filenames_H = nf2ff.filenames_H; + +if (~isrow(nf2ff.directions)) + nf2ff.directions = nf2ff.directions'; +end + +% read time domain field data and transform into frequency domain +for n=find(nf2ff.directions==1) + [Ef{n}, E_mesh{n}] = ReadHDF5Dump( [Sim_Path '/' filenames_E{n} '.h5'], 'Frequency', f ); + + if (Ef{n}.FD.frequency(1) ~= f) + error 'frequency mismach' + end + + %clear out time domain data + if isfield(Ef{n},'TD') + Ef{n} = rmfield(Ef{n},'TD'); + end + + [Hf{n}, H_mesh{n}] = ReadHDF5Dump( [Sim_Path '/' filenames_H{n} '.h5'], 'Frequency', f ); + %clear out time domain data + if isfield(Hf{n},'TD') + Hf{n} = rmfield(Hf{n},'TD'); + end + + % reshape mesh into row vector + mesh{n}.x = reshape( E_mesh{n}.lines{1}, 1, [] ); + mesh{n}.y = reshape( E_mesh{n}.lines{2}, 1, [] ); + mesh{n}.z = reshape( E_mesh{n}.lines{3}, 1, [] ); +end + +% create a normal vector for every plane +% FIXME!!! this is dependent upon the order of filenames_* +n = {}; +for a=1:6 + temp = [(a<=2), ((a>=3)&&(a<=4)), (a>=5)]; + n{a} = temp - 2*mod(a,2)*temp; +end + + +physical_constants + +k = 2*pi*f/c0; +center = [0 0 0]; +Umax = 0; + +phi_idx = 0; +for phi_deg_aufpunkt = phi + phi_rad_aufpunkt = phi_deg_aufpunkt/180*pi; % radiant + phi_idx = phi_idx + 1; + + theta_idx = 0; + for theta_deg_aufpunkt = theta + theta_rad_aufpunkt = theta_deg_aufpunkt/180*pi; % radiant + theta_idx = theta_idx + 1; + + N_theta = 0; + N_phi = 0; + L_theta = 0; + L_phi = 0; + for a=find(nf2ff.directions==1) + [N_theta_,N_phi_,L_theta_,L_phi_] = process_plane( k, n{a}, center, mesh{a}, Ef{a}.FD.values{1}, Hf{a}.FD.values{1}, theta_rad_aufpunkt, phi_rad_aufpunkt ); + N_theta = N_theta + N_theta_; N_phi = N_phi + N_phi_; + L_theta = L_theta + L_theta_; L_phi = L_phi + L_phi_; + end + + % E-fields + erg_E_theta = -1i*k*exp(-1i*k*r) / (4*pi*r)*(L_phi+Z0*N_theta); + erg_E_phi = 1i*k*exp(-1i*k*r) / (4*pi*r)*(L_theta-Z0*N_phi); + + % output + E_theta(theta_idx,phi_idx) = erg_E_theta; + E_phi(theta_idx,phi_idx) = erg_E_phi; + + % directivity + U = r^2/(2*Z0) * sum(abs([erg_E_theta erg_E_phi]).^2); + Umax = max( [Umax U] ); + end +end + +% power +Prad = 0; +for a=find(nf2ff.directions==1) + [~,~,~,~,P] = process_plane( k, n{a}, center, mesh{a}, Ef{a}.FD.values{1}, Hf{a}.FD.values{1}, theta_rad_aufpunkt, phi_rad_aufpunkt ); + Prad = Prad + P; +end + +% directivity +Dmax = 4*pi*Umax / Prad; + + +% integrate over one plane +function [N_theta,N_phi,L_theta,L_phi,Prad] = process_plane( k, n, center, mesh, E_field, H_field, theta_rad_aufpunkt, phi_rad_aufpunkt ) +% [N_theta,N_phi,L_theta,L_phi,Prad] = process_plane( k, n, center, mesh, E_field, H_field, theta_rad_aufpunkt, phi_rad_aufpunkt ) +% +% k: wave number +% n: normal vector of the plane +% center: correction coordinates for the center of the antenna +% mesh: mesh info +% E_field: E field array ?x?x?x3 +% H_field: H field array ?x?x?x3 + +% speed up +sin__theta_rad_aufpunkt = sin(theta_rad_aufpunkt); +cos__theta_rad_aufpunkt = cos(theta_rad_aufpunkt); +sin__phi_rad_aufpunkt = sin(phi_rad_aufpunkt); +cos__phi_rad_aufpunkt = cos(phi_rad_aufpunkt); + +if abs(n(1)) == 1 + % x-plane + x = mesh.x(1); + [y z] = ndgrid( mesh.y, mesh.z ); + coord1 = mesh.y.'; + coord2 = mesh.z.'; + Ex = squeeze( E_field(1,:,:,1) ); + Ey = squeeze( E_field(1,:,:,2) ); + Ez = squeeze( E_field(1,:,:,3) ); + Hx = squeeze( H_field(1,:,:,1) ); + Hy = squeeze( H_field(1,:,:,2) ); + Hz = squeeze( H_field(1,:,:,3) ); +elseif abs(n(2)) == 1 + % y-plane + y = mesh.y(1); + [x z] = ndgrid( mesh.x, mesh.z ); + coord1 = mesh.x.'; + coord2 = mesh.z.'; + Ex = squeeze( E_field(:,1,:,1) ); + Ey = squeeze( E_field(:,1,:,2) ); + Ez = squeeze( E_field(:,1,:,3) ); + Hx = squeeze( H_field(:,1,:,1) ); + Hy = squeeze( H_field(:,1,:,2) ); + Hz = squeeze( H_field(:,1,:,3) ); +elseif abs(n(3)) == 1 + % z-plane + z = mesh.z(1); + [x y] = ndgrid( mesh.x, mesh.y ); + coord1 = mesh.x.'; + coord2 = mesh.y.'; + Ex = squeeze( E_field(:,:,1,1) ); + Ey = squeeze( E_field(:,:,1,2) ); + Ez = squeeze( E_field(:,:,1,3) ); + Hx = squeeze( H_field(:,:,1,1) ); + Hy = squeeze( H_field(:,:,1,2) ); + Hz = squeeze( H_field(:,:,1,3) ); +end + +Jx = n(2) .* Hz - n(3) .* Hy; +Jy = n(3) .* Hx - n(1) .* Hz; +Jz = n(1) .* Hy - n(2) .* Hx; +Mx = -n(2) .* Ez + n(3) .* Ey; +My = -n(3) .* Ex + n(1) .* Ez; +Mz = -n(1) .* Ey + n(2) .* Ex; +r_cos_psi = x*sin__theta_rad_aufpunkt*cos__phi_rad_aufpunkt + y*sin__theta_rad_aufpunkt*sin__phi_rad_aufpunkt + z*cos__theta_rad_aufpunkt; +e_fkt = exp( +1i*k*r_cos_psi ); +N_theta = dbltrapz( ( Jx*cos__theta_rad_aufpunkt*cos__phi_rad_aufpunkt + Jy*cos__theta_rad_aufpunkt*sin__phi_rad_aufpunkt - Jz*sin__theta_rad_aufpunkt) .* e_fkt, coord1, coord2 ); +N_phi = dbltrapz( (-Jx*sin__phi_rad_aufpunkt + Jy*cos__phi_rad_aufpunkt) .* e_fkt, coord1, coord2 ); +L_theta = dbltrapz( ( Mx*cos__theta_rad_aufpunkt*cos__phi_rad_aufpunkt + My*cos__theta_rad_aufpunkt*sin__phi_rad_aufpunkt - Mz*sin__theta_rad_aufpunkt) .* e_fkt, coord1, coord2 ); +L_phi = dbltrapz( (-Mx*sin__phi_rad_aufpunkt + My*cos__phi_rad_aufpunkt) .* e_fkt, coord1, coord2 ); + +if nargout > 4 + % Prad requested + + % this is crap! recode it! + EH = zeros(size(Ex)); + for i1 = 1:numel(coord1) + for i2 = 1:numel(coord2) + E = [Ex(i1,i2) Ey(i1,i2) Ez(i1,i2)]; + H = [Hx(i1,i2) Hy(i1,i2) Hz(i1,i2)]; + EH(i1,i2) = real( dot(cross(E,conj(H)),n) ); + end + end + Prad = 0.5 * dbltrapz( EH, coord1, coord2 ); +end + + + + +function Q = dbltrapz(matrix,a,b) +%DBLTRAPZ Trapezoidal numerical integration in two dimensions. +% Z = DBLTRAPZ(MATRIX,A,B) computes an approximation of the double integral +% of MATRIX via the trapezoidal method (with respect to A and B). A and B must be +% column vectors of the same length. +% index like this: MATRIX(A,B) + +if nargin < 3, error('MATLAB:dblquad:NotEnoughInputs',... + 'Requires at least three inputs.'); end +if size(a,2) ~= 1, error('column vectors required'); end +if size(b,2) ~= 1, error('column vectors required'); end + +temp = zeros(size(b)); +for i = 1:length(b) + temp(i) = trapz( a, matrix(:,i) ); +end + +Q = trapz( b, temp ); diff --git a/openEMS/matlab/CalcNF2FF.m b/openEMS/matlab/CalcNF2FF.m new file mode 100644 index 0000000..c80b52e --- /dev/null +++ b/openEMS/matlab/CalcNF2FF.m @@ -0,0 +1,161 @@ +function nf2ff = CalcNF2FF(nf2ff, Sim_Path, freq, theta, phi, varargin) +% function nf2ff = CalcNF2FF(nf2ff, Sim_Path, freq, theta, phi, varargin) +% +% Calculate the near-field to far-field transformation created by +% CreateNF2FFBox +% +% IMPORTANT: +% Make sure to define the correct nf2ff phase center, aka. central antenna +% position! See optional parameter below!! Default is [0 0 0] +% +% parameter: +% nf2ff: data structure created by CreateNF2FFBox +% Sim_Path: path to simulation data +% freq: array of frequencies to analyse +% theta,phi: spherical coordinates to evaluate the far-field on (in radians) +% +% optional paramater: +% 'Center': nf2ff phase center, default is [0 0 0] +% !! Make sure the center is never outside of your nf2ff box!! +% Definition is the correct coordinate system necessary +% --> either Cartesian or cylindrical coordinates +% 'Mode': 'Mode', 0 -> read only, if data already exist (default) +% 'Mode', 1 -> calculate anyway, overwrite existing +% 'Mode', 2 -> read only, fail if not existing +% 'Outfile': alternative nf2ff result hdf5 file name +% default is: .h5 +% 'Verbose': set verbose level for the nf2ff calculation 0-2 supported +% 'Radius': specify the radius for the nf2ff +% 'Eps_r': specify the relative electric permittivity for the nf2ff +% 'Mue_r': specify the relative magnetic permeability for the nf2ff +% +% 'Mirror': Add mirroring in a given direction (dir), with a given +% mirror type (PEC or PMC) and a mirror position in the given +% direction. +% Example: 'Mirror', {0, 'PMC', +100} +% +% See also: CreateNF2FFBox, ReadNF2FF +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig, 2012 + +mode = 0; + +filename = nf2ff.name; +nf2ff_xml.Planes = {}; + +nf2ff_xml.ATTRIBUTE.Outfile = [filename '.h5']; + +if (isfield(nf2ff,'Eps_r')) + nf2ff_xml.ATTRIBUTE.Eps_r = nf2ff.Eps_r; +end +if (isfield(nf2ff,'Mue_r')) + nf2ff_xml.ATTRIBUTE.Mue_r = nf2ff.Mue_r; +end + +for n=1:2:numel(varargin)-1 + if (strcmp(varargin{n},'Mode')) + mode = varargin{n+1}; + elseif (strcmp(varargin{n},'Mirror')) + if isfield(nf2ff_xml,'Mirror') + pos = length(nf2ff_xml.Mirror)+1; + else + pos = 1; + end + nf2ff_xml.Mirror{pos}.ATTRIBUTE.Dir=varargin{n+1}{1}; + nf2ff_xml.Mirror{pos}.ATTRIBUTE.Type=varargin{n+1}{2}; + nf2ff_xml.Mirror{pos}.ATTRIBUTE.Pos=varargin{n+1}{3}; + else + nf2ff_xml.ATTRIBUTE.(varargin{n})=varargin{n+1}; + end +end + +for (n=1:numel(nf2ff.filenames_E)) + if (nf2ff.directions(n)~=0) + files_E = dir([Sim_Path '/*' nf2ff.filenames_E{n} '.h5']); + files_H = dir([Sim_Path '/*' nf2ff.filenames_H{n} '.h5']); + if (numel(files_E)~=numel(files_H)) + error 'number of E/H planes mismatch!' + end + for fn = 1:numel(files_E) + nf2ff_xml.Planes{end+1}.ATTRIBUTE.E_Field = files_E(fn).name; + nf2ff_xml.Planes{end}.ATTRIBUTE.H_Field = files_H(fn).name; + end + end +end + +nf2ff_xml.ATTRIBUTE.freq = freq; +nf2ff_xml.theta = theta; +nf2ff_xml.phi = phi; + +nf2ff.xml = [Sim_Path '' filesep '' filename '.xml']; +nf2ff.hdf5 = [Sim_Path '' filesep '' nf2ff_xml.ATTRIBUTE.Outfile]; + +% create nf2ff structure +struct_2_xml(nf2ff.xml,nf2ff_xml,'nf2ff'); + +m_filename = mfilename('fullpath'); +dir_name = fileparts( m_filename ); + +if isunix + nf2ff_bin = searchBinary('nf2ff', ... + {[dir_name filesep '..' filesep 'nf2ff' filesep], ... + [dir_name filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}, 0); +else + nf2ff_bin = searchBinary('nf2ff.exe',[dir_name filesep '..' filesep], 0); +end + +if ((exist(nf2ff.hdf5,'file') && (mode==0)) || (mode==2)) + disp('CalcNF2FF: Reading nf2ff data only...') + nf2ff = ReadNF2FF(nf2ff); + + % verify read data + if ( (vectorEqual(nf2ff.freq,freq)==0) || (vectorEqual(nf2ff.theta,theta)==0) || (vectorEqual(nf2ff.phi,phi)==0) ) + error('openEMS:CalcNF2FF','data mismatch between read and requested data --> recalculate nf2ff --> Set Mode to 1 '); + end + return; +end + +savePath = pwd; +cd(Sim_Path); + +try + if (isempty(nf2ff_bin)) + error('openEMS:CalcNF2FF','nf2ff binary not found!'); + end + if isunix + % remove LD_LIBRARY_PATH set by matlab + system(['export LD_LIBRARY_PATH=; ' nf2ff_bin ' ' filename '.xml']); + else + system([nf2ff_bin ' ' filename '.xml']); + end + nf2ff.hdf5; + cd(savePath); +catch + cd(savePath); + error 'CalcNF2FF: failed' +end + +nf2ff = ReadNF2FF(nf2ff); + +% verify read data +if ( (vectorEqual(nf2ff.freq,freq)==0) || (vectorEqual(nf2ff.theta,theta)==0) || (vectorEqual(nf2ff.phi,phi)==0) ) + error('openEMS:CalcNF2FF','data mismatch between read and requested data --> THIS SHOULD NOT HAPPEN!'); +end + +function equal = vectorEqual(v1, v2, acc) +if (nargin<3) + acc = 1e-6; +end + +equal = 0; +if numel(v1)~=numel(v2) + return; +end + +if sum(abs((v1(:)-v2(:))/v1(:)) > acc)>0 + return; +end +equal = 1; +return diff --git a/openEMS/matlab/CheckQueue.m b/openEMS/matlab/CheckQueue.m new file mode 100644 index 0000000..748d706 --- /dev/null +++ b/openEMS/matlab/CheckQueue.m @@ -0,0 +1,60 @@ +function [queue running] = CheckQueue(queue, query_time) +% function [queue running] = CheckQueue(queue, ) +% +% Check the given queue for finished tasks. +% +% Parameter: +% query_time (optional): time interval to check for finished tasks +% (in seconds, default is 5) +% +% For more details see: InitQueue +% +% See also: InitQueue, ResultsQueue, Add2Queue, RunOpenEMS +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +if ~isfield(queue,'jobs') + running = 0; + return +end + +if (nargin<2) + query_time = 5; +end + +numJobs = numel(queue.jobs); + +pause(query_time); + +for n=1:numJobs + if (queue.jobs_finished(n)==0) + if (queue_checkProcess( queue.jobs{n}.pid, queue.jobs{n}.filenames)==0) + queue.jobs_finished(n)=1; + load(queue.jobs{n}.outargsfile); + if ~isempty(err) + disp(['Job with number ' num2str(n) ' failed to execute: Error message:']); + error(['CheckQueue:' err.message]); + end + queue.jobs{n}.outargs = outargs; + + % read in output and cleanup + [queue.jobs{n}.stdout,queue.jobs{n}.stderr] = queue_delProcess( queue.jobs{n}.pid, queue.jobs{n}.filenames ); + + % cleanup + delete( queue.jobs{n}.argsfile ); + clear queue.jobs{n}.argsfile; + delete( queue.jobs{n}.outargsfile ); + clear queue.jobs{n}.outargsfile; + + queue.jobs_finished(n) = 1; + + if (queue.verbose>=1) + disp(['CheckQueue: Job #' num2str(n) ' is finished!']); + end + end + end +end + +running = numel(queue.jobs_finished) - sum(queue.jobs_finished); diff --git a/openEMS/matlab/ConvertHDF5_VTK.m b/openEMS/matlab/ConvertHDF5_VTK.m new file mode 100644 index 0000000..545ba01 --- /dev/null +++ b/openEMS/matlab/ConvertHDF5_VTK.m @@ -0,0 +1,100 @@ +function ConvertHDF5_VTK(hdf_file, vtk_prefix, varargin) +% ConvertHDF5_VTK(hdf_file, vtk_prefix, varargin) +% +% Convert openEMS field data stored in the given hdf5 file to a vtk file. +% +% arguments: +% hdf_file: source hdf5 file +% vtk_prefix: output vtk files prefix +% +% optional arguments: +% 'TD_Dump': activate dump for time-domain data (default is off) +% 'FD_Dump': activate dump for frequency-domain data (default is on) +% 'NumPhase': number of phase to dump frequency domain data animation +% (default is 36 --> 10°) +% 'FieldName': field name written to vtk, e.g. 'E-Field' +% 'weight': field weighting +% +% for more optional aguments have a look at ReadHDF5Dump +% +% example: +% % read time-domian data from hdf5, perform dft and dump as vtk +% ConvertHDF5_VTK('Et.h5','Ef','NumPhase',18,'Frequency',1e9) +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also ReadHDF5Dump Dump2VTK + +do_FD_dump = 1; +do_TD_dump = 0; +phase_N = 36; +weight = 1; + +fieldname = 'unknown'; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'TD_Dump')==1); + do_TD_dump = varargin{n+1}; + elseif (strcmp(varargin{n},'FD_Dump')==1); + do_FD_dump = varargin{n+1}; + elseif (strcmp(varargin{n},'NumPhase')==1); + phase_N = varargin{n+1}; + elseif (strcmp(varargin{n},'FieldName')==1); + fieldname = varargin{n+1}; + elseif (strcmp(varargin{n},'weight')==1); + weight = varargin{n+1}; + end +end + +[field mesh] = ReadHDF5Dump(hdf_file, varargin{:}); + +if ((do_TD_dump==0) && (do_FD_dump==0)) + warning('openEMS:ConvertHDF5_VTK','FD and TD dump disabled, nothing to be done...'); +end + +if (do_FD_dump) + if (~isfield(field,'FD')) + warning('openEMS:ConvertHDF5_VTK','no FD data found skipping frequency domian vtk dump...'); + else + %set weighting + if (numel(weight)~=numel(field.FD.frequency)) + FD_weight = ones(size(field.FD.frequency))*weight(1); + else + FD_weight = weight; + end + if (field.FD.DataType==1) % dump complex value FD data + ph = linspace(0,360,phase_N+1); + ph = ph(1:end-1); + for n = 1:numel(field.FD.frequency) + for p = ph + filename = [vtk_prefix '_' num2str(field.FD.frequency(n)) '_' num2str(p,'%03d') '.vtk' ]; + Dump2VTK(filename, real(FD_weight(n)*field.FD.values{n}*exp(1j*p*pi/180)), mesh, fieldname, varargin{:}); + end + filename = [vtk_prefix '_' num2str(field.FD.frequency(n)) '_abs.vtk' ]; + Dump2VTK(filename, abs(FD_weight(n)*field.FD.values{n}), mesh, fieldname, varargin{:}); + filename = [vtk_prefix '_' num2str(field.FD.frequency(n)) '_ang.vtk' ]; + Dump2VTK(filename, angle(FD_weight(n)*field.FD.values{n}), mesh, fieldname, varargin{:}); + end + else % dump real value FD data + for n = 1:numel(field.FD.frequency) + filename = [vtk_prefix '_' num2str(field.FD.frequency(n)) '.vtk' ]; + Dump2VTK(filename, real(FD_weight(n)*field.FD.values{n}), mesh, fieldname, varargin{:}); + end + end + end +end + +if (do_TD_dump) + if (~isfield(field,'TD')) + warning('openEMS:ConvertHDF5_VTK','no TD data found skipping time domian vtk dump...'); + else + disp('dumping time domain data...') + acc = ['%0' int2str(ceil(log10(numel(field.TD.time)+1))) 'd']; + for n = 1:numel(field.TD.time) + filename = [vtk_prefix '_TD_' num2str(n,acc) '.vtk' ]; + Dump2VTK(filename, abs(weight(1))*field.TD.values{n}, mesh, fieldname, varargin{:}); + end + end +end diff --git a/openEMS/matlab/CreateNF2FFBox.m b/openEMS/matlab/CreateNF2FFBox.m new file mode 100644 index 0000000..a97f0d2 --- /dev/null +++ b/openEMS/matlab/CreateNF2FFBox.m @@ -0,0 +1,94 @@ +function [CSX nf2ff] = CreateNF2FFBox(CSX, name, start, stop, varargin) +% function [CSX nf2ff] = CreateNF2FFBox(CSX, name, start, stop, varargin) +% +% create the dump boxes needed for the near field to far field transformation +% +% input: +% name: name of this nf2ff box +% start/stop: start/stop coordinates for the nf2ff box (this box has to +% enclose all radiating structures!) +% optional inputs: +% 'Directions': enable/disable specific directions, e.g. +% 'Directions',[1 1 0 0 1 1] +% -> disable nf2ff in +/-y direction +% 'Frequency': dump nf2ff in frequency domain, this will save disk-space +% but is less flexible, since only this frequencies can be +% used for the nf2ff calculations by CalcNF2FF +% See also AddDump for more information +% 'OptResolution': specify a dump resolution, this will save disk-space +% See also AddDump for more information +% e.g.: 'OptResolution', c0/max_freq/unit/15 +% +% example: +% see Tutorials/Simple_Patch_Antenna.m +% see Tutorials/Helical_Antenna.m +% +% See also CalcNF2FF +% +% (C) 2010 Sebastian Held +% (C) 2010-2012 Thorsten Liebig + +if (nargin<5) + directions = ones(6,1); +end + +directions = ones(6,1); +add_args = {}; +dump_type = 0; +dump_mode = 1; + +for n=1:numel(varargin)/2 + if strcmp(varargin{2*n-1},'Frequency') + add_args = {add_args{:}, 'Frequency', varargin{2*n}}; + dump_type = 10; + elseif strcmp(varargin{2*n-1},'Directions') + directions=varargin{2*n}; + else + add_args = {add_args{:}, varargin{2*n-1}, varargin{2*n}}; + end +end + +nf2ff.name = name; +nf2ff.filenames_E = {[name '_E_xn'],[name '_E_xp'],[name '_E_yn'],[name '_E_yp'],[name '_E_zn'],[name '_E_zp']}; +nf2ff.filenames_H = {[name '_H_xn'],[name '_H_xp'],[name '_H_yn'],[name '_H_yp'],[name '_H_zn'],[name '_H_zp']}; +nf2ff.directions = directions; + +if (isfield(CSX,'ATTRIBUTE')) + if (isfield(CSX.ATTRIBUTE,'CoordSystem')) + nf2ff.CoordSystem = CSX.ATTRIBUTE.CoordSystem; + end + if (isfield(CSX,'BackgroundMaterial')) + if (isfield(CSX.ATTRIBUTE,'Epsilon')) + nf2ff.Eps_r = CSX.ATTRIBUTE.BG_epsR; + end + if (isfield(CSX.ATTRIBUTE,'Mue')) + nf2ff.Mue_r = CSX.ATTRIBUTE.BG_mueR; + end + end +end + +for nd = 1:3 + pos = 2*nd-1; + if (directions(pos)) + l_start = start; + l_stop = stop; + l_stop(nd) = start(nd); + CSX = AddBox( AddDump(CSX,nf2ff.filenames_E{pos},'DumpType',dump_type,'DumpMode',dump_mode,'FileType',1,add_args{:}), nf2ff.filenames_E{pos}, 0, l_start, l_stop ); + CSX = AddBox( AddDump(CSX,nf2ff.filenames_H{pos},'DumpType',dump_type+1,'DumpMode',dump_mode,'FileType',1,add_args{:}), nf2ff.filenames_H{pos}, 0, l_start, l_stop ); + else + nf2ff.filenames_E{pos}=''; + nf2ff.filenames_H{pos}=''; + end + pos = 2*nd; + if (directions(pos)) + l_start = start; + l_stop = stop; + l_start(nd) = stop(nd); + CSX = AddBox( AddDump(CSX,nf2ff.filenames_E{pos},'DumpType',dump_type,'DumpMode',dump_mode,'FileType',1,add_args{:}), nf2ff.filenames_E{pos}, 0, l_start, l_stop ); + CSX = AddBox( AddDump(CSX,nf2ff.filenames_H{pos},'DumpType',dump_type+1,'DumpMode',dump_mode,'FileType',1,add_args{:}), nf2ff.filenames_H{pos}, 0, l_start, l_stop ); + else + nf2ff.filenames_E{pos}=''; + nf2ff.filenames_H{pos}=''; + end +end + diff --git a/openEMS/matlab/DFT_time2freq.m b/openEMS/matlab/DFT_time2freq.m new file mode 100644 index 0000000..ac84035 --- /dev/null +++ b/openEMS/matlab/DFT_time2freq.m @@ -0,0 +1,47 @@ +function f_val = DFT_time2freq( t, val, freq, signal_type ) +% f_val = DFT_time2freq( t, val, freq, signal_type ) +% +% computes the DFT at the given frequencies +% +% parameter: +% t : time vector +% val: data vector +% freq: DFT frequency vector +% signal_type: 'pulse' (default), 'periodic' +% +% return values: +% f_val: single-sided spectrum +% +% example: +% t=linspace(0,1,100); +% t_val=0.9*sin(2*pi*3*t); % sine wave; amplitude 0.9; frequency 3 Hz +% f=linspace(1,5,101); +% f_val=DFT_time2freq( t, t_val, f, 'periodic' ); +% interp1(f,abs(f_val),3) +% ans = 0.8910 +% plot( t, t_val ) +% plot( f, abs(f_val) ) + +if numel(t) ~= numel(val) + error 'numel(t) ~= numel(val)' +end + +if nargin<4 + signal_type = 'pulse'; +end + +f_val = zeros(1,numel(freq)); +for f_idx=1:numel(freq) + f_val(f_idx) = sum( val .* exp( -1i * 2*pi*freq(f_idx) * t ) ); +end + +if strcmpi(signal_type, 'pulse') + dt = t(2)-t(1); + f_val = f_val * dt; +elseif strcmpi(signal_type, 'periodic') + f_val = f_val / length(t); +else + error 'unknown signal type' +end + +f_val = f_val * 2; % single-sided spectrum diff --git a/openEMS/matlab/DelayFidelity.m b/openEMS/matlab/DelayFidelity.m new file mode 100644 index 0000000..3cc0ae2 --- /dev/null +++ b/openEMS/matlab/DelayFidelity.m @@ -0,0 +1,93 @@ +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) +% +% +% This function calculates the time delay from the source port to the phase center of the antenna and the fidelity. +% The fidelity is the similarity between the excitation pulse and the radiated pulse (normalized scalar product). +% The resolution of the delay will be equal to or better than ((f_0 + f_c)*Oversampling)^-1 when using Gaussian excitation. +% Oversampling is an input parameter to InitFDTD. The rows of delay and fidelity correspond to theta and the columns to phi. +% +% input: +% 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 +% -> with both (possibly complex) parameters any polarization can be examined +% theta: theta values to be simulated +% phi: phi values to be simulated +% f_0: center frequency of SetGaussExcite +% f_c: cutoff frequency of SetGaussExcite +% +% variable input: +% 'Center': phase center of the antenna for CalcNF2FF +% 'Radius': radius for CalcNF2FF +% 'Mode': mode CalcNF2FF +% +% 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); +% figure +% polar(theta.', delay(:,1) * 3e11); % delay in mm +% figure +% polar(theta', (fidelity(:,1)-0.95)/0.05); % last 5 percent of fidelity +% +% Author: Georg Michel + +C0 = 299792458; +center = [0, 0, 0]; +radius = 1; +nf2ff_mode = 0; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'Center')==1); + center = varargin{n+1}; + elseif (strcmp(varargin{n},'Radius')==1); + radius = varargin{n+1}; + elseif (strcmp(varargin{n},'Mode')==1); + nf2ff_mode = varargin{n+1}; + end +end + + +port_ut = load(fullfile(path, port.U_filename)); +port_it = load(fullfile(path, port.I_filename)); +dt = port_ut(2,1) - port_ut(1,1); +fftsize = 2^(nextpow2(size(port_ut)(1)) + 1); +df = 1 / (dt * fftsize); +uport = fft(port_ut(:, 2), fftsize)(1:fftsize/2+1); +iport = fft(port_it(:, 2), fftsize)(1:fftsize/2+1); +fport = df * (0:fftsize/2); +f_ind = find(fport > (f_0 - f_c ) & fport < (f_0 + f_c)); +disp(["frequencies: ", num2str(numel(f_ind))]); +exc_f = uport.' + iport.' * port.Feed_R; %excitation in freq domain +exc_f(!f_ind) = 0; +exc_f /= sqrt(exc_f * exc_f'); % normalization (transposing also conjugates) + +nf2ff = CalcNF2FF(nf2ff, path, fport(f_ind), theta, phi, ... + 'Center', center, 'Radius', radius, 'Mode', nf2ff_mode); +radfield = weight_theta * cell2mat(nf2ff.E_theta) + weight_phi * cell2mat(nf2ff.E_phi); % rows: theta(f1), columns: phi(f1), phi(f2), ...phi(fn) +radfield = reshape(radfield, [length(nf2ff.theta), length(nf2ff.phi), length(nf2ff.freq)]); +correction = reshape(exp(-2i*pi*nf2ff.r/C0*nf2ff.freq), 1,1,numel(nf2ff.freq)); %dimensions: theta, phi, frequencies +radfield = radfield./correction; % correct for radius delay +% normalize radfield +radnorm = sqrt(dot(radfield, radfield, 3)); +radfield ./= radnorm; + +%initialize radiated field in fully populated frequency domain +rad_f = zeros([numel(nf2ff.theta), numel(nf2ff.phi), numel(fport)]); +rad_f(:, :, f_ind) = radfield; % assign selected frequencies +exc_f = reshape(exc_f, [1,1,numel(exc_f)]); %make exc_f confomant with rad_f + +cr_f = rad_f .* conj(exc_f); % calculate cross correlation +% calculate the cross correlation in time domain (analytic signal) +cr = ifft(cr_f(:, :, 1:end-1), [], 3) * (numel(fport) -1); % twice the FFT normalization (sqrt^2) because product of two normalized functions +%search for the maxiumum of the envelope +[fidelity, delay_ind] = max(abs(cr), [], 3); +delay = (delay_ind - 1) * dt * 2; % double time step because of single-sided FFT +nf2ff_out = nf2ff; %possibly needed for plotting the far field and other things +disp(["DelayFidelity: delay resolution = ", num2str(dt*2e9), "ns"]); +return; + + diff --git a/openEMS/matlab/Dump2VTK.m b/openEMS/matlab/Dump2VTK.m new file mode 100644 index 0000000..e57b153 --- /dev/null +++ b/openEMS/matlab/Dump2VTK.m @@ -0,0 +1,179 @@ +function Dump2VTK(filename, fields, mesh, fieldname, varargin) +% Dump2VTK(filename, fields, mesh, fieldname, varargin) +% +% Dump fields extraced from an hdf5 file to a vtk file format +% +% possible arguments: +% 'NativeDump': 0 (default) / 1, dump in native coordinate system +% 'CloseAlpha': 0 (default) / 1, repeat first/last line in +% alpha-direction for a full cylindrical mesh +% +% example: +% +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also ReadHDF5FieldData ReadHDF5Mesh GetField_TD2FD GetField_Interpolation + +NativeDump = 0; +CloseAlpha = 0; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'NativeDump')==1); + NativeDump = varargin{n+1}; + elseif (strcmp(varargin{n},'CloseAlpha')==1); + CloseAlpha = varargin{n+1}; + end +end + +x = mesh.lines{1}; +y = mesh.lines{2}; +z = mesh.lines{3}; + +fid = fopen(filename,'w+'); + +% set nan values to zero +ind = find(isnan(fields)); +if (~isempty(ind)) + warning('openEMS:Dump2VTK','field contains nan, setting to zero'); + fields(ind)=0; +end + +% set inf values to zero +ind = find(isinf(fields)); +if (~isempty(ind)) + warning('openEMS:Dump2VTK','field contains inf, setting to zero'); + fields(ind)=0; +end + +if ((CloseAlpha~=0) && (mesh.type==1) && (range(y)<2*pi)) + y(end+1) = y(1)+2*pi; + fields(:,end+1,:,:) = fields(:,1,:,:); +end + +if (mesh.type==0) %write cartesian mesh to vtk + fprintf(fid,'# vtk DataFile Version 2.0\n'); + fprintf(fid,'Rectilinear Grid by matlab-interface of openEMS\n'); + fprintf(fid,'ASCII\n'); + fprintf(fid,'DATASET RECTILINEAR_GRID\n'); + + fprintf(fid,'DIMENSIONS %d %d %d\n',numel(x),numel(y),numel(z)); + + fprintf(fid,'X_COORDINATES %d double\n',numel(x)); + fprintf(fid,'%e',x(1)); + for n=2:numel(x) + fprintf(fid,' %e',x(n)); + end + fprintf(fid,'\n'); + + fprintf(fid,'Y_COORDINATES %d double\n',numel(y)); + fprintf(fid,'%e',y(1)); + for n=2:numel(y) + fprintf(fid,' %e',y(n)); + end + fprintf(fid,'\n'); + + fprintf(fid,'Z_COORDINATES %d double\n',numel(z)); + fprintf(fid,'%e',z(1)); + for n=2:numel(z) + fprintf(fid,' %e',z(n)); + end + +elseif (mesh.type==1) %write cylindrical mesh to vtk + fprintf(fid,'# vtk DataFile Version 3.0\n'); + fprintf(fid,'Structured Grid by matlab-interface of openEMS\n'); + fprintf(fid,'ASCII\n'); + fprintf(fid,'DATASET STRUCTURED_GRID\n'); + + fprintf(fid,'DIMENSIONS %d %d %d\n',numel(x),numel(y),numel(z)); + + fprintf(fid,'POINTS %d double\n',numel(x)*numel(y)*numel(z)); + + for nz=1:numel(z) + for ny=1:numel(y) + for nx=1:numel(x) + fprintf(fid,'%e %e %e\n',x(nx)*cos(y(ny)),x(nx)*sin(y(ny)),z(nz)); + end + end + end + if ((ndims(fields)==4) && (NativeDump==0)) + [R A Z] = ndgrid(x,y,z); + sinA = sin(A); + cosA = cos(A); + field_CC(:,:,:,1) = fields(:,:,:,1) .* cosA - fields(:,:,:,2) .* sinA; + field_CC(:,:,:,2) = fields(:,:,:,1) .* sinA + fields(:,:,:,2) .* cosA; + field_CC(:,:,:,3) = fields(:,:,:,3); + fields = field_CC; + clear R A Z sinA cosA field_CC + end +elseif (mesh.type==2) %write spherical mesh to vtk + fprintf(fid,'# vtk DataFile Version 3.0\n'); + fprintf(fid,'Structured Grid by matlab-interface of openEMS\n'); + fprintf(fid,'ASCII\n'); + fprintf(fid,'DATASET STRUCTURED_GRID\n'); + + fprintf(fid,'DIMENSIONS %d %d %d\n',numel(x),numel(y),numel(z)); + + fprintf(fid,'POINTS %d double\n',numel(x)*numel(y)*numel(z)); + + for nz=1:numel(z) + for ny=1:numel(y) + for nx=1:numel(x) + fprintf(fid,'%e %e %e\n',... + x(nx)*sin(y(ny))*cos(z(nz)),... + x(nx)*sin(y(ny))*sin(z(nz)),... + x(nx)*cos(y(ny))); + end + end + end + + if ((ndims(fields)==4) && (NativeDump==0)) + [R T A] = ndgrid(x,y,z); + sinA = sin(A); + cosA = cos(A); + sinT = sin(T); + cosT = cos(T); + field_CC(:,:,:,1) = fields(:,:,:,1) .* sinT .* cosA + fields(:,:,:,2) .*cosT .* cosA - fields(:,:,:,3) .* sinA; + field_CC(:,:,:,2) = fields(:,:,:,1) .* sinT .* cosA + fields(:,:,:,2) .*cosT .* sinA + fields(:,:,:,3) .* cosA; + field_CC(:,:,:,3) = fields(:,:,:,1) .* cosT - fields(:,:,:,2) .*sinT; + fields = field_CC; + clear R A T sinA cosA sinT cosT field_CC + end +end + + +fprintf(fid,'\n\n'); + +fprintf(fid,'POINT_DATA %d\n',numel(x)*numel(y)*numel(z)); +% dump vector field data +if (size(fields,4)>1) + if (nargin>3) + fprintf(fid,['VECTORS ' fieldname ' double\n']); + else + fprintf(fid,'VECTORS field double\n'); + end + fclose(fid); + field_x = fields(:,:,:,1); + field_y = fields(:,:,:,2); + field_z = fields(:,:,:,3); + clear fields + dumpField(:,1) = field_x(:); + dumpField(:,2) = field_y(:); + dumpField(:,3) = field_z(:); + save('-ascii','-append',filename,'dumpField') + return +elseif (size(fields,4)==1) % scalar field + if (nargin>3) + fprintf(fid,['SCALARS ' fieldname ' double 1\nLOOKUP_TABLE default\n']); + else + fprintf(fid,'SCALARS field double 1\nLOOKUP_TABLE default\n'); + end + fclose(fid); + dumpField = fields(:); + save('-ascii','-append',filename,'dumpField') + return +end + +fclose(fid); diff --git a/openEMS/matlab/DumpFF2VTK.m b/openEMS/matlab/DumpFF2VTK.m new file mode 100644 index 0000000..8e6e2f8 --- /dev/null +++ b/openEMS/matlab/DumpFF2VTK.m @@ -0,0 +1,105 @@ +function DumpFF2VTK(filename, farfield, thetaRange, phiRange, varargin) +% DumpFF2VTK(filename, farfield, thetaRange, phiRange, varargin) +% +% Dump 3D far field pattern to a vtk file +% +% input: +% filename: filename of VTK file, existing file will be overwritten +% farfield: farfield in V/m +% thetaRange: theta range in deg +% phiRange: phi range in deg +% +% variable input: +% 'scale': - linear scale of plot, doesn't affect gain values +% 'logscale': - if set, show farfield with logarithmic scale +% - set the dB value for point of origin +% - values below will be clamped +% 'maxgain': - add max gain in dB to normalized farfield +% - only valid if logscale is set +% - default is 0dB +% +% example: +% DumpFF2VTK(filename, farfield, thetaRange, phiRange, ... +% 'scale', 2, 'logscale', -20, 'maxgain', 3) +% +% see also examples/NF2FF/infDipol.m +% +% See also CreateNF2FFBox, CalcNF2FF +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + + +% defaults +scale = 1; +maxgain = 0; +logscale = []; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'maxgain')==1); + maxgain = varargin{n+1}; + elseif (strcmp(varargin{n},'logscale')==1); + logscale = varargin{n+1}; + elseif (strcmp(varargin{n},'scale')==1); + scale = varargin{n+1}; + end +end + +if ~isempty(logscale) + farfield = 20*log10(farfield) + maxgain - logscale; + ind = find(farfield<0); + farfield(ind)=0; +else + % force 0 for linear plot + logscale = 0; +end + +t = thetaRange*pi/180; +a = phiRange*pi/180; + +fid = fopen(filename,'w+'); + +% set nan values to zero +ind = find(isnan(farfield)); +if (~isempty(ind)) + warning('openEMS:Dump2VTK','field contains nan, setting to zero'); + farfield(ind)=0; +end + +% set inf values to zero +ind = find(isinf(farfield)); +if (~isempty(ind)) + warning('openEMS:Dump2VTK','field contains inf, setting to zero'); + farfield(ind)=0; +end + + +fprintf(fid,'# vtk DataFile Version 3.0\n'); +fprintf(fid,'Structured Grid by matlab-interface of openEMS\n'); +fprintf(fid,'ASCII\n'); +fprintf(fid,'DATASET STRUCTURED_GRID\n'); + +fprintf(fid,'DIMENSIONS %d %d %d\n',1,numel(t),numel(a)); + +fprintf(fid,'POINTS %d double\n',numel(t)*numel(a)); + +for na=1:numel(phiRange) + for nt=1:numel(thetaRange) + fprintf(fid,'%e %e %e\n',... + scale*farfield(nt,na)*sin(t(nt))*cos(a(na)),... + scale*farfield(nt,na)*sin(t(nt))*sin(a(na)),... + scale*farfield(nt,na)*cos(t(nt))); + end +end + + + +fprintf(fid,'\n\n'); + +fprintf(fid,'POINT_DATA %d\n',numel(t)*numel(a)); + +fprintf(fid,['SCALARS gain double 1\nLOOKUP_TABLE default\n']); +fclose(fid); +dumpField = farfield(:) + logscale; +save('-ascii','-append',filename,'dumpField') diff --git a/openEMS/matlab/FFT_time2freq.m b/openEMS/matlab/FFT_time2freq.m new file mode 100644 index 0000000..a82c435 --- /dev/null +++ b/openEMS/matlab/FFT_time2freq.m @@ -0,0 +1,18 @@ +function [f,val] = FFT_time2freq( t, val ) +% [f,val] = FFT_time2freq( t, val ) +% +% Note: This function can only be used for pulse signals +% +% See also DFT_time2freq + +dt=t(2)-t(1); % timestep +L=numel(val); % signal length +NFFT = 2^nextpow2(L); % next power of 2 (makes fft fast) +%very fine freq resolution... NFFT = NFFT+100000; +val = fft( val, NFFT)*dt; +f = 1/(2*dt) * linspace(0,1,NFFT/2+1); + +val = 2*val(1:NFFT/2+1); % single-sided spectrum + +%correct phase for time-shifted signals +val = val .* exp(-1j*2*pi*f * t(1)); diff --git a/openEMS/matlab/FindFreeSSH.m b/openEMS/matlab/FindFreeSSH.m new file mode 100644 index 0000000..8fd6c22 --- /dev/null +++ b/openEMS/matlab/FindFreeSSH.m @@ -0,0 +1,87 @@ +function host = FindFreeSSH(host_list, Settings, wait_time, command) +% function host = FindFreeSSH(host_list, Settings, wait_time, command) +% +% Find a free ssh host not running openEMS +% +% internal function used by RunOpenEMS +% +% host_list: give a list of possible host +% +% wait_time: wait x seconds after not finding a free host and rechecking +% default: 600 seconds +% +% command: unix command to check for free host (empty result --> free) +% default: 'ps -e | grep openEMS' +% +% See also RunOpenEMS +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +if (nargin<4) + % command which should return an empty string if host is available + command = 'ps -e | grep openEMS'; +end + +% 10 seconds ssh timeout +time_out = 10; + +if (nargin<3) + wait_time = 600; +end + +if ~isunix + ssh_command = [Settings.SSH.Putty.Path '/plink ']; + ssh_options = [' -i ' Settings.SSH.Putty.Key]; + command = ['"' command '"']; +else + ssh_command = 'ssh'; + ssh_options = ['-o ConnectTimeout=' num2str(time_out)]; + command = ['''' command '''']; +end + +if ischar(host_list) + fid=fopen(host_list); + if (fid==-1) + error('FindFreeSSH: cant open host file'); + end + clear host_list; + host_list = {}; + while 1 + line = fgetl(fid); + if ischar(line) + host_list{end+1} = line; + else + break; + end + end + fclose(fid); +elseif ~iscell(host_list) + error('FindFreeSSH: unknown host list format'); +end + +while 1 + for n = 1:numel(host_list) + host = host_list{n}; + [status, result] = unix([ssh_command ' ' ssh_options ' ' host ' ' command ]); + if (isempty(result) && status==1) + disp(['FindFreeSSH:: found a free host: ' host ]); + return + elseif (~isempty(result) && status==0) + disp(['FindFreeSSH:: ' host ' is busy running openEMS ... ' ]); + else + disp(['FindFreeSSH:: shh connection to ' host ' failed ... ' ]); + end + end + + host = ''; + + if (wait_time<=0) + warning('openEMS:FindFreeSSH',' unable to find a free host '); + return + end + + disp([' no free host found waiting for ' num2str(wait_time) ' seconds ... ']) + pause(wait_time) +end \ No newline at end of file diff --git a/openEMS/matlab/FinishQueue.m b/openEMS/matlab/FinishQueue.m new file mode 100644 index 0000000..10020c5 --- /dev/null +++ b/openEMS/matlab/FinishQueue.m @@ -0,0 +1,40 @@ +function [queue] = FinishQueue(queue, query_time) +% function [queue] = FinishQueue(queue, ) +% +% Wait for the given queue to finish. +% +% Parameter: +% query_time (optional): time interval to check for finished tasks +% (in seconds, default is 5) +% +% For more details see: InitQueue +% +% See also: InitQueue, ResultsQueue, Add2Queue, RunOpenEMS +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +if ~isfield(queue,'jobs') + return +end + +if (nargin<2) + query_time = 5; +end + +numJobs = numel(queue.jobs); + +if (queue.verbose>=1) + disp(['FinishQueue: Waiting for ' num2str(sum(~queue.jobs_finished)) ' of ' num2str(numJobs) ' jobs to finish...']); +end + +running = numel(queue.jobs_finished) - sum(queue.jobs_finished); + +while sum(running)>0 + [queue running] = CheckQueue(queue, query_time); +end + +if (queue.verbose>=1) + disp(['FinishQueue: All jobs done!']) +end diff --git a/openEMS/matlab/GetField_Interpolation.m b/openEMS/matlab/GetField_Interpolation.m new file mode 100644 index 0000000..6682a83 --- /dev/null +++ b/openEMS/matlab/GetField_Interpolation.m @@ -0,0 +1,147 @@ +function [field_i mesh_i] = GetField_Interpolation(field, mesh, lines, varargin) +% [field_i mesh_i] = GetField_Interpolation(field, mesh, lines, varargin) +% +% Get an interpolated field, e.g. read by ReadHDF5Dump +% +% homogen interpolation given by a 3x1 vector: e.g. [21,1,101] +% +% abitrary interpolation on a given mesh: +% e.g.: mesh_interp{1} = linspace(0, 1,101) * 1e-3; +% mesh_interp{2} = linspace(0,0.5, 51) * 1e-3; +% mesh_interp{3} = linspace(0,0.2, 21) * 1e-3; +% +% example: +% [field mesh] = ReadHDF5Dump('Et.h5'); +% %interpolate on a mesh with 21x21x101 lines +% [field_i mesh_i] = GetField_Interpolation(field, mesh, [21 21 101]); +% or +% [field_i mesh_i] = GetField_Interpolation(field, mesh, mesh_interp); +% +% %or both steps in one with the same result: +% [field_i mesh_i] = ReadHDF5Dump('Et.h5','Interpolation', [21 21 101]); +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also ReadHDF5Dump ReadHDF5FieldData ReadHDF5Mesh + +if ((~iscell(lines) && ~isnumeric(lines)) || numel(lines)~=3) + error('openEMS:GetField_Interpolation: numLines for interpolation must be a vector...'); +end + +x = mesh.lines{1}; +y = mesh.lines{2}; +z = mesh.lines{3}; + +if (isnumeric(lines)) + if (lines(1)==0) + x_i = x; + else + x_i = linspace(x(1),x(end),lines(1)); + end + if (lines(2)==0) + y_i = y; + else + y_i = linspace(y(1),y(end),lines(2)); + end + if (lines(3)==0) + z_i = z; + else + z_i = linspace(z(1),z(end),lines(3)); + end +else + if isempty(lines{1}) + x_i = x; + else + x_i = lines{1}; + end + if isempty(lines{2}) + y_i = y; + else + y_i = lines{2}; + end + if isempty(lines{3}) + z_i = z; + else + z_i = lines{3}; + end +end + +field_i = field; +mesh_i = mesh; +mesh_i.lines{1} = x_i; +mesh_i.lines{2} = y_i; +mesh_i.lines{3} = z_i; + +% clear or create empty original indices list, since such do not make any +% sense with interpolated field values +mesh_i.original_indices = {}; + +if (isfield(field,'TD')) + field_i.TD = interpolate_fields(field.TD,x,y,z, x_i, y_i, z_i); + field_i.TD.time = field.TD.time; + field_i.TD.names= field.TD.names; +end + +if (isfield(field,'FD')) + field_i.FD = interpolate_fields(field.FD,x,y,z, x_i, y_i, z_i); + field_i.FD.frequency = field.FD.frequency; + field_i.FD.DataType = field.FD.DataType; +end + +return + +function field_i = interpolate_fields(field, x,y,z, x_i, y_i, z_i) + +% matlab cannot handle 3D data to be 2D data, workaround for these cases +if (numel(x)==1) + [Y Z] = ndgrid(y,z); + [Y_I Z_I] = ndgrid(y_i,z_i); + for n=1:numel(field.values) + field_i.values{n}(1,:,:,1) = interpn(Y,Z,squeeze(field.values{n}(1,:,:,1)),Y_I,Z_I); + if (size(field.values{n},4)>1) + field_i.values{n}(1,:,:,2) = interpn(Y,Z,squeeze(field.values{n}(1,:,:,2)),Y_I,Z_I); + field_i.values{n}(1,:,:,3) = interpn(Y,Z,squeeze(field.values{n}(1,:,:,3)),Y_I,Z_I); + end + end + return; +end + +if (numel(y)==1) + [X Z] = ndgrid(x,z); + [X_I Z_I] = ndgrid(x_i,z_i); + for n=1:numel(field.values) + field_i.values{n}(:,1,:,1) = interpn(X,Z,squeeze(field.values{n}(:,1,:,1)),X_I,Z_I); + if (size(field.values{n},4)>1) + field_i.values{n}(:,1,:,2) = interpn(X,Z,squeeze(field.values{n}(:,1,:,2)),X_I,Z_I); + field_i.values{n}(:,1,:,3) = interpn(X,Z,squeeze(field.values{n}(:,1,:,3)),X_I,Z_I); + end + end + return; +end + +if (numel(z)==1) + [X Y] = ndgrid(x,y); + [X_I Y_I] = ndgrid(x_i,y_i); + for n=1:numel(field.values) + field_i.values{n}(:,:,1,1) = interpn(X,Y,squeeze(field.values{n}(:,:,1,1)),X_I,Y_I); + if (size(field.values{n},4)>1) + field_i.values{n}(:,:,1,2) = interpn(X,Y,squeeze(field.values{n}(:,:,1,2)),X_I,Y_I); + field_i.values{n}(:,:,1,3) = interpn(X,Y,squeeze(field.values{n}(:,:,1,3)),X_I,Y_I); + end + end + return; +end + + +%real 3D case +[X Y Z] = ndgrid(x,y,z); +[X_I Y_I Z_I] = ndgrid(x_i,y_i,z_i); +for n=1:numel(field.values) + field_i.values{n}(:,:,:,1) = interpn(X,Y,Z,field.values{n}(:,:,:,1),X_I,Y_I,Z_I); + if (size(field.values{n},4)>1) + field_i.values{n}(:,:,:,2) = interpn(X,Y,Z,field.values{n}(:,:,:,2),X_I,Y_I,Z_I); + field_i.values{n}(:,:,:,3) = interpn(X,Y,Z,field.values{n}(:,:,:,3),X_I,Y_I,Z_I); + end +end diff --git a/openEMS/matlab/GetField_Range.m b/openEMS/matlab/GetField_Range.m new file mode 100644 index 0000000..8d489b9 --- /dev/null +++ b/openEMS/matlab/GetField_Range.m @@ -0,0 +1,71 @@ +function [field_i mesh_i] = GetField_Range(field, mesh, range) +% [field_i mesh_i] = GetField_Range(field, mesh, range) +% +% Get a field dump subset within a given mesh range +% +% example: +% % specify a mesh range +% range{1} = [0 150] * 1e-3; % x in range 0..150mm +% range{2} = [0]; % only one line close to y==0 +% range{3} = []; % no range restriction +% +% % read hdf data +% [field mesh] = ReadHDF5Dump('Et.h5'); +% % extract a ranged subset +% [field_i mesh_i] = GetField_Range(field, mesh, range); +% +% %or both steps in one with the same result: +% [field_i mesh_i] = ReadHDF5Dump('Et.h5','Range', range); +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also ReadHDF5Dump ReadHDF5FieldData ReadHDF5Mesh + +mesh_i = mesh; +for n=1:3 + if (numel(range{n})==0) + ind_range{n} = []; + + ind_range{n} = 1:numel( mesh.lines{n}); + + elseif (numel(range{n})==1) + ind_range{n} = find( mesh.lines{n}>=range{n}(1) , 1); + + if (isempty(ind_range{n})) + ind_range{n} = find( mesh.lines{n}>=range{n}(1) , 1, 'first'); + end + if (isempty(ind_range{n})) + ind_range{n} = find( mesh.lines{n}<=range{n}(2) , 1, 'last'); + end + + else + ind_range{n} = find( mesh.lines{n}>=range{n}(1) & mesh.lines{n}<=range{n}(2)); + end + + mesh_i.lines{n} = mesh.lines{n}(ind_range{n}); +end + +% store original indices +if (isfield(mesh_i,'original_indices')) + for n=1:3 + mesh_i.original_indices{n} = mesh_i.original_indices{n}(ind_range{n}); + end +else + mesh_i.original_indices = ind_range; +end + +field_i = field; + +if (isfield(field,'FD')) + for n=1:numel(field.FD.values) + field_i.FD.values{n} = field.FD.values{n}(ind_range{1},ind_range{2},ind_range{3},:); + end +end + +if (isfield(field,'TD')) + for n=1:numel(field.TD.values) + field_i.TD.values{n} = field.TD.values{n}(ind_range{1},ind_range{2},ind_range{3},:); + end +end diff --git a/openEMS/matlab/GetField_SubSampling.m b/openEMS/matlab/GetField_SubSampling.m new file mode 100644 index 0000000..9c792e0 --- /dev/null +++ b/openEMS/matlab/GetField_SubSampling.m @@ -0,0 +1,63 @@ +function [field_i mesh_i] = GetField_SubSampling(field, mesh, subsampling, varargin) +% [field_i mesh_i] = GetField_SubSampling(field, mesh, subsampling, varargin) +% +% Get a sub-sampled field, e.g. read by ReadHDF5Dump +% +% sub-sampling e.g. skipping every second line in x/r direction: [2 1 1] +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also ReadHDF5Dump ReadHDF5FieldData ReadHDF5Mesh + +if (~isnumeric(subsampling) || numel(subsampling)~=3) + error('openEMS:GetField_Interpolation: numLines for interpolation must be a vector...'); +end + +x = mesh.lines{1}; +y = mesh.lines{2}; +z = mesh.lines{3}; + +ss_idx{1} = 1:subsampling(1):numel(x); +ss_idx{2} = 1:subsampling(2):numel(y); +ss_idx{3} = 1:subsampling(3):numel(z); + +x_i = x(ss_idx{1}); +y_i = y(ss_idx{2}); +z_i = z(ss_idx{3}); + +field_i = field; +mesh_i = mesh; +mesh_i.lines{1} = x_i; +mesh_i.lines{2} = y_i; +mesh_i.lines{3} = z_i; + +% store original indices +if (isfield(mesh_i,'original_indices')) + for n=1:3 + mesh_i.original_indices{n} = mesh_i.original_indices{n}(ss_idx{n}); + end +else + mesh_i.original_indices = ss_idx; +end + +if (isfield(field,'TD')) + field_i.TD = subsample_fields(field.TD,ss_idx); + field_i.TD.time = field.TD.time; + field_i.TD.names= field.TD.names; +end + +if (isfield(field,'FD')) + field_i.FD = subsample_fields(field.FD,ss_idx); + field_i.FD.frequency = field.FD.frequency; + field_i.FD.DataType = field.FD.DataType; +end + +return + +function field_i = subsample_fields(field, ss_idx) + +for n=1:numel(field.values) + field_i.values{n} = field.values{n}(ss_idx{1},ss_idx{2},ss_idx{3},:); +end diff --git a/openEMS/matlab/GetField_TD2FD.m b/openEMS/matlab/GetField_TD2FD.m new file mode 100644 index 0000000..014c6d6 --- /dev/null +++ b/openEMS/matlab/GetField_TD2FD.m @@ -0,0 +1,48 @@ +function field = GetField_TD2FD(field, freq) +% function field = GetField_TD2FD(field, freq) +% +% Transforms time-domain field data into the frequency domain +% Autocorrects the half-timestep offset of the H-field +% +% example: +% freq = linspace(0,1e9,100); %target frequency vector (Hz) +% field = ReadHDF5FieldData('tmp/Ht.h5'); +% field_FD = GetField_TD2FD(field, freq); +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also ReadHDF5FieldData + +if (~isfield(field,'TD')) + warning('openEMS:GetField_TD2FD','field has no time domain data... skipping FD transformation...'); + return +end + +t = field.TD.time; +dt = t(2)-t(1); + +clear field.FD + +field.FD.frequency = freq; + +for nf = 1:numel(freq) + field.FD.values{nf} = 0; +end + +numTS = numel(field.TD.values); + +for n=1:numTS + for nf = 1:numel(freq) + f = freq(nf); + field.FD.values{nf} = field.FD.values{nf} + field.TD.values{n}.*exp(-1i*2*pi*f*t(n)) * 2 * dt; + % t(n) is absolute time and therefore the half-timestep offset of + % the H-field is automatically compensated + % openEMS output: E-fields start at t=0 + % openEMS output: H-fields start at t=delta_t/2 + end +end + +field.FD.DataType=1; + diff --git a/openEMS/matlab/InitCylindricalFDTD.m b/openEMS/matlab/InitCylindricalFDTD.m new file mode 100644 index 0000000..9da649f --- /dev/null +++ b/openEMS/matlab/InitCylindricalFDTD.m @@ -0,0 +1,21 @@ +function FDTD = InitCylindricalFDTD(NrTS, endCrit, varargin) +% function FDTD = InitCylindricalFDTD(NrTS, endCrit, varargin) +% +% see also InitFDTD +% +% e.g FDTD = InitCylindricalFDTD(5e5,1e-6,'OverSampling',10) +% +% WARNING: This function is depreciated, use InitFDTD with 'CoordSystem',1 +% e.g.: InitFDTD(5e5,1e-6,'OverSampling',10, 'CoordSystem',1) +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +warning('InitCylindricalFDTD: This function is depreciated, use InitFDTD with ''CoordSystem'',1'); + +FDTD = InitFDTD(NrTS, endCrit, varargin{:}); + +FDTD.ATTRIBUTE.CylinderCoords=1; + + diff --git a/openEMS/matlab/InitFDTD.m b/openEMS/matlab/InitFDTD.m new file mode 100644 index 0000000..dba5120 --- /dev/null +++ b/openEMS/matlab/InitFDTD.m @@ -0,0 +1,64 @@ +function FDTD = InitFDTD(varargin) +% function FDTD = InitFDTD(varargin) +% +% Inititalize the FDTD data-structure. +% +% optional field arguments for usage with openEMS: +% NrTS: max. number of timesteps to simulate (e.g. default=1e9) +% EndCriteria: end criteria, e.g. 1e-5, simulations stops if energy has +% decayed by this value (<1e-4 is recommended, default=1e-5) +% MaxTime: max. real time in seconds to simulate +% OverSampling: nyquist oversampling of time domain dumps +% CoordSystem: choose coordinate system (0 Cartesian, 1 Cylindrical) +% MultiGrid: define a cylindrical sub-grid radius +% TimeStep: force to use a given timestep (dangerous!) +% TimeStepFactor: reduce the timestep by a given factor (>0 to <=1) +% TimeStepMethod: 1 or 3 chose timestep method (1=CFL, 3=Rennigs (default)) +% CellConstantMaterial: set to 1 to assume a material is constant inside +% a cell (material probing in cell center) +% +% examples: +% %default init with 1e9 max. timesteps and -50dB end-criteria +% FDTD = InitFDTD(); +% +% %init with 1e6 max. timesteps and -60dB end-criteria +% FDTD = InitFDTD('NrTS', 1e6, 'EndCriteria', 1e-6); +% +% %cylindrical FDTD simulation +% FDTD = InitFDTD('CoordSystem', 1); +% +% See also InitCSX +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig (c) 2010-2013 + +% default values +NrTS = 1e9; +endCrit = 1e-5; + +% legacy support +if ((nargin==1) && (isnumeric(varargin{1}))) + NrTS = varargin{1}; + warning('openEMS:InitFDTD',['Syntax for InitFDTD has changed, use: "InitFDTD(''NrTS'', ' num2str(NrTS) ')" instead! Legacy support enabled.']); +elseif ((nargin>1) && (isnumeric(varargin{1})) && (isnumeric(varargin{2}))) + NrTS = varargin{1}; + endCrit = varargin{2}; + varargin(1:2) = []; + warning('openEMS:InitFDTD',['Syntax for InitFDTD has changed, use: "InitFDTD(''NrTS'', ' num2str(NrTS) ', ''EndCriteria'', ' num2str(endCrit) ')" instead! Legacy support enabled.']); +end + +for n=1:numel(varargin)/2 + if strcmpi(varargin{2*n-1},'CoordSystem')==1 + FDTD.ATTRIBUTE.CylinderCoords=varargin{2*n}==1; + elseif strcmpi(varargin{2*n-1},'NrTS')==1 + NrTS=varargin{2*n}; + elseif strcmpi(varargin{2*n-1},'EndCriteria')==1 + endCrit=varargin{2*n}; + else + FDTD.ATTRIBUTE.(varargin{2*n-1})=varargin{2*n}; + end +end + +FDTD.ATTRIBUTE.NumberOfTimesteps=NrTS; +FDTD.ATTRIBUTE.endCriteria=endCrit; diff --git a/openEMS/matlab/InitQueue.m b/openEMS/matlab/InitQueue.m new file mode 100644 index 0000000..feec5cc --- /dev/null +++ b/openEMS/matlab/InitQueue.m @@ -0,0 +1,90 @@ +function [queue] = InitQueue(varargin) +% function [queue] = InitQueue(varargin) +% +% Use this function to initialize a queue to run one or more matlab scripts +% in parallel. +% This can be used to efficiently run an openEMS parameter sweep in parallel +% on multiple remote machines. +% +% Options: +% DependPath: Add multiple paths, your script may depend on +% UseOctave: Enable/Disable octave usage +% MaxThreads: max. number of parallel executions +% +% Note: +% - Currently only Linux/Unix is supported +% - By default Octave is used to spawn parallel functions (saves +% licenses), but this can be changed by: +% [queue] = InitQueue('UseOctave', 0); +% You may need to change this, if your script is not octave compatible +% - To efficiently run openEMS in parallel, you need to run it on several +% machines using a SSH.host_list setting --> See also RunOpenEMS +% +% Example: +% %serial version: +% for n=1:10 +% % manipulate parameter etc. +% [result1(n) result2(n)] = Parallel_Func_Name(param1, param2); +% end +% +% %parallel version: +% queue = InitQueue('DependPath',{'/opt/openEMS/CSXCAD/matlab', ... +% '/opt/openEMS/openEMS/matlab'}); +% for n=1:10 +% % manipulate parameter etc. +% queue = Add2Queue(queue, 'Parallel_Func_Name', {param1, param2}); +% end +% +% % wait for all to finish +% [queue] = FinishQueue(queue); +% +% % retrieve result +% for n=1:numel(stub_sweep) +% [result1(n) result2(n)] = ResultsQueue(queue,n); +% end +% +% See also: Add2Queue, FinishQueue, ResultsQueue, RunOpenEMS, +% RunOpenEMS_Parallel, FindFreeSSH +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +if ~isunix + error 'your OS is not supported (Unix only)' +end + +queue.use_octave = exist('OCTAVE_VERSION','builtin') ~= 0; + +queue.verbose = 1; + +queue.maxThreads = Inf; + +% add current path +queue.DependPath = ['addpath(''' pwd ''');']; + +for n=1:2:nargin + if strcmp(varargin{n},'DependPath'); + for m=1:numel(varargin{n+1}) + queue.DependPath = [queue.DependPath 'addpath(''' varargin{n+1}{m} ''');']; + end + end + if strcmp(varargin{n},'UseOctave'); + queue.use_octave = varargin{n+1}; + end + if strcmp(varargin{n},'MaxThreads'); + queue.maxThreads = varargin{n+1}; + end +end + + +% set binaries and options +if (queue.use_octave) + queue.bin = ['export LD_LIBRARY_PATH=""; octave']; + queue.bin_options = [' --silent --eval']; +else + queue.bin = [matlabroot '/bin/matlab']; + queue.bin_options = [' -nodesktop -nosplash -r']; +end + +queue.jobs_finished = []; diff --git a/openEMS/matlab/PlotHDF5FieldData.m b/openEMS/matlab/PlotHDF5FieldData.m new file mode 100644 index 0000000..9aaf899 --- /dev/null +++ b/openEMS/matlab/PlotHDF5FieldData.m @@ -0,0 +1,94 @@ +function PlotHDF5FieldData(file, PlotArgs) +% function PlotHDF5FieldData(file, PlotArgs) +% +% e.g. +% PlotArgs.slice = {0 [10 20] 0}; +% PlotArgs.pauseTime=0.01; +% PlotArgs.component=2; +% PlotArgs.Limit = 'auto'; +% +% PlotHDF5FieldData('tmp/Et.h5',PlotArgs) +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +component = PlotArgs.component; + +if (isfield(PlotArgs,'pauseTime')) + pauseT = PlotArgs.pauseTime; +else + pauseT = 0.01; +end + +mesh = ReadHDF5Mesh(file); +fields = ReadHDF5FieldData(file); + +if (mesh.type==0) + % cartesian mesh + [X Y Z] = meshgrid(mesh.lines{1},mesh.lines{2},mesh.lines{3}); + for n=1:numel(fields.TD.values) + % since Matlab 7.1SP3 the field needs to be reordered + fields.TD.values{n} = permute(fields.TD.values{n},[2 1 3 4]); % reorder: y,x,z (or y,x) + end +else + disp(['PlotHDF5FieldData:: Error: unknown mesh type ' num2str(mesh.type)]); +end + +max_amp = 0; + +if (component>0) + for n=1:numel(fields.TD.values) + Field{n} = fields.TD.values{n}(:,:,:,component); + end +else + for n=1:numel(fields.TD.values) + fx = fields.TD.values{n}(:,:,:,1); + fy = fields.TD.values{n}(:,:,:,2); + fz = fields.TD.values{n}(:,:,:,3); + Field{n} = sqrt(fx.^2 + fy.^2 + fz.^2); + end +end + +for n=1:numel(Field) + amp = max(max(max(abs(Field{n})))); + if (amp>max_amp) + max_amp = amp; + end +end + +if (max_amp==0) + disp('max found amplitude was 0 --> nothing to plot'); + return +end + +for n=1:numel(Field) + if size(Field{n},3) > 1 + % Field is a volume + hsurfaces = slice(X,Y,Z, Field{n} , PlotArgs.slice{:}); + set(hsurfaces,'FaceColor','interp','EdgeColor','none'); + else + % Field is already a 2D cut + pcolor(X,Y,Field{n}); + shading( 'interp' ); + xlabel( 'x' ); + ylabel( 'y' ); + end + title(fields.TD.names{n}); + %view(3) + axis equal + if (isfield(PlotArgs,'Limit')) + if ~ischar(PlotArgs.Limit) + caxis(PlotArgs.Limit); + elseif strcmp(PlotArgs.Limit,'auto') + if (component>0) + caxis([-max_amp,max_amp]); + else + caxis([0,max_amp]); + end + end + end + + drawnow + pause(pauseT) +end diff --git a/openEMS/matlab/ReadHDF5Attribute.m b/openEMS/matlab/ReadHDF5Attribute.m new file mode 100644 index 0000000..3361ee9 --- /dev/null +++ b/openEMS/matlab/ReadHDF5Attribute.m @@ -0,0 +1,33 @@ +function attr = ReadHDF5Attribute(file, groupname, attr_name) +% attr = ReadHDF5Attribute(file, groupname, attr_name) +% +% internal function for openEMS to read hdf5 attributes +% +% See also: ReadHDF5ComplexData +% +% openEMS Matlab/Octave interface +% ----------------------- +% author: Thorsten Liebig, 2012 + + +if isOctave + if (exist('h5readatt_octave')==0) + warning('openEMS:ReadHDF5Attribute','function "h5readatt_octave" not found, trying to run "setup"'); + try + setup + catch + error('openEMS:ReadHDF5Attribute','running "setup" failed...'); + end + end + attr = double(h5readatt_octave(file,groupname,attr_name)); +else + %check for different matlab versions + if verLessThan('matlab','7.9') + attr = double(hdf5read(file,[groupname '/' attr_name])); + elseif verLessThan('matlab','7.12') + attr = double(hdf5read(file,groupname,attr_name)); + else + attr = double(h5readatt(file,groupname,attr_name)); + end + +end \ No newline at end of file diff --git a/openEMS/matlab/ReadHDF5Dump.m b/openEMS/matlab/ReadHDF5Dump.m new file mode 100644 index 0000000..9fc8c43 --- /dev/null +++ b/openEMS/matlab/ReadHDF5Dump.m @@ -0,0 +1,92 @@ +function [field mesh] = ReadHDF5Dump(file, varargin) +%[field mesh] = ReadHDF5Dump(file, varargin) +% +% Read a hdf5 field dump, including an interpolation and frequency domain +% transformation. +% +% For more information about the output, refer to the help of +% ReadHDF5Mesh and ReadHDF5FieldData +% +% possible arguments: +% 'Range' see GetField_Range +% 'Interpolation' see GetField_Interpolation +% 'SubSampling' see GetField_SubSampling +% 'Frequency' see GetField_TD2FD +% 'CloseAlpha': 0 (default) / 1 +% +% example: +% [field mesh] = ReadHDF5Dump('Et.h5'); +% or +% [field mesh] = ReadHDF5Dump('Et.h5','Range',{[0 100],[-20 20],[50 90]}); +% or +% [field mesh] = ReadHDF5Dump('Et.h5','Interpolation',[21 1 101],'Frequency',300e6); +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also ReadHDF5Mesh ReadHDF5FieldData GetField_Interpolation GetField_SubSampling +% GetField_TD2FD GetField_Range + +field = ReadHDF5FieldData(file); +mesh = ReadHDF5Mesh(file); + +if (nargin<2) + return +end + +% evaluate arguments in a specific order +for n=1:2:(nargin-1) + if (strcmp(varargin{n},'Range')==1); + [field mesh] = GetField_Range(field, mesh, varargin{n+1}); + end +end + +for n=1:2:(nargin-1) + if (strcmp(varargin{n},'SubSampling')==1); + [field mesh] = GetField_SubSampling(field,mesh,varargin{n+1}); + end +end + +for n=1:2:(nargin-1) + if (strcmp(varargin{n},'Interpolation')==1); + [field mesh] = GetField_Interpolation(field,mesh,varargin{n+1}); + end +end + +for n=1:2:(nargin-1) + if (strcmp(varargin{n},'Frequency')==1); + field = GetField_TD2FD(field,varargin{n+1}); + end +end + +for n=1:2:(nargin-1) + if (strcmp(varargin{n},'CloseAlpha')==1); + if ((varargin{n+1}==1) && (mesh.type==1) && (range(mesh.lines{2})<2*pi)) + mesh.lines{2}(end+1)=mesh.lines{2}(1)+2*pi; + if (isfield(field,'TD')) + for n = 1:numel(field.TD.values) + field.TD.values{n}(:,end+1,:,:) = field.TD.values{n}(:,1,:,:); + end + end + if (isfield(field,'FD')) + for n = 1:numel(field.FD.values) + field.FD.values{n}(:,end+1,:,:) = field.FD.values{n}(:,1,:,:); + end + end + if (isfield(mesh,'original_indices')) + if (~isempty(mesh.original_indices)) + mesh.original_indices{2} = [mesh.original_indices{2} 1]; + end + else + mesh.original_indices = {1:numel(mesh.lines{1}),[1:numel(mesh.lines{2}) 1],[1:numel(mesh.lines{3})]}; + end + end + end +end + +end + +function rng = range(x) + rng = max(x)-min(x); +end \ No newline at end of file diff --git a/openEMS/matlab/ReadHDF5FieldData.m b/openEMS/matlab/ReadHDF5FieldData.m new file mode 100644 index 0000000..c45f9ad --- /dev/null +++ b/openEMS/matlab/ReadHDF5FieldData.m @@ -0,0 +1,119 @@ +function hdf_fielddata = ReadHDF5FieldData(file) +% function hdf_fielddata = ReadHDF5FieldData(file) +% +% returns: +% % time domain data (if exist) +% hdf_fielddata.TD.time +% hdf_fielddata.TD.names +% hdf_fielddata.TD.values +% hdf_fielddata.TD.DataType (0 --> real value data) +% +% % frequency domain data (if exist) +% hdf_fielddata.FD.frequency +% hdf_fielddata.FD.values +% hdf_fielddata.FD.DataType (0 / 1 --> real / complex value data) +% +% example: values of timestep 12: +% hdf_fielddata.TD.values{12}: array (x,y,z,polarization) +% +% plot z-field component along y-direction for timestep 12: +% plot( hdf_fielddata.TD.values{12}(1,:,1,3) ) +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also ReadHDF5Mesh ReadHDF5Dump + +if isOctave + hdf_fielddata = ReadHDF5FieldData_octave(file); + return +end + +info = hdf5info(file); +TD.names = {}; +hdf_fielddata = []; + +for n=1:numel(info.GroupHierarchy.Groups) + if strcmp(info.GroupHierarchy.Groups(n).Name,'/FieldData') + %found /FieldData, look for either TD or FD data + for nGroup=1:numel(info.GroupHierarchy.Groups(n).Groups) + %search and read TD data + if strcmp(info.GroupHierarchy.Groups(n).Groups(nGroup).Name,'/FieldData/TD') + for m=1:numel(info.GroupHierarchy.Groups(n).Groups(nGroup).Datasets) + TD.names{m} = info.GroupHierarchy.Groups(n).Groups(nGroup).Datasets(m).Name; + for a = 1:numel(info.GroupHierarchy.Groups(n).Groups(nGroup).Datasets(m).Attributes) + str = regexp(info.GroupHierarchy.Groups(n).Groups(nGroup).Datasets(m).Attributes(a).Name,'\w/*\w*','match'); + TD.(str{end})(m) = double(info.GroupHierarchy.Groups(n).Groups(nGroup).Datasets(m).Attributes(a).Value); + end + end + end + end + + end +end + +if (numel(TD.names)>0) + hdf_fielddata.TD=TD; + hdf_fielddata.TD.DataType = 0; %real value data + for n=1:numel(hdf_fielddata.TD.names) + hdf_fielddata.TD.values{n} = double(hdf5read(file,hdf_fielddata.TD.names{n})); + end +end + +% extract FD data +try + hdf_fielddata.FD.frequency = ReadHDF5Attribute(file,'/FieldData/FD','frequency'); +catch err +% disp(err) + return +end + +for n=1:numel(hdf_fielddata.FD.frequency) + try + hdf_fielddata.FD.values{n} = double(hdf5read(file,['/FieldData/FD/f' int2str(n-1) '_real']) + 1i*hdf5read(file,['/FieldData/FD/f' int2str(n-1) '_imag'])); + hdf_fielddata.FD.DataType = 1; %complex value data + catch + try + hdf_fielddata.FD.values{n} = double(hdf5read(file,['/FieldData/FD/f' int2str(n-1)])); + hdf_fielddata.FD.DataType = 0; %real value data + catch + error('openEMS:ReadHDF5FieldData','FD data invalid...') + end + end +end + +function hdf_fielddata = ReadHDF5FieldData_octave(file) +hdf = load( '-hdf5', file ); +if ~isfield(hdf,'FieldData') + error('no field data found') +end +if isfield(hdf.FieldData,'TD') + %read TD data + hdf_fielddata_names = fieldnames(hdf.FieldData.TD); + for n=1:numel(hdf_fielddata_names) + hdf_fielddata.TD.values{n} = hdf.FieldData.TD.(hdf_fielddata_names{n}); + hdf_fielddata.TD.names{n} = ['/FieldData/TD/' hdf_fielddata_names{n}(2:end)]; + hdf_fielddata.TD.time(n) = ReadHDF5Attribute(file, hdf_fielddata.TD.names{n},'time'); + end + hdf_fielddata.TD.DataType = 0; %real value data +end +if isfield(hdf.FieldData,'FD') + %read FD data + hdf_fielddata.FD.frequency = ReadHDF5Attribute(file,'/FieldData/FD/','frequency'); + try %try reading complex data + for n=1:numel(hdf_fielddata.FD.frequency) + hdf_fielddata.FD.values{n} = double(hdf.FieldData.FD.(['f' int2str(n-1) '_real']) +1i*hdf.FieldData.FD.(['f' int2str(n-1) '_imag']) ); + end + hdf_fielddata.FD.DataType = 1; %complex value data + catch + try %try reading real value data + for n=1:numel(hdf_fielddata.FD.frequency) + hdf_fielddata.FD.values{n} = double(hdf.FieldData.FD.(['f' int2str(n-1)])); + end + hdf_fielddata.FD.DataType = 0; %real value data + catch + error('openEMS:ReadHDF5FieldData','FD data invalid...') + end + end +end diff --git a/openEMS/matlab/ReadHDF5Mesh.m b/openEMS/matlab/ReadHDF5Mesh.m new file mode 100644 index 0000000..b276391 --- /dev/null +++ b/openEMS/matlab/ReadHDF5Mesh.m @@ -0,0 +1,80 @@ +function hdf_mesh = ReadHDF5Mesh(file) +% function hdf_mesh = ReadHDF5Mesh(file) +% +% Get the raw mesh data stored in the hdf5 dump file created by openEMS +% +% returns: +% hdf_mesh.type (0-> cartesian, 1-> cylindrical mesh type) +% hdf_mesh.names (e.g. 'Mesh/y') +% hdf_mesh.lines (e.g. [0,1,2,3,4]) +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also ReadHDF5FieldData + +isOctave = exist('OCTAVE_VERSION','builtin') ~= 0; +if isOctave + hdf_mesh = ReadHDF5Mesh_octave(file); + return +end + +info = hdf5info(file); + +for n=1:numel(info.GroupHierarchy.Groups) + if strcmp(info.GroupHierarchy.Groups(n).Name,'/Mesh') + for m=1:numel(info.GroupHierarchy.Groups(n).Datasets) + names{m} = info.GroupHierarchy.Groups(n).Datasets(m).Name; + end + end +end + +hdf_mesh.names = names; +for n=1:numel(names) + hdf_mesh.lines{n} = double(hdf5read(file,names{n})); +end + +if (strcmp(names{1},'/Mesh/alpha')) + % alpha and rho are in the wrong order, flip to have rho, alpha, z + hdf_mesh.names(1:2) = fliplr(hdf_mesh.names(1:2)); + hdf_mesh.lines(1:2) = fliplr(hdf_mesh.lines(1:2)); + hdf_mesh.type=1; + return +end +if (strcmp(names{1},'/Mesh/phi')) + % reorder coordinates + hdf_mesh.names = hdf_mesh.names([2 3 1]); + hdf_mesh.lines = hdf_mesh.lines([2 3 1]); + hdf_mesh.type=2; + return +end + +hdf_mesh.type=0; + + +function hdf_mesh = ReadHDF5Mesh_octave(file) +hdf = load( '-hdf5', file ); +hdf_mesh.names = fieldnames(hdf.Mesh); +hdf_mesh.type = 0; % cartesian mesh +for n=1:numel(hdf_mesh.names) + hdf_mesh.lines{n} = hdf.Mesh.(hdf_mesh.names{n}); + hdf_mesh.names{n} = ['/Mesh/' hdf_mesh.names{n}]; + if strcmp(hdf_mesh.names{n},'/Mesh/alpha') + hdf_mesh.type = 1; % cylindrical mesh + end + if strcmp(hdf_mesh.names{n},'/Mesh/phi') + hdf_mesh.type = 2; % cylindrical mesh + end +end + +if (hdf_mesh.type==1) + % alpha and rho are in the wrong order, flip to have rho, alpha, z + hdf_mesh.names(1:2) = fliplr(hdf_mesh.names(1:2)); + hdf_mesh.lines(1:2) = fliplr(hdf_mesh.lines(1:2)); +end +if (hdf_mesh.type==2) + % alpha and rho are in the wrong order, flip to have rho, alpha, z + hdf_mesh.names = hdf_mesh.names([2 3 1]); + hdf_mesh.lines = hdf_mesh.lines([2 3 1]); +end diff --git a/openEMS/matlab/ReadUI.m b/openEMS/matlab/ReadUI.m new file mode 100644 index 0000000..23fe342 --- /dev/null +++ b/openEMS/matlab/ReadUI.m @@ -0,0 +1,107 @@ +function UI = ReadUI(files, path, freq, varargin) +% function UI = ReadUI(files, path, freq, varargin) +% +% read current and voltages from multiple files found in path +% +% returns voltages/currents in time and frequency-domain +% +% remarks on the frequency-domain: +% - all signals are assumed to start at t=0 +% - currents that e.g. start at t = +delta_t/2 will be phase shifted by +% exp(-j*w*t(1)) +% +% optional parameter: +% freq: frequency-domain values will be calculated according to 'freq' +% if 'freq' is not given, a (zero padded) FFT will be used +% +% optional key,value pairs: +% 'AR' : auto-regressive model to improve FD accuracy +% values: order to use within an AR model or 'auto' +% +% % examples: +% U = ReadUI({'ut1_1','ut1_2'},'tmp' ); +% I = ReadUI('it1' ,'tmp',[0.5e9 1e9 1.5e9]); +% +% % using the auto-regressive model +% U = ReadUI('port_ut1' , 'tmp', 'AR', 'auto'); +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig +% +% See also DFT_time2freq, AR_estimate + +if (nargin<2) + path =''; +end + +AR_order = 0; +SignalType = 'pulse'; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'AR')==1) + AR_order = varargin{n+1}; + elseif strcmpi(varargin{n},'SignalType') + SignalType = varargin{n+1}; + else + warning('CSXCAD:ReadUI', ['"' varargin{n} '" is an unknown argument']); + end +end + +if strcmpi(SignalType,'periodic') && AR_order>0 + error 'auto-regressive model not compatible with periodic signals' +end + +if (ischar(files)) + filenames{1}=files; +else + filenames=files; +end + +UI.TD = {}; +UI.FD = {}; +for n=1:numel(filenames) + tmp = load( fullfile(path,filenames{n}) ); + t = tmp(:,1)'; + val = tmp(:,2)'; + + UI.TD{n}.t = t; + UI.TD{n}.val = val; + + if (numel(tmp(1,:))>2) + UI.TD{n}.additional = tmp(:,3:end)'; + end + + if (nargin<3) || isempty(freq) + if strcmpi(SignalType,'periodic') + warning 'ReadUI: periodic signal type not supported by FFT' + end + [UI.FD{n}.f,UI.FD{n}.val] = FFT_time2freq( t,val ); + else + UI.FD{n}.f = freq; + if strcmpi(AR_order,'auto') + AR_order = 2; + EC = -1; + while 1 + [val_ar t_ar UI.FD{n}.val EC] = AR_estimate( t, val, freq, AR_order); + if (EC==11) + AR_order = AR_order*2; + else + break; + end + end + if (EC~=0) + warning('CSXCAD:ReadUI','AR estimation failed, skipping...') + UI.FD{n}.val = DFT_time2freq( t, val, freq, SignalType ); + end + elseif (AR_order<=0) + UI.FD{n}.val = DFT_time2freq( t, val, freq, SignalType ); + else + [val_ar t_ar UI.FD{n}.val EC] = AR_estimate( t, val, freq, AR_order); + if (EC~=0) + warning('CSXCAD:ReadUI','AR estimation failed, skipping...') + UI.FD{n}.val = DFT_time2freq( t, val, freq, SignalType ); + end + end + end +end diff --git a/openEMS/matlab/ResultsQueue.m b/openEMS/matlab/ResultsQueue.m new file mode 100644 index 0000000..cc9f745 --- /dev/null +++ b/openEMS/matlab/ResultsQueue.m @@ -0,0 +1,24 @@ +function [varargout] = ResultsQueue(queue, n) +% function [varargout] = ResultsQueue(queue, n) +% +% Use this function to retrieve the results from a finished queue. +% +% For more details see: InitQueue +% +% See also: InitQueue, FinishQueue, Add2Queue, RunOpenEMS +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +if n>numel(queue.jobs) + error 'ResultsQueue:job is missing' +end + +if (nargout>numel(queue.jobs{n}.outargs)) + error 'not enough job output arguments' +end + +for k=1:numel(queue.jobs{n}.outargs) + varargout{k} = queue.jobs{n}.outargs{k}; +end diff --git a/openEMS/matlab/RunOpenEMS.m b/openEMS/matlab/RunOpenEMS.m new file mode 100644 index 0000000..3894adc --- /dev/null +++ b/openEMS/matlab/RunOpenEMS.m @@ -0,0 +1,186 @@ +function RunOpenEMS(Sim_Path, Sim_File, opts, Settings) +% function RunOpenEMS(Sim_Path, Sim_File, ) +% +% Run an openEMS simulation. +% +% arguments: +% Sim_Path: specifiy the simulation folder (folder must exist!) +% Sim_File: xml-filename to simulate, created by WriteOpenEMS +% +% optional arguments +% +% opts: list of openEMS options +% possible options: +% --disable-dumps Disable all field dumps for faster simulation +% --debug-material Dump material distribution to a vtk file for debugging +% --debug-PEC Dump metal distribution to a vtk file for debugging +% --debug-operator Dump operator to vtk file for debugging +% --debug-boxes Dump e.g. probe boxes to vtk file for debugging +% --debug-CSX Write CSX geometry file to debugCSX.xml +% --engine= Choose engine type +% --engine=fastest fastest available engine (default) +% --engine=basic basic FDTD engine +% --engine=sse engine using sse vector extensions +% --engine=sse-compressed engine using compressed operator + sse vector extensions +% --engine=MPI engine using compressed operator + sse vector extensions + MPI parallel processing +% --engine=multithreaded engine using compressed operator + sse vector extensions + MPI + multithreading +% --numThreads= Force use n threads for multithreaded engine +% --no-simulation only run preprocessing; do not simulate +% --dump-statistics dump simulation statistics to 'openEMS_run_stats.txt' and 'openEMS_stats.txt' +% +% Additional global arguments +% --showProbeDiscretization Show probe discretization information +% --nativeFieldDumps Dump all fields using the native field components +% -v,-vv,-vvv Set debug level: 1 to 3 +% +% +% settings: list of Matlab settings +% possible settings: +% Settings.LogFile = 'openEMS.log' +% Settings.Silent = 0 +% +% additional remote simulation settings +% Note: ssh only on unix with working ssh client or windows with putty client +% openEMS Linux server or Windows with cygwin necessary +% Settings.SSH.host = '' +% Settings.SSH.bin = '/openEMS.sh' +% ssh optional: +% Settings.SSH.host_list = {'list','of','hosts'}; %searches for a free host +% %on Windows needed additionally +% Settings.SSH.Putty.Path = '\putty'; +% Settings.SSH.Putty.Key = '\putty_private_key.ppk'; +% +% MPI settings: +% Settings.MPI.xxx --> help RunOpenEMS_MPI +% +% +% example: +% %create CSX and FDTD +% WriteOpenEMS('/tmp/path_to_run_in/myfile.xml', FDTD, CSX) +% RunOpenEMS('/tmp/path_to_run_in','myfile.xml','-v') +% +% See also WriteOpenEMS FindFreeSSH InitCSX InitFDTD RunOpenEMS_MPI +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +if nargin < 2 + error 'specify the Sim_Path and Sim_file to simulate' +end + +if nargin < 3 + opts = ''; +end + +if (nargin<4) + Settings = []; +end + +if (isfield(Settings,'MPI') && isunix) + if (Settings.MPI.NrProc>1) + RunOpenEMS_MPI(Sim_Path, Sim_File, opts, Settings); + return; + end +end + +ssh_command = 'ssh'; +scp_command = 'scp'; +scp_options = ''; +ssh_options = ''; + +enable_ssh = 0; +enable_ssh = isfield(Settings,'SSH') && isunix; + +if ~isunix + enable_ssh = isfield(Settings,'SSH') && isfield(Settings.SSH,'Putty'); + if (enable_ssh) + ssh_command = [Settings.SSH.Putty.Path '/plink ']; + ssh_options = [ssh_options ' -i ' Settings.SSH.Putty.Key]; + + scp_command = [Settings.SSH.Putty.Path '/pscp ']; + scp_options = [scp_options ' -i ' Settings.SSH.Putty.Key]; + end +end + +savePath = pwd; +cd(Sim_Path); + +if (enable_ssh) + scp_options = [scp_options ' -C']; + ssh_options = [ssh_options ' -x -C']; + + % ssh options: no X forwarding; no password prompt (use pub keys!); no host checking + if (isunix) + ssh_options = [ssh_options ' -o "PasswordAuthentication no" -o "StrictHostKeyChecking no"']; + scp_options = [scp_options ' -o "PasswordAuthentication no" -o "StrictHostKeyChecking no"']; + end + + if isfield(Settings.SSH,'host_list') + host = FindFreeSSH(Settings.SSH.host_list, Settings); + if ~isempty(host) + Settings.SSH.host = host; + else + error('openEMS:RunOpenEMS', 'unable to find host, abort openEMS'); + end + end + + % create a tmp working dir + [status, result] = system([ssh_command ' ' ssh_options ' ' Settings.SSH.host ' "mktemp -d /tmp/openEMS_XXXXXXXXXXXX"']); + if (status~=0) + disp(result); + error('openEMS:RunOpenEMS','mktemp failed to create tmp directory!'); + end + ssh_work_path = strtrim(result); %remove tailing \n + + disp(['Running remote openEMS on ' Settings.SSH.host ' at working dir: ' ssh_work_path]); + + %copy openEMS all simulation files to the ssh host + [stat, res] = system([scp_command ' ' scp_options ' * ' Settings.SSH.host ':' ssh_work_path '/']); + if (stat~=0) + disp(res); + error('openEMS:RunOpenEMS','scp failed!'); + end + + %run openEMS (with log file if requested) + if isfield(Settings,'LogFile') && isunix + append_unix = [' 2>&1 | tee ' Settings.LogFile]; + else + append_unix = []; + end + status = system([ssh_command ' ' ssh_options ' ' Settings.SSH.host ' "cd ' ssh_work_path ' && ' Settings.SSH.bin ' ' Sim_File ' ' opts '"' append_unix]); + if (status~=0) + disp(result); + error('openEMS:RunOpenEMS','ssh openEMS failed!'); + end + + disp( 'Remote simulation done... copying back results and cleaning up...' ); + + %copy back all results + [stat, res] = system([scp_command ' -r ' scp_options ' ' Settings.SSH.host ':' ssh_work_path '/* ' pwd '/']); + if (stat~=0); + disp(res); + error('openEMS:RunOpenEMS','scp failed!'); + end + + %cleanup + [stat, res] = system([ssh_command ' ' ssh_options ' ' Settings.SSH.host ' rm -r ' ssh_work_path]); + if (stat~=0); + disp(res); + warning('openEMS:RunOpenEMS','remote cleanup failed!'); + end +else + args = [Sim_File ' ' opts]; + if isfield(Settings,'LogFile') && isfield(Settings,'Silent') + invoke_openEMS(args,Settings.LogFile,Settings.Silent); + elseif isfield(Settings,'LogFile') + invoke_openEMS(args,Settings.LogFile); + elseif isfield(Settings,'Silent') + invoke_openEMS(args,[],Settings.Silent); + else + invoke_openEMS(args); + end +end + +cd(savePath); +return diff --git a/openEMS/matlab/RunOpenEMS_MPI.m b/openEMS/matlab/RunOpenEMS_MPI.m new file mode 100644 index 0000000..779b038 --- /dev/null +++ b/openEMS/matlab/RunOpenEMS_MPI.m @@ -0,0 +1,125 @@ +function RunOpenEMS_MPI(Sim_Path, Sim_File, opts, Settings) +% function RunOpenEMS_MPI(Sim_Path, Sim_File, NrProc, opts, Settings) +% +% Run an openEMS simulation with MPI support +% +% % mpi binary path on all nodes needed +% Settings.MPI.Binary = '/opt/openEMS/openEMS'; +% % number of processes to run +% Settings.MPI.NrProc = 3; +% % define the mpi hosts : +% Settings.MPI.Hosts = {'host1','host2','host3'}; +% +% RunOpenEMS(Sim_Path, Sim_File, NrProc, opts, Settings) +% +% See also SetupMPI, WriteOpenEMS, RunOpenEMS +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +if (isunix ~= 1) + error 'MPI version of openEMS currently only available using Linux' +end + +if nargin < 4 + error 'missing arguments: specify the Sim_Path, Sim_file, opts and Settings...' +end + +NrProc = Settings.MPI.NrProc; + +if (NrProc<2) + error('openEMS:RunOpenEMS_MPI','MPI number of processes to small...'); +end + +if ~isfield(Settings,'MPI') + error('openEMS:RunOpenEMS_MPI','MPI settings not found...'); +end + +savePath = pwd; +cd(Sim_Path); + +scp_options = '-C -o "PasswordAuthentication no" -o "StrictHostKeyChecking no"'; +ssh_options = [scp_options ' -x']; + +if isfield(Settings.MPI,'Hosts') + Remote_Nodes = Settings.MPI.Hosts; + HostList = ''; + for n=1:numel(Remote_Nodes) + remote_name = Remote_Nodes{n}; + + if (n==1) + [status, result] = unix(['ssh ' ssh_options ' ' remote_name ' "mktemp -d /tmp/openEMS_MPI_XXXXXXXXXXXX"']); + if (status~=0) + disp(result); + error('openEMS:RunOpenEMS','mktemp failed to create tmp directory!'); + end + work_path = strtrim(result); %remove tailing \n + HostList = remote_name; + else + [status, result] = unix(['ssh ' ssh_options ' ' remote_name ' "mkdir ' work_path '"']); + if (status~=0) + disp(result); + error('openEMS:RunOpenEMS',['mkdir failed to create tmp directory on remote ' remote_name ' !']); + end + HostList = [HostList ',' remote_name]; + end + + [stat, res] = unix(['scp ' scp_options ' * ' remote_name ':' work_path '/']); + if (stat~=0) + disp(res); + error('openEMS:RunOpenEMS',['scp to remote ' remote_name ' failed!']); + end + end +end + + +%run openEMS (with log file if requested) +if isfield(Settings,'LogFile') + append_unix = [' 2>&1 | tee ' Settings.LogFile]; +else + append_unix = []; +end + +if ~isfield(Settings.MPI,'GlobalArgs') + Settings.MPI.GlobalArgs = ''; +end + +if isfield(Settings.MPI,'Hosts') + disp(['Running remote openEMS_MPI in working dir: ' work_path]); + [status] = system(['mpiexec ' Settings.MPI.GlobalArgs ' -host ' HostList ' -n ' int2str(NrProc) ' -wdir ' work_path ' ' Settings.MPI.Binary ' ' Sim_File ' ' opts ' ' append_unix]); +else + disp('Running local openEMS_MPI'); + [status] = system(['mpiexec ' Settings.MPI.GlobalArgs ' -n ' int2str(NrProc) ' ' Settings.MPI.Binary ' ' Sim_File ' ' opts ' ' append_unix]); +end + +if (status~=0) + error('openEMS:RunOpenEMS','mpirun openEMS failed!'); +end + +if isfield(Settings.MPI,'Hosts') + disp( 'Remote simulation done... copying back results and cleaning up...' ); + + if (strncmp(work_path,'/tmp/',5)~=1) % savety precaution... + error('openEMS:RunOpenEMS','working path invalid for deletion'); + end + + for n=1:numel(Remote_Nodes) + remote_name = Remote_Nodes{n}; + disp(['Copy data from remote node: ' remote_name]); + [stat, res] = unix(['scp -r ' scp_options ' ' remote_name ':' work_path '/* ''' pwd '''/']); + if (stat~=0); + disp(res); + error('openEMS:RunOpenEMS','remote scp failed!'); + end + + %cleanup + [stat, res] = unix(['ssh ' ssh_options ' ' remote_name ' rm -r ' work_path]); + if (stat~=0); + disp(res); + warning('openEMS:RunOpenEMS','remote cleanup failed!'); + end + end +end + +cd(savePath); diff --git a/openEMS/matlab/RunOpenEMS_Parallel.m b/openEMS/matlab/RunOpenEMS_Parallel.m new file mode 100644 index 0000000..cd5d4bd --- /dev/null +++ b/openEMS/matlab/RunOpenEMS_Parallel.m @@ -0,0 +1,92 @@ +function [stdout, stderr] = RunOpenEMS_Parallel(Sim_Paths, Sim_Files, opts, Settings, varargin) +% function [stdout, stderr] = RunOpenEMS_Parallel(Sim_Paths, Sim_Files, opts, Settings, varargin) +% +% Run multiple openEMS simulations in parallel, distributed on multiple +% machines using a ssh host_list! (currently on Linux only) +% +% This function relies on InitQueue etc. +% +% input: +% Sim_Paths: cell array of pathes to simulate by RunOpenEMS +% Sim_Files: filename or cell array of filenames to simulate +% opts: openEMS options. sa RunOpenEMS +% Settings: use the settings to define multiple host for simulation +% e.g.: Settings.SSH.bin ='/openEMS.sh'; +% Settings.SSH.host_list = {'list','of','hosts'}; +% +% Note: If no SSH host_list is defined, this function will skip the +% parallel run and switch back to a default RunOpenEMS! +% +% See also RunOpenEMS, FindFreeSSH, InitQueue +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig 2011 + +pause_queue = 5; %pause between consecutive runs (needed for FindFreeSSH) + +skip_parallel = 0; + +% currently only supporting linux, run conventional RunOpenEMS +if ~isunix + warning 'your OS is not supported (Unix only), running default RunOpenEMS'; + skip_parallel = 1; +end + +% in case only one path is given, run conventional RunOpenEMS +if ischar(Sim_Paths) + warning 'only a single path given, running default RunOpenEMS' + skip_parallel = 1; +end + +% in case SSH.host_list is not defined, run conventional RunOpenEMS +if ~isfield(Settings,'SSH') + warning 'SSH options missing, running default RunOpenEMS' + skip_parallel = 1; +elseif ~isfield(Settings.SSH,'host_list') + warning 'SSH.host_list option missing, running default RunOpenEMS' + skip_parallel = 1; +end + +if (skip_parallel) + for n=1:numel(Sim_Paths) + if iscell(Sim_Files) + Sim_File = Sim_Files{n}; + else + Sim_File = Sim_Files; + end + RunOpenEMS(Sim_Paths{n}, Sim_Files, opts, Settings) + end + stdout = []; + stderr = []; + return +end + +if ~iscell(Sim_Paths) + error('RunOpenEMS_Parallel:needs a cell array of Sim_Paths to simulate'); +end + +% get the path to this file +[dir] = fileparts( mfilename('fullpath') ); + +queue = InitQueue('DependPath',{dir}, varargin{:}); + +% spawn multiple simulations +for n=1:numel(Sim_Paths) + if iscell(Sim_Files) + Sim_File = Sim_Files{n}; + else + Sim_File = Sim_Files; + end + + queue = Add2Queue(queue,'RunOpenEMS',{Sim_Paths{n}, Sim_File, opts, Settings}); + disp(['openEMS simulation #' int2str(n) ' in directory: ' Sim_Paths{n} ' started!']); + pause(pause_queue); +end + +[queue] = FinishQueue(queue); + +for n=1:numel(Sim_Paths) + stdout{n} = queue.jobs{n}.stdout; + stderr{n} = queue.jobs{n}.stderr; +end diff --git a/openEMS/matlab/SetBoundaryCond.m b/openEMS/matlab/SetBoundaryCond.m new file mode 100644 index 0000000..fbfbd4c --- /dev/null +++ b/openEMS/matlab/SetBoundaryCond.m @@ -0,0 +1,68 @@ +function FDTD = SetBoundaryCond(FDTD, BC, varargin) +% FDTD = SetBoundaryCond(FDTD, BC, varargin) +% +% BC = [xmin xmax ymin ymax zmin zmax]; +% or BC = {xmin xmax ymin ymax zmin zmax}; +% ?min/?max: +% 0 = PEC or 'PEC' +% 1 = PMC or 'PMC' +% 2 = MUR-ABC or 'MUR' +% 3 = PML-ABC or 'PML_x' with pml size x => 4..50 +% +% example: +% BC = [ 1 1 0 0 2 3 ] %using numbers or +% BC = {'PMC' 'PMC' 'PEC' 'PEC' 'MUR' 'PML_8'} %usign equivalent strings +% +% mur-abc definitions +% define a phase-velocity to be used by the mur-abc +% useful e.g. for dispersive waveguides +% FDTD = SetBoundaryCond(FDTD,BC,'MUR_PhaseVelocity',299792457.93272); +% +% +% pml definitions +% arguments: 'PML_Grading','gradFunction' +% Define the pml grading grading function. +% Predefined variables in this grading function are: +% D = depth in the pml in meter +% dl = mesh delta inside the pml in meter +% W = width (length) of the pml in meter +% N = number of cells for the pml +% Z = wave impedance at the current depth and position +% +% example: +% FDTD = SetBoundaryCond(FDTD,BC); +% or +% FDTD = SetBoundaryCond(FDTD,BC,'PML_Grading','-log(1e-6)*log(2.5)/(2*dl*pow(2.5,W/dl)-1) * pow(2.5, D/dl) / Z'); +% +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +if (numel(BC)~=6) + error('openEMS:SetBoundaryCond','wrong number of boundary conditions'); +end + +if isnumeric(BC) + FDTD.BoundaryCond.ATTRIBUTE.xmin=BC(1); + FDTD.BoundaryCond.ATTRIBUTE.xmax=BC(2); + FDTD.BoundaryCond.ATTRIBUTE.ymin=BC(3); + FDTD.BoundaryCond.ATTRIBUTE.ymax=BC(4); + FDTD.BoundaryCond.ATTRIBUTE.zmin=BC(5); + FDTD.BoundaryCond.ATTRIBUTE.zmax=BC(6); +elseif iscell(BC) + FDTD.BoundaryCond.ATTRIBUTE.xmin=BC{1}; + FDTD.BoundaryCond.ATTRIBUTE.xmax=BC{2}; + FDTD.BoundaryCond.ATTRIBUTE.ymin=BC{3}; + FDTD.BoundaryCond.ATTRIBUTE.ymax=BC{4}; + FDTD.BoundaryCond.ATTRIBUTE.zmin=BC{5}; + FDTD.BoundaryCond.ATTRIBUTE.zmax=BC{6}; +else + error('openEMS:SetBoundaryCond','unknown boundary condition type'); +end + + +for n=1:(nargin-2)/2 + FDTD.BoundaryCond.ATTRIBUTE.(varargin{2*n-1}) = varargin{2*n}; +end + \ No newline at end of file diff --git a/openEMS/matlab/SetCustomExcite.m b/openEMS/matlab/SetCustomExcite.m new file mode 100644 index 0000000..6f87a49 --- /dev/null +++ b/openEMS/matlab/SetCustomExcite.m @@ -0,0 +1,21 @@ +function FDTD = SetCustomExcite(FDTD,f0,funcStr) +% function FDTD = SetCustomExcite(FDTD,f0,funcStr) +% +% f0 : nyquist rate +% funcStr : string desribing the excitation function e(t) +% +% see also SetSinusExcite SetGaussExcite +% +% e.g for a ramped sinus excite... +% T = 1/f0; +% FDTD = SetCustomExcite(FDTD,1e9,.. +% [ '(1-exp(-1*(t/' num2str(T) ')^2) ) * sin(2*pi*' num2str(f0) '*t)' ]); +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +FDTD.Excitation.ATTRIBUTE.Type=10; +FDTD.Excitation.ATTRIBUTE.f0=f0; +FDTD.Excitation.ATTRIBUTE.Function=funcStr; +FDTD.ATTRIBUTE.f_max=f0; diff --git a/openEMS/matlab/SetDiracExcite.m b/openEMS/matlab/SetDiracExcite.m new file mode 100644 index 0000000..18a342d --- /dev/null +++ b/openEMS/matlab/SetDiracExcite.m @@ -0,0 +1,3 @@ +function FDTD = SetDiracExcite(FDTD) + +FDTD.Excitation.ATTRIBUTE.Type=2; diff --git a/openEMS/matlab/SetGaussExcite.m b/openEMS/matlab/SetGaussExcite.m new file mode 100644 index 0000000..be650ba --- /dev/null +++ b/openEMS/matlab/SetGaussExcite.m @@ -0,0 +1,18 @@ +function FDTD = SetGaussExcite(FDTD,f0,fc) +% function FDTD = SetGaussExcite(FDTD,f0,fc); +% +% f0 : center frequency +% fc : 20dB cutoff frequency --> bandwidth is 2*fc +% +% see also SetSinusExcite SetCustomExcite +% +% e.g FDTD = SetGaussExcite(FDTD,1e9,1e8); +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +FDTD.Excitation.ATTRIBUTE.Type=0; +FDTD.Excitation.ATTRIBUTE.f0=f0; +FDTD.Excitation.ATTRIBUTE.fc=fc; +FDTD.ATTRIBUTE.f_max=f0+fc; diff --git a/openEMS/matlab/SetSinusExcite.m b/openEMS/matlab/SetSinusExcite.m new file mode 100644 index 0000000..22aadde --- /dev/null +++ b/openEMS/matlab/SetSinusExcite.m @@ -0,0 +1,14 @@ +function FDTD = SetSinusExcite(FDTD,f0) +% function FDTD = SetSinusExcite(FDTD,f0) +% +% see also SetGaussExcite SetCustomExcite +% +% e.g FDTD = SetSinusExcite(FDTD,1e9); +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +FDTD.Excitation.ATTRIBUTE.Type=1; +FDTD.Excitation.ATTRIBUTE.f0=f0; +FDTD.ATTRIBUTE.f_max=f0; diff --git a/openEMS/matlab/SetStepExcite.m b/openEMS/matlab/SetStepExcite.m new file mode 100644 index 0000000..ff87e4f --- /dev/null +++ b/openEMS/matlab/SetStepExcite.m @@ -0,0 +1,3 @@ +function FDTD = SetStepExcite(FDTD) + +FDTD.Excitation.ATTRIBUTE.Type=3; diff --git a/openEMS/matlab/SetupMPI.m b/openEMS/matlab/SetupMPI.m new file mode 100644 index 0000000..51d6f65 --- /dev/null +++ b/openEMS/matlab/SetupMPI.m @@ -0,0 +1,17 @@ +function FDTD = SetupMPI(FDTD, varargin) +% function FDTD = SetupMPI(FDTD, varargin); +% +% % example, split the FDTD mesh in 2 equal parts in x-direction +% % and split the FDTD mesh in 3 parts in z-direction, split at z=-500 and z=500 +% % this will need a Settings.MPI.NrProc of 2*3=6 +% FDTD = SetupMPI(FDTD,'SplitN_X',2 ,'SplitPos_Z', '-500,500'); +% +% See also RunOpenEMS_MPI +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +for n=1:(nargin-1)/2 + FDTD.MPI.ATTRIBUTE.(varargin{2*n-1})=varargin{2*n}; +end diff --git a/openEMS/matlab/Tutorials/Bent_Patch_Antenna.m b/openEMS/matlab/Tutorials/Bent_Patch_Antenna.m new file mode 100644 index 0000000..33d5cac --- /dev/null +++ b/openEMS/matlab/Tutorials/Bent_Patch_Antenna.m @@ -0,0 +1,197 @@ +% +% Tutorials / bent patch antenna +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_Bent_Patch_Antenna +% +% Tested with +% - Matlab 2011a / Octave 4.0 +% - openEMS v0.0.33 +% +% (C) 2013-2015 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation +physical_constants; +unit = 1e-3; % all length in mm + +% 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 = InitFDTD('CoordSystem', 1); % init a cylindrical FDTD +f0 = 2e9; % center frequency +fc = 1e9; % 20 dB corner frequency +FDTD = SetGaussExcite( FDTD, f0, fc ); +BC = {'MUR' 'MUR' 'MUR' 'MUR' 'MUR' 'MUR'}; % boundary conditions +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +% init a cylindrical mesh +CSX = InitCSX('CoordSystem',1); + +% 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 +CSX = AddMetal( CSX, '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(CSX,'patch',10,start,stop); % add a box-primitive to the metal property 'patch' + +%% create substrate +CSX = AddMaterial( CSX, 'substrate' ); +CSX = SetMaterialProperty( CSX, '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]; +CSX = AddBox( CSX, 'substrate', 0, start, stop); + +%% save current density oon the patch +CSX = AddDump(CSX, 'Jt_patch','DumpType',3,'FileType',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]; +CSX = AddBox( CSX, 'Jt_patch', 0, start, stop ); + +%% create ground (not really necessary, only for esthetic reasons) +CSX = AddMetal( CSX, '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]; +CSX = AddBox(CSX,'gnd',10,start,stop); + +%% apply the excitation & resist as a current source +start = [patch.radius feed_angle 0]; +stop = [patch.radius+substrate.thickness feed_angle 0]; +[CSX port] = AddLumpedPort(CSX, 50 ,1 ,feed.R, start, stop, [1 0 0], true); + + +%% finalize the mesh +% detect all edges +mesh = DetectEdges(CSX); + +% add the simulation domain size +mesh.r = [mesh.r patch.radius+[-20 SimBox.rad]]; +mesh.a = [mesh.a -0.75*pi 0.75*pi]; +mesh.z = [mesh.z -SimBox.height/2 SimBox.height/2]; + +% add some lines for the substrate +mesh.r = [mesh.r patch.radius+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 = SmoothMesh(mesh, [max_res max_ang max_res], 1.4); + +disp(['Num of cells: ' num2str(numel(mesh.r)*numel(mesh.a)*numel(mesh.z))]); +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% create nf2ff, keep some distance to the boundary conditions, e.g. 8 cells pml +start = [mesh.r(4) mesh.a(8) mesh.z(8)]; +stop = [mesh.r(end-9) mesh.a(end-9) mesh.z(end-9)]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop, 'Directions',[1 1 1 1 1 1]); + +%% prepare simulation folder & run +Sim_Path = ['tmp_' mfilename]; +Sim_CSX = [mfilename '.xml']; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +% write openEMS compatible xml-file +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + +% show the structure +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + +% run openEMS +RunOpenEMS( Sim_Path, Sim_CSX); + +%% postprocessing & do the plots +freq = linspace( max([1e9,f0-fc]), f0+fc, 501 ); +port = calcPort(port, Sim_Path, freq); + +Zin = port.uf.tot ./ port.if.tot; +s11 = port.uf.ref ./ port.uf.inc; +P_in = 0.5*real(port.uf.tot .* conj(port.if.tot)); % antenna feed power + +% plot feed point impedance +figure +plot( freq/1e6, real(Zin), 'k-', 'Linewidth', 2 ); +hold on +grid on +plot( freq/1e6, imag(Zin), 'r--', 'Linewidth', 2 ); +title( 'feed point impedance' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'impedance Z_{in} / Ohm' ); +legend( 'real', 'imag' ); + +% plot reflection coefficient S11 +figure +plot( freq/1e6, 20*log10(abs(s11)), 'k-', 'Linewidth', 2 ); +grid on +title( 'reflection coefficient S_{11}' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'reflection coefficient |S_{11}|' ); + +drawnow + +%find resonance frequncy from s11 +f_res_ind = find(s11==min(s11)); +f_res = freq(f_res_ind); + +%% +disp('dumping resonant current distribution to vtk file, use Paraview to visualize'); +ConvertHDF5_VTK([Sim_Path '/Jt_patch.h5'],[Sim_Path '/Jf_patch'],'Frequency',f_res,'FieldName','J-Field'); + +%% NFFF contour plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% calculate the far field at phi=0 degree +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_res, [-180:2:180]*pi/180, 0,'Center',[patch.radius+substrate.thickness 0 0]*unit, 'Outfile','pattern_phi_0.h5'); +% normalized directivity as polar plot +figure +polarFF(nf2ff,'xaxis','theta','param',1,'normalize',1) + +% calculate the far field at phi=0 degree +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_res, pi/2, (-180:2:180)*pi/180,'Center',[patch.radius+substrate.thickness 0 0]*unit, 'Outfile','pattern_theta_90.h5'); +% normalized directivity as polar plot +figure +polarFF(nf2ff,'xaxis','phi','param',1,'normalize',1) + +% display power and directivity +disp( ['radiated power: Prad = ' num2str(nf2ff.Prad) ' Watt']); +disp( ['directivity: Dmax = ' num2str(nf2ff.Dmax) ' (' num2str(10*log10(nf2ff.Dmax)) ' dBi)'] ); +disp( ['efficiency: nu_rad = ' num2str(100*nf2ff.Prad./real(P_in(f_res_ind))) ' %']); + +drawnow + +%% +disp( 'calculating 3D far field pattern and dumping to vtk (use Paraview to visualize)...' ); +thetaRange = (0:2:180); +phiRange = (0:2:360) - 180; +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_res, thetaRange*pi/180, phiRange*pi/180,'Verbose',1,'Outfile','3D_Pattern.h5','Center',[patch.radius+substrate.thickness 0 0]*unit); + +figure +plotFF3D(nf2ff,'logscale',-20); + diff --git a/openEMS/matlab/Tutorials/CRLH_Extraction.m b/openEMS/matlab/Tutorials/CRLH_Extraction.m new file mode 100644 index 0000000..e0bc361 --- /dev/null +++ b/openEMS/matlab/Tutorials/CRLH_Extraction.m @@ -0,0 +1,155 @@ +% +% Tutorials / CRLH_Extraction +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_CRLH_Extraction +% +% Tested with +% - Matlab 2011a / Octave 4.0 +% - openEMS v0.0.33 +% +% (C) 2011-2015 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants; +unit = 1e-6; % specify everything in um + +feed_length = 30000; + +substrate_thickness = [1524 101 254]; +substrate_epsr = [3.48 3.48 3.48]; + +CRLH.LL = 14e3; %CRLH totel (line) length +CRLH.LW = 4e3; %CRLH unit cell width (without the stubs) +CRLH.GLB = 1950; %CRLH gap width bottom layer +CRLH.GLT = 4700; %CRLH gap width top layer +CRLH.SL = 7800; %CRLH stub length (bottom layer, both sides) +CRLH.SW = 1000; %CRLH stub width (bottom layer, both sides) +CRLH.VR = 250; %CRLH via hole radius (stub -> ground) +CRLH.TopSig = sum(substrate_thickness); %top layer height +CRLH.BottomSig = CRLH.TopSig - substrate_thickness(end); %bottom layer height + +% frequency range of interest +f_start = 0.8e9; +f_stop = 6e9; + +%% setup FDTD parameters & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD(); +FDTD = SetGaussExcite( FDTD, (f_start+f_stop)/2, (f_stop-f_start)/2 ); +BC = {'PML_8' 'PML_8' 'MUR' 'MUR' 'PEC' 'PML_8'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% Setup a basic mesh and create the CRLH unit cell +CSX = InitCSX(); +resolution = c0/(f_stop*sqrt(max(substrate_epsr)))/unit /30; % resolution of lambda/30 + +mesh.x = [-feed_length-CRLH.LL/2 0 feed_length+CRLH.LL/2]; +mesh.y = [-30000 0 30000]; +substratelines = cumsum(substrate_thickness); +mesh.z = [0 cumsum(substrate_thickness) linspace(substratelines(end-1),substratelines(end),4) 20000]; + +% create the CRLH unit cell (will define additional fixed mesh lines) +[CSX mesh] = CreateCRLH(CSX, mesh, CRLH, resolution/4); + +% Smooth the given mesh +mesh = SmoothMesh(mesh, resolution, 1.5, 'algorithm',[1 3]); +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% Setup the substrate layer +substratelines = [0 substratelines]; +for n=1:numel(substrate_thickness) + CSX = AddMaterial( CSX, ['substrate' int2str(n)] ); + CSX = SetMaterialProperty( CSX, ['substrate' int2str(n)], 'Epsilon', substrate_epsr(n) ); + start = [mesh.x(1), mesh.y(1), substratelines(n)]; + stop = [mesh.x(end), mesh.y(end), substratelines(n+1)]; + CSX = AddBox( CSX, ['substrate' int2str(n)], 0, start, stop ); +end + +%% add the feeding MSL ports +CSX = AddMetal( CSX, 'PEC' ); +portstart = [ mesh.x(1) , -CRLH.LW/2, substratelines(end)]; +portstop = [ -CRLH.LL/2, CRLH.LW/2, 0]; +[CSX,port{1}] = AddMSLPort( CSX, 999, 1, 'PEC', portstart, portstop, 0, [0 0 -1], 'ExcitePort', true, 'FeedShift', 10*resolution(1), 'MeasPlaneShift', feed_length/2); + +portstart = [ mesh.x(end) , -CRLH.LW/2, substratelines(end)]; +portstop = [ +CRLH.LL/2, CRLH.LW/2, 0]; +[CSX,port{2}] = AddMSLPort( CSX, 999, 2, 'PEC', portstart, portstop, 0, [0 0 -1], 'MeasPlaneShift', feed_length/2 ); + +%% write/show/run the openEMS compatible xml-file +Sim_Path = 'tmp'; +Sim_CSX = 'CRLH.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +RunOpenEMS( Sim_Path, Sim_CSX ); + +%% post-processing +close all +f = linspace( f_start, f_stop, 1601 ); +port = calcPort( port, Sim_Path, f, 'RefPlaneShift', feed_length); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; + +plot(f/1e9,20*log10(abs(s11)),'k-','LineWidth',2); +hold on; +grid on; +plot(f/1e9,20*log10(abs(s21)),'r--','LineWidth',2); +l = legend('S_{11}','S_{21}','Location','Best'); +set(l,'FontSize',12); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (GHz) \rightarrow','FontSize',12); +ylim([-40 2]); + +%% extract parameter +A = ((1+s11).*(1-s11) + s21.*s21)./(2*s21); +C = ((1-s11).*(1-s11) - s21.*s21)./(2*s21) ./ port{2}.ZL; + +Y = C; +Z = 2*(A-1)./C; + +iZ = imag(Z); +iY = imag(Y); + +fse = interp1(iZ,f,0); +fsh = interp1(iY,f,0); + +df = f(2)-f(1); +fse_idx = find(f>fse,1); +fsh_idx = find(f>fsh,1); + +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; + +disp([' Series tank: CL = ' num2str(CL*1e12,3) 'pF; LR = ' num2str(LR*1e9,3) 'nH -> f_se = ' num2str(fse*1e-9,3) 'GHz ']); +disp([' Shunt tank: CR = ' num2str(CR*1e12,3) 'pF; LL = ' num2str(LL*1e9,3) 'nH -> f_sh = ' num2str(fsh*1e-9,3) 'GHz ']); + +%% 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(acos(1-(w.^2-wse^2).*(w.^2-wsh^2)./(2*w.^2/CR/LR))); + +%% +figure +beta = -angle(s21)/CRLH.LL/unit; +plot(abs(beta)*CRLH.LL*unit/pi,f*1e-9,'k-','LineWidth',2) +grid on; +hold on; +plot(beta_calc/pi,f*1e-9,'c--','LineWidth',2) +plot(real(port{2}.beta)*CRLH.LL*unit/pi,f*1e-9,'g-','LineWidth',2) +ylim([1 6]) +xlabel('|\beta| p / \pi \rightarrow','FontSize',12) +ylabel('frequency (GHz) \rightarrow','FontSize',12) +l = legend('\beta_{CRLH, 1 cell}','\beta_{CRLH, \infty cells}','\beta_{MSL}','Location','East'); +set(l,'FontSize',12); diff --git a/openEMS/matlab/Tutorials/CRLH_LeakyWaveAnt.m b/openEMS/matlab/Tutorials/CRLH_LeakyWaveAnt.m new file mode 100644 index 0000000..a8359b7 --- /dev/null +++ b/openEMS/matlab/Tutorials/CRLH_LeakyWaveAnt.m @@ -0,0 +1,168 @@ +% +% Tutorials / CRLH_LeakyWaveAnt +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_CRLH_Leaky_Wave_Antenna +% +% Tested with +% - Matlab 2011a / Octave 4.0 +% - openEMS v0.0.33 +% +% (C) 2011-2015 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants; +unit = 1e-6; % specify everything in um + +feed_length = 20000; + +substrate_thickness = [1524 101 254]; +substrate_epsr = [3.48 3.48 3.48]; +substrate_tanD = [1 1 1]*1e-3; + +N_Cells = 8; %number of CRLH unit cells + +CRLH.LL = 14e3; %CRLH totel (line) length +CRLH.LW = 4e3; %CRLH unit cell width (without the stubs) +CRLH.GLB = 1950; %CRLH gap width bottom layer +CRLH.GLT = 4700; %CRLH gap width top layer +CRLH.SL = 7800; %CRLH stub length (bottom layer, both sides) +CRLH.SW = 1000; %CRLH stub width (bottom layer, both sides) +CRLH.VR = 250; %CRLH via hole radius (stub -> ground) +CRLH.TopSig = sum(substrate_thickness); %top layer height +CRLH.BottomSig = CRLH.TopSig - substrate_thickness(end); %bottom layer height + +substrate_width = CRLH.LW + 2*CRLH.SL; +Air_Spacer = 30000; + +% frequency range of interest +f_start = 1e9; +f_stop = 6e9; + +% frequencies to calculate the 3D radiation pattern +f_rad = (1.9:0.05:4.2)*1e9; +nf2ff_resolution = c0/max(f_rad)/unit/15; + +%% setup FDTD parameters & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD('EndCriteria', 1e-3); +FDTD = SetGaussExcite( FDTD, (f_start+f_stop)/2, (f_stop-f_start)/2 ); +BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% Setup a basic mesh and create the CRLH unit cell +CSX = InitCSX(); +resolution = c0/(f_stop*sqrt(max(substrate_epsr)))/unit /30; % resolution of lambda/30 + +mesh.x = [-feed_length-(N_Cells*CRLH.LL)/2-Air_Spacer -feed_length-(N_Cells*CRLH.LL)/2 0 feed_length+(N_Cells*CRLH.LL)/2 feed_length+(N_Cells*CRLH.LL)/2+Air_Spacer]; +mesh.y = [-Air_Spacer-substrate_width/2 0 Air_Spacer+substrate_width/2]; +substratelines = cumsum(substrate_thickness); +mesh.z = [-0.5*Air_Spacer 0 cumsum(substrate_thickness) linspace(substratelines(end-1),substratelines(end),4) Air_Spacer]; + +% create the CRLH unit cells (will define additional fixed mesh lines) +pos_x = -(N_Cells*CRLH.LL)/2 + CRLH.LL/2; +for n=1:N_Cells + [CSX mesh] = CreateCRLH(CSX, mesh, CRLH, resolution/4, [pos_x 0 0]); + pos_x = pos_x + CRLH.LL; +end + +% Smooth the given mesh +mesh = SmoothMesh(mesh, resolution, 1.5, 'algorithm',[1 3]); +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% Setup the substrate layer +substratelines = [0 substratelines]; +for n=1:numel(substrate_thickness) + CSX = AddMaterial( CSX, ['substrate' int2str(n)] ); + CSX = SetMaterialProperty( CSX, ['substrate' int2str(n)], 'Epsilon', substrate_epsr(n), 'Kappa', substrate_tanD(n)*substrate_epsr(n)*EPS0*2*pi*3e9 ); + start = [-feed_length-(N_Cells*CRLH.LL)/2, -substrate_width/2, substratelines(n)]; + stop = [+feed_length+(N_Cells*CRLH.LL)/2, substrate_width/2, substratelines(n+1)]; + CSX = AddBox( CSX, ['substrate' int2str(n)], 0, start, stop ); +end + +%% add the feeding MSL ports +%ground plane +CSX = AddMetal( CSX, 'ground' ); +start = [-feed_length-(N_Cells*CRLH.LL)/2, -substrate_width/2, 0]; +stop = [+feed_length+(N_Cells*CRLH.LL)/2, substrate_width/2, 0]; +CSX = AddBox( CSX, 'ground', 0, start, stop ); + +CSX = AddMetal( CSX, 'PEC' ); +portstart = [ -feed_length-(N_Cells*CRLH.LL)/2 , -CRLH.LW/2, substratelines(end)]; +portstop = [ -(N_Cells*CRLH.LL)/2, CRLH.LW/2, 0]; +[CSX,port{1}] = AddMSLPort( CSX, 999, 1, 'PEC', portstart, portstop, 0, [0 0 -1], 'ExcitePort', true, 'MeasPlaneShift', feed_length/2, 'Feed_R', 50); + +portstart = [ feed_length+(N_Cells*CRLH.LL)/2 , -CRLH.LW/2, substratelines(end)]; +portstop = [ +(N_Cells*CRLH.LL)/2, CRLH.LW/2, 0]; +[CSX,port{2}] = AddMSLPort( CSX, 999, 2, 'PEC', portstart, portstop, 0, [0 0 -1], 'MeasPlaneShift', feed_length/2, 'Feed_R', 50 ); + +%% nf2ff calc +start = [mesh.x(1) mesh.y(1) mesh.z(1) ] + 10*resolution; +stop = [mesh.x(end) mesh.y(end) mesh.z(end)] - 10*resolution; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop, 'OptResolution', nf2ff_resolution); + +%% write/show/run the openEMS compatible xml-file +Sim_Path = 'tmp_CRLH_LeakyWave'; +Sim_CSX = 'CRLH.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +RunOpenEMS( Sim_Path, Sim_CSX ); + +%% post-processing +close all +f = linspace( f_start, f_stop, 1601 ); +port = calcPort( port, Sim_Path, f, 'RefPlaneShift', feed_length*unit); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; + +plot(f/1e9,20*log10(abs(s11)),'k-','LineWidth',2); +hold on; +grid on; +plot(f/1e9,20*log10(abs(s21)),'r--','LineWidth',2); +l = legend('S_{11}','S_{21}','Location','Best'); +set(l,'FontSize',12); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (GHz) \rightarrow','FontSize',12); +ylim([-40 2]); + +drawnow + +%% calculate 3D pattern +phi = 0:2:360; +theta = 0:2:180; + +disp( 'calculating 3D far field pattern...' ); +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_rad, theta*pi/180, phi*pi/180, 'Outfile','3D_Pattern.h5', 'Mode', 0,'Verbose',1); + +%% +P_in = interp1(f, port{1}.P_acc, f_rad); + +figure() + +[AX,H1,H2] = plotyy(f_rad/1e9,nf2ff.Dmax',f_rad/1e9,100*nf2ff.Prad'./P_in,'plot'); +grid on +xlabel( 'frequency (GHz)' ); +set(get(AX(1),'Ylabel'),'String','directivity (dBi)') +set(get(AX(2),'Ylabel'),'String','radiation efficiency (%)') +set(H1,'Linewidth',2) +set(H2,'Linewidth',2) +set(H1,'Marker','*') +set(H2,'Marker','s') + +drawnow + +%% +disp( 'dumping 3D far field pattern to vtk, use Paraview to visualize...' ); +for n=1:numel(f_rad) + E_far_normalized_3D = nf2ff.E_norm{n} / max(max(nf2ff.E_norm{n})) * nf2ff.Dmax(n); + DumpFF2VTK( [Sim_Path '/FF_Pattern_' int2str(f_rad(n)/1e6) 'MHz.vtk'],E_far_normalized_3D,theta,phi,'scale',1e-3); +end + diff --git a/openEMS/matlab/Tutorials/Circ_Waveguide.m b/openEMS/matlab/Tutorials/Circ_Waveguide.m new file mode 100644 index 0000000..d61a713 --- /dev/null +++ b/openEMS/matlab/Tutorials/Circ_Waveguide.m @@ -0,0 +1,105 @@ +% +% Tutorials / Circ_Waveguide +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_Circular_Waveguide +% +% Tested with +% - Matlab 2011a / Octave 3.4.3 +% - openEMS v0.0.31 +% +% (C) 2010-2013 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants; +unit = 1e-3; %drawing unit in mm + +% waveguide dimensions +length = 2000; +rad = 350; %waveguide radius in mm + +% frequency range of interest +f_start = 300e6; +f_stop = 500e6; + +mesh_res = [10 2*pi/49.999 10]; %targeted mesh resolution + +%% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD('EndCriteria',1e-4,'CoordSystem',1); +FDTD = SetGaussExcite(FDTD,0.5*(f_start+f_stop),0.5*(f_stop-f_start)); + +% boundary conditions +BC = [0 0 0 0 3 3]; %pml in pos. and neg. z-direction +FDTD = SetBoundaryCond(FDTD,BC); + +%% setup CSXCAD mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX('CoordSystem',1); % init a cylindrical mesh +mesh.r = SmoothMeshLines([0 rad], mesh_res(1)); %mesh in radial direction +mesh.a = SmoothMeshLines([0 2*pi], mesh_res(2)); % mesh in aziumthal dir. +mesh.z = SmoothMeshLines([0 length], mesh_res(3)); +CSX = DefineRectGrid(CSX, unit,mesh); + +%% apply the waveguide port %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start=[mesh.r(1) mesh.a(1) mesh.z(8)]; +stop =[mesh.r(end) mesh.a(end) mesh.z(15)]; +[CSX, port{1}] = AddCircWaveGuidePort( CSX, 0, 1, start, stop, rad*unit, 'TE11', 0, 1); + +start=[mesh.r(1) mesh.a(1) mesh.z(end-13)]; +stop =[mesh.r(end) mesh.a(end) mesh.z(end-14)]; +[CSX, port{2}] = AddCircWaveGuidePort( CSX, 0, 2, start, stop, rad*unit, 'TE11'); + +%% define dump box... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddDump(CSX,'Et','FileType',1,'SubSampling','4,4,4'); +start = [mesh.r(1) mesh.a(1) mesh.z(1)]; +stop = [mesh.r(end) mesh.a(end) mesh.z(end)]; +CSX = AddBox(CSX,'Et',0 , start,stop); + +%% Write openEMS compatoble xml-file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Sim_Path = 'tmp'; +Sim_CSX = 'circ_wg.xml'; + +[status, message, messageid] = rmdir(Sim_Path,'s'); +[status, message, messageid] = mkdir(Sim_Path); + +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + +RunOpenEMS(Sim_Path, Sim_CSX) + +%% postproc %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +freq = linspace(f_start,f_stop,201); +port = calcPort( port, Sim_Path, freq); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; +ZL = port{1}.uf.tot./port{1}.if.tot; + + +%% plot s-parameter %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +figure +plot(freq*1e-6,20*log10(abs(s11)),'k-','Linewidth',2); +xlim([freq(1) freq(end)]*1e-6); +grid on; +hold on; +plot(freq*1e-6,20*log10(abs(s21)),'r--','Linewidth',2); +l = legend('S_{11}','S_{21}','Location','Best'); +set(l,'FontSize',12); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (MHz) \rightarrow','FontSize',12); + +%% compare analytic and numerical wave-impedance %%%%%%%%%%%%%%%%%%%%%%%%%% +figure +plot(freq*1e-6,real(ZL),'Linewidth',2); +hold on; +grid on; +plot(freq*1e-6,imag(ZL),'r--','Linewidth',2); +plot(freq*1e-6,port{1}.ZL,'g-.','Linewidth',2); +ylabel('ZL (\Omega)','FontSize',12); +xlabel('frequency (MHz) \rightarrow','FontSize',12); +xlim([freq(1) freq(end)]*1e-6); +l = legend('\Re(Z_L)','\Im(Z_L)','Z_L analytic','Location','Best'); +set(l,'FontSize',12); + diff --git a/openEMS/matlab/Tutorials/Conical_Horn_Antenna.m b/openEMS/matlab/Tutorials/Conical_Horn_Antenna.m new file mode 100644 index 0000000..f266993 --- /dev/null +++ b/openEMS/matlab/Tutorials/Conical_Horn_Antenna.m @@ -0,0 +1,180 @@ +% +% Tutorials / conical horn antenna +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_Conical_Horn_Antenna +% +% Tested with +% - Matlab 2011a / Octave 4.0 +% - openEMS v0.0.33 +% +% (C) 2011-2015 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation +physical_constants; +unit = 1e-3; % all length in mm + +% horn radius +horn.radius = 20; +% horn length in z-direction +horn.length = 50; + +horn.feed_length = 50; + +horn.thickness = 2; + +% horn opening angle +horn.angle = 20*pi/180; + +% size of the simulation box +SimBox = [100 100 100]*2; + +% frequency range of interest +f_start = 10e9; +f_stop = 20e9; + +% frequency of interest +f0 = 15e9; + +%% setup FDTD parameter & excitation function +FDTD = InitFDTD( 'NrTS', 30000, 'EndCriteria', 1e-4 ); +FDTD = SetGaussExcite(FDTD,0.5*(f_start+f_stop),0.5*(f_stop-f_start)); +BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; % boundary conditions +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +% currently, openEMS cannot automatically generate a mesh +max_res = c0 / (f_stop) / unit / 15; % cell size: lambda/20 +CSX = InitCSX(); + +%create fixed lines for the simulation box, substrate and port +mesh.x = [-SimBox(1)/2 -horn.radius 0 horn.radius SimBox(1)/2]; +mesh.x = SmoothMeshLines( mesh.x, max_res, 1.4); % create a smooth mesh between specified fixed mesh lines + +mesh.y = mesh.x; + +%create fixed lines for the simulation box and given number of lines inside the substrate +mesh.z = [-horn.feed_length 0 SimBox(3) ]; +mesh.z = SmoothMeshLines( mesh.z, max_res, 1.4 ); + +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% create horn +% horn + waveguide, defined by a rotational polygon +CSX = AddMetal(CSX, 'Conical_Horn'); +p(1,1) = horn.radius+horn.thickness; % x-coord point 1 +p(2,1) = -horn.feed_length; % z-coord point 1 +p(1,end+1) = horn.radius+horn.thickness; % x-coord point 1 +p(2,end) = 0; % z-coord point 1 +p(1,end+1) = horn.radius+horn.thickness + sin(horn.angle)*horn.length; % x-coord point 2 +p(2,end) = horn.length; % y-coord point 2 +p(1,end+1) = horn.radius + sin(horn.angle)*horn.length; % x-coord point 2 +p(2,end) = horn.length; % y-coord point 2 +p(1,end+1) = horn.radius; % x-coord point 1 +p(2,end) = 0; % z-coord point 1 +p(1,end+1) = horn.radius; % x-coord point 1 +p(2,end) = -horn.feed_length; % z-coord point 1 +CSX = AddRotPoly(CSX,'Conical_Horn',10,'x',p,'z'); + +% horn aperture +A = pi*((horn.radius + sin(horn.angle)*horn.length)*unit)^2; + +%% apply the excitation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start=[-horn.radius -horn.radius mesh.z(10) ]; +stop =[+horn.radius +horn.radius mesh.z(1)+horn.feed_length/2 ]; +[CSX, port] = AddCircWaveGuidePort( CSX, 0, 1, start, stop, horn.radius*unit, 'TE11', 0, 1); + +%% +CSX = AddDump(CSX,'Exc_dump'); +start=[-horn.radius -horn.radius mesh.z(8)]; +stop =[+horn.radius +horn.radius mesh.z(8)]; +CSX = AddBox(CSX,'Exc_dump',0,start,stop); + +%% nf2ff calc +start = [mesh.x(9) mesh.y(9) mesh.z(9)]; +stop = [mesh.x(end-8) mesh.y(end-8) mesh.z(end-8)]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop, 'Directions', [1 1 1 1 0 1]); + +%% prepare simulation folder +Sim_Path = 'tmp'; +Sim_CSX = 'horn_ant.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +%% write openEMS compatible xml-file +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + +%% show the structure +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + +%% run openEMS +RunOpenEMS( Sim_Path, Sim_CSX); + +%% postprocessing & do the plots +freq = linspace(f_start,f_stop,201); + +port = calcPort(port, Sim_Path, freq); + +Zin = port.uf.tot ./ port.if.tot; +s11 = port.uf.ref ./ port.uf.inc; + +% plot reflection coefficient S11 +figure +plot( freq/1e9, 20*log10(abs(s11)), 'k-', 'Linewidth', 2 ); +ylim([-60 0]); +grid on +title( 'reflection coefficient S_{11}' ); +xlabel( 'frequency f / GHz' ); +ylabel( 'reflection coefficient |S_{11}|' ); + +drawnow + +%% NFFF contour plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% calculate the far field at phi=0 degrees and at phi=90 degrees +thetaRange = (0:2:359) - 180; +disp( 'calculating far field at phi=[0 90] deg...' ); +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f0, thetaRange*pi/180, [0 90]*pi/180); + +Dlog=10*log10(nf2ff.Dmax); +G_a = 4*pi*A/(c0/f0)^2; +e_a = nf2ff.Dmax/G_a; + +% display some antenna parameter +disp( ['radiated power: Prad = ' num2str(nf2ff.Prad) ' Watt']); +disp( ['directivity: Dmax = ' num2str(Dlog) ' dBi'] ); +disp( ['aperture efficiency: e_a = ' num2str(e_a*100) '%'] ); + +%% +% normalized directivity +figure +plotFFdB(nf2ff,'xaxis','theta','param',[1 2]); +drawnow +% D_log = 20*log10(nf2ff.E_norm{1}/max(max(nf2ff.E_norm{1}))); +% D_log = D_log + 10*log10(nf2ff.Dmax); +% plot( nf2ff.theta, D_log(:,1) ,'k-', nf2ff.theta, D_log(:,2) ,'r-' ); + +% polar plot +figure +polarFF(nf2ff,'xaxis','theta','param',[1 2],'logscale',[-40 20], 'xtics', 12); +drawnow +% polar( nf2ff.theta, nf2ff.E_norm{1}(:,1) ) + +%% calculate 3D pattern +phiRange = sort( unique( [-180:5:-100 -100:2.5:-50 -50:1:50 50:2.5:100 100:5:180] ) ); +thetaRange = sort( unique([ 0:1:50 50:2.:100 100:5:180 ])); + +disp( 'calculating 3D far field...' ); +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f0, thetaRange*pi/180, phiRange*pi/180, 'Verbose',2,'Outfile','nf2ff_3D.h5'); + +figure +plotFF3D(nf2ff); % plot liear 3D far field + +%% +E_far_normalized = nf2ff.E_norm{1}/max(nf2ff.E_norm{1}(:)); +DumpFF2VTK([Sim_Path '/Conical_Horn_Pattern.vtk'],E_far_normalized,thetaRange,phiRange,'scale',1e-3); diff --git a/openEMS/matlab/Tutorials/CreateCRLH.m b/openEMS/matlab/Tutorials/CreateCRLH.m new file mode 100644 index 0000000..6c10732 --- /dev/null +++ b/openEMS/matlab/Tutorials/CreateCRLH.m @@ -0,0 +1,55 @@ +function [CSX mesh] = CreateCRLH(CSX, mesh, CRLH, resolution, translate) +% function [CSX mesh] = CreateCRLH(CSX, mesh, CRLH, resolution, translate) +% +% support function to create a CRLH unit cell +% +% currently used by Tutorials/CRLH_Extraction +% +% Tested with +% - Matlab 2009b +% - openEMS v0.0.23 +% +% (C) 2011 Thorsten Liebig + +if (nargin<5) + translate = [0 0 0]; +end + +CSX = AddMetal(CSX, 'metal_top'); +one_two_third = [-resolution/3 2*resolution/3]; + +start = [-CRLH.LL/2 -CRLH.LW/2 CRLH.TopSig]+translate; +stop = [-CRLH.GLT/2 CRLH.LW/2 CRLH.TopSig]+translate; +CSX = AddBox(CSX, 'metal_top', 10, start, stop); +mesh.x = [mesh.x start(1) stop(1)+one_two_third]; +mesh.y = [mesh.y start(2)-one_two_third stop(2)+one_two_third]; + +start = [+CRLH.LL/2 -CRLH.LW/2 CRLH.TopSig]+translate; +stop = [+CRLH.GLT/2 CRLH.LW/2 CRLH.TopSig]+translate; +CSX = AddBox(CSX, 'metal_top', 10, start, stop); +mesh.x = [mesh.x start(1) stop(1)-one_two_third]; + +CSX = AddMetal(CSX, 'metal_bot'); +start = [-(CRLH.LL-CRLH.GLB)/2 -CRLH.LW/2 CRLH.BottomSig]+translate; +stop = [+(CRLH.LL-CRLH.GLB)/2 CRLH.LW/2 CRLH.BottomSig]+translate; +CSX = AddBox(CSX, 'metal_bot', 10, start, stop); +mesh.x = [mesh.x start(1)-one_two_third stop(1)+one_two_third]; + +start = [-CRLH.SW/2 -CRLH.LW/2-CRLH.SL CRLH.BottomSig]+translate; +stop = [+CRLH.SW/2 CRLH.LW/2+CRLH.SL CRLH.BottomSig]+translate; +CSX = AddBox(CSX, 'metal_bot', 10, start, stop); +mesh.x = [mesh.x start(1)-one_two_third stop(1)+one_two_third]; +mesh.y = [mesh.y start(2) stop(2)]; + +CSX = AddMetal(CSX, 'via'); +start = [0 -CRLH.LW/2-CRLH.SL+CRLH.SW/2 0]+translate; +stop = [0 -CRLH.LW/2-CRLH.SL+CRLH.SW/2 CRLH.BottomSig]+translate; +CSX = AddCylinder(CSX, 'via', 10, start, stop, CRLH.VR); +mesh.x = [mesh.x start(1)+[-1 0 1]*CRLH.VR]; +mesh.y = [mesh.y start(2)+[-1 0 1]*CRLH.VR]; + +start(2) = -start(2); +stop(2) = -stop(2); +CSX = AddCylinder(CSX, 'via', 10, start, stop, CRLH.VR); +mesh.y = [mesh.y start(2)+[-1 0 1]*CRLH.VR]; +end \ No newline at end of file diff --git a/openEMS/matlab/Tutorials/CylindricalWave_CC.m b/openEMS/matlab/Tutorials/CylindricalWave_CC.m new file mode 100644 index 0000000..b81d2d4 --- /dev/null +++ b/openEMS/matlab/Tutorials/CylindricalWave_CC.m @@ -0,0 +1,104 @@ +% +% Tutorials / CylindricalWave_CC +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_2D_Cylindrical_Wave +% +% Tested with +% - Matlab 2011a/ Octave 4.0 +% - openEMS v0.0.33 +% +% (C) 2011-2015 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants +mesh_res = 10; %desired mesh resolution +radius = 2560; %simulation domain radius +split = ['80,160,320,640,1280']; %radii to split the mesh into sub-grids +split_N = 5; %number of nested sub-grids +heigth = mesh_res*4; + +f0 = 1e9; + +exite_offset = 1300; +excite_angle = 45; + +%% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD('NrTS', 100000, 'EndCriteria', 1e-4, 'CoordSystem', 1, 'MultiGrid', split); +FDTD = SetGaussExcite(FDTD,f0,f0/2); +BC = [0 3 0 0 0 0]; % pml in positive r-direction +FDTD = SetBoundaryCond(FDTD,BC); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 50 mesh lines for the inner most mesh +% increase the total number of meshlines in alpha direcion for all sub-grids +N_alpha = 50 * 2^split_N + 1; + +CSX = InitCSX('CoordSystem',1); +mesh.r = SmoothMeshLines([0 radius],mesh_res); +mesh.a = linspace(-pi,pi,N_alpha); +mesh.z = SmoothMeshLines([-heigth/2 0 heigth/2],mesh_res); +CSX = DefineRectGrid(CSX, 1e-3,mesh); + +%% add the dipol %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start = [exite_offset excite_angle/180*pi-0.001 -20]; +stop = [exite_offset excite_angle/180*pi+0.001 20]; +if (exite_offset==0) + start(2) = mesh.a(1); + stop(2) = mesh.a(1); +end +CSX = AddExcitation(CSX,'excite',1,[0 0 1]); +CSX = AddBox(CSX,'excite',0 ,start,stop); + +%% define dump boxes... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start = [mesh.r(1) mesh.a(1) 0]; +stop = [mesh.r(end-8) mesh.a(end) 0]; + +% time domain vtk dump +CSX = AddDump(CSX,'Et_ra','DumpType',0,'FileType',0,'SubSampling','4,10,1'); +CSX = AddBox(CSX,'Et_ra',0 , start,stop); + +% frequency domain hdf5 dump +CSX = AddDump(CSX,'Ef_ra','DumpType',10,'FileType',1,'SubSampling','2,2,2','Frequency',f0); +CSX = AddBox(CSX,'Ef_ra',0 , start,stop); + +%% write/run the openEMS compatible xml-file +Sim_Path = 'tmp'; +Sim_CSX = '2D_CC_Wave.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); +RunOpenEMS(Sim_Path, Sim_CSX); + +%% +disp('use Paraview to visualize the vtk field dump...'); + +%% +[field mesh_h5] = ReadHDF5Dump([Sim_Path '/Ef_ra.h5']); + +r = mesh_h5.lines{1}; +a = mesh_h5.lines{2}; +a(end+1) = a(1); %closeup mesh for visualization +[R A] = ndgrid(r,a); +X = R.*cos(A); +Y = R.*sin(A); + +Ez = squeeze(field.FD.values{1}(:,:,1,3)); +Ez(:,end+1) = Ez(:,1); %closeup mesh for visualization + +E_max = max(max(abs(Ez))); %get maximum E_z amplitude + +while 1 + for ph = linspace(0,360,41) %animate phase from 0..360 degree + surf(X,Y,real(Ez*exp(1j*ph*pi/180)),'EdgeColor','none') + caxis([-E_max E_max]/10) + zlim([-E_max E_max]) + pause(0.3) + end +end diff --git a/openEMS/matlab/Tutorials/Dipole_SAR.m b/openEMS/matlab/Tutorials/Dipole_SAR.m new file mode 100644 index 0000000..a172117 --- /dev/null +++ b/openEMS/matlab/Tutorials/Dipole_SAR.m @@ -0,0 +1,221 @@ +% +% Tutorials / Dipole SAR + Power budget +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_Dipole_SAR +% +% Tested with +% - openEMS v0.0.33 +% +% (C) 2013-2015 Thorsten Liebig + +close all +clear +clc + +%% switches & options... +postprocessing_only = 0; + +%% prepare simulation folder +Sim_Path = 'tmp_Dipole_SAR'; +Sim_CSX = 'Dipole_SAR.xml'; + +%% setup the simulation +physical_constants; +unit = 1e-3; % all lengths in mm + +feed.R = 50; % feed resistance + +%% define phantom +phantom{1}.name='skin'; +phantom{1}.epsR = 50; +phantom{1}.kappa = 0.65; % S/m +phantom{1}.density = 1100; % kg/m^3 +phantom{1}.radius = [80 100 100]; % ellipsoide +phantom{1}.center = [100 0 0]; + +phantom{2}.name='headbone'; +phantom{2}.epsR = 13; +phantom{2}.kappa = 0.1; % S/m +phantom{2}.density = 2000; % kg/m^3 +phantom{2}.radius = [75 95 95]; % ellipsoide +phantom{2}.center = [100 0 0]; + +phantom{3}.name='brain'; +phantom{3}.epsR = 60; +phantom{3}.kappa = 0.7; % S/m +phantom{3}.density = 1040; % kg/m^3 +phantom{3}.radius = [65 85 85]; % ellipsoide +phantom{3}.center = [100 0 0]; + +%% setup FDTD parameter & excitation function +f0 = 1e9; % center frequency +lambda0 = c0/f0; + +f_stop = 1.5e9; % 20 dB corner frequency +lambda_min = c0/f_stop; + +mesh_res_air = lambda_min/20/unit; +mesh_res_phantom = 2.5; + +dipole_length = 0.46*lambda0/unit; +disp(['Lambda-half dipole length: ' num2str(dipole_length) 'mm']) + +%% +FDTD = InitFDTD(); +FDTD = SetGaussExcite( FDTD, 0, f_stop ); +% apply PML-8 boundary conditions in all directions +BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +CSX = InitCSX(); + +%% Dipole +CSX = AddMetal( CSX, 'Dipole' ); % create a perfect electric conductor (PEC) +CSX = AddBox(CSX, 'Dipole', 1, [0 0 -dipole_length/2], [0 0 dipole_length/2]); + +% mesh lines for the dipole +mesh.x = 0; +mesh.y = 0; +mesh.z = [-dipole_length/2-[-1/3 2/3]*mesh_res_phantom dipole_length/2+[-1/3 2/3]*mesh_res_phantom]; + +%% add the dielectrics +for n=1:numel(phantom) + CSX = AddMaterial( CSX, phantom{n}.name ); + CSX = SetMaterialProperty( CSX, phantom{n}.name, 'Epsilon', phantom{n}.epsR, 'Kappa', phantom{n}.kappa, 'Density', phantom{n}.density); + CSX = AddSphere( CSX, phantom{n}.name, 10+n, [0 0 0], 1,'Transform',{'Scale',phantom{n}.radius, 'Translate', phantom{n}.center} ); + + %% mesh lines for the dielectrics + mesh.x = [mesh.x phantom{n}.radius(1)*[-1 1]+phantom{n}.center(1) ]; + mesh.y = [mesh.y phantom{n}.radius(2)*[-1 1]+phantom{n}.center(2) ]; + mesh.z = [mesh.z phantom{n}.radius(3)*[-1 1]+phantom{n}.center(3) ]; +end + +%% apply the excitation & resist as a current source +[CSX port] = AddLumpedPort(CSX, 100, 1, feed.R, [-0.1 -0.1 -mesh_res_phantom/2], [0.1 0.1 +mesh_res_phantom/2], [0 0 1], true); + +% mesh lines for the port +mesh.z = [mesh.z -mesh_res_phantom/2 +mesh_res_phantom/2]; + +%% smooth the mesh over the dipole and phantom +mesh = SmoothMesh(mesh, mesh_res_phantom); + +%% add lines for the air-box +mesh.x = [mesh.x -200 250+100]; +mesh.y = [mesh.y -250 250]; +mesh.z = [mesh.z -250 250]; + +% smooth the final mesh (incl. air box) +mesh = SmoothMesh(mesh, mesh_res_air, 1.2); + +%% dump SAR +start = [-10 -100 -100]; +stop = [180 100 100]; +CSX = AddDump( CSX, 'SAR', 'DumpType', 20, 'Frequency', f0,'FileType',1,'DumpMode',2); +CSX = AddBox( CSX, 'SAR', 0, start, stop); + +%% nf2ff calc +start = [mesh.x(1) mesh.y(1) mesh.z(1)]; +stop = [mesh.x(end) mesh.y(end) mesh.z(end)]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop, 'OptResolution', lambda_min/15/unit); + +%% +% add 10 equidistant cells (air) +% around the structure to keep the pml away from the nf2ff box +mesh = AddPML( mesh, 10 ); + +% Define the mesh +CSX = DefineRectGrid(CSX, unit, mesh); + +%% +if (postprocessing_only==0) + [status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory + [status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + + % write openEMS compatible xml-file + WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + + % show the structure + CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + + % run openEMS + RunOpenEMS( Sim_Path, Sim_CSX ); +end + + +%% postprocessing & make the plots +freq = linspace(500e6, 1500e6, 501 ); +port = calcPort(port, Sim_Path, freq); + +s11 = port.uf.ref./port.uf.inc; +Zin = port.uf.tot./port.if.tot; + +Pin_f0 = interp1(freq, port.P_acc, f0); + +%% +% plot feed point impedance +figure +plot( freq/1e6, real(Zin), 'k-', 'Linewidth', 2 ); +hold on +grid on +plot( freq/1e6, imag(Zin), 'r--', 'Linewidth', 2 ); +title( 'feed point impedance' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'impedance Z_{in} / Ohm' ); +legend( 'real', 'imag' ); + +% plot reflection coefficient S11 +figure +plot( freq/1e9, 20*log10(abs(s11)), 'k-', 'Linewidth', 2 ); +grid on +title( 'reflection coefficient' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'S_{11} (dB)' ); + +%% read SAR and visualize +SAR_field = ReadHDF5Dump([Sim_Path '/SAR.h5']); + +SAR = SAR_field.FD.values{1}; +ptotal = ReadHDF5Attribute([Sim_Path '/SAR.h5'],'/FieldData/FD/f0','power'); + +%% calculate 3D pattern +phi = 0:3:360; +theta = 0:3:180; + +disp( 'calculating 3D far field pattern...' ); +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f0, theta*pi/180, phi*pi/180, 'Outfile','3D_Pattern.h5'); + +%% +disp(['max SAR: ' num2str(max(SAR(:))/Pin_f0) ' W/kg normalized to 1 W accepted power']); +disp(['accepted power: ' num2str(Pin_f0) ' W (100 %)']); +disp(['radiated power: ' num2str(nf2ff.Prad) ' W ( ' num2str(round(100*(nf2ff.Prad) / Pin_f0)) ' %)']); +disp(['absorbed power: ' num2str(ptotal) ' W ( ' num2str(round(100*(ptotal) / Pin_f0)) ' %)']); +disp(['power budget: ' num2str(100*(nf2ff.Prad + ptotal) / Pin_f0) ' %']); + +%% plot on a x/y-plane +[SAR_field SAR_mesh] = ReadHDF5Dump([Sim_Path '/SAR.h5'],'Range',{[],[],0}); +figure +[X Y] = ndgrid(SAR_mesh.lines{1},SAR_mesh.lines{2}); +h = pcolor(X,Y,log10(SAR_field.FD.values{1}/abs(Pin_f0))); +title( 'logarithmic SAR on an xy-plane' ); +xlabel('x -->') +ylabel('y -->') +axis equal tight +set(h,'EdgeColor','none'); + +%% plot on a x/z-plane +[SAR_field SAR_mesh] = ReadHDF5Dump([Sim_Path '/SAR.h5'],'Range',{[],0,[]}); +figure +[X Z] = ndgrid(SAR_mesh.lines{1},SAR_mesh.lines{3}); +h = pcolor(X,Z,log10(squeeze(SAR_field.FD.values{1}))/abs(Pin_f0)); +title( 'logarithmic SAR on an xz-plane' ); +xlabel('x -->') +ylabel('z -->') +axis equal tight +set(h,'EdgeColor','none'); + +%% dump SAR to vtk file +disp(['Full local/normalized SAR has been dumped to vtk file! Use Paraview to visualize']); +ConvertHDF5_VTK([Sim_Path '/SAR.h5'],[Sim_Path '/SAR'],'weight',1/abs(Pin_f0),'FieldName','SAR_local' ); + diff --git a/openEMS/matlab/Tutorials/Helical_Antenna.m b/openEMS/matlab/Tutorials/Helical_Antenna.m new file mode 100644 index 0000000..b94ebd6 --- /dev/null +++ b/openEMS/matlab/Tutorials/Helical_Antenna.m @@ -0,0 +1,202 @@ +% +% Tutorials / helical antenna +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_Helical_Antenna +% +% Tested with +% - Matlab 2011a / Octave 4.0 +% - openEMS v0.0.33 +% +% (C) 2012-2015 Thorsten Liebig + +close all +clear +clc + +post_proc_only = 0; + +close all + +%% setup the simulation +physical_constants; +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 = [1 1 1.5]*2*lambda0; + +%% setup FDTD parameter & excitation function +FDTD = InitFDTD( ); +FDTD = SetGaussExcite( FDTD, f0, fc ); +BC = {'MUR' 'MUR' 'MUR' 'MUR' 'MUR' 'PML_8'}; % boundary conditions +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +max_res = floor(c0 / (f0+fc) / unit / 20); % cell size: lambda/20 +CSX = InitCSX(); + +% create helix mesh +mesh.x = SmoothMeshLines([-Helix.radius 0 Helix.radius],Helix.mesh_res); +% add the air-box +mesh.x = [mesh.x -SimBox(1)/2-gnd.radius SimBox(1)/2+gnd.radius]; +% create a smooth mesh between specified fixed mesh lines +mesh.x = SmoothMeshLines( mesh.x, max_res, 1.4); + +% copy x-mesh to y-direction +mesh.y = mesh.x; + +% create helix mesh in z-direction +mesh.z = SmoothMeshLines([0 feed.heigth Helix.turns*Helix.pitch+feed.heigth],Helix.mesh_res); +% add the air-box +mesh.z = unique([mesh.z -SimBox(3)/2 max(mesh.z)+SimBox(3)/2 ]); +% create a smooth mesh between specified fixed mesh lines +mesh.z = SmoothMeshLines( mesh.z, max_res, 1.4 ); + +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% create helix using the wire primitive +CSX = AddMetal( CSX, 'helix' ); % create a perfect electric conductor (PEC) + +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=[]; +helix.y=[]; +helix.z=[]; +zpos = feed.heigth; +for n=0:Helix.turns-1 + helix.x = [helix.x coil_x]; + helix.y = [helix.y coil_y]; + helix.z = [helix.z coil_z+zpos]; + zpos = zpos + Helix.pitch; +end +clear p +p(1,:) = helix.x; +p(2,:) = helix.y; +p(3,:) = helix.z; +CSX = AddCurve(CSX, 'helix', 0, p); + +%% create ground circular ground +CSX = AddMetal( CSX, 'gnd' ); % create a perfect electric conductor (PEC) +% add a box using cylindrical coordinates +start = [0 0 0]; +stop = [gnd.radius 2*pi 0]; +CSX = AddBox(CSX,'gnd',10,start,stop,'CoordSystem',1); + +%% apply the excitation & resist as a current source +start = [Helix.radius 0 0]; +stop = [Helix.radius 0 feed.heigth]; +[CSX port] = AddLumpedPort(CSX, 5 ,1 ,feed.R, start, stop, [0 0 1], true); + +%%nf2ff calc +start = [mesh.x(11) mesh.y(11) mesh.z(11)]; +stop = [mesh.x(end-10) mesh.y(end-10) mesh.z(end-10)]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop, 'OptResolution', lambda0/15); + +%% prepare simulation folder +Sim_Path = 'tmp_Helical_Ant'; +Sim_CSX = 'Helix_Ant.xml'; + +if (post_proc_only==0) + [status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory + [status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + + %% write openEMS compatible xml-file + WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + + %% show the structure + CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + + %% run openEMS + RunOpenEMS( Sim_Path, Sim_CSX); +end + +%% postprocessing & do the plots +freq = linspace( f0-fc, f0+fc, 501 ); +port = calcPort(port, Sim_Path, freq); + +Zin = port.uf.tot ./ port.if.tot; +s11 = port.uf.ref ./ port.uf.inc; + +% plot feed point impedance +figure +plot( freq/1e6, real(Zin), 'k-', 'Linewidth', 2 ); +hold on +grid on +plot( freq/1e6, imag(Zin), 'r--', 'Linewidth', 2 ); +title( 'feed point impedance' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'impedance Z_{in} / Ohm' ); +legend( 'real', 'imag' ); + +% plot reflection coefficient S11 +figure +plot( freq/1e6, 20*log10(abs(s11)), 'k-', 'Linewidth', 2 ); +grid on +title( 'reflection coefficient S_{11}' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'reflection coefficient |S_{11}|' ); + +drawnow + +%% NFFF contour plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%find resonance frequncy from s11 +f_res = f0; + +% get accepted antenna power at frequency f0 +P_in_0 = interp1(freq, port.P_acc, f0); + +% calculate the far field at phi=0 degrees and at phi=90 degrees +thetaRange = unique([0:0.5:90 90:180]); +phiRange = (0:2:360) - 180; +disp( 'calculating the 3D far field...' ); + +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_res, thetaRange*pi/180, phiRange*pi/180,'Mode',0,'Outfile','3D_Pattern.h5','Verbose',1); + +theta_HPBW = interp1(nf2ff.E_norm{1}(:,1)/max(nf2ff.E_norm{1}(:,1)),thetaRange,1/sqrt(2))*2; + +% display power and directivity +disp( ['radiated power: Prad = ' num2str(nf2ff.Prad) ' Watt']); +disp( ['directivity: Dmax = ' num2str(nf2ff.Dmax) ' (' num2str(10*log10(nf2ff.Dmax)) ' dBi)'] ); +disp( ['efficiency: nu_rad = ' num2str(100*nf2ff.Prad./P_in_0) ' %']); +disp( ['theta_HPBW = ' num2str(theta_HPBW) ' °']); + + +%% +directivity = nf2ff.P_rad{1}/nf2ff.Prad*4*pi; +directivity_CPRH = abs(nf2ff.E_cprh{1}).^2./max(nf2ff.E_norm{1}(:)).^2*nf2ff.Dmax; +directivity_CPLH = abs(nf2ff.E_cplh{1}).^2./max(nf2ff.E_norm{1}(:)).^2*nf2ff.Dmax; + +%% +figure +plot(thetaRange, 10*log10(directivity(:,1)'),'k-','LineWidth',2); +hold on +grid on +xlabel('theta (deg)'); +ylabel('directivity (dBi)'); +plot(thetaRange, 10*log10(directivity_CPRH(:,1)'),'g--','LineWidth',2); +plot(thetaRange, 10*log10(directivity_CPLH(:,1)'),'r-.','LineWidth',2); +legend('norm','CPRH','CPLH'); + +%% dump to vtk +DumpFF2VTK([Sim_Path '/3D_Pattern.vtk'],directivity,thetaRange,phiRange,'scale',1e-3); +DumpFF2VTK([Sim_Path '/3D_Pattern_CPRH.vtk'],directivity_CPRH,thetaRange,phiRange,'scale',1e-3); +DumpFF2VTK([Sim_Path '/3D_Pattern_CPLH.vtk'],directivity_CPLH,thetaRange,phiRange,'scale',1e-3); + diff --git a/openEMS/matlab/Tutorials/Horn_Antenna.m b/openEMS/matlab/Tutorials/Horn_Antenna.m new file mode 100644 index 0000000..d463734 --- /dev/null +++ b/openEMS/matlab/Tutorials/Horn_Antenna.m @@ -0,0 +1,202 @@ +% +% Tutorials / horn antenna +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_Horn_Antenna +% +% Tested with +% - Matlab 2011a / Octave 3.6.4 +% - openEMS v0.0.31 +% +% (C) 2011,2012,2013 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation +physical_constants; +unit = 1e-3; % all length in mm + +% horn width in x-direction +horn.width = 20; +% horn height in y-direction +horn.height = 30; +% horn length in z-direction +horn.length = 50; + +horn.feed_length = 50; + +horn.thickness = 2; + +% horn opening angle in x, y +horn.angle = [20 20]*pi/180; + +% size of the simulation box +SimBox = [200 200 200]; + +% frequency range of interest +f_start = 10e9; +f_stop = 20e9; + +% frequency of interest +f0 = 15e9; + +%waveguide TE-mode definition +TE_mode = 'TE10'; +a = horn.width; +b = horn.height; + +%% setup FDTD parameter & excitation function +FDTD = InitFDTD('EndCriteria', 1e-4); +FDTD = SetGaussExcite(FDTD,0.5*(f_start+f_stop),0.5*(f_stop-f_start)); +BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; % boundary conditions +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +% currently, openEMS cannot automatically generate a mesh +max_res = c0 / (f_stop) / unit / 15; % cell size: lambda/20 +CSX = InitCSX(); + +%create fixed lines for the simulation box, substrate and port +mesh.x = [-SimBox(1)/2 -a/2 a/2 SimBox(1)/2]; +mesh.x = SmoothMeshLines( mesh.x, max_res, 1.4); % create a smooth mesh between specified fixed mesh lines + +mesh.y = [-SimBox(2)/2 -b/2 b/2 SimBox(2)/2]; +mesh.y = SmoothMeshLines( mesh.y, max_res, 1.4 ); + +%create fixed lines for the simulation box and given number of lines inside the substrate +mesh.z = [-horn.feed_length 0 SimBox(3)-horn.feed_length ]; +mesh.z = SmoothMeshLines( mesh.z, max_res, 1.4 ); + +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% create horn +% horn feed rect waveguide +CSX = AddMetal(CSX, 'horn'); +start = [-a/2-horn.thickness -b/2 mesh.z(1)]; +stop = [-a/2 b/2 0]; +CSX = AddBox(CSX,'horn',10,start,stop); +start = [a/2+horn.thickness -b/2 mesh.z(1)]; +stop = [a/2 b/2 0]; +CSX = AddBox(CSX,'horn',10,start,stop); +start = [-a/2-horn.thickness b/2+horn.thickness mesh.z(1)]; +stop = [ a/2+horn.thickness b/2 0]; +CSX = AddBox(CSX,'horn',10,start,stop); +start = [-a/2-horn.thickness -b/2-horn.thickness mesh.z(1)]; +stop = [ a/2+horn.thickness -b/2 0]; +CSX = AddBox(CSX,'horn',10,start,stop); + +% horn opening +p(2,1) = a/2; +p(1,1) = 0; +p(2,2) = a/2 + sin(horn.angle(1))*horn.length; +p(1,2) = horn.length; +p(2,3) = -a/2 - sin(horn.angle(1))*horn.length; +p(1,3) = horn.length; +p(2,4) = -a/2; +p(1,4) = 0; +CSX = AddLinPoly( CSX, 'horn', 10, 1, -horn.thickness/2, p, horn.thickness, 'Transform', {'Rotate_X',horn.angle(2),'Translate',['0,' num2str(-b/2-horn.thickness/2) ',0']}); +CSX = AddLinPoly( CSX, 'horn', 10, 1, -horn.thickness/2, p, horn.thickness, 'Transform', {'Rotate_X',-horn.angle(2),'Translate',['0,' num2str(b/2+horn.thickness/2) ',0']}); + +p(1,1) = b/2+horn.thickness; +p(2,1) = 0; +p(1,2) = b/2+horn.thickness + sin(horn.angle(2))*horn.length; +p(2,2) = horn.length; +p(1,3) = -b/2-horn.thickness - sin(horn.angle(2))*horn.length; +p(2,3) = horn.length; +p(1,4) = -b/2-horn.thickness; +p(2,4) = 0; +CSX = AddLinPoly( CSX, 'horn', 10, 0, -horn.thickness/2, p, horn.thickness, 'Transform', {'Rotate_Y',-horn.angle(2),'Translate',[ num2str(-a/2-horn.thickness/2) ',0,0']}); +CSX = AddLinPoly( CSX, 'horn', 10, 0, -horn.thickness/2, p, horn.thickness, 'Transform', {'Rotate_Y',+horn.angle(2),'Translate',[ num2str(a/2+horn.thickness/2) ',0,0']}); + +% horn aperture +A = (a + 2*sin(horn.angle(1))*horn.length)*unit * (b + 2*sin(horn.angle(2))*horn.length)*unit; + +%% apply the excitation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start=[-a/2 -b/2 mesh.z(8) ]; +stop =[ a/2 b/2 mesh.z(1)+horn.feed_length/2 ]; +[CSX, port] = AddRectWaveGuidePort( CSX, 0, 1, start, stop, 2, a*unit, b*unit, TE_mode, 1); + +%% nf2ff calc +start = [mesh.x(9) mesh.y(9) mesh.z(9)]; +stop = [mesh.x(end-8) mesh.y(end-8) mesh.z(end-8)]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop, 'Directions', [1 1 1 1 0 1]); + +%% prepare simulation folder +Sim_Path = 'tmp_Horn_Antenna'; +Sim_CSX = 'horn_ant.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +%% write openEMS compatible xml-file +WriteOpenEMS([Sim_Path '/' Sim_CSX], FDTD, CSX); + +%% show the structure +CSXGeomPlot([Sim_Path '/' Sim_CSX]); + +%% run openEMS +RunOpenEMS(Sim_Path, Sim_CSX); + +%% postprocessing & do the plots +freq = linspace(f_start,f_stop,201); + +port = calcPort(port, Sim_Path, freq); + +Zin = port.uf.tot ./ port.if.tot; +s11 = port.uf.ref ./ port.uf.inc; + +plot( freq/1e9, 20*log10(abs(s11)), 'k-', 'Linewidth', 2 ); +ylim([-60 0]); +grid on +title( 'reflection coefficient S_{11}' ); +xlabel( 'frequency f / GHz' ); +ylabel( 'reflection coefficient |S_{11}|' ); + +drawnow + +%% NFFF contour plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% calculate the far field at phi=0 degrees and at phi=90 degrees +thetaRange = (0:2:359) - 180; +disp( 'calculating far field at phi=[0 90] deg...' ); +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f0, thetaRange*pi/180, [0 90]*pi/180); + +Dlog=10*log10(nf2ff.Dmax); +G_a = 4*pi*A/(c0/f0)^2; +e_a = nf2ff.Dmax/G_a; + +% display some antenna parameter +disp( ['radiated power: Prad = ' num2str(nf2ff.Prad) ' Watt']); +disp( ['directivity: Dmax = ' num2str(Dlog) ' dBi'] ); +disp( ['aperture efficiency: e_a = ' num2str(e_a*100) '%'] ); + +%% +% normalized directivity +figure +plotFFdB(nf2ff,'xaxis','theta','param',[1 2]); +drawnow +% D_log = 20*log10(nf2ff.E_norm{1}/max(max(nf2ff.E_norm{1}))); +% D_log = D_log + 10*log10(nf2ff.Dmax); +% plot( nf2ff.theta, D_log(:,1) ,'k-', nf2ff.theta, D_log(:,2) ,'r-' ); + +% polar plot +figure +polarFF(nf2ff,'xaxis','theta','param',[1 2],'logscale',[-40 20], 'xtics', 12); +drawnow +% polar( nf2ff.theta, nf2ff.E_norm{1}(:,1) ) + +%% calculate 3D pattern +phiRange = sort( unique( [-180:5:-100 -100:2.5:-50 -50:1:50 50:2.5:100 100:5:180] ) ); +thetaRange = sort( unique([ 0:1:50 50:2.:100 100:5:180 ])); + +disp( 'calculating 3D far field...' ); +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f0, thetaRange*pi/180, phiRange*pi/180, 'Verbose',2,'Outfile','nf2ff_3D.h5'); + +figure +plotFF3D(nf2ff); + +%% +E_far_normalized = nf2ff.E_norm{1}/max(nf2ff.E_norm{1}(:)); +DumpFF2VTK([Sim_Path '/Horn_Pattern.vtk'],E_far_normalized,thetaRange,phiRange,'scale',1e-3); diff --git a/openEMS/matlab/Tutorials/MRI_LP_Birdcage.m b/openEMS/matlab/Tutorials/MRI_LP_Birdcage.m new file mode 100644 index 0000000..2434f03 --- /dev/null +++ b/openEMS/matlab/Tutorials/MRI_LP_Birdcage.m @@ -0,0 +1,320 @@ +% +% Tutorials / 3T MRI Low Pass Birdcage coil +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_MRI_LP_Birdcage +% +% Estimated time to run: ~7h @ ~65MC/s +% Memory requirement (RAM): ~ 700MB +% +% Tested with +% - openEMS v0.0.33 +% - Matlab 7.12.0 (R2011a) +% +% (C) 2013-2015 Thorsten Liebig + + +close all +clear +clc + +% simulation setup +f0 = 128e6; +excite.f_0 = 75e6; % excite gaussian pulse center frequency +excite.f_c = 75e6; % excite gaussian pulse cutoff frequency + +postproc_only = 0; % set to 1 to perform only post processing +GeomPlot = 1; % set to 0 to skip geometry viewer + +% bore setup +Bore.rad = 320; +Bore.length = 1600; + +% birdcage setup +BC.N_rungs = 8; +BC.rad = 120; +BC.stripwidth = 10; +BC.portwidth = BC.stripwidth/2; +BC.portlength = BC.stripwidth/2; +BC.length = 250; +BC.cap = 2.6e-12; + +% feed amplitude and phase at given rungs +BC.feed_pos = [1 3]; +BC.feed_amp = [1 -1j]; + +%% define the human body model (virtual family) +% set file name for human body model to create with "Convert_VF_DiscMaterial" +% the file name should contain a full path +body_model_file = [pwd '/Ella_centered_' num2str(f0/1e6) 'MHz.h5']; + +% convert only part of the model (head/shoulder section) +body_model_range = {[],[],[-0.85 0]}; + +body_mesh_res = 2.5; % should be something like: BC.stripwidth/4 + +% paths to virtual family voxel models (VFVM), adept to your install! +VF_raw_filesuffix = '/tmp/Ella_26y_V2_1mm'; +VF_mat_db_file = '/tmp/DB_h5_20120711_SEMCADv14.8.h5'; + +% delete(body_model_file); % uncomment to delete old model if something changed + +% convert model (if it does not exist) +Convert_VF_DiscMaterial(VF_raw_filesuffix, VF_mat_db_file, body_model_file, ... + 'Frequency', f0, 'Center', 1, ... + 'Range', body_model_range); + +% rotate model to face the nose in +y-dir, and translate +body_model_transform = {'Rotate_X',pi,'Rotate_Z',pi, ... + 'Translate',[0,5,-720]}; + +%% some internal parameter +physical_constants % load important physical constans +end_crit = 1e-5; %abort simulation at -50dB energy drop +unit = 1e-3; %drawing unit used + +%capacity footprint is 4mm x 4mm +lambda_min = c0/(excite.f_0+excite.f_c); + +% meshing options +% desired mesh resolution +mesh_res([1 3]) = min(15,lambda_min/20/unit); +mesh_res(2) = body_mesh_res / BC.rad; + +%% setup FDTD parameter & excitation function +FDTD = InitFDTD('CoordSystem', 1, ... %init a cylindrical FDTD setup + 'EndCriteria', 1e-4, ... % with an end criteria of -40dB (1e-4) + 'MultiGrid', '10,20',... % add two cylindrical sub-grids at a radius of 10 and 20 mm + 'CellConstantMaterial', 1); % assume a material is constant inside + % a cell (material probing in cell center) + +% define the excitation time-signal (unmodulated gaussian pulse) +FDTD = SetGaussExcite(FDTD,excite.f_0,excite.f_c); + +% define & set boundary conditions +% - pml in +/- z-direction +% - boundaries in -r and +/- alpha direction disabled (full cylindrical mesh) +% - PEC boundary in +r-direction to model bore RF shield +FDTD = SetBoundaryCond(FDTD, [0 0 0 0 3 3]); + + +%% setup CSXCAD geometry & mesh (cylindrical) +CSX = InitCSX('CoordSystem',1); + +% init empty mesh structure +mesh.r = []; +mesh.a = []; +mesh.z = []; + +%% Create metal bird cage and rung capacities +CSX = AddMetal(CSX,'metal'); +CSX = AddLumpedElement(CSX,'caps','z','C',BC.cap); + +da_Strip = BC.stripwidth/BC.rad; % width of a strip in radiant +da_Caps = BC.portwidth/BC.rad; % width of a cap/port in radiant +da_Segs = 2*pi/BC.N_rungs; % width of a rung in radiant + +a_start = -pi-da_Segs/2; % starting angle + +w0 = 2*pi*f0; +T0 = 1/f0; + +% port counter +port_Nr = 1; + +a0 = a_start; + +for n=1:BC.N_rungs + start = [BC.rad a0+da_Segs/2-da_Caps/2 -0.5*BC.portlength]; + stop = [BC.rad a0+da_Segs/2+da_Caps/2 +0.5*BC.portlength]; + CSX = AddBox(CSX,'caps',1, start, stop); + + start = [BC.rad a0+da_Segs/2-da_Caps/2 0.5*BC.length-BC.stripwidth/2-BC.portlength]; + stop = [BC.rad a0+da_Segs/2+da_Caps/2 0.5*BC.length-BC.stripwidth/2]; + if (~isempty(intersect(n, BC.feed_pos)) && (BC.feed_amp(port_Nr)~=0)) % active port + exc_amp = abs(BC.feed_amp(port_Nr)); + + % calculate time delay to achieve a given phase shift at f0 + T = -angle(BC.feed_amp(port_Nr)) / w0; + if T<0 + T = T + T0; + end + [CSX port{port_Nr}] = AddLumpedPort(CSX, 100, port_Nr, 50, start, stop, [0 0 1]*exc_amp, true,'Delay',T); + + %increase port count + port_Nr = port_Nr+1; + + start = [BC.rad a0+da_Segs/2-da_Strip/2 0.5*BC.length-BC.stripwidth/2-BC.portlength]; + elseif ~isempty(intersect(n, BC.feed_pos)) % passive port + [CSX port{port_Nr}] = AddLumpedPort(CSX, 100, port_Nr, 50, start, stop, [0 0 1], false); + + %increase port count + port_Nr = port_Nr+1; + + start = [BC.rad a0+da_Segs/2-da_Strip/2 0.5*BC.length-BC.stripwidth/2-BC.portlength]; + else + start = [BC.rad a0+da_Segs/2-da_Strip/2 0.5*BC.length]; + end + + % the start z-coordinate depends on the port (see above) + stop = [BC.rad a0+da_Segs/2+da_Strip/2 0.5*BC.portlength]; + CSX = AddBox(CSX,'metal',1, start, stop); + + start = [BC.rad a0+da_Segs/2-da_Strip/2 -0.5*BC.length]; + stop = [BC.rad a0+da_Segs/2+da_Strip/2 -0.5*BC.portlength]; + CSX = AddBox(CSX,'metal',1, start, stop); + + % some additonal mesh lines + mesh.a = [mesh.a a0+da_Segs/2]; + + a0 = a0 + da_Segs; +end + +% create metal top ring +start = [BC.rad a_start -(BC.length-BC.stripwidth)/2]; +stop = [BC.rad a_start+2*pi -(BC.length+BC.stripwidth)/2]; +CSX = AddBox(CSX,'metal',1, start, stop); + +% create metal bottom ring +start = [BC.rad a_start (BC.length-BC.stripwidth)/2]; +stop = [BC.rad a_start+2*pi (BC.length+BC.stripwidth)/2]; +CSX = AddBox(CSX,'metal',1, start, stop); + +%% create smooth mesh +mesh = DetectEdges(CSX, mesh); +mesh.r = [0 SmoothMeshLines([body_mesh_res*1.5 mesh.r], body_mesh_res)]; +mesh.z = SmoothMeshLines(mesh.z, body_mesh_res); + +mesh.r = [mesh.r Bore.rad]; %mesh lines in radial direction +mesh.z = [-Bore.length/2 mesh.z Bore.length/2]; %mesh lines in z-direction + +mesh = SmoothMesh(mesh, mesh_res, 1.5); + +%% check the cell limit +numCells = numel(mesh.r)*numel(mesh.a)*numel(mesh.z); + +%% define human body model +CSX = AddDiscMaterial(CSX, 'body_model', 'File', body_model_file, 'Scale', 1/unit, 'Transform', body_model_transform); +start = [mesh.r(1) mesh.a(1) mesh.z(1)]; +stop = [mesh.r(end) mesh.a(end) mesh.z(end)]; +CSX = AddBox(CSX, 'body_model', 0, start, stop); + + +%% define dump boxes... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start = [0 mesh.a(1) -BC.length/2]; +stop = [BC.rad mesh.a(end) +BC.length/2]; + +CSX = AddDump(CSX,'Ef','FileType',1,'DumpType',10,'DumpMode',2,'Frequency',f0); +CSX = AddBox(CSX,'Ef',0 , start,stop); + +CSX = AddDump(CSX,'Hf','FileType',1,'DumpType',11,'DumpMode',2,'Frequency',f0); +CSX = AddBox(CSX,'Hf',0 , start,stop); + +CSX = AddDump(CSX,'SAR','FileType',1,'DumpType',20,'DumpMode',2,'Frequency',f0); +CSX = AddBox(CSX,'SAR',0 , start,stop); + +start = [0 mesh.a(1) 0]; +stop = [BC.rad mesh.a(end) 0]; +CSX = AddDump(CSX,'Ht','FileType',1,'DumpType',1,'DumpMode',2); +CSX = AddBox(CSX,'Ht',0 , start,stop); + +%% finalize mesh +% add some lines for the pml in +/- z- direction +mesh = AddPML(mesh, [0 0 0 0 10 10], 1); + +% define the mesh +CSX = DefineRectGrid(CSX, unit, mesh); + +%% Write file & run openEMS +Sim_Path = ['tmp_' mfilename]; + +if (postproc_only==0) + [status, message, messageid] = rmdir(Sim_Path,'s'); %delete old results + [status, message, messageid] = mkdir(Sim_Path); %create folder + + WriteOpenEMS([Sim_Path '/BirdCage.xml'],FDTD,CSX); +end + +if (GeomPlot==1) + CSXGeomPlot( [Sim_Path '/BirdCage.xml'] , ['--export-polydata-vtk=' Sim_Path ' --RenderDiscMaterial -v']); +end + +if (postproc_only==0) + RunOpenEMS(Sim_Path, 'BirdCage.xml'); +end + +%% +freq = linspace(excite.f_0-excite.f_c,excite.f_0+excite.f_c,201); +port = calcPort(port, Sim_Path, freq); + +close all +s11 = port{1}.uf.ref./port{1}.uf.inc; +s22 = port{2}.uf.ref./port{2}.uf.inc; + +% the s-parameter may be larger than 1 (0dB) since all ports are excited +% and do not have a perfect port isolation +plot(freq*1e-6,20*log10(abs(s11)),'Linewidth',2) +hold on +grid on +plot(freq*1e-6,20*log10(abs(s22)),'r--','Linewidth',2) +legend('s11','s22'); + +%% read SAR values on a xy-plane (range) +[SAR SAR_mesh] = ReadHDF5Dump([Sim_Path '/SAR.h5'],'Range',{[],[],0},'CloseAlpha',1); +SAR = SAR.FD.values{1}; + +% SAR plot +figure() +[R A] = ndgrid(SAR_mesh.lines{1},SAR_mesh.lines{2}); +X = R.*cos(A);Y = R.*sin(A); +colormap('hot'); +h = pcolor(X,Y,(squeeze(SAR))); +% h = pcolor(X,Y,log10(squeeze(SAR))); +set(h,'EdgeColor','none'); +xlabel('x -->'); +ylabel('y -->'); +title('local SAR'); +axis equal tight + +%% plot B1+/- on an xy-plane +[H_field H_mesh] = ReadHDF5Dump([Sim_Path '/Hf.h5'],'Range',{[0 0.1],[],0},'CloseAlpha',1); +% create a 2D grid to plot on +[R A] = ndgrid(H_mesh.lines{1},H_mesh.lines{2}); +X = R.*cos(A); +Y = R.*sin(A); + +% calc Bx,By (from Br and Ba), B1p, B1m +Bx = MUE0*(H_field.FD.values{1}(:,:,:,1).*cos(A) - H_field.FD.values{1}(:,:,:,2).*sin(A)); +By = MUE0*(H_field.FD.values{1}(:,:,:,1).*sin(A) + H_field.FD.values{1}(:,:,:,2).*cos(A)); +B1p = 0.5*(Bx+1j*By); +B1m = 0.5*(Bx-1j*By); + +Dump2VTK([Sim_Path '/B1p_xy.vtk'], abs(B1p), H_mesh, 'B-Field'); +Dump2VTK([Sim_Path '/B1m_xy.vtk'], abs(B1m), H_mesh, 'B-Field'); + +maxB1 = max([abs(B1p(:)); abs(B1m(:))]); + +% B1+ plot +figure() +subplot(1,2,1); +h = pcolor(X,Y,abs(B1p)); +set(h,'EdgeColor','none'); +xlabel('x -->'); +ylabel('y -->'); +title('B_1^+ field (dB)'); +caxis([0 maxB1]); +axis equal tight + +% B1- plot +subplot(1,2,2); +h = pcolor(X,Y,abs(B1m)); +set(h,'EdgeColor','none'); +xlabel('x -->'); +ylabel('y -->'); +title('B_1^- field (dB)'); +caxis([0 maxB1]); +axis equal tight + +%% +ConvertHDF5_VTK([Sim_Path '/Hf.h5'],[Sim_Path '/Hf_xy'],'Range',{[],[],0},'CloseAlpha',1) +ConvertHDF5_VTK([Sim_Path '/SAR.h5'],[Sim_Path '/SAR_xy'],'Range',{[],[],0},'CloseAlpha',1) diff --git a/openEMS/matlab/Tutorials/MRI_Loop_Coil.m b/openEMS/matlab/Tutorials/MRI_Loop_Coil.m new file mode 100644 index 0000000..088f8f3 --- /dev/null +++ b/openEMS/matlab/Tutorials/MRI_Loop_Coil.m @@ -0,0 +1,334 @@ +% +% Tutorials / 7T MRI Loop Coil +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_MRI_Loop_Coil +% +% Tested with +% - openEMS v0.0.33 +% - Matlab 7.12.0 (R2011a) +% +% (C) 2013-2015 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation +physical_constants; %get some physical constants like c0 and MUE0 +unit = 1e-3; % all length in mm + +% Loop-Coil parameter +loop.length = 80; % length of the loop (in z-direction) +loop.width = 60; % width of the loop (in y-direction) +loop.strip_width = 5; % metal strip width +loop.strip_N_cells = 3; % number of cells over the strip length +loop.air_gap = loop.strip_width/3; % air gap width for lumped capacitors +loop.pos_x = -130; % position of loop +loop.C_gap = 5.4e-12; % lumped cap value +loop.port_R = 10; % feeding port resistance + +%% define the human body model (virtual family) +% set file name for human body model to create with "Convert_VF_DiscMaterial" +% the file name should contain a full path +body_model_file = [pwd '/Ella_centered_298MHz.h5']; + +% convert only part of the model (head/shoulder section) +body_model_range = {[],[],[-0.85 -0.4]}; + +% paths to virtual family voxel models (VFVM), adept to your install! +VF_raw_filesuffix = '/tmp/Ella_26y_V2_1mm'; +VF_mat_db_file = '/tmp/DB_h5_20120711_SEMCADv14.8.h5'; + +% delete(body_model_file); % uncomment to delete old model if something changed + +% convert model (if it does not exist) +Convert_VF_DiscMaterial(VF_raw_filesuffix, VF_mat_db_file, body_model_file, ... + 'Frequency', 298e6, 'Center', 1, ... + 'Range', body_model_range); + +% rotate model to face the nose in x-dir, and translate +body_model_transform = {'Rotate_X',pi,'Rotate_Z',pi/2, ... + 'Translate',[0,5,-720]}; + +% the head should + part of shoulder should fit this box +body_box.start = [-120 -150 -200]; +body_box.stop = [+100 +150 +130]; + +% box with high res mesh +mesh_box.start = [-120 -80 -120]; +mesh_box.stop = [+100 +80 +120]; +mesh_box.resolution = 2; + +%% some mesh parameter +Air_Box = 150; % size of the surrounding air box (150mm) + +%% setup FDTD parameter & excitation function +% init FDTD structure +FDTD = InitFDTD( 'EndCriteria', 1e-4, 'CellConstantMaterial', 0); + +% define gaussian pulse excitation signal +f0 = 298e6; % center frequency +fc = 300e6; % 20 dB corner frequency +FDTD = SetGaussExcite( FDTD, f0, fc ); + +% setup boundary conditions +BC = {'MUR' 'MUR' 'MUR' 'MUR' 'MUR' 'MUR'}; % boundary conditions +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +CSX = InitCSX(); + +%% create loop +% setup all properties needed +CSX = AddMetal( CSX, 'loop' ); +CSX = AddLumpedElement( CSX, 'caps_y', 1, 'C', loop.C_gap); +CSX = AddLumpedElement( CSX, 'caps_z', 2, 'C', loop.C_gap); + +% horizontal (y-direction) strips +start = [loop.pos_x -loop.width/2 -loop.length/2]; +stop = [loop.pos_x -loop.air_gap/2 -loop.length/2+loop.strip_width]; +CSX = AddBox(CSX,'loop',10,start,stop); + +start = [loop.pos_x -loop.width/2 loop.length/2 ]; +stop = [loop.pos_x -loop.air_gap/2 loop.length/2-loop.strip_width]; +CSX = AddBox(CSX,'loop',10,start,stop); + +start = [loop.pos_x loop.width/2 -loop.length/2]; +stop = [loop.pos_x loop.air_gap/2 -loop.length/2+loop.strip_width]; +CSX = AddBox(CSX,'loop',10,start,stop); + +start = [loop.pos_x loop.width/2 loop.length/2 ]; +stop = [loop.pos_x loop.air_gap/2 loop.length/2-loop.strip_width]; +CSX = AddBox(CSX,'loop',10,start,stop); + +% vertical (z-direction) strips +start = [loop.pos_x -loop.width/2 -loop.length/2+loop.strip_width]; +stop = [loop.pos_x -loop.width/2+loop.strip_width -loop.air_gap/2]; +CSX = AddBox(CSX,'loop',10,start,stop); + +start = [loop.pos_x -loop.width/2 loop.length/2-loop.strip_width]; +stop = [loop.pos_x -loop.width/2+loop.strip_width loop.air_gap/2]; +CSX = AddBox(CSX,'loop',10,start,stop); + +start = [loop.pos_x loop.width/2 -loop.length/2+loop.strip_width]; +stop = [loop.pos_x loop.width/2-loop.strip_width -loop.air_gap/2]; +CSX = AddBox(CSX,'loop',10,start,stop); + +start = [loop.pos_x loop.width/2 loop.length/2-loop.strip_width ]; +stop = [loop.pos_x loop.width/2-loop.strip_width loop.air_gap/2]; +CSX = AddBox(CSX,'loop',10,start,stop); + +% add the lumped capacities +start = [loop.pos_x -loop.width/2+loop.strip_width/2-loop.air_gap/2 -loop.air_gap/2]; +stop = [loop.pos_x -loop.width/2+loop.strip_width/2+loop.air_gap/2 +loop.air_gap/2]; +CSX = AddBox(CSX,'caps_z',10,start,stop); + +start = [loop.pos_x loop.width/2-loop.strip_width/2-loop.air_gap/2 -loop.air_gap/2]; +stop = [loop.pos_x loop.width/2-loop.strip_width/2+loop.air_gap/2 +loop.air_gap/2]; +CSX = AddBox(CSX,'caps_z',10,start,stop); + +start = [loop.pos_x -loop.air_gap/2 loop.length/2-loop.strip_width/2-loop.air_gap/2]; +stop = [loop.pos_x +loop.air_gap/2 loop.length/2-loop.strip_width/2+loop.air_gap/2]; +CSX = AddBox(CSX,'caps_y',10,start,stop); + +% add a lumped port as excitation +start = [loop.pos_x -loop.air_gap/2 -loop.length/2+loop.strip_width/2-loop.air_gap/2]; +stop = [loop.pos_x +loop.air_gap/2 -loop.length/2+loop.strip_width/2+loop.air_gap/2]; +[CSX port] = AddLumpedPort(CSX, 100, 1, loop.port_R, start, stop, [0 1 0], true); + +%% define human body model +CSX = AddDiscMaterial(CSX, 'body_model', 'File', body_model_file, 'Scale', 1/unit, 'Transform', body_model_transform); +CSX = AddBox(CSX, 'body_model', 0, body_box.start, body_box.stop); + +%% finalize mesh +% create loop mesh +mesh = DetectEdges(CSX); + +% add a dense homegeneous mesh inside the human body model +mesh.x = [mesh.x mesh_box.start(1) mesh_box.stop(1)]; +mesh.y = [mesh.y mesh_box.start(2) mesh_box.stop(2)]; +mesh.z = [mesh.z mesh_box.start(3) mesh_box.stop(3)]; + +% add lines in x-dir for the loop and a cell centered around 0 +mesh.x = [mesh.x loop.pos_x -mesh_box.resolution/2 mesh_box.resolution/2]; + +% smooth the mesh for the loop & body +mesh = SmoothMesh(mesh, mesh_box.resolution); + +% add air spacer +mesh.x = [-Air_Box+mesh.x(1) mesh.x mesh.x(end)+Air_Box]; +mesh.y = [-Air_Box+mesh.y(1) mesh.y mesh.y(end)+Air_Box]; +mesh.z = [-Air_Box+mesh.z(1) mesh.z mesh.z(end)+Air_Box]; + +mesh = SmoothMesh(mesh, c0 / (f0+fc) / unit / 10, 1.5, 'algorithm', 1); + +%% Add Dump boxes (2D boxes) for H and SAR on xy- and xz-plane +CSX = AddDump(CSX,'Hf_xy','DumpType',11,'FileType',1,'Frequency',f0); +CSX = AddBox(CSX,'Hf_xy',0, body_box.start.*[1 1 0], body_box.stop.*[1 1 0]); +CSX = AddDump(CSX,'SAR_xy','DumpType',20,'DumpMode',2,'FileType',1,'Frequency',f0); +CSX = AddBox(CSX,'SAR_xy',0, body_box.start.*[1 1 0], body_box.stop.*[1 1 0]); + +CSX = AddDump(CSX,'Hf_xz','DumpType',11,'FileType',1,'Frequency',f0); +CSX = AddBox(CSX,'Hf_xz',0, body_box.start.*[1 0 1], body_box.stop.*[1 0 1]); +CSX = AddDump(CSX,'SAR_xz','DumpType',20,'DumpMode',2,'FileType',1,'Frequency',f0); +CSX = AddBox(CSX,'SAR_xz',0, body_box.start.*[1 0 1], body_box.stop.*[1 0 1]); + +%% add 10 lines in all direction to make space for PML or MUR absorbing +%% boundary conditions +mesh = AddPML(mesh, 10); + +%% finaly define the FDTD mesh grid +disp(['number of cells: ' num2str(1e-6*numel(mesh.x)*numel(mesh.y)*numel(mesh.z)) ' Mcells']) +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% prepare simulation folder +Sim_Path = ['tmp_' mfilename]; +Sim_CSX = [mfilename '.xml']; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +%% write openEMS compatible xml-file +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + +%% show the structure and export as vtk data automatically +CSXGeomPlot( [Sim_Path '/' Sim_CSX] , ['--export-polydata-vtk=' Sim_Path ' --RenderDiscMaterial -v']); + +%% run openEMS +RunOpenEMS( Sim_Path, Sim_CSX); + +%% postprocessing & do the plots +freq = linspace( f0-fc, f0+fc, 501 ); +port = calcPort(port, Sim_Path, freq); + +Zin = port.uf.tot ./ port.if.tot; +s11 = port.uf.ref ./ port.uf.inc; + +% get the feeding power for frequency f0 +P0_in = interp1(freq, port.P_acc, f0); + +%% +% plot reflection coefficient S11 +figure +h = plot( freq/1e6, 20*log10(abs(s11)), 'k-', 'Linewidth', 2 ); +grid on +title( 'reflection coefficient S_{11}' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'reflection coefficient |S_{11}| (dB)' ); + +% plot feed point admittance +figure +h = plot( freq/1e6, real(1./Zin), 'k-', 'Linewidth', 2 ); +hold on +grid on +plot( freq/1e6, imag(1./Zin), 'r--', 'Linewidth', 2 ); +title( 'feed port admittance' ); +xlabel( 'frequency f (MHz)' ); +ylabel( 'admittance Y_{in} (S)' ); +legend( 'real', 'imag' ); + +%% read SAR values on a xy-plane (range) +[SAR SAR_mesh] = ReadHDF5Dump([Sim_Path '/SAR_xy.h5']); +SAR = SAR.FD.values{1}/P0_in; + +% SAR plot +figure() +subplot(1,2,1); +[X Y] = ndgrid(SAR_mesh.lines{1},SAR_mesh.lines{2}); +colormap('hot'); +h = pcolor(X,Y,(squeeze(SAR))); +% h = pcolor(X,Y,log10(squeeze(SAR))); +set(h,'EdgeColor','none'); +xlabel('x -->'); +ylabel('y -->'); +title('local SAR'); +axis equal tight + +%% read SAR values on a xz-plane (range) +[SAR SAR_mesh] = ReadHDF5Dump([Sim_Path '/SAR_xz.h5']); +SAR = SAR.FD.values{1}/P0_in; + +% SAR plot +subplot(1,2,2); +[X Z] = ndgrid(SAR_mesh.lines{1},SAR_mesh.lines{3}); +colormap('hot'); +h = pcolor(X,Z,(squeeze(SAR))); +% h = pcolor(X,Y,log10(squeeze(SAR))); +set(h,'EdgeColor','none'); +xlabel('x -->'); +ylabel('z -->'); +title('local SAR'); +axis equal tight + +%% plot B1+/- on an xy-plane +[H_field H_mesh] = ReadHDF5Dump([Sim_Path '/Hf_xy.h5']); +% calc Bx,By, B1p, B1m normalize to the input-power +Bx = MUE0*H_field.FD.values{1}(:,:,:,1)/sqrt(P0_in); +By = MUE0*H_field.FD.values{1}(:,:,:,2)/sqrt(P0_in); +B1p = 0.5*(Bx+1j*By); +B1m = 0.5*(Bx-1j*By); +% create a 2D grid to plot on +[X Y] = ndgrid(H_mesh.lines{1},H_mesh.lines{2}); + +Dump2VTK([Sim_Path '/B1p_xy.vtk'], abs(B1p), H_mesh, 'B-Field'); +Dump2VTK([Sim_Path '/B1m_xy.vtk'], abs(B1m), H_mesh, 'B-Field'); + +% B1+ plot +figure() +subplot(1,2,1); +h = pcolor(X,Y,log10(abs(B1p))); +set(h,'EdgeColor','none'); +xlabel('x -->'); +ylabel('y -->'); +title('B_1^+ field (dB)'); +axis equal tight + +% B1- plot +subplot(1,2,2); +h = pcolor(X,Y,log10(abs(B1m))); +set(h,'EdgeColor','none'); +xlabel('x -->'); +ylabel('y -->'); +title('B_1^- field (dB)'); +axis equal tight + +%% plot B1+/- on an xz-plane +[H_field H_mesh] = ReadHDF5Dump([Sim_Path '/Hf_xz.h5']); +% calc Bx,By, B1p, B1m normalize to the input-power +Bx = MUE0*H_field.FD.values{1}(:,:,:,1)/sqrt(P0_in); +By = MUE0*H_field.FD.values{1}(:,:,:,2)/sqrt(P0_in); +B1p = 0.5*(Bx+1j*By); +B1m = 0.5*(Bx-1j*By); +% create a 2D grid to plot on +[X Z] = ndgrid(H_mesh.lines{1},H_mesh.lines{3}); + +Dump2VTK([Sim_Path '/B1p_xz.vtk'], abs(B1p), H_mesh, 'B-Field'); +Dump2VTK([Sim_Path '/B1m_xz.vtk'], abs(B1m), H_mesh, 'B-Field'); + +% B1+ plot +figure() +subplot(1,2,1); +h = pcolor(X,Z,log10(squeeze(abs(B1p)))); +set(h,'EdgeColor','none'); +xlabel('x -->'); +ylabel('z -->'); +title('B_1^+ field (dB)'); +axis equal tight + +% B1- plot +subplot(1,2,2); +h = pcolor(X,Z,log10(squeeze(abs(B1m)))); +set(h,'EdgeColor','none'); +xlabel('x -->'); +ylabel('z -->'); +title('B_1^- field (dB)'); +axis equal tight + +%% dump to vtk to view in Paraview +ConvertHDF5_VTK([Sim_Path '/SAR_xy.h5'],[Sim_Path '/SAR_xy'], 'weight', 1/P0_in, 'FieldName', 'SAR'); +ConvertHDF5_VTK([Sim_Path '/SAR_xz.h5'],[Sim_Path '/SAR_xz'], 'weight', 1/P0_in, 'FieldName', 'SAR'); + +%% +ConvertHDF5_VTK([Sim_Path '/Hf_xy.h5'],[Sim_Path '/B1_xy'], 'weight', MUE0/sqrt(P0_in), 'FieldName', 'B1-field'); +ConvertHDF5_VTK([Sim_Path '/Hf_xz.h5'],[Sim_Path '/B1_xz'], 'weight', MUE0/sqrt(P0_in), 'FieldName', 'B1-field'); diff --git a/openEMS/matlab/Tutorials/MSL_NotchFilter.m b/openEMS/matlab/Tutorials/MSL_NotchFilter.m new file mode 100644 index 0000000..612456c --- /dev/null +++ b/openEMS/matlab/Tutorials/MSL_NotchFilter.m @@ -0,0 +1,92 @@ +% +% Tutorials / MSL_NotchFilter +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_Microstrip_Notch_Filter +% +% Tested with +% - Matlab 2011a / Octave 4.0 +% - openEMS v0.0.33 +% +% (C) 2011-2015 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants; +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 = InitFDTD(); +FDTD = SetGaussExcite( FDTD, f_max/2, f_max/2 ); +BC = {'PML_8' 'PML_8' 'MUR' 'MUR' 'PEC' 'MUR'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +resolution = c0/(f_max*sqrt(substrate_epr))/unit /50; % resolution of lambda/50 +mesh.x = SmoothMeshLines( [0 MSL_width/2+[2*resolution/3 -resolution/3]/4], resolution/4, 1.5 ,0 ); +mesh.x = SmoothMeshLines( [-MSL_length -mesh.x mesh.x MSL_length], resolution, 1.5 ,0 ); +mesh.y = SmoothMeshLines( [0 MSL_width/2+[-resolution/3 +resolution/3*2]/4], resolution/4 , 1.5 ,0); +mesh.y = SmoothMeshLines( [-15*MSL_width -mesh.y mesh.y stub_length+[-resolution/3 +resolution/3*2]/4 15*MSL_width+stub_length], resolution, 1.3 ,0); +mesh.z = SmoothMeshLines( [linspace(0,substrate_thickness,5) 10*substrate_thickness], resolution ); +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% substrate +CSX = AddMaterial( CSX, 'RO4350B' ); +CSX = SetMaterialProperty( CSX, 'RO4350B', 'Epsilon', substrate_epr ); +start = [mesh.x(1), mesh.y(1), 0]; +stop = [mesh.x(end), mesh.y(end), substrate_thickness]; +CSX = AddBox( CSX, 'RO4350B', 0, start, stop ); + +%% MSL port +CSX = AddMetal( CSX, 'PEC' ); +portstart = [ mesh.x(1), -MSL_width/2, substrate_thickness]; +portstop = [ 0, MSL_width/2, 0]; +[CSX,port{1}] = AddMSLPort( CSX, 999, 1, 'PEC', portstart, portstop, 0, [0 0 -1], 'ExcitePort', true, 'FeedShift', 10*resolution, 'MeasPlaneShift', MSL_length/3); + +portstart = [mesh.x(end), -MSL_width/2, substrate_thickness]; +portstop = [0 , MSL_width/2, 0]; +[CSX,port{2}] = AddMSLPort( CSX, 999, 2, 'PEC', portstart, portstop, 0, [0 0 -1], 'MeasPlaneShift', MSL_length/3 ); + +%% Filter-stub +start = [-MSL_width/2, MSL_width/2, substrate_thickness]; +stop = [ MSL_width/2, MSL_width/2+stub_length, substrate_thickness]; +CSX = AddBox( CSX, 'PEC', 999, start, stop ); + +%% write/show/run the openEMS compatible xml-file +Sim_Path = 'tmp'; +Sim_CSX = 'msl.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +RunOpenEMS( Sim_Path, Sim_CSX ); + +%% post-processing +close all +f = linspace( 1e6, f_max, 1601 ); +port = calcPort( port, Sim_Path, f, 'RefImpedance', 50); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; + +plot(f/1e9,20*log10(abs(s11)),'k-','LineWidth',2); +hold on; +grid on; +plot(f/1e9,20*log10(abs(s21)),'r--','LineWidth',2); +legend('S_{11}','S_{21}'); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (GHz) \rightarrow','FontSize',12); +ylim([-40 2]); + diff --git a/openEMS/matlab/Tutorials/Parallel_Plate_Waveguide.m b/openEMS/matlab/Tutorials/Parallel_Plate_Waveguide.m new file mode 100644 index 0000000..cbf76c0 --- /dev/null +++ b/openEMS/matlab/Tutorials/Parallel_Plate_Waveguide.m @@ -0,0 +1,51 @@ +% +% Tutorials / Parallel_Plate_Waveguide +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_Parallel_Plate_Waveguide +% +% Tested with +% - Matlab 2011a / Octave 4.0 +% - openEMS v0.0.33 +% +% (C) 2011,2012 Sebastian Held +% (C) 2011-2015 Thorsten Liebig + +close all +clear +clc + +% init and define FDTD parameter +FDTD = InitFDTD(100,0,'OverSampling',50); +FDTD = SetSinusExcite(FDTD,10e6); +BC = {'PMC' 'PMC' 'PEC' 'PEC' 'MUR' 'MUR'}; +FDTD = SetBoundaryCond(FDTD,BC); + +% init and define FDTD mesh +CSX = InitCSX(); +mesh.x = -10:10; +mesh.y = -10:10; +mesh.z = -10:30; +CSX = DefineRectGrid(CSX, 1, mesh); + +% define the excitation +CSX = AddExcitation(CSX,'excitation',0,[0 1 0]); +CSX = AddBox(CSX,'excitation',0,[-10 -10 0],[10 10 0]); + +% define a time domain e-field dump box +CSX = AddDump(CSX,'Et','DumpMode',0); +CSX = AddBox(CSX,'Et',0,[-10 0 -10],[10 0 30]); + +% remove old simulation results (if exist) +rmdir('tmp','s');mkdir('tmp'); + +% write openEMS xml data file +WriteOpenEMS('tmp/tmp.xml',FDTD,CSX); + +% view defined structure +CSXGeomPlot( 'tmp/tmp.xml' ); + +% run openEMS simulation +RunOpenEMS('tmp','tmp.xml',''); + +disp('use Paraview to visualize the FDTD result...'); diff --git a/openEMS/matlab/Tutorials/Patch_Antenna_Array.m b/openEMS/matlab/Tutorials/Patch_Antenna_Array.m new file mode 100644 index 0000000..ed12c67 --- /dev/null +++ b/openEMS/matlab/Tutorials/Patch_Antenna_Array.m @@ -0,0 +1,170 @@ +function [port nf2ff] = Patch_Antenna_Array(Sim_Path, postproc_only, show_structure, xpos, caps, resist, active ) +% [port nf2ff] = Patch_Antenna_Array(Sim_Path, postproc_only, show_structure, xpos, caps, resist, active ) +% +% Script to setup the patch array as described in [1]. +% Run main script in Patch_Antenna_Phased_Array.m instead! +% +% Sim_Path: Simulation path +% postproc_only: set to post process only 0/1 +% show_structure: show the strucuture in AppCSXCAD 0/1 +% xpos: the x-position for each antenna is defined +% caps: the port capacity (will override active port) +% resist: port resitance +% active: switch port active +% +% References: +% [1] Y. Yusuf and X. Gong, “A low-cost patch antenna phased array with +% analog beam steering using mutual coupling and reactive loading,†IEEE +% Antennas Wireless Propag. Lett., vol. 7, pp. 81–84, 2008. +% +% Tested with +% - Matlab 2011a +% - openEMS v0.0.31 +% +% (C) 2013 Thorsten Liebig + +% example +% xpos = [-41 0 41]; +% caps = [0.2e-12 0 0.2e-12]; +% active = [0 1 0]; +% resist = [50 50 50]; + +%% setup the simulation +physical_constants; +unit = 1e-3; % all length in mm + +% patch geometry setup +patch.W = 35; % width +patch.L = 28.3; % length +patch.Ws = 3.8; % width of feeding stub +patch.Gs = 1; % width of feeding gab +patch.l = 6; % length of feeding stub +patch.y0 = 10; % depth of feeding stub into into patch + +% patch resonance frequency +f0 = 3e9; + +%substrate setup +substrate.name = 'Ro3003'; +substrate.epsR = 3; +substrate.kappa = 0.0013 * 2*pi*f0 * EPS0*substrate.epsR; +substrate.thickness = 1.524; +substrate.cells = 4; + +substrate.width = patch.W + max(xpos) - min(xpos) + 4*patch.l; +substrate.length = 3*patch.l + patch.L; + +% size of the simulation box +AirSpacer = [50 50 30]; + +edge_res = [-1/3 2/3]*1; + +%% setup FDTD parameter & excitation function +fc = 2e9; % 20 dB corner frequency +FDTD = InitFDTD( 'EndCriteria', 1e-4 ); +FDTD = SetGaussExcite( FDTD, f0, fc ); +BC = [1 1 1 1 1 1]*3; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +CSX = InitCSX(); + +mesh.x = []; +mesh.y = []; +mesh.z = []; + +%% create patch +CSX = AddMetal( CSX, 'patch' ); % create a perfect electric conductor (PEC) + +for port_nr=1:numel(xpos) + start = [xpos(port_nr)-patch.W/2 patch.l substrate.thickness]; + stop = [xpos(port_nr)-patch.Ws/2-patch.Gs patch.l+patch.L substrate.thickness]; + CSX = AddBox(CSX,'patch',10, start, stop); + mesh.x = [mesh.x xpos(port_nr)-patch.W/2-edge_res]; + + start = [xpos(port_nr)+patch.W/2 patch.l substrate.thickness]; + stop = [xpos(port_nr)+patch.Ws/2+patch.Gs patch.l+patch.L substrate.thickness]; + CSX = AddBox(CSX,'patch',10, start, stop); + mesh.x = [mesh.x xpos(port_nr)+patch.W/2+edge_res]; + + mesh.y = [mesh.y patch.l-edge_res patch.l+patch.L+edge_res]; + + start = [xpos(port_nr)-patch.Ws/2-patch.Gs patch.l+patch.y0 substrate.thickness]; + stop = [xpos(port_nr)+patch.Ws/2+patch.Gs patch.l+patch.L substrate.thickness]; + CSX = AddBox(CSX,'patch',10, start, stop); + + % feed line + start = [xpos(port_nr)-patch.Ws/2 patch.l+patch.y0 substrate.thickness]; + stop = [xpos(port_nr)+patch.Ws/2 0 substrate.thickness]; + CSX = AddBox(CSX,'patch',10, start, stop); + + mesh.x = [mesh.x xpos(port_nr)+linspace(-patch.Ws/2-patch.Gs,-patch.Ws/2,3) xpos(port_nr)+linspace(patch.Ws/2,patch.Ws/2+patch.Gs,3)]; + + start = [xpos(port_nr)-patch.Ws/2 0 0]; + stop = [xpos(port_nr)+patch.Ws/2 0 substrate.thickness]; + if (caps(port_nr)>0) + CSX = AddLumpedElement(CSX, ['C_' num2str(port_nr)], 2, 'C', caps(port_nr)); + CSX = AddBox(CSX,['C_' num2str(port_nr)],10, start, stop); + + [CSX port{port_nr}] = AddLumpedPort(CSX, 5 ,port_nr ,inf, start, stop, [0 0 1], 0); + else + % feed port + [CSX port{port_nr}] = AddLumpedPort(CSX, 5 ,port_nr, resist(port_nr), start, stop, [0 0 1], active(port_nr)); + end +end + +%% create substrate +CSX = AddMaterial( CSX, substrate.name ); +CSX = SetMaterialProperty( CSX, substrate.name, 'Epsilon', substrate.epsR, 'Kappa', substrate.kappa ); +start = [-substrate.width/2 0 0]; +stop = [ substrate.width/2 substrate.length substrate.thickness]; +CSX = AddBox( CSX, substrate.name, 0, start, stop ); + +mesh.x = [mesh.x start(1) stop(1)]; +mesh.y = [mesh.y start(2) stop(2)]; + +% add extra cells to discretize the substrate thickness +mesh.z = [linspace(0,substrate.thickness,substrate.cells+1) mesh.z]; + +%% create ground (same size as substrate) +CSX = AddMetal( CSX, 'gnd' ); % create a perfect electric conductor (PEC) +start(3)=0; +stop(3) =0; +CSX = AddBox(CSX,'gnd',10,start,stop); + +%% finalize the mesh +% generate a smooth mesh with max. cell size: lambda_min / 20 +mesh = SmoothMesh(mesh, 2, 1.3); +mesh.x = [mesh.x min(mesh.x)-AirSpacer(1) max(mesh.x)+AirSpacer(1)]; +mesh.y = [mesh.y min(mesh.y)-AirSpacer(2) max(mesh.y)+AirSpacer(2)]; +mesh.z = [mesh.z min(mesh.z)-AirSpacer(3) max(mesh.z)+2*AirSpacer(3)]; + +mesh = SmoothMesh(mesh, c0 / (f0+fc) / unit / 20, 1.3); + +%% add a nf2ff calc box; size is 3 cells away from MUR boundary condition +start = [mesh.x(4) mesh.y(4) mesh.z(4)]; +stop = [mesh.x(end-3) mesh.y(end-3) mesh.z(end-3)]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop); + +mesh = AddPML(mesh,(BC==3)*8); +CSX = DefineRectGrid(CSX, unit, mesh); + +%% prepare simulation folder +Sim_CSX = 'patch_array.xml'; + +if (postproc_only==0) + [status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory + [status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + + %% write openEMS compatible xml-file + WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + + %% show the structure + if (show_structure>0) + CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + end + + %% run openEMS + RunOpenEMS( Sim_Path, Sim_CSX); +end + diff --git a/openEMS/matlab/Tutorials/Patch_Antenna_Phased_Array.m b/openEMS/matlab/Tutorials/Patch_Antenna_Phased_Array.m new file mode 100644 index 0000000..873f345 --- /dev/null +++ b/openEMS/matlab/Tutorials/Patch_Antenna_Phased_Array.m @@ -0,0 +1,166 @@ +% +% Tutorials / Patch Antenna Phased Array +% +% Describtion at: +% +% Tested with +% - Matlab 2011a +% - Octave 4.0 +% - openEMS v0.0.33 +% +% References: +% [1] Y. Yusuf and X. Gong, “A low-cost patch antenna phased array with +% analog beam steering using mutual coupling and reactive loading,†IEEE +% Antennas Wireless Propag. Lett., vol. 7, pp. 81–84, 2008. +% [2] S. Otto, S. Held, A. Rennings, and K. Solbach, +% "Array and multiport antenna farfield simulation using +% EMPIRE, MATLAB and ADS," 39th European Microwave Conf. (EuMC 2009), +% Sept. 29 – Oct. 1, Rome, Italy, pp. 1547-1550, 2009. +% [3] K. Karlsson, J. Carlsson, I. Belov, G. Nilsson, and P.-S. Kildal, +% “Optimization of antenna diversity gain by combining full-wave and +% circuit simulations,†in Proc. Second European Conference on Antennas +% and Propagation EuCAP 2007, 11–16 Nov. 2007, pp. 1–5. +% +% (C) 2013-2015 Thorsten Liebig + + +close all +clear +clc + +% we need the "Cuircuit Toolbox" +addpath('C:\CTB'); +% get the latest version from: +% using git: https://github.com/thliebig/CTB +% or zip: https://github.com/thliebig/CTB/archive/master.zip + +% set this to 0 to NOT run a reference simulation with the given C2 and C3 +% for comparison +do_reference_simulation = 1; + +% set to 1 if you want to run AppCSXCAD to see the simulated structure +show_structure = 1; + +% set this to 1, to force openEMS to run again even if the data already exist +force_rerun = 0; + +% frequency range of interest +f = linspace( 1e9, 5e9, 1601 ); + +% resonant frequency for far-field calculations +f0 = 3e9; + +% capacities for port 2 and 3 to shift the far-field pattern +C2 = 0.2e-12; +C3 = 0.2e-12; + +Sim_Path_Root = ['tmp_' mfilename]; + +%% calculate the full S-parameter set for all 3 patch antennas running 3 +% individual openEMS simulations in which one antenna is active and the +% other two a passive (50 Ohm load) respectively +xpos = [0 -41 41]; % x-center position of the 3 antennas +caps = [0 0 0]; +resist = [50 50 50]; + +spara = []; +color_code = {'k-','r--','m-.'}; + +for n=1:3 + active = [0 0 0]; + active(n) = 1; % activate antenna n + Sim_Path = [Sim_Path_Root '_' num2str(n)]; % create an individual path + [port{n} nf2ff{n}] = Patch_Antenna_Array(Sim_Path, ((exist(Sim_Path,'dir')>0) && (force_rerun==0)), show_structure, xpos, caps, resist, active); + port{n} = calcPort( port{n}, Sim_Path, f, 'RefImpedance', 50); + nf2ff{n} = CalcNF2FF(nf2ff{n}, Sim_Path, f0, [-180:2:180]*pi/180, 0); + + figure + hold on + grid on + for p=1:3 + I(p,n) = interp1(f, port{n}{p}.if.tot,f0); + P_in(p) = 0.5*interp1(f, port{n}{n}.uf.inc,f0)*conj(interp1(f, port{n}{n}.if.inc,f0)); + spara(p,n,:) = port{n}{p}.uf.ref./ port{n}{n}.uf.inc; + plot(f, squeeze(20*log10(abs(spara(p,n,:)))),color_code{p},'Linewidth',2); + end +end + +%% export sparameter to touchstone file +write_touchstone('s',f,spara,[Sim_Path_Root '.s3p']); + +% instructions for Qucs: +% load the written touchstone file +% attach C2 and C3 to port 2 and 3 +% attach a signal port to port 1 +% probe the currents going into port 1 to 3 + +% example currents for ports 1 to 3 for C2 = 0.2pF and C3=0.2pF +I_qucs(1,1) = 0.00398-0.000465j; +I_qucs(2,1) = 2.92e-5-0.000914j; +I_qucs(3,1) = 2.92e-5-0.000914j; + +disp(['I2/I1: Qucs: ' num2str(I_qucs(2)/I_qucs(1)) ' (defined manually)']) +disp(['I3/I1: Qucs: ' num2str(I_qucs(3)/I_qucs(1)) ' (defined manually)']) + +%% Calculate the currents of port 1 to 3 using Matlab [1] +z = s2z(spara); + +Z2 = 1/(1j*2*pi*f0*C2); +Z3 = 1/(1j*2*pi*f0*C3); + +z23(1,1) = interp1(f,squeeze(z(2,2,:)),f0) + Z2; +z23(1,2) = interp1(f,squeeze(z(2,3,:)),f0); +z23(2,1) = interp1(f,squeeze(z(3,2,:)),f0); +z23(2,2) = interp1(f,squeeze(z(3,3,:)),f0) + Z3; + +%set input/feeding current of port 1 to 1mA +I_out(1,1) = 1e-3; +% calc current for port 2 and 3 +I_out([2 3],1) = z23\[-interp1(f,squeeze(z(2,1,:)),f0);-interp1(f,squeeze(z(3,1,:)),f0)]*I_out(1); + +disp(['I2/I1: Matlab: ' num2str(I_out(2)/I_out(1))]) +disp(['I3/I1: Matlab: ' num2str(I_out(3)/I_out(1))]) + + +%% do a referenc simulation for the given C2/C3 values +if (do_reference_simulation) + active = [1 0 0]; + caps = [0 C2 C3]; + resist = [50 inf inf]; + Sim_Path = [Sim_Path_Root '_C2=' num2str(C2*1e12) '_C3=' num2str(C3*1e12)]; + [port_ref nf2ff_ref] = Patch_Antenna_Array(Sim_Path, ((exist(Sim_Path,'dir')>0) && (force_rerun==0)), show_structure, xpos, caps, resist, active); + port_ref = calcPort( port_ref, Sim_Path, f, 'RefImpedance', 50); + nf2ff_ref = CalcNF2FF(nf2ff_ref, Sim_Path, f0, [-180:2:180]*pi/180, 0); + + % extract currents from referenc simulation + for p=1:3 + I_ref(p,1) = interp1(f, port_ref{p}.if.tot,f0); + end + + disp(['I2/I1: openEMS: ' num2str(I_ref(2)/I_ref(1))]) + disp(['I3/I1: openEMS: ' num2str(I_ref(3)/I_ref(1))]) +end + +%% calculate and apply weighting cooefficients [3] +% calculate +coeff = I\I_out; + +% apply +E_ff_phi = 0*nf2ff{1}.E_phi{1}; +E_ff_theta = 0*nf2ff{1}.E_phi{1}; +for n=1:3 + E_ff_phi = E_ff_phi + coeff(n)*nf2ff{n}.E_phi{1}; + E_ff_theta = E_ff_theta + coeff(n)*nf2ff{n}.E_theta{1}; +end + +%% plot far-field patterns +figure +polar([-180:2:180]'*pi/180,abs(E_ff_phi(:))/max(abs(E_ff_phi(:)))); +hold on +if (do_reference_simulation) + polar([-180:2:180]'*pi/180,abs(nf2ff_ref.E_norm{1}(:,1))/max(abs(nf2ff_ref.E_norm{1}(:,1))),'r--'); +end +title('normalized far-field pattern','Interpreter', 'none') +legend('calculated','reference') + + diff --git a/openEMS/matlab/Tutorials/RCS_Sphere.m b/openEMS/matlab/Tutorials/RCS_Sphere.m new file mode 100644 index 0000000..b8bb5bc --- /dev/null +++ b/openEMS/matlab/Tutorials/RCS_Sphere.m @@ -0,0 +1,138 @@ +% +% Tutorials / radar cross section of a metal sphere +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_RCS_Sphere +% +% Tested with +% - Matlab 2013a / Octave 3.8.1 +% - openEMS v0.0.32 +% +% (C) 2012-2014 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation +physical_constants; +unit = 1e-3; % all length in mm + +sphere.rad = 200; + +inc_angle = 0 /180*pi; %incident angle (to x-axis) in rad + +% size of the simulation box +SimBox = 1000; +PW_Box = 750; + +%% setup FDTD parameter & excitation function +f_start = 50e6; % start frequency +f_stop = 1000e6; % stop frequency +f0 = 500e6; + +FDTD = InitFDTD( ); +FDTD = SetGaussExcite( FDTD, 0.5*(f_start+f_stop), 0.5*(f_stop-f_start) ); +BC = [1 1 1 1 1 1]*3; % set boundary conditions +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +max_res = c0 / f_stop / unit / 20; % cell size: lambda/20 +CSX = InitCSX(); + +%create mesh +smooth_mesh = SmoothMeshLines([0 SimBox/2], max_res); +mesh.x = unique([-smooth_mesh smooth_mesh]); +mesh.y = mesh.x; +mesh.z = mesh.x; + +%% create metal sphere +CSX = AddMetal( CSX, 'sphere' ); % create a perfect electric conductor (PEC) +CSX = AddSphere(CSX,'sphere',10,[0 0 0],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 + +CSX = AddPlaneWaveExcite(CSX, 'plane_wave', k_dir, E_dir, f0); +start = [-PW_Box/2 -PW_Box/2 -PW_Box/2]; +stop = -start; +CSX = AddBox(CSX, 'plane_wave', 0, start, stop); + +%% dump boxes +CSX = AddDump(CSX, 'Et'); +start = [mesh.x(1) mesh.y(1) 0]; +stop = [mesh.x(end) mesh.y(end) 0]; +CSX = AddBox(CSX, 'Et', 0, start, stop); + +%%nf2ff calc +start = [mesh.x(1) mesh.y(1) mesh.z(1)]; +stop = [mesh.x(end) mesh.y(end) mesh.z(end)]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop); + +% add 8 lines in all direction as pml spacing +mesh = AddPML(mesh,8); + +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% prepare simulation folder +Sim_Path = 'Sphere_RCS'; +Sim_CSX = 'Sphere_RCS.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +%% write openEMS compatible xml-file +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + +%% show the structure +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + +%% run openEMS +RunOpenEMS( Sim_Path, Sim_CSX); + +%% +disp('Use Paraview to display the elctric fields dumped by openEMS'); + +%% +EF = ReadUI( 'et', Sim_Path, f0 ); % time domain/freq domain voltage +Pin = 0.5*norm(E_dir)^2/Z0 .* abs(EF.FD{1}.val).^2; + +%% +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f0, pi/2, [-180:2:180]*pi/180, 'Mode',1); +RCS = 4*pi./Pin(1).*nf2ff.P_rad{1}(:); +polar(nf2ff.phi,RCS); +xlabel('x -->'); +ylabel('y -->'); +hold on +grid on + +drawnow + +%% +freq = linspace(f_start,f_stop,100); +EF = ReadUI( 'et', Sim_Path, freq ); % time domain/freq domain voltage +Pin = 0.5*norm(E_dir)^2/Z0 .* abs(EF.FD{1}.val).^2; + +nf2ff = CalcNF2FF(nf2ff, Sim_Path, freq, pi/2, pi+inc_angle, 'Mode',1); +for fn=1:numel(freq) + back_scat(fn) = 4*pi./Pin(fn).*nf2ff.P_rad{fn}(1); +end + +%% +figure +plot(freq/1e6,back_scat,'Linewidth',2); +grid on; +xlabel('frequency (MHz) \rightarrow'); +ylabel('RCS (m^2) \rightarrow'); +title('radar cross section'); + +%% +figure +lambda = c0./freq; +semilogy(sphere.rad*unit./lambda,back_scat/(pi*sphere.rad*unit*sphere.rad*unit),'Linewidth',2); +ylim([10^-2 10^1]) +grid on; +xlabel('sphere radius / wavelength \rightarrow'); +ylabel('RCS / (\pi a^2) \rightarrow'); +title('normalized radar cross section'); diff --git a/openEMS/matlab/Tutorials/RadarUWBTutorial.m b/openEMS/matlab/Tutorials/RadarUWBTutorial.m new file mode 100644 index 0000000..6fd2f5b --- /dev/null +++ b/openEMS/matlab/Tutorials/RadarUWBTutorial.m @@ -0,0 +1,236 @@ +% Tutorial on time delay and signal integrity for radar +% and UWB applications +% +% Tested with +% - Octave 4.0 +% - openEMS v0.0.35 +% +% Author: Georg Michel, 2016 + + clear; + close all; + +physical_constants; + +% --- start of configuration section --- + +% In radar and ultrawideband applications it is important to know the +% delay and fidelity of RF pulses. The delay is the retardation of the +% signal from the source to the phase center of the antenna. It is +% composed out of linear delay, dispersion and minimum-phase +% delay. Dispersion due to waveguides or frequency-dependent +% permittivity and minimum-phase delay due to resonances will degrade +% the fidelity which is the normalized similarity between excitation and +% radiated signal. In this tutorial you can examine the performance of a +% simple ultrawideband (UWB) monopole. The delay and fidelity of this +% antenna are calculated and plotted. You can compare these properties +% in different channels. +% +% The Gaussian excitation is set to the same 3dB bandwidth as the +% channels of the IEEE 802.15.4 UWB PHY. One exeption is channel4twice +% which has the double bandwidth of channel 4. It can be seen that the +% delay is larger and the fidelity is smaller in the vicinity of the +% (undesired) resonances of the antenna. Note that for a real UWB system +% the total delay and fidelity result from both the transmitting and +% receiving antenna or twice the delay and the square of the fidelity +% for monostatic radar. +% +% The resolution of the delay will depend on the 'Oversampling' +% parameter to InitFDTD. See the description of DelayFidelity +% +% In the configuration section below you can uncomment the respective +% parameter settings. As an exercise, you can examine how the permittivity +% of the substrate influences gain, delay and fidelity. + + +%suffix = "channel1"; +%f_0 = 3.5e9; % center frequency of the channel +%f_c = 0.25e9 / 0.3925; % 3dB bandwidth is 0.3925 times 20dB bandwidth for Gaussian excitation + +%suffix = "channel2"; +%f_0 = 4.0e9; % center frequency of the channel +%f_c = 0.25e9 / 0.3925; + +%suffix = "channel3"; +%f_0 = 4.5e9; % center frequency of the channel +%f_c = 0.25e9 / 0.3925; + +suffix = "channel4"; +f_0 = 4.0e9; % center frequency of the channel +f_c = 0.5e9 / 0.3925; + +%suffix = "channel5"; +%f_0 = 6.5e9; % center frequency of the channel +%f_c = 0.25e9 / 0.3925; + +%suffix = "channel7"; +%f_0 = 6.5e9; % center frequency of the channel +%f_c = 0.5e9 / 0.3925; + +%suffix = "channel4twice"; % this is just to demonstrate the degradation of the fidelity with increasing bandwidth +%f_0 = 4.0e9; % center frequency of the channel +%f_c = 1e9 / 0.3925; + +tilt = 45 * pi / 180; % polarization tilt angle against co-polarization (90DEG is cross polarized) + +% --- end of configuration section --- + +% path and filename setup +Sim_Path = 'tmp'; +Sim_CSX = 'uwb.xml'; + +% properties of the substrate +substrate.epsR = 4; % FR4 +substrate.height = 0.707; +substrate.cells = 3; % thickness in cells + +% size of the monopole and the gap to the ground plane +gap = 0.62; % 0.5 +patchsize = 14; + +% we will use millimeters +unit = 1e-3; + +% set the resolution for the finer structures, e.g. the antenna gap +fineResolution = C0 / (f_0 + f_c) / sqrt(substrate.epsR) / unit / 40; +% set the resolution for the coarser structures, e.g. the surrounding air +coarseResolution = C0/(f_0 + f_c) / unit / 20; + + +% initialize the CSX structure +CSX = InitCSX(); + +% add the properties which are used to model the antenna +CSX = AddMetal(CSX, 'Ground' ); +CSX = AddMetal(CSX, 'Patch'); +CSX = AddMetal(CSX, 'Line'); +CSX = AddMaterial(CSX, 'Substrate' ); +CSX = SetMaterialProperty(CSX, 'Substrate', 'Epsilon', substrate.epsR); + +% define the supstrate and sheet-like primitives for the properties +CSX = AddBox(CSX, 'Substrate', 1, [-16, -16, -substrate.height], [16, 18, 0]); +CSX = AddBox(CSX, 'Ground', 2, [-16, -16, -substrate.height], [16, 0, -substrate.height]); +CSX = AddBox(CSX, 'Line', 2, [-1.15, -16, 0], [1.15, gap, 0]); +CSX = AddBox(CSX, 'Patch', 2, [-patchsize/2, gap, 0], [patchsize/2, gap + patchsize, 0]); + +% setup a mesh +mesh.x = []; +mesh.y = []; + +% two mesh lines for the metal coatings of teh substrate +mesh.z = linspace(-substrate.height, 0, substrate.cells +1); + +% find optimal mesh lines for the patch and ground, not yes the microstrip line +mesh = DetectEdges(CSX, mesh, 'SetProperty',{'Patch', 'Ground'}, '2D_Metal_Edge_Res', fineResolution/2); + +%replace gap mesh lines which are too close by a single mesh line +tooclose = find (diff(mesh.y) < fineResolution/4); +if ~isempty(tooclose) + mesh.y(tooclose) = (mesh.y(tooclose) + mesh.y(tooclose+1))/2; + mesh.y(tooclose + 1) = []; +endif + +% store the microstrip edges in a temporary variable +meshline = DetectEdges(CSX, [], 'SetProperty', 'Line', '2D_Metal_Edge_Res', fineResolution/2); +% as well as the edges of the substrate (without 1/3 - 2/3 rule) +meshsubstrate = DetectEdges(CSX, [], 'SetProperty', 'Substrate'); +% add only the x mesh lines of the microstrip +mesh.x = [mesh.x meshline.x]; +% and only the top of the substrate, the other edges are covered by the ground plane +mesh.y = [mesh.y, meshsubstrate.y(end)]; % top of substrate + +% for now we have only the edges, now calculate mesh lines inbetween +mesh = SmoothMesh(mesh, fineResolution); + +% add the outer boundary +mesh.x = [mesh.x -60, 60]; +mesh.y = [mesh.y, -60, 65]; +mesh.z = [mesh.z, -46, 45]; + +% add coarse mesh lines for the free space +mesh = SmoothMesh(mesh, coarseResolution); + +% define the grid +CSX = DefineRectGrid( CSX, unit, mesh); +% and the feeding port +[CSX, port] = AddLumpedPort( CSX, 999, 1, 50, [-1.15, meshline.y(2), -substrate.height], [1.15, meshline.y(2), 0], [0 0 1], true); + +%setup a NF2FF box for the calculation of the far field +start = [mesh.x(10) mesh.y(10) mesh.z(10)]; +stop = [mesh.x(end-9) mesh.y(end-9) mesh.z(end-9)]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop); + +% initialize the FDTD structure with excitation and open boundary conditions +FDTD = InitFDTD( 'NrTs', 30000, 'EndCriteria', 1e-5, 'OverSampling', 20); +FDTD = SetGaussExcite(FDTD, f_0, f_c ); +BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; +FDTD = SetBoundaryCond(FDTD, BC ); + + +% remove old data, show structure, calculate new data +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +% write the data to the working directory +WriteOpenEMS([Sim_Path '/' Sim_CSX], FDTD, CSX); +% show the geometry for checking +CSXGeomPlot([Sim_Path '/' Sim_CSX]); +% run the simulation +RunOpenEMS( Sim_Path, Sim_CSX); + +% plot amplitude and phase of the reflection coefficient +freq = linspace(f_0-f_c, f_0+f_c, 200); +port = calcPort(port, Sim_Path, freq); +s11 = port.uf.ref ./ port.uf.inc; +s11phase = unwrap(arg(s11)); +figure %("visible", "off"); % use this to plot only into files at the end of this script +ax = plotyy( freq/1e6, 20*log10(abs(s11)), freq/1e6, s11phase); +grid on +title( ['reflection coefficient ', suffix, ' S_{11}']); +xlabel( 'frequency f / MHz' ); +ylabel( ax(1), 'reflection coefficient |S_{11}|' ); +ylabel(ax(2), 'S_{11} phase (rad)'); + +% define an azimuthal trace around the monopole +phi = [0] * pi / 180; +theta = [-180:10:180] * pi / 180; + +% calculate the delay, the fidelity and the farfield +[delay, fidelity, nf2ff] = DelayFidelity(nf2ff, port, Sim_Path, sin(tilt), cos(tilt), theta, phi, f_0, f_c, 'Mode', 1); + +%plot the gain at (close to) f_0 +f_0_nearest_ind = nthargout(2, @min, abs(nf2ff.freq -f_0)); +%turn directivity into gain +nf2ff.Dmax(f_0_nearest_ind) *= nf2ff.Prad(f_0_nearest_ind) / calcPort(port, Sim_Path, nf2ff.freq(f_0_nearest_ind)).P_inc; +figure %("visible", "off"); +polarFF(nf2ff, 'xaxis', 'theta', 'freq_index', f_0_nearest_ind, 'logscale', [-4, 4]); +title(["gain ", suffix, " / dBi"]); + + +% We trick polarFF into plotting the delay in mm because +% the axes of the vanilla polar plot can not be scaled. +plotvar = delay * C0 * 1000; +maxplot = 80; +minplot = 30; +nf2ff.Dmax(1) = 10^(max(plotvar)/10); +nf2ff.E_norm{1} = 10.^(plotvar/20); +figure %("visible", "off"); +polarFF(nf2ff, 'xaxis', 'theta', 'logscale', [minplot, maxplot]); +title(["delay ", suffix, " / mm"]); + +% The same for the fidelity in percent. +plotvar = fidelity * 100; +maxplot = 100; +minplot = 98; +nf2ff.Dmax(1) = 10^(max(plotvar)/10); +nf2ff.E_norm{1} = 10.^(plotvar/20); +figure %("visible", "off"); +polarFF(nf2ff, 'xaxis', 'theta', 'logscale', [minplot, maxplot]); +title(["fidelity ", suffix, " / %"]); + +% save the plots in order to compare them afer simulating the different channels +print(1, ["s11_", suffix, ".png"]); +print(2, ["farfield_", suffix, ".png"]); +print(3, ["delay_mm_", suffix, ".png"]); +print(4, ["fidelity_", suffix, ".png"]); +return; \ No newline at end of file diff --git a/openEMS/matlab/Tutorials/Rect_Waveguide.m b/openEMS/matlab/Tutorials/Rect_Waveguide.m new file mode 100644 index 0000000..3b1a79a --- /dev/null +++ b/openEMS/matlab/Tutorials/Rect_Waveguide.m @@ -0,0 +1,121 @@ +% +% Tutorials / Rect_Waveguide +% +% Describtion at: +% http://openems.de/index.php/Tutorial:_Rectangular_Waveguide +% +% Tested with +% - Octave 4.0.0 +% - openEMS v0.0.33 +% +% (C) 2010-2015 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants; +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 30 30]; + +%% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD('NrTS',1e4, 'OverSampling', 5); +FDTD = SetGaussExcite(FDTD,0.5*(f_start+f_stop),0.5*(f_stop-f_start)); + +% boundary conditions +BC = [0 0 0 0 3 3]; %pml in pos. and neg. z-direction +FDTD = SetBoundaryCond(FDTD,BC); + +%% setup CSXCAD mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +mesh.x = SmoothMeshLines([0 a], mesh_res(1)); +mesh.y = SmoothMeshLines([0 b], mesh_res(2)); +mesh.z = SmoothMeshLines([0 length], mesh_res(3)); +CSX = DefineRectGrid(CSX, unit,mesh); + +%% apply the waveguide port %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start=[mesh.x(1) mesh.y(1) mesh.z(11)]; +stop =[mesh.x(end) mesh.y(end) mesh.z(15)]; +[CSX, port{1}] = AddRectWaveGuidePort( CSX, 0, 1, start, stop, 'z', a*unit, b*unit, TE_mode, 1); + +start=[mesh.x(1) mesh.y(1) mesh.z(end-13)]; +stop =[mesh.x(end) mesh.y(end) mesh.z(end-14)]; +[CSX, port{2}] = AddRectWaveGuidePort( CSX, 0, 2, start, stop, 'z', a*unit, b*unit, TE_mode); + +%% define dump box... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddDump(CSX,'Et','FileType',1,'SubSampling','2,2,2'); +start = [mesh.x(1) mesh.y(1) mesh.z(1)]; +stop = [mesh.x(end) mesh.y(end) mesh.z(end)]; +CSX = AddBox(CSX,'Et',0 , start,stop); + +%% Write openEMS compatoble xml-file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Sim_Path = 'tmp_mod'; +Sim_CSX = 'rect_wg.xml'; + +[status, message, messageid] = rmdir(Sim_Path,'s'); +[status, message, messageid] = mkdir(Sim_Path); + +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + +RunOpenEMS(Sim_Path, Sim_CSX) + +%% postproc %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +freq = linspace(f_start,f_stop,201); +port = calcPort(port, Sim_Path, freq); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; +ZL = port{1}.uf.tot./port{1}.if.tot; +ZL_a = port{1}.ZL; % analytic waveguide impedance + +%% plot s-parameter %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +figure +plot(freq*1e-6,20*log10(abs(s11)),'k-','Linewidth',2); +xlim([freq(1) freq(end)]*1e-6); +grid on; +hold on; +plot(freq*1e-6,20*log10(abs(s21)),'r--','Linewidth',2); +l = legend('S_{11}','S_{21}','Location','Best'); +set(l,'FontSize',12); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (MHz) \rightarrow','FontSize',12); + +%% compare analytic and numerical wave-impedance %%%%%%%%%%%%%%%%%%%%%%%%%% +figure +plot(freq*1e-6,real(ZL),'Linewidth',2); +hold on; +grid on; +plot(freq*1e-6,imag(ZL),'r--','Linewidth',2); +plot(freq*1e-6,ZL_a,'g-.','Linewidth',2); +ylabel('ZL (\Omega)','FontSize',12); +xlabel('frequency (MHz) \rightarrow','FontSize',12); +xlim([freq(1) freq(end)]*1e-6); +l = legend('\Re(Z_L)','\Im(Z_L)','Z_L analytic','Location','Best'); +set(l,'FontSize',12); + +%% Plot the field dumps %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +figure +dump_file = [Sim_Path '/Et.h5']; +PlotArgs.slice = {a/2*unit b/2*unit 0}; +PlotArgs.pauseTime=0.01; +PlotArgs.component=0; +PlotArgs.Limit = 'auto'; +PlotHDF5FieldData(dump_file, PlotArgs) diff --git a/openEMS/matlab/Tutorials/Simple_Patch_Antenna.m b/openEMS/matlab/Tutorials/Simple_Patch_Antenna.m new file mode 100644 index 0000000..1e24c4c --- /dev/null +++ b/openEMS/matlab/Tutorials/Simple_Patch_Antenna.m @@ -0,0 +1,187 @@ +%% Simple Patch Antenna Tutorial +% +% Describtion at: +% +% +% Tested with +% - Matlab 2013a / Octave 4.0 +% - openEMS v0.0.35 +% +% (C) 2010-2017 Thorsten Liebig +%% + +close all +clear +clc + +%% Setup the Simulation +physical_constants; +unit = 1e-3; % all length in mm + +% patch width in x-direction +patch.width = 32; % resonant length +% 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 = [200 200 150]; + +%% Setup FDTD Parameter & Excitation Function +f0 = 2e9; % center frequency +fc = 1e9; % 20 dB corner frequency +FDTD = InitFDTD( 'NrTs', 30000 ); +FDTD = SetGaussExcite( FDTD, f0, fc ); +BC = {'MUR' 'MUR' 'MUR' 'MUR' 'MUR' 'MUR'}; % boundary conditions +FDTD = SetBoundaryCond( FDTD, BC ); + +%% Setup CSXCAD Geometry & Mesh +CSX = InitCSX(); + +%initialize the mesh with the "air-box" dimensions +mesh.x = [-SimBox(1)/2 SimBox(1)/2]; +mesh.y = [-SimBox(2)/2 SimBox(2)/2]; +mesh.z = [-SimBox(3)/3 SimBox(3)*2/3]; + +% Create Patch +CSX = AddMetal( CSX, '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]; +CSX = AddBox(CSX,'patch',10,start,stop); % add a box-primitive to the metal property 'patch' + +% Create Substrate +CSX = AddMaterial( CSX, 'substrate' ); +CSX = SetMaterialProperty( CSX, 'substrate', 'Epsilon', substrate.epsR, 'Kappa', substrate.kappa ); +start = [-substrate.width/2 -substrate.length/2 0]; +stop = [ substrate.width/2 substrate.length/2 substrate.thickness]; +CSX = AddBox( CSX, 'substrate', 0, start, stop ); + +% add extra cells to discretize the substrate thickness +mesh.z = [linspace(0,substrate.thickness,substrate.cells+1) mesh.z]; + +% Create Ground same size as substrate +CSX = AddMetal( CSX, 'gnd' ); % create a perfect electric conductor (PEC) +start(3)=0; +stop(3) =0; +CSX = AddBox(CSX,'gnd',10,start,stop); + +% Apply the Excitation & Resist as a Current Source +start = [feed.pos 0 0]; +stop = [feed.pos 0 substrate.thickness]; +[CSX port] = AddLumpedPort(CSX, 5 ,1 ,feed.R, start, stop, [0 0 1], true); + +% Finalize the Mesh +% detect all edges except of the patch +mesh = DetectEdges(CSX, mesh,'ExcludeProperty','patch'); +% detect and set a special 2D metal edge mesh for the patch +mesh = DetectEdges(CSX, mesh,'SetProperty','patch','2D_Metal_Edge_Res', c0/(f0+fc)/unit/50); +% generate a smooth mesh with max. cell size: lambda_min / 20 +mesh = SmoothMesh(mesh, c0/(f0+fc)/unit/20); +CSX = DefineRectGrid(CSX, unit, mesh); + +CSX = AddDump(CSX,'Hf', 'DumpType', 11, 'Frequency',[2.4e9]); +CSX = AddBox(CSX,'Hf',10,[-substrate.width -substrate.length -10*substrate.thickness],[substrate.width +substrate.length 10*substrate.thickness]); %assign box + +% add a nf2ff calc box; size is 3 cells away from MUR boundary condition +start = [mesh.x(4) mesh.y(4) mesh.z(4)]; +stop = [mesh.x(end-3) mesh.y(end-3) mesh.z(end-3)]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop); + +%% Prepare and Run Simulation +Sim_Path = 'tmp_Patch_Ant'; +Sim_CSX = 'patch_ant.xml'; + +% create an empty working directory +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +% write openEMS compatible xml-file +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + +% show the structure +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + +% run openEMS +RunOpenEMS( Sim_Path, Sim_CSX); + +%% Postprocessing & Plots +freq = linspace( max([1e9,f0-fc]), f0+fc, 501 ); +port = calcPort(port, Sim_Path, freq); + +%% Smith chart port reflection +plotRefl(port, 'threshold', -10) +title( 'reflection coefficient' ); + +% plot feed point impedance +Zin = port.uf.tot ./ port.if.tot; +figure +plot( freq/1e6, real(Zin), 'k-', 'Linewidth', 2 ); +hold on +grid on +plot( freq/1e6, imag(Zin), 'r--', 'Linewidth', 2 ); +title( 'feed point impedance' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'impedance Z_{in} / Ohm' ); +legend( 'real', 'imag' ); + +% plot reflection coefficient S11 +s11 = port.uf.ref ./ port.uf.inc; +figure +plot( freq/1e6, 20*log10(abs(s11)), 'k-', 'Linewidth', 2 ); +grid on +title( 'reflection coefficient S_{11}' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'reflection coefficient |S_{11}|' ); + +drawnow + +%% NFFF Plots +%find resonance frequncy from s11 +f_res_ind = find(s11==min(s11)); +f_res = freq(f_res_ind); + +% calculate the far field at phi=0 degrees and at phi=90 degrees +disp( 'calculating far field at phi=[0 90] deg...' ); + +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_res, [-180:2:180]*pi/180, [0 90]*pi/180); + +% display power and directivity +disp( ['radiated power: Prad = ' num2str(nf2ff.Prad) ' Watt']); +disp( ['directivity: Dmax = ' num2str(nf2ff.Dmax) ' (' num2str(10*log10(nf2ff.Dmax)) ' dBi)'] ); +disp( ['efficiency: nu_rad = ' num2str(100*nf2ff.Prad./port.P_inc(f_res_ind)) ' %']); + +% normalized directivity as polar plot +figure +polarFF(nf2ff,'xaxis','theta','param',[1 2],'normalize',1) + +% log-scale directivity plot +figure +plotFFdB(nf2ff,'xaxis','theta','param',[1 2]) +% conventional plot approach +% plot( nf2ff.theta*180/pi, 20*log10(nf2ff.E_norm{1}/max(nf2ff.E_norm{1}(:)))+10*log10(nf2ff.Dmax)); + +drawnow + +% Show 3D pattern +disp( 'calculating 3D far field pattern and dumping to vtk (use Paraview to visualize)...' ); +thetaRange = (0:2:180); +phiRange = (0:2:360) - 180; +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_res, thetaRange*pi/180, phiRange*pi/180,'Verbose',1,'Outfile','3D_Pattern.h5'); + +figure +plotFF3D(nf2ff,'logscale',-20); + + +E_far_normalized = nf2ff.E_norm{1} / max(nf2ff.E_norm{1}(:)) * nf2ff.Dmax; +DumpFF2VTK([Sim_Path '/3D_Pattern.vtk'],E_far_normalized,thetaRange,phiRange,'scale',1e-3); diff --git a/openEMS/matlab/Tutorials/StripLine2MSL.m b/openEMS/matlab/Tutorials/StripLine2MSL.m new file mode 100644 index 0000000..64eeaa1 --- /dev/null +++ b/openEMS/matlab/Tutorials/StripLine2MSL.m @@ -0,0 +1,133 @@ +% +% Stripline to Microstrip Line Transition +% +% Describtion at: +% +% +% Tested with +% - Octave 4.0 +% - openEMS v0.0.35 +% +% (C) 2017 Thorsten Liebig + +close all +clear +clc + +%% Setup the Simulation +physical_constants; +unit = 1e-6; % specify everything in um + +line_length = 15000; % line length of strip line and microstrip line +substrate_width = 6000; +air_spacer = 4000; % air spacer above the substrate + +msl_width = 500; +msl_substrate_thickness = 254; + +strip_width = 500; +strip_substrate_thickness = 512; + +connect_via_rad = 500/2; +connect_via_gap = 1250/2; + +substrate_epr = 3.66; +substrate_kappa = 1e-3 * 2*pi*2.45e9 * EPS0*substrate_epr; % substrate losses + +f_max = 10e9; +resolution = 250; +edge_res = 25; +feed_shift = 2500; +meas_shift = 5000; + +%% Setup FDTD Parameters & Excitation Function +FDTD = InitFDTD(); +FDTD = SetGaussExcite( FDTD, f_max/2, f_max/2); +BC = {'PML_8' 'PML_8' 'PEC' 'PEC' 'PEC' 'MUR'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% Setup CSXCAD Geometry & Mesh +CSX = InitCSX(); +edge_mesh = [-1/3 2/3]*edge_res; % 1/3 - 2/3 rule for 2D metal edges + +mesh.x = SmoothMeshLines( [-connect_via_gap 0 connect_via_gap], 2*edge_res, 1.5 ); +mesh.x = SmoothMeshLines( [-line_length mesh.x line_length], resolution, 1.5); +mesh.y = SmoothMeshLines( [0 msl_width/2+edge_mesh substrate_width/2], resolution/4 , 1.5); +mesh.y = sort(unique([-mesh.y mesh.y])); +mesh.z = SmoothMeshLines( [linspace(-strip_substrate_thickness,0,5) linspace(0,strip_substrate_thickness,5) linspace(strip_substrate_thickness,msl_substrate_thickness+strip_substrate_thickness,5) 2*strip_substrate_thickness+air_spacer] , resolution ); +CSX = DefineRectGrid( CSX, unit, mesh ); + +% Create Substrate +CSX = AddMaterial( CSX, 'RO4350B' ); +CSX = SetMaterialProperty( CSX, 'RO4350B', 'Epsilon', substrate_epr, 'Kappa', substrate_kappa ); +start = [mesh.x(1), mesh.y(1), -strip_substrate_thickness]; +stop = [mesh.x(end), mesh.y(end), +strip_substrate_thickness+msl_substrate_thickness]; +CSX = AddBox( CSX, 'RO4350B', 0, start, stop ); + +% Create a PEC called 'metal' and 'gnd' +CSX = AddMetal( CSX, 'gnd' ); +CSX = AddMetal( CSX, 'metal' ); + +% Create strip line port (incl. metal stip line) +start = [-line_length -strip_width/2 0]; +stop = [0 +strip_width/2 0]; +[CSX,port{1}] = AddStripLinePort( CSX, 100, 1, 'metal', start, stop, strip_substrate_thickness, 'x', [0 0 -1], 'ExcitePort', true, 'FeedShift', feed_shift, 'MeasPlaneShift', meas_shift ); + +% Create MSL port on top +start = [line_length -strip_width/2 strip_substrate_thickness+msl_substrate_thickness]; +stop = [0 +strip_width/2 strip_substrate_thickness]; +[CSX,port{2}] = AddMSLPort( CSX, 100, 2, 'metal', start, stop, 'x', [0 0 -1], 'MeasPlaneShift', meas_shift ); + +% transitional via +start = [0, 0, 0]; +stop = [0, 0, strip_substrate_thickness+msl_substrate_thickness]; +CSX = AddCylinder(CSX, 'metal', 100, start, stop, connect_via_rad); + +% metal plane between strip line and MSL, including hole for transition +p(1,1) = mesh.x(1); +p(2,1) = mesh.y(1); +p(1,2) = 0; +p(2,2) = mesh.y(1); +for a = linspace(-pi, pi, 21) + p(1,end+1) = connect_via_gap*sin(a); + p(2,end) = connect_via_gap*cos(a); +endfor +p(1,end+1) = 0; +p(2,end ) = mesh.y(1); +p(1,end+1) = mesh.x(end); +p(2,end ) = mesh.y(1); +p(1,end+1) = mesh.x(end); +p(2,end ) = mesh.y(end); +p(1,end+1) = mesh.x(1); +p(2,end ) = mesh.y(end); +CSX = AddPolygon( CSX, 'gnd', 1, 'z', strip_substrate_thickness, p); + +%% Write/Show/Run the openEMS compatible xml-file +Sim_Path = 'tmp'; +Sim_CSX = 'strip2msl.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +RunOpenEMS( Sim_Path, Sim_CSX ); + +%% Post-Processing +close all +f = linspace( 0, f_max, 1601 ); +port = calcPort( port, Sim_Path, f, 'RefImpedance', 50); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; + +plot(f/1e9,20*log10(abs(s11)),'k-','LineWidth',2); +hold on; +grid on; +plot(f/1e9,20*log10(abs(s21)),'r--','LineWidth',2); +legend('S_{11}','S_{21}'); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (GHz) \rightarrow','FontSize',12); +ylim([-40 2]); + + diff --git a/openEMS/matlab/Tutorials/readme b/openEMS/matlab/Tutorials/readme new file mode 100644 index 0000000..a80dfa6 --- /dev/null +++ b/openEMS/matlab/Tutorials/readme @@ -0,0 +1 @@ +* Find the tutorial describtions at http://openems.de/index.php/Tutorials diff --git a/openEMS/matlab/WriteHDF5.m b/openEMS/matlab/WriteHDF5.m new file mode 100644 index 0000000..df6a8d7 --- /dev/null +++ b/openEMS/matlab/WriteHDF5.m @@ -0,0 +1,73 @@ +function WriteHDF5(filename,hdf_fielddata,hdf_mesh) +% function WriteHDF5(filename,hdf_fielddata,hdf_mesh) +% +% input: +% hdf_fielddata.time +% hdf_fielddata.names +% hdf_fielddata.values +% hdf_mesh.type +% hdf_mesh.names +% hdf_mesh.lines +% +% openEMS matlab interface +% ----------------------- +% (C) 2010 Sebastian Held +% See also ReadHDF5FieldData ReadHDF5Mesh + +isOctave = exist('OCTAVE_VERSION','builtin') ~= 0; +if isOctave + WriteHDF5_octave(filename,hdf_fielddata,hdf_mesh); + return +end + +writemode = 'overwrite'; +if isfield( hdf_fielddata, 'TD' ) + % this is a time domain data set + time = hdf_fielddata.TD.time; + for n=1:numel(time) + name = ['/FieldData/TD/' int2str(n)]; + [details.Location, details.Name] = fileparts(name); + attribute_details.AttachedTo = name; + attribute_details.AttachType = 'dataset'; + attribute_details.Name = 'time'; + hdf5write( filename, details, hdf_fielddata.TD.values{n}, ... + attribute_details, time(n), ... + 'WriteMode', writemode ); + writemode = 'append'; + end +end +if isfield( hdf_fielddata, 'FD' ) + % this is a frequency domain data set + freq = hdf_fielddata.FD.frequency; + for n=1:numel(freq) + name = ['/FieldData/FD/f' int2str(n-1) '_real']; + [details.Location, details.Name] = fileparts(name); + hdf5write( filename, details, real(hdf_fielddata.FD.values{n}), ... + 'WriteMode', writemode ); + name = ['/FieldData/FD/f' int2str(n-1) '_imag']; + [details.Location, details.Name] = fileparts(name); + hdf5write( filename, details, imag(hdf_fielddata.FD.values{n}), ... + 'WriteMode', 'append' ); + writemode = 'append'; + end + name = '/FieldData/FD'; + [details.Location, details.Name] = fileparts(name); + attribute_details.AttachedTo = name; + attribute_details.AttachType = 'group'; + attribute_details.Name = 'frequency'; + hdf5write( filename, attribute_details, freq, ... + 'WriteMode', 'append' ); +end + +names = hdf_mesh.names; % names is a cell array +for n=1:numel(names) + [details.Location, details.Name, ext] = fileparts(names{n}); + details.Name = [details.Name ext]; + hdf5write( filename, details, hdf_mesh.lines{n}, ... + 'WriteMode', 'append' ); +end + + + +function WriteHDF5_octave(filename,hdf_fielddata,hdf_mesh) +error 'not yet implemented' diff --git a/openEMS/matlab/WriteOpenEMS.m b/openEMS/matlab/WriteOpenEMS.m new file mode 100644 index 0000000..d7c9cbd --- /dev/null +++ b/openEMS/matlab/WriteOpenEMS.m @@ -0,0 +1,19 @@ +function WriteOpenEMS(filename, FDTD, CSX) +% function WriteOpenEMS(filename, FDTD, CSX) +% +% Write the FDTD and CSX structures to a file. +% +% example: +% CSX = InitCSX(); +% FDTD = InitFDTD(); +% WriteOpenEMS('test.xml',FDTD,CSX) +% +% See also InitFDTD InitCSX CSXGeomPlot +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig + +openEMS.FDTD = FDTD; +openEMS.ContinuousStructure = CSX; +struct_2_xml(filename,openEMS,'openEMS'); \ No newline at end of file diff --git a/openEMS/matlab/calcLumpedPort.m b/openEMS/matlab/calcLumpedPort.m new file mode 100644 index 0000000..69dba69 --- /dev/null +++ b/openEMS/matlab/calcLumpedPort.m @@ -0,0 +1,107 @@ +function [port] = calcLumpedPort( port, SimDir, f, varargin) +% [port] = calcLumpedPort( port, SimDir, f, varargin) +% +% Calculate voltages and currents of given lumped port. +% +% The port has to be created by e.g. AddLumpedPort(). +% +% input: +% port: return value of e.g. AddMSLPort() +% SimDir: directory, where the simulation files are +% f: frequency vector for DFT +% +% variable input: +% 'RefImpedance': - use a given reference impedance to calculate inc and +% ref voltages and currents +% - default is given port or calculated line impedance +% 'SwitchDirection': 0/1, switch assumed direction of propagation +% +% output: +% % output signals/values in time domain (TD): +% port.ut.tot total voltage (time-domain) +% port.ut.time voltage time vector +% port.it.tot total current (time-domain) +% port.it.time current time vector +% +% % output signals/values in frequency domain (FD): +% port.f the given frequency fector +% port.uf.tot/inc/ref total, incoming and reflected voltage +% port.if.tot/inc/ref total, incoming and reflected current +% +% example: +% port{1} = calcLumpedPort( port{1}, Sim_Path, f, 'RefImpedance', 50); +% +% openEMS matlab interface +% ----------------------- +% (C) 2012 Thorsten Liebig +% +% See also AddLumpedPort, calcPort + +if (iscell(port)) + for n=1:numel(port) + port{n}=calcLumpedPort(port{n}, SimDir, f, varargin{:}); + end + return; +end + +if (strcmpi(port.type,'Lumped')~=1 && strcmpi(port.type,'Curve')~=1) + error('openEMS:calcLumpedPort','error, type is not a lumped port'); +end + + +%% read optional arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%set defaults +ref_ZL = port.Feed_R; +switch_dir = 1; + +UI_args = {}; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'RefImpedance')==1); + ref_ZL = varargin{n+1}; + elseif (strcmpi(varargin{n},'SwitchDirection')==1); + if (varargin{n+1}) + switch_dir = -1; + end + else + UI_args(end+1) = varargin(n); + UI_args(end+1) = varargin(n+1); + end +end + +port.ZL_ref = ref_ZL; + +% read time domain data +U = ReadUI( port.U_filename, SimDir, f, UI_args{:} ); +I = ReadUI( port.I_filename, SimDir, f, UI_args{:} ); + +% store the original frequency domain waveforms +u_f = U.FD{1}.val; +i_f = switch_dir*I.FD{1}.val; + +port.ut.time = U.TD{1}.t; +port.ut.tot = U.TD{1}.val; + +port.it.time = I.TD{1}.t; +port.it.tot = switch_dir*I.TD{1}.val; + +port.Zin = u_f./i_f; + +port.f = f; +uf_inc = 0.5 * ( u_f + i_f .* ref_ZL ); +if_inc = 0.5 * ( i_f + u_f ./ ref_ZL ); + +uf_ref = u_f - uf_inc; +if_ref = if_inc - i_f; + +port.uf.tot = u_f; +port.uf.inc = uf_inc; +port.uf.ref = uf_ref; + +port.if.tot = i_f; +port.if.inc = if_inc; +port.if.ref = if_ref; + +port.raw.U = U; +port.raw.I = I; diff --git a/openEMS/matlab/calcPort.m b/openEMS/matlab/calcPort.m new file mode 100644 index 0000000..9b56955 --- /dev/null +++ b/openEMS/matlab/calcPort.m @@ -0,0 +1,82 @@ +function [port] = calcPort( port, SimDir, f, varargin) +% [port] = calcPort( port, SimDir, f, varargin) +% +% Calculate: +% - voltages and currents +% - the propagation constant and the characteristic impedance (if applicable) +% +% The port has to be created by e.g. AddMSLPort(), AddLumpedPort() or AddCurvePort +% +% input: +% port: return value of AddMSLPort() +% SimDir: directory, where the simulation files are +% f: frequency vector for DFT +% +% variable input: +% 'RefImpedance': - use a given reference impedance to calculate inc and +% ref voltages and currents +% - default is given port or calculated line impedance +% 'RefPlaneShift': for transmission lines only, See also calcTLPort for +% more details +% 'SwitchDirection': 0/1, switch assumed direction of propagation +% 'SignalType': 'pulse' (default) or 'periodic' +% +% output: +% % output signals/values in time domain (TD): +% port.ut.tot total voltage (time-domain) +% port.ut.time voltage time vector +% port.it.tot total current (time-domain) +% port.it.time current time vector +% +% % output signals/values in frequency domain (FD): +% port.f the given frequency fector +% port.uf.tot/inc/ref total, incoming and reflected voltage +% port.if.tot/inc/ref total, incoming and reflected current +% port.ZL_ref used refernce impedance +% +% port.P_inc incoming power +% port.P_ref reflected power +% port.P_acc accepted power (incoming minus reflected, +% may be negative for passive ports) +% +% if port is a transmission line port: +% port.beta: propagation constant +% port.ZL: characteristic line impedance +% +% example: +% port = calcPort(port, Sim_Path, f, 'RefImpedance', 50); +% +% openEMS matlab interface +% ----------------------- +% (C) 2012 Thorsten Liebig +% +% See also AddMSLPort, AddLumpedPort, AddCurvePort, calcTLPort, calcLumpedPort + +if (iscell(port)) + for n=1:numel(port) + port{n}=calcPort(port{n}, SimDir, f, varargin{:}); + end + return; +end + +if isempty(port) + return; +end + +if (strcmpi(port.type,'MSL') || strcmpi(port.type,'Coaxial') || strcmpi(port.type,'StripLine') || strcmpi(port.type,'CPW')) + port = calcTLPort( port, SimDir, f, varargin{:}); +elseif strcmpi(port.type,'WaveGuide') + port = calcWGPort( port, SimDir, f, varargin{:}); +elseif (strcmpi(port.type,'Lumped') || strcmpi(port.type,'Curve')) + port = calcLumpedPort( port, SimDir, f, varargin{:}); +else + error 'unknown port type' +end + +% calc some more port parameter +% incoming power +port.P_inc = 0.5*real(port.uf.inc.*conj(port.if.inc)); +% reflected power +port.P_ref = 0.5*real(port.uf.ref.*conj(port.if.ref)); +% accepted power (incoming - reflected) +port.P_acc = 0.5*real(port.uf.tot.*conj(port.if.tot)); diff --git a/openEMS/matlab/calcTLPort.m b/openEMS/matlab/calcTLPort.m new file mode 100644 index 0000000..3a631ba --- /dev/null +++ b/openEMS/matlab/calcTLPort.m @@ -0,0 +1,173 @@ +function [port] = calcTLPort( port, SimDir, f, varargin) +% [port] = calcTLPort( port, SimDir, f, varargin) +% +% Calculate voltages and currents, the propagation constant beta +% and the characteristic impedance ZL of the given transmission line port. +% +% The port has to be created by e.g. AddMSLPort(). +% +% input: +% port: return value of e.g. AddMSLPort() +% SimDir: directory, where the simulation files are +% f: frequency vector for DFT +% +% variable input: +% 'RefImpedance': - use a given reference impedance to calculate inc and +% ref voltages and currents +% - default is given port or calculated line impedance +% 'RefPlaneShift': - use a given reference plane shift from port beginning +% for a desired phase correction +% - default is the measurement plane +% - the plane shift has to be given in drawing units! +% 'SwitchDirection': 0/1, switch assumed direction of propagation +% +% output: +% % output signals/values in time domain (TD): +% port.ut.tot total voltage (time-domain) +% port.ut.time voltage time vector +% port.it.tot total current (time-domain) +% port.it.time current time vector +% +% % output signals/values in frequency domain (FD): +% port.f the given frequency fector +% port.uf.tot/inc/ref total, incoming and reflected voltage +% port.if.tot/inc/ref total, incoming and reflected current +% port.beta: propagation constant +% port.ZL: characteristic line impedance +% port.ZL_ref used refernce impedance +% +% example: +% port{1} = calcTLPort( port{1}, Sim_Path, f, 'RefImpedance', 50); +% +% reference: W. K. Gwarek, "A Differential Method of Reflection Coefficient Extraction From FDTD Simulations", +% IEEE Microwave and Guided Wave Letters, Vol. 6, No. 5, May 1996 +% +% openEMS matlab interface +% ----------------------- +% (C) 2010 Sebastian Held +% +% See also AddMSLPort, calcPort + +if (iscell(port)) + for n=1:numel(port) + port{n}=calcTLPort(port{n}, SimDir, f, varargin{:}); + end + return; +end + +if ((strcmpi(port.type,'MSL')~=1) && (strcmpi(port.type,'Coaxial')~=1) && (strcmpi(port.type,'StripLine')~=1) && (strcmpi(port.type,'CPW')~=1)) + error('openEMS:calcTLPort','error, type is not a transmission line port'); +end + +% check +if abs((port.v_delta(1) - port.v_delta(2)) / port.v_delta(1))>1e-6 + warning( 'openEMS:calcPort:mesh', 'mesh is not equidistant; expect degraded accuracy' ); +end + + +%% read optional arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%set defaults +ref_ZL = -1; +ref_shift = nan; +switch_dir = 1; + +UI_args = {}; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'RefPlaneShift')==1); + ref_shift = varargin{n+1}; + elseif (strcmp(varargin{n},'RefImpedance')==1); + ref_ZL = varargin{n+1}; + elseif (strcmpi(varargin{n},'SwitchDirection')==1); + if (varargin{n+1}) + switch_dir = -1; + end + else + UI_args(end+1) = varargin(n); + UI_args(end+1) = varargin(n+1); + end +end + +if ((strcmpi(port.type,'StripLine')==1) || (strcmpi(port.type,'CPW')==1)) + U1 = ReadUI( port.U_filename(:,1), SimDir, f, UI_args{:} ); + U2 = ReadUI( port.U_filename(:,1), SimDir, f, UI_args{:} ); + U = U1; + for n=1:3 + U.TD{n}.val = U1.TD{n}.val+U2.TD{n}.val; + U.FD{n}.val = U1.FD{n}.val+U2.FD{n}.val; + end +else + U = ReadUI( port.U_filename, SimDir, f, UI_args{:} ); +end +% read time domain data (multiples files) +I = ReadUI( port.I_filename, SimDir, f, UI_args{:} ); + +% time domain signals +port.ut.time = U.TD{2}.t; +port.ut.tot = U.TD{2}.val; + +port.it.time = I.TD{1}.t; +port.it.tot = switch_dir*(I.TD{1}.val + I.TD{2}.val) / 2; % interpolate to same position as v + +% store the original frequency domain waveforms +u_f = U.FD{2}.val; +i_f = switch_dir*(I.FD{1}.val + I.FD{2}.val) / 2; % shift to same position as v + +f = U.FD{2}.f; +Et = U.FD{2}.val; +dEt = (U.FD{3}.val - U.FD{1}.val) / (sum(abs(port.v_delta(1:2))) * port.drawingunit); +Ht = (I.FD{1}.val + I.FD{2}.val)/2; % space averaging: Ht is now defined at the same pos as Et +dHt = (I.FD{2}.val - I.FD{1}.val) / (abs(port.i_delta(1)) * port.drawingunit); + +beta = sqrt( - dEt .* dHt ./ (Ht .* Et) ); +beta(real(beta) < 0) = -beta(real(beta) < 0); % determine correct sign (unlike the paper) + +% determine ZL +ZL = sqrt(Et .* dEt ./ (Ht .* dHt)); + +% if (strcmpi(port.type,'Coaxial')) +% port.ZL = Z0/2/pi/ref_index*log(port.r_o/port.r_i); +% end + +% reference plane shift (lossless) +if ~isnan(ref_shift) + ref_shift = ref_shift * port.LengthScale; + % shift to the beginning of MSL + ref_shift = ref_shift - port.measplanepos; + ref_shift = ref_shift * port.drawingunit; + + % store the shifted frequency domain waveforms + phase = real(beta)*ref_shift; + U.FD{1}.val = u_f .* cos(-phase) + 1i * i_f.*ZL .* sin(-phase); + I.FD{1}.val = i_f .* cos(-phase) + 1i * u_f./ZL .* sin(-phase); + + u_f = U.FD{1}.val; + i_f = I.FD{1}.val; +end + +if (ref_ZL < 0) + ref_ZL = ZL; +end + +port.ZL = ZL; +port.beta = beta; +port.ZL_ref = ref_ZL; + +port.f = f; +uf_inc = 0.5 * ( u_f + i_f .* ref_ZL ); +if_inc = 0.5 * ( i_f + u_f ./ ref_ZL ); + +uf_ref = u_f - uf_inc; +if_ref = if_inc - i_f; + +port.uf.tot = u_f; +port.uf.inc = uf_inc; +port.uf.ref = uf_ref; + +port.if.tot = i_f; +port.if.inc = if_inc; +port.if.ref = if_ref; + +port.raw.U = U; +port.raw.I = I; diff --git a/openEMS/matlab/calcWGPort.m b/openEMS/matlab/calcWGPort.m new file mode 100644 index 0000000..ba845af --- /dev/null +++ b/openEMS/matlab/calcWGPort.m @@ -0,0 +1,145 @@ +function [port] = calcWGPort( port, SimDir, f, varargin) +% [port] = calcWGPort( port, SimDir, f, varargin) +% +% Calculate voltages and currents, the propagation constant beta +% and the characteristic impedance ZL of the given waveguide port. +% +% The port has to be created by e.g. AddWaveGuidePort(). +% +% input: +% port: return value of e.g. AddWaveGuidePort() +% SimDir: directory, where the simulation files are +% f: frequency vector for DFT +% +% variable input: +% 'RefImpedance': - use a given reference impedance to calculate inc and +% ref voltages and currents +% - default is given port or calculated line impedance +% 'RefPlaneShift': - use a given reference plane shift from port beginning +% for a desired phase correction +% - default is the measurement plane at the end of the +% port +% - the plane shift has to be given in drawing units! +% 'RefractiveIndex': set a material refractive index +% 'SwitchDirection': 0/1, switch assumed direction of propagation +% +% output: +% % output signals/values in time domain (TD): +% port.ut.tot total voltage (time-domain) +% port.ut.time voltage time vector +% port.it.tot total current (time-domain) +% port.it.time current time vector +% +% % output signals/values in frequency domain (FD): +% port.f the given frequency fector +% port.uf.tot/inc/ref total, incoming and reflected voltage +% port.if.tot/inc/ref total, incoming and reflected current +% port.beta: propagation constant +% port.ZL: characteristic line impedance +% port.ZL_ref used reference impedance +% +% example: +% port{1} = calcWGPort( port{1}, Sim_Path, f, 'RefImpedance', 50); +% +% openEMS matlab interface +% ----------------------- +% (C) 2013 Thorsten Liebig (thorsten.liebig@gmx.de) +% +% See also AddWaveGuidePort, calcPort + +if (iscell(port)) + for n=1:numel(port) + port{n}=calcWGPort(port{n}, SimDir, f, varargin{:}); + end + return; +end + +if (strcmpi(port.type,'WaveGuide')~=1) + error('openEMS:calcWGPort','error, type is not a waveguide port'); +end + +%set defaults +ref_ZL = -1; +ref_shift = nan; +ref_index = 1; +switch_dir = 1; + +UI_args = {}; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'RefPlaneShift')==1); + ref_shift = varargin{n+1}; + elseif (strcmp(varargin{n},'RefImpedance')==1); + ref_ZL = varargin{n+1}; + elseif (strcmp(varargin{n},'RefractiveIndex')==1); + ref_index = varargin{n+1}; + elseif (strcmpi(varargin{n},'SwitchDirection')==1); + if (varargin{n+1}) + switch_dir = -1; + end + else + UI_args(end+1) = varargin(n); + UI_args(end+1) = varargin(n+1); + end +end + +% read time domain data +U = ReadUI( port.U_filename, SimDir, f, UI_args{:} ); +I = ReadUI( port.I_filename, SimDir, f, UI_args{:} ); + +% store the original frequency domain waveforms +u_f = U.FD{1}.val; +i_f = I.FD{1}.val * switch_dir; + +% time domain signal +port.ut.time = U.TD{1}.t; +port.ut.tot = U.TD{1}.val; + +port.it.time = I.TD{1}.t; +port.it.tot = switch_dir*I.TD{1}.val; + + +physical_constants +k = 2*pi*f/C0*ref_index; +fc = C0*port.kc/2/pi/ref_index; +port.beta = sqrt(k.^2 - port.kc^2); +port.ZL = k * Z0 ./ port.beta; %analytic waveguide impedance + +% reference plane shift (lossless) +if ~isnan(ref_shift) + % shift relative to the beginning of the waveguide + ref_shift = ref_shift - port.measplanepos; + ref_shift = ref_shift * port.drawingunit; + + % store the shifted frequency domain waveforms + phase = real(beta)*ref_shift; + u_f_shift = u_f .* cos(-phase) + 1i * i_f.*port.ZL .* sin(-phase); + i_f_shift = i_f .* cos(-phase) + 1i * u_f./port.ZL .* sin(-phase); + + u_f = u_f_shift; + i_f = i_f_shift; +end + +if (ref_ZL < 0) + ref_ZL = port.ZL; +end + +port.ZL_ref = ref_ZL; + +port.f = f; +uf_inc = 0.5 * ( u_f + i_f .* ref_ZL ); +if_inc = 0.5 * ( i_f + u_f ./ ref_ZL ); + +uf_ref = u_f - uf_inc; +if_ref = if_inc - i_f; + +port.uf.tot = u_f; +port.uf.inc = uf_inc; +port.uf.ref = uf_ref; + +port.if.tot = i_f; +port.if.inc = if_inc; +port.if.ref = if_ref; + +port.raw.U = U; +port.raw.I = I; diff --git a/openEMS/matlab/calc_ypar.m b/openEMS/matlab/calc_ypar.m new file mode 100644 index 0000000..f6ae1bd --- /dev/null +++ b/openEMS/matlab/calc_ypar.m @@ -0,0 +1,69 @@ +function Y = calc_ypar( f, ports, Sim_Path_Prefix ) +% Y = calc_ypar( f, ports, Sim_Path_Prefix ) +% +% f: frequency vector (Hz) +% ports: cell array of ports (see AddMSLPort() and AddLumpedPort()) +% Sim_Path_Prefix: prefix of the simulation dirs (will be postfixed by +% excitation port number) +% +% This function calculates the Y-matrix representation of the ports +% +% It is assumed that each port (inside ports) is excited and the +% corresponding simulation was carried out at Sim_Path + portnr (e.g. for +% port 2: '/tmp/sim2') +% +% Sebastian Held +% Jun 9 2010 +% +% See also AddMSLPort AddLumpedPort + +% sanitize input arguments +f = reshape(f,1,[]); % make it a row vector + +% prepare result matrix +maxportnr = max( cellfun(@(x) x.nr, ports) ); +Y = ones(maxportnr,maxportnr,numel(f)) * NaN; +U = ones(maxportnr,maxportnr,numel(f)) * NaN; +I = ones(maxportnr,maxportnr,numel(f)) * NaN; + +% read time domain simulation results +for runnr = 1:numel(ports) + Sim_Path = [Sim_Path_Prefix num2str(ports{runnr}.nr)]; + for pnr = 1:numel(ports) + if isfield( ports{pnr}, 'v_delta' ) + % this is an MSLPort + temp_U = ReadUI( ['port_ut' num2str(ports{pnr}.nr) 'B'], Sim_Path ); + temp = ReadUI( {['port_it' num2str(ports{pnr}.nr) 'A'],['port_it' num2str(ports{pnr}.nr) 'B']}, Sim_Path ); + temp_I.TD{1}.t = temp.TD{1}.t; + temp_I.TD{1}.val = (temp.TD{1}.val + temp.TD{2}.val) / 2; % space averaging + else + % this is a lumped port + temp_U = ReadUI( ['port_ut' num2str(ports{pnr}.nr)], Sim_Path ); + temp_I = ReadUI( ['port_it' num2str(ports{pnr}.nr)], Sim_Path ); + +% % correct the orientation of the probes (FIXME to be done inside +% % openEMS) +% temp_U.TD{1}.val = temp_U.TD{1}.val * (-ports{pnr}.direction); + end + +% % correct the orientation of the probes (FIXME to be done inside +% % openEMS) +% temp_I.TD{1}.val = temp_I.TD{1}.val * ports{pnr}.direction; +% if runnr == 5 % DEBUG +% temp_I.TD{1}.val = temp_I.TD{1}.val * -1; +% end + + % time domain -> frequency domain + U(ports{pnr}.nr,ports{runnr}.nr,:) = DFT_time2freq( temp_U.TD{1}.t, temp_U.TD{1}.val, f ); + I(ports{pnr}.nr,ports{runnr}.nr,:) = DFT_time2freq( temp_I.TD{1}.t, temp_I.TD{1}.val, f ); + + % compensate H-field time advance + delta_t_2 = temp_I.TD{1}.t(1) - temp_U.TD{1}.t(1); % half time-step (s) + I(ports{pnr}.nr,ports{runnr}.nr,:) = squeeze(I(ports{pnr}.nr,ports{runnr}.nr,:)).' .* exp(-1i*2*pi*f*delta_t_2); + end +end + +% calc Y-parameters +for a=1:numel(f) + Y(:,:,a) = I(:,:,a) / U(:,:,a); +end diff --git a/openEMS/matlab/examples/__deprecated__/MSL2.m b/openEMS/matlab/examples/__deprecated__/MSL2.m new file mode 100644 index 0000000..31a2600 --- /dev/null +++ b/openEMS/matlab/examples/__deprecated__/MSL2.m @@ -0,0 +1,254 @@ +% +% EXAMPLE / microstrip / MSL2 +% +% This example shows how to use the MSL-port. +% The MSL is excited at the center of the computational volume. The +% boundary at xmin is an absorbing boundary (Mur) and at xmax an electric +% wall. The reflection coefficient at this wall is S11 = -1. +% Direction of propagation is x. +% +% This example demonstrates: +% - simple microstrip geometry (made of PEC) +% - MSL port +% - MSL analysis +% +% You may modify the PEC boundary condition at xmax to become a MUR +% boundary. This resembles a matched microstrip line. +% +% Tested with +% - Matlab 2009b +% - Octave 3.3.52 +% - openEMS v0.0.14 +% +% (C) 2010 Sebastian Held + +close all +clear +clc + +%% switches +postproc_only = 0; + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants; +unit = 1e-6; % specify everything in um +MSL_length = 10000; +MSL_width = 1000; +substrate_thickness = 254; +substrate_epr = 3.66; + +% mesh_res = [200 0 0]; + +%% prepare simulation folder +Sim_Path = 'tmp'; +Sim_CSX = 'msl2.xml'; +if ~postproc_only + [status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory + [status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder +end + +%% setup FDTD parameters & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%% +max_timesteps = 20000; +min_decrement = 1e-6; +f_max = 7e9; +FDTD = InitFDTD( max_timesteps, min_decrement, 'OverSampling', 10 ); +FDTD = SetGaussExcite( FDTD, f_max/2, f_max/2 ); +BC = {'MUR' 'MUR' 'PEC' 'PEC' 'PEC' 'PMC'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +resolution = c0/(f_max*sqrt(substrate_epr))/unit /50; % resolution of lambda/50 +mesh.x = SmoothMeshLines( [-MSL_length MSL_length], resolution ); +mesh.y = SmoothMeshLines( [-4*MSL_width -MSL_width/2 MSL_width/2 4*MSL_width], resolution ); +mesh.z = SmoothMeshLines( [linspace(0,substrate_thickness,5) 10*substrate_thickness], resolution ); +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% substrate +CSX = AddMaterial( CSX, 'RO4350B' ); +CSX = SetMaterialProperty( CSX, 'RO4350B', 'Epsilon', substrate_epr ); +start = [mesh.x(1), mesh.y(1), 0]; +stop = [mesh.x(end), mesh.y(end), substrate_thickness]; +CSX = AddBox( CSX, 'RO4350B', 0, start, stop ); + +%% MSL port +CSX = AddMetal( CSX, 'PEC' ); +portstart = [ 0, -MSL_width/2, substrate_thickness]; +portstop = [ MSL_length, MSL_width/2, 0]; +[CSX,portstruct] = AddMSLPort( CSX, 999, 1, 'PEC', portstart, portstop, [1 0 0], [0 0 1], [], 'excite' ); + +%% MSL +start = [-MSL_length, -MSL_width/2, substrate_thickness]; +stop = [ 0, MSL_width/2, substrate_thickness]; +CSX = AddBox( CSX, 'PEC', 999, start, stop ); % priority needs to be higher than + +%% define dump boxes +start = [mesh.x(1), mesh.y(1), substrate_thickness/2]; +stop = [mesh.x(end), mesh.y(end), substrate_thickness/2]; +CSX = AddDump( CSX, 'Et_', 'DumpType', 0,'DumpMode', 2 ); % cell interpolated +CSX = AddBox( CSX, 'Et_', 0, start, stop ); +CSX = AddDump( CSX, 'Ht_', 'DumpType', 1,'DumpMode', 2 ); % cell interpolated +CSX = AddBox( CSX, 'Ht_', 0, start, stop ); + +%% write openEMS compatible xml-file +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + +%% show the structure +if ~postproc_only + CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +end + +%% run openEMS +openEMS_opts = ''; +openEMS_opts = [openEMS_opts ' --engine=fastest']; +% openEMS_opts = [openEMS_opts ' --debug-material']; +% openEMS_opts = [openEMS_opts ' --debug-boxes']; +% openEMS_opts = [openEMS_opts ' --debug-PEC']; +if ~postproc_only + RunOpenEMS( Sim_Path, Sim_CSX, openEMS_opts ); +end + + +%% postprocess +f = linspace( 1e6, f_max, 1601 ); +U = ReadUI( {'port_ut1A','port_ut1B','port_ut1C','et'}, 'tmp/', f ); +I = ReadUI( {'port_it1A','port_it1B'}, 'tmp/', f ); + +% Z = (U.FD{1}.val+U.FD{2}.val)/2 ./ I.FD{1}.val; +% plot( f*1e-9, [real(Z);imag(Z)],'Linewidth',2); +% xlabel('frequency (GHz)'); +% ylabel('impedance (Ohm)'); +% grid on; +% legend( {'real','imaginary'}, 'location', 'northwest' ) +% title( 'line impedance (will fail in case of reflections!)' ); + +figure +ax = plotyy( U.TD{1}.t/1e-6, [U.TD{1}.val;U.TD{2}.val;U.TD{3}.val], U.TD{4}.t/1e-6, U.TD{4}.val ); +xlabel( 'time (us)' ); +ylabel( 'amplitude (V)' ); +grid on +title( 'Time domain voltage probes and excitation signal' ); +legend( {'ut1A','ut1B','ut1C','excitation'} ); +% now make the y-axis symmetric to y=0 (align zeros of y1 and y2) +y1 = ylim(ax(1)); +y2 = ylim(ax(2)); +ylim( ax(1), [-max(abs(y1)) max(abs(y1))] ); +ylim( ax(2), [-max(abs(y2)) max(abs(y2))] ); + +figure +plot( I.TD{1}.t/1e-6, [I.TD{1}.val;I.TD{2}.val] ); +xlabel( 'time (us)' ); +ylabel( 'amplitude (A)' ); +grid on +title( 'Time domain current probes' ); +legend( {'it1A','it1B'} ); + +figure +ax = plotyy( U.FD{1}.f/1e9, abs([U.FD{1}.val;U.FD{2}.val;U.FD{3}.val]), U.FD{1}.f/1e9, angle([U.FD{1}.val;U.FD{2}.val;U.FD{3}.val])/pi*180 ); +xlabel( 'frequency (GHz)' ); +ylabel( ax(1), 'amplitude (A)' ); +ylabel( ax(2), 'phase (deg)' ); +grid on +title( 'Frequency domain voltage probes' ); +legend( {'abs(uf1A)','abs(uf1B)','abs(uf1C)','angle(uf1A)','angle(uf1B)','angle(uf1C)'} ); + +figure +ax = plotyy( I.FD{1}.f/1e9, abs([I.FD{1}.val;I.FD{2}.val]), I.FD{1}.f/1e9, angle([I.FD{1}.val;I.FD{2}.val])/pi*180 ); +xlabel( 'frequency (GHz)' ); +ylabel( ax(1), 'amplitude (A)' ); +ylabel( ax(2), 'phase (deg)' ); +grid on +title( 'Frequency domain current probes' ); +legend( {'abs(if1A)','abs(if1B)','angle(if1A)','angle(if1B)'} ); + +%% port analysis +[U,I,beta,ZL] = calcPort( portstruct, Sim_Path, f ); +%% attention! the reflection coefficient S11 is normalized to ZL! + +figure +plot( sin(0:0.01:2*pi), cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); +hold on +plot( 0.5+0.5*sin(0:0.01:2*pi), 0.5*cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); +plot( [-1 1], [0 0], 'Color', [.7 .7 .7] ); +plot( S11, 'k' ); +plot( real(S11(1)), imag(S11(1)), '*r' ); +axis equal +title( 'Reflection coefficient S11 at the measurement plane' ); + +figure +plot( sin(0:0.01:2*pi), cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); +hold on +plot( 0.5+0.5*sin(0:0.01:2*pi), 0.5*cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); +plot( [-1 1], [0 0], 'Color', [.7 .7 .7] ); +Z = vi.FD.v.val ./ vi.FD.i.val; +S11_ = (Z-ZL) ./ (Z+ZL); +plot( S11_, 'k' ); +plot( real(S11_(1)), imag(S11_(1)), '*r' ); +axis equal +title( {'Reflection coefficient S11 at the measurement plane' 'calculated from voltages and currents'} ); + +figure +plot( f/1e9, [real(S11);imag(S11)], 'Linewidth',2 ); +legend( {'Re(S11)', 'Im(S11)'} ); +ylabel( 'amplitude' ); +xlabel( 'frequency (GHz)' ); +title( 'Reflection coefficient S11 at the measurement plane' ); + +figure +plotyy( f/1e9, 20*log10(abs(S11)), f/1e9, angle(S11)/pi*180 ); +legend( {'|S11|', 'angle(S11)'} ); +xlabel( 'frequency (GHz)' ); +ylabel( '|S11| (dB)' ); +title( 'Reflection coefficient S11 at the measurement plane' ); + +figure +plot( f/1e9, [real(beta);imag(beta)], 'Linewidth',2 ); +legend( 'Re(beta)', 'Im(beta)' ); +ylabel( 'propagation constant beta (1/m)' ); +xlabel( 'frequency (GHz)' ); +title( 'Propagation constant of the MSL' ); + +figure +plot( f/1e9, [real(ZL);imag(ZL)], 'Linewidth',2); +xlabel('frequency (GHz)'); +ylabel('impedance (Ohm)'); +grid on; +legend( {'real','imaginary'}, 'location', 'northeast' ) +title( 'Characteristic line impedance ZL' ); + +%% reference plane shift (to the end of the port) +ref_shift = abs(portstop(1) - portstart(1)); +[U, I,beta,ZL] = calcPort( portstruct, Sim_Path, f ); +%% + +figure +plotyy( f/1e9, 20*log10(abs(S11)), f/1e9, angle(S11)/pi*180 ); +legend( {'abs(S11)', 'angle(S11)'} ); +xlabel( 'frequency (GHz)' ); +title( 'Reflection coefficient S11 at the reference plane (at the electric wall)' ); + +figure +plot( sin(0:0.01:2*pi), cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); +hold on +plot( 0.5+0.5*sin(0:0.01:2*pi), 0.5*cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); +plot( [-1 1], [0 0], 'Color', [.7 .7 .7] ); +plot( S11, 'k' ); +plot( real(S11(1)), imag(S11(1)), '*r' ); +axis equal +title( 'Reflection coefficient S11 at the reference plane (at the electric wall)' ); + +figure +plot( sin(0:0.01:2*pi), cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); +hold on +plot( 0.5+0.5*sin(0:0.01:2*pi), 0.5*cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); +plot( [-1 1], [0 0], 'Color', [.7 .7 .7] ); +Z = vi.FD.v.val_shifted ./ vi.FD.i.val_shifted; +S11_ = (Z-ZL) ./ (Z+ZL); +plot( S11_, 'k' ); +plot( real(S11_(1)), imag(S11_(1)), '*r' ); +axis equal +title( {'Reflection coefficient S11 at the reference plane (at the electric wall)' 'calculated from shifted voltages and currents'} ); + +%% visualize electric and magnetic fields +% you will find vtk dump files in the simulation folder (tmp/) +% use paraview to visualize them diff --git a/openEMS/matlab/examples/antennas/Bi_Quad_Antenna.m b/openEMS/matlab/examples/antennas/Bi_Quad_Antenna.m new file mode 100644 index 0000000..80ae97f --- /dev/null +++ b/openEMS/matlab/examples/antennas/Bi_Quad_Antenna.m @@ -0,0 +1,139 @@ +% +% Tutorials / bi-quad antenna +% +% Tested with +% - Octave 3.8.1 +% - openEMS v0.0.32 +% +% (C) 2011-2014 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation +physical_constants; +unit = 1e-3; % all length in mm + +quad_size = 110; +port_length = 10; +quad_mesh = 5; + +Feed_R = 75; + +% size of the simulation box +SimBox = [800 800 400]; + +% frequency range of interest +f_start = 400e6; +f_stop = 1000e6; + +% frequency of interest +f0 = 700e6; +freq = linspace(f_start,f_stop,201); + +%% setup FDTD parameter & excitation function +FDTD = InitFDTD( 'endCriteria', 1e-4 ); +FDTD = SetGaussExcite(FDTD,0.5*(f_start+f_stop),0.5*(f_stop-f_start)); +BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; % boundary conditions +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +CSX = InitCSX(); + +%create fixed lines for the antenna outline and port +mesh.x = [-quad_size*sqrt(2) -quad_size/sqrt(2) 0 quad_size/sqrt(2) quad_size*sqrt(2)]; +mesh.y = [-quad_size/sqrt(2) -port_length/2 0 port_length/2 quad_size/sqrt(2)]; +mesh.z = [0]; + +mesh = SmoothMesh(mesh, quad_mesh, 1.3); + +% add air box +mesh.x = [mesh.x -SimBox(1)/2 SimBox(1)/2]; +mesh.y = [mesh.y -SimBox(2)/2 SimBox(2)/2]; +mesh.z = [-SimBox(3)/2 0 SimBox(3)/2]; + +max_res = c0 / (f_stop) / unit / 20; % cell size: lambda/20 +mesh = SmoothMesh(mesh, max_res, 1.4); + +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% create bi-quad +points(1,1) = 0; +points(2,1) = port_length/2; +points(3,1) = 0; +points(1,end+1) = quad_size/sqrt(2); +points(2,end) = quad_size/sqrt(2); +points(1,end+1) = quad_size*sqrt(2); +points(2,end) = 0; +points(1,end+1) = quad_size/sqrt(2); +points(2,end) = -quad_size/sqrt(2); +points(1,end+1) = 0; +points(2,end) = -port_length/2; +points(1,end+1) = -quad_size/sqrt(2); +points(2,end) = -quad_size/sqrt(2); +points(1,end+1) = -quad_size*sqrt(2); +points(2,end) = 0; +points(1,end+1) = -quad_size/sqrt(2); +points(2,end) = quad_size/sqrt(2); +points(1,end+1) = 0; +points(2,end) = port_length/2; + +% create a thin metal wire... +CSX = AddMetal(CSX,'metal'); %create PEC with propName 'metal' +CSX = AddCurve(CSX,'metal',10, points); + +%% apply the excitation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start = [0 -port_length/2 0]; +stop = [0 port_length/2 0]; +[CSX port] = AddLumpedPort(CSX,10,0,Feed_R,start,stop,[0 1 0], true); + +%% nf2ff calc +start = [mesh.x(9) mesh.y(9) mesh.z(9)]; +stop = [mesh.x(end-8) mesh.y(end-8) mesh.z(end-8)]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop); + +%% prepare simulation folder +Sim_Path = 'tmp'; +Sim_CSX = 'bi_quad_ant.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +%% write openEMS compatible xml-file +WriteOpenEMS([Sim_Path '/' Sim_CSX], FDTD, CSX); + +%% show the structure +CSXGeomPlot([Sim_Path '/' Sim_CSX]); + +%% run openEMS +RunOpenEMS(Sim_Path, Sim_CSX); + +%% postprocessing & do the plots +port = calcPort(port, Sim_Path, freq); +s11 = port.uf.ref ./ port.uf.inc; + +% plot reflection coefficient S11 +figure +plot( freq/1e9, 20*log10(abs(s11)), 'k-', 'Linewidth', 2 ); +ylim([-30 0]); +grid on +title( 'reflection coefficient S_{11}' ); +xlabel( 'frequency f / GHz' ); +ylabel( 'reflection coefficient |S_{11}|' ); + +%% calculate 3D far field pattern +phiRange = -180:2.5:180; +thetaRange = 0:2.5:180; + +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f0, thetaRange*pi/180, phiRange*pi/180); + +disp( ['directivity: Dmax = ' num2str(10*log10(nf2ff.Dmax)) ' dBi'] ); + +% plot far-field pattern with Matlab +figure +plotFF3D(nf2ff, 'logscale', -20) + +%% +disp( 'Dumping far-field pattern to vtk (use Paraview to visualize)...' ); +DumpFF2VTK('Bi_Quad_Pattern.vtk', nf2ff.E_norm{1} / max(nf2ff.E_norm{1}(:)) * nf2ff.Dmax, thetaRange, phiRange, 'scale', 0.05); diff --git a/openEMS/matlab/examples/antennas/Patch_Antenna.m b/openEMS/matlab/examples/antennas/Patch_Antenna.m new file mode 100644 index 0000000..2011d6f --- /dev/null +++ b/openEMS/matlab/examples/antennas/Patch_Antenna.m @@ -0,0 +1,218 @@ +% +% EXAMPLE / antennas / patch antenna +% +% This example demonstrates how to: +% - calculate the reflection coefficient of a patch antenna +% +% +% Tested with +% - Matlab 2009b +% - Octave 3.3.52 +% - openEMS v0.0.23 +% +% (C) 2010,2011 Thorsten Liebig + +close all +clear +clc + +%% switches & options... +postprocessing_only = 0; +draw_3d_pattern = 0; % this may take a while... +use_pml = 0; % use pml boundaries instead of mur +openEMS_opts = ''; + +%% setup the simulation +physical_constants; +unit = 1e-3; % all length in mm + +% width in x-direction +% length in y-direction +% main radiation in z-direction +patch.width = 32.86; % resonant length +patch.length = 41.37; + +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; + +feed.pos = -5.5; +feed.width = 2; +feed.R = 50; % feed resistance + +% size of the simulation box +SimBox = [100 100 25]; + +%% prepare simulation folder +Sim_Path = 'tmp'; +Sim_CSX = 'patch_ant.xml'; +if (postprocessing_only==0) + [status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory + [status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder +end + +%% setup FDTD parameter & excitation function +max_timesteps = 30000; +min_decrement = 1e-5; % equivalent to -50 dB +f0 = 0e9; % center frequency +fc = 3e9; % 20 dB corner frequency (in this case 0 Hz - 3e9 Hz) +FDTD = InitFDTD( 'NrTS', max_timesteps, 'EndCriteria', min_decrement ); +FDTD = SetGaussExcite( FDTD, f0, fc ); +BC = {'MUR' 'MUR' 'MUR' 'MUR' 'MUR' 'MUR'}; % boundary conditions +if (use_pml>0) + BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; % use pml instead of mur +end +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +% currently, openEMS cannot automatically generate a mesh +max_res = c0 / (f0+fc) / unit / 20; % cell size: lambda/20 +CSX = InitCSX(); +mesh.x = [-SimBox(1)/2 SimBox(1)/2 -substrate.width/2 substrate.width/2 feed.pos]; +% add patch mesh with 2/3 - 1/3 rule +mesh.x = [mesh.x -patch.width/2-max_res/2*0.66 -patch.width/2+max_res/2*0.33 patch.width/2+max_res/2*0.66 patch.width/2-max_res/2*0.33]; +mesh.x = SmoothMeshLines( mesh.x, max_res, 1.4); % create a smooth mesh between specified mesh lines +mesh.y = [-SimBox(2)/2 SimBox(2)/2 -substrate.length/2 substrate.length/2 -feed.width/2 feed.width/2]; +% add patch mesh with 2/3 - 1/3 rule +mesh.y = [mesh.y -patch.length/2-max_res/2*0.66 -patch.length/2+max_res/2*0.33 patch.length/2+max_res/2*0.66 patch.length/2-max_res/2*0.33]; +mesh.y = SmoothMeshLines( mesh.y, max_res, 1.4 ); +mesh.z = [-SimBox(3)/2 linspace(0,substrate.thickness,substrate.cells) SimBox(3) ]; +mesh.z = SmoothMeshLines( mesh.z, max_res, 1.4 ); +mesh = AddPML( mesh, [8 8 8 8 8 8] ); % add equidistant cells (air around the structure) +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% create patch +CSX = AddMetal( CSX, '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]; +CSX = AddBox(CSX,'patch',10,start,stop); + +%% create substrate +CSX = AddMaterial( CSX, 'substrate' ); +CSX = SetMaterialProperty( CSX, 'substrate', 'Epsilon', substrate.epsR, 'Kappa', substrate.kappa ); +start = [-substrate.width/2 -substrate.length/2 0]; +stop = [ substrate.width/2 substrate.length/2 substrate.thickness]; +CSX = AddBox( CSX, 'substrate', 0, start, stop ); + +%% create ground (same size as substrate) +CSX = AddMetal( CSX, 'gnd' ); % create a perfect electric conductor (PEC) +start(3)=0; +stop(3) =0; +CSX = AddBox(CSX,'gnd',10,start,stop); + +%% apply the excitation & resist as a current source +start = [feed.pos-.1 -feed.width/2 0]; +stop = [feed.pos+.1 +feed.width/2 substrate.thickness]; +[CSX] = AddLumpedPort(CSX, 5 ,1 ,feed.R, start, stop, [0 0 1], true); + +%% dump magnetic field over the patch antenna +CSX = AddDump( CSX, 'Ht_', 'DumpType', 1, 'DumpMode', 2); % cell interpolated +start = [-patch.width -patch.length substrate.thickness+1]; +stop = [ patch.width patch.length substrate.thickness+1]; +CSX = AddBox( CSX, 'Ht_', 0, start, stop ); + +%%nf2ff calc +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', -SimBox/2, SimBox/2); + +if (postprocessing_only==0) + %% write openEMS compatible xml-file + WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + + %% show the structure + CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + + %% run openEMS + RunOpenEMS( Sim_Path, Sim_CSX, openEMS_opts ); +end + +%% postprocessing & do the plots +freq = linspace( max([1e9,f0-fc]), f0+fc, 501 ); +U = ReadUI( {'port_ut1','et'}, 'tmp/', freq ); % time domain/freq domain voltage +I = ReadUI( 'port_it1', 'tmp/', freq ); % time domain/freq domain current (half time step is corrected) + +% plot time domain voltage +figure +[ax,h1,h2] = plotyy( U.TD{1}.t/1e-9, U.TD{1}.val, U.TD{2}.t/1e-9, U.TD{2}.val ); +set( h1, 'Linewidth', 2 ); +set( h1, 'Color', [1 0 0] ); +set( h2, 'Linewidth', 2 ); +set( h2, 'Color', [0 0 0] ); +grid on +title( 'time domain voltage' ); +xlabel( 'time t / ns' ); +ylabel( ax(1), 'voltage ut1 / V' ); +ylabel( ax(2), 'voltage et / V' ); +% now make the y-axis symmetric to y=0 (align zeros of y1 and y2) +y1 = ylim(ax(1)); +y2 = ylim(ax(2)); +ylim( ax(1), [-max(abs(y1)) max(abs(y1))] ); +ylim( ax(2), [-max(abs(y2)) max(abs(y2))] ); + +% plot feed point impedance +figure +Zin = U.FD{1}.val ./ I.FD{1}.val; +plot( freq/1e6, real(Zin), 'k-', 'Linewidth', 2 ); +hold on +grid on +plot( freq/1e6, imag(Zin), 'r--', 'Linewidth', 2 ); +title( 'feed point impedance' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'impedance Z_{in} / Ohm' ); +legend( 'real', 'imag' ); + +% plot reflection coefficient S11 +figure +uf_inc = 0.5*(U.FD{1}.val + I.FD{1}.val * 50); +if_inc = 0.5*(I.FD{1}.val - U.FD{1}.val / 50); +uf_ref = U.FD{1}.val - uf_inc; +if_ref = I.FD{1}.val - if_inc; +s11 = uf_ref ./ uf_inc; +plot( freq/1e6, 20*log10(abs(s11)), 'k-', 'Linewidth', 2 ); +grid on +title( 'reflection coefficient S_{11}' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'reflection coefficient |S_{11}|' ); + +P_in = 0.5*U.FD{1}.val .* conj( I.FD{1}.val ); + +%% NFFF contour plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +f_res_ind = find(s11==min(s11)); +f_res = freq(f_res_ind); + +% calculate the far field at phi=0 degrees and at phi=90 degrees +thetaRange = (0:2:359) - 180; +phiRange = [0 90]; +disp( 'calculating far field at phi=[0 90] deg...' ); +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_res, thetaRange*pi/180, phiRange*pi/180); + +Dlog=10*log10(nf2ff.Dmax); + +% display power and directivity +disp( ['radiated power: Prad = ' num2str(nf2ff.Prad) ' Watt']); +disp( ['directivity: Dmax = ' num2str(Dlog) ' dBi'] ); +disp( ['efficiency: nu_rad = ' num2str(100*nf2ff.Prad./real(P_in(f_res_ind))) ' %']); + +% display phi +figure +plotFFdB(nf2ff,'xaxis','theta','param',[1 2]); +drawnow + +if (draw_3d_pattern==0) + return +end + +%% calculate 3D pattern +phiRange = 0:2:360; +thetaRange = 0:2:180; +disp( 'calculating 3D far field...' ); +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_res, thetaRange*pi/180, phiRange*pi/180, 'Verbose',2,'Outfile','nf2ff_3D.h5'); +figure +plotFF3D(nf2ff); + + +%% visualize magnetic fields +% you will find vtk dump files in the simulation folder (tmp/) +% use paraview to visulaize them diff --git a/openEMS/matlab/examples/antennas/Patch_Antenna_Array.m b/openEMS/matlab/examples/antennas/Patch_Antenna_Array.m new file mode 100644 index 0000000..40b3b46 --- /dev/null +++ b/openEMS/matlab/examples/antennas/Patch_Antenna_Array.m @@ -0,0 +1,256 @@ +% +% EXAMPLE / antennas / patch antenna array +% +% This example demonstrates how to: +% - calculate the reflection coefficient of a patch antenna array +% +% +% Tested with +% - Matlab 2009b +% - Octave 3.3.52 +% - openEMS v0.0.23 +% +% (C) 2010 Thorsten Liebig + +close all +clear +clc + +%% switches & options... +postprocessing_only = 0; +draw_3d_pattern = 0; % this may take a (very long) while... +use_pml = 0; % use pml boundaries instead of mur +openEMS_opts = ''; + +%% setup the simulation +physical_constants; +unit = 1e-3; % all length in mm + +% width in x-direction +% length in y-direction +% main radiation in z-direction +patch.width = 32.86; % resonant length +patch.length = 41.37; + +% define array size and dimensions +array.xn = 4; +array.yn = 4; +array.x_spacing = patch.width * 3; +array.y_spacing = patch.length * 3; + +substrate.epsR = 3.38; +substrate.kappa = 1e-3 * 2*pi*2.45e9 * EPS0*substrate.epsR; +substrate.width = 60 + (array.xn-1) * array.x_spacing; +substrate.length = 60 + (array.yn-1) * array.y_spacing; +substrate.thickness = 1.524; +substrate.cells = 4; + +feed.pos = -5.5; +feed.width = 2; +feed.R = 50; % feed resistance + +% size of the simulation box around the array +SimBox = [50+substrate.width 50+substrate.length 25]; + +%% prepare simulation folder +Sim_Path = 'tmp'; +Sim_CSX = 'patch_array.xml'; +if (postprocessing_only==0) + [status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory + [status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder +end + +%% setup FDTD parameter & excitation function +max_timesteps = 30000; +min_decrement = 1e-5; % equivalent to -50 dB +f0 = 0e9; % center frequency +fc = 3e9; % 10 dB corner frequency (in this case 0 Hz - 3e9 Hz) +FDTD = InitFDTD( 'NrTS', max_timesteps, 'EndCriteria', min_decrement ); +FDTD = SetGaussExcite( FDTD, f0, fc ); +BC = {'MUR' 'MUR' 'MUR' 'MUR' 'MUR' 'MUR'}; % boundary conditions +if (use_pml>0) + BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; % use pml instead of mur +end +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +% currently, openEMS cannot automatically generate a mesh +max_res = c0 / (f0+fc) / unit / 20; % cell size: lambda/20 +CSX = InitCSX(); +mesh.x = [-SimBox(1)/2 SimBox(1)/2 -substrate.width/2 substrate.width/2]; +mesh.y = [-SimBox(2)/2 SimBox(2)/2 -substrate.length/2 substrate.length/2]; + +mesh.z = [-SimBox(3)/2 linspace(0,substrate.thickness,substrate.cells) SimBox(3) ]; +mesh.z = SmoothMeshLines( mesh.z, max_res, 1.4 ); + +for xn=1:array.xn + for yn=1:array.yn + midX = (array.xn/2 - xn + 1/2) * array.x_spacing; + midY = (array.yn/2 - yn + 1/2) * array.y_spacing; + + % feeding mesh + mesh.x = [mesh.x midX+feed.pos]; + mesh.y = [mesh.y midY-feed.width/2 midY+feed.width/2]; + + % add patch mesh with 2/3 - 1/3 rule + mesh.x = [mesh.x midX-patch.width/2-max_res/2*0.66 midX-patch.width/2+max_res/2*0.33 midX+patch.width/2+max_res/2*0.66 midX+patch.width/2-max_res/2*0.33]; + % add patch mesh with 2/3 - 1/3 rule + mesh.y = [mesh.y midY-patch.length/2-max_res/2*0.66 midY-patch.length/2+max_res/2*0.33 midY+patch.length/2+max_res/2*0.66 midY+patch.length/2-max_res/2*0.33]; + end +end +mesh.x = SmoothMeshLines( mesh.x, max_res, 1.4); % create a smooth mesh between specified mesh lines +mesh.y = SmoothMeshLines( mesh.y, max_res, 1.4 ); + +mesh = AddPML( mesh, [8 8 8 8 8 8] ); % add equidistant cells (air around the structure) +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% create substrate +CSX = AddMaterial( CSX, 'substrate' ); +CSX = SetMaterialProperty( CSX, 'substrate', 'Epsilon', substrate.epsR, 'Kappa', substrate.kappa); +start = [-substrate.width/2 -substrate.length/2 0]; +stop = [ substrate.width/2 substrate.length/2 substrate.thickness]; +CSX = AddBox( CSX, 'substrate', 0, start, stop ); + +%% create ground (same size as substrate) +CSX = AddMetal( CSX, 'gnd' ); % create a perfect electric conductor (PEC) +start(3)=0; +stop(3) =0; +CSX = AddBox(CSX,'gnd',10,start,stop); +%% +CSX = AddMetal( CSX, 'patch' ); % create a perfect electric conductor (PEC) +number = 1; +for xn=1:array.xn + for yn=1:array.yn + + midX = (array.xn/2 - xn + 1/2) * array.x_spacing; + midY = (array.yn/2 - yn + 1/2) * array.y_spacing; + + % create patch + start = [midX-patch.width/2 midY-patch.length/2 substrate.thickness]; + stop = [midX+patch.width/2 midY+patch.length/2 substrate.thickness]; + CSX = AddBox(CSX,'patch',10,start,stop); + + % apply the excitation & resist as a current source + start = [midX+feed.pos-feed.width/2 midY-feed.width/2 0]; + stop = [midX+feed.pos+feed.width/2 midY+feed.width/2 substrate.thickness]; + [CSX] = AddLumpedPort(CSX, 5, number,feed.R, start, stop,[0 0 1],true); + number=number+1; + end +end + +%%nf2ff calc +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', -SimBox/2, SimBox/2); + +if (postprocessing_only==0) + %% write openEMS compatible xml-file + WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + + %% show the structure + CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + + %% run openEMS + RunOpenEMS( Sim_Path, Sim_CSX, openEMS_opts ); +end + +%% postprocessing & do the plots +freq = linspace( max([1e9,f0-fc]), f0+fc, 501 ); +U = ReadUI( {'port_ut1','et'}, 'tmp/', freq ); % time domain/freq domain voltage +I = ReadUI( 'port_it1', 'tmp/', freq ); % time domain/freq domain current (half time step is corrected) + +% plot time domain voltage +figure +[ax,h1,h2] = plotyy( U.TD{1}.t/1e-9, U.TD{1}.val, U.TD{2}.t/1e-9, U.TD{2}.val ); +set( h1, 'Linewidth', 2 ); +set( h1, 'Color', [1 0 0] ); +set( h2, 'Linewidth', 2 ); +set( h2, 'Color', [0 0 0] ); +grid on +title( 'time domain voltage' ); +xlabel( 'time t / ns' ); +ylabel( ax(1), 'voltage ut1 / V' ); +ylabel( ax(2), 'voltage et / V' ); +% now make the y-axis symmetric to y=0 (align zeros of y1 and y2) +y1 = ylim(ax(1)); +y2 = ylim(ax(2)); +ylim( ax(1), [-max(abs(y1)) max(abs(y1))] ); +ylim( ax(2), [-max(abs(y2)) max(abs(y2))] ); + +% plot feed point impedance +figure +Zin = U.FD{1}.val ./ I.FD{1}.val; +plot( freq/1e6, real(Zin), 'k-', 'Linewidth', 2 ); +hold on +grid on +plot( freq/1e6, imag(Zin), 'r--', 'Linewidth', 2 ); +title( 'feed point impedance' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'impedance Z_{in} / Ohm' ); +legend( 'real', 'imag' ); + +% plot reflection coefficient S11 +figure +uf_inc = 0.5*(U.FD{1}.val + I.FD{1}.val * 50); +if_inc = 0.5*(I.FD{1}.val - U.FD{1}.val / 50); +uf_ref = U.FD{1}.val - uf_inc; +if_ref = I.FD{1}.val - if_inc; +s11 = uf_ref ./ uf_inc; +plot( freq/1e6, 20*log10(abs(s11)), 'k-', 'Linewidth', 2 ); +grid on +title( 'reflection coefficient S_{11}' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'reflection coefficient |S_{11}|' ); + +%% +number = 1; +P_in = 0; +for xn=1:array.xn + for yn=1:array.yn + + U = ReadUI( ['port_ut' int2str(number)], 'tmp/', freq ); % time domain/freq domain voltage + I = ReadUI( ['port_it' int2str(number)], 'tmp/', freq ); % time domain/freq domain current (half time step is corrected) + + P_in = P_in + 0.5*U.FD{1}.val .* conj( I.FD{1}.val ); + number=number+1; + end +end + + +%% NFFF contour plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +f_res_ind = find(s11==min(s11)); +f_res = freq(f_res_ind); + +% calculate the far field at phi=0 degrees and at phi=90 degrees +thetaRange = (0:2:359) - 180; +phiRange = [0 90]; +r = 1; % evaluate fields at radius r +disp( 'calculating far field at phi=[0 90] deg...' ); + +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_res, thetaRange*pi/180, phiRange*pi/180); + +Dlog=10*log10(nf2ff.Dmax); + +% display power and directivity +disp( ['radiated power: Prad = ' num2str(nf2ff.Prad) ' Watt']); +disp( ['directivity: Dmax = ' num2str(Dlog) ' dBi'] ); +disp( ['efficiency: nu_rad = ' num2str(100*nf2ff.Prad./real(P_in(f_res_ind))) ' %']); + +% display phi +figure +plotFFdB(nf2ff,'xaxis','theta','param',[1 2]); +drawnow + +if (draw_3d_pattern==0) + return +end + +%% calculate 3D pattern +phiRange = 0:3:360; +thetaRange = unique([0:0.5:15 10:3:180]); +disp( 'calculating 3D far field...' ); +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_res, thetaRange*pi/180, phiRange*pi/180, 'Verbose',2,'Outfile','nf2ff_3D.h5'); +figure +plotFF3D(nf2ff); + +%% visualize magnetic fields +% you will find vtk dump files in the simulation folder (tmp/) +% use paraview to visulaize them diff --git a/openEMS/matlab/examples/antennas/infDipol.m b/openEMS/matlab/examples/antennas/infDipol.m new file mode 100644 index 0000000..0a43bc8 --- /dev/null +++ b/openEMS/matlab/examples/antennas/infDipol.m @@ -0,0 +1,121 @@ +% +% infinitesimal dipole example +% + +close all +clear +clc + +postprocessing_only = 0; + +physical_constants + +% setup the simulation +drawingunit = 1e-6; % specify everything in um +Sim_Path = 'tmp'; +Sim_CSX = 'tmp.xml'; + +f_max = 1e9; +lambda = c0/f_max; + +% setup geometry values +dipole_length = lambda/50 /drawingunit; + + +dipole_orientation = 3; % 1,2,3: x,y,z + + +CSX = InitCSX(); + +% create an equidistant mesh +mesh.x = -dipole_length*10:dipole_length/2:dipole_length*10; +mesh.y = -dipole_length*10:dipole_length/2:dipole_length*10; +mesh.z = -dipole_length*10:dipole_length/2:dipole_length*10; + +% excitation +ex_vector = [0 0 0]; +ex_vector(dipole_orientation) = 1; +start = ex_vector * -dipole_length/2; +stop = ex_vector * dipole_length/2; +CSX = AddExcitation( CSX, 'infDipole', 1, ex_vector ); +% enlarge the box to be sure that one mesh line is covered by it +start = start - [0.1 0.1 0.1] * dipole_length/2; +stop = stop + [0.1 0.1 0.1] * dipole_length/2; +CSX = AddBox( CSX, 'infDipole', 1, start, stop ); + +% NFFF contour +start = [mesh.x(1) mesh.y(1) mesh.z(1) ]; +stop = [mesh.x(end) mesh.y(end) mesh.z(end) ]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop); + +% add space for PML +mesh = AddPML( mesh, [8 8 8 8 8 8] ); +% define the mesh +CSX = DefineRectGrid( CSX, drawingunit, mesh ); + +if ~postprocessing_only + % setup FDTD parameters & excitation function + max_timesteps = 2000; + min_decrement = 1e-6; + FDTD = InitFDTD( 'NrTS', max_timesteps, 'EndCriteria', min_decrement, 'OverSampling',10 ); + FDTD = SetGaussExcite( FDTD, f_max/2, f_max/2 ); + BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; + FDTD = SetBoundaryCond( FDTD, BC ); + + % Write openEMS compatible xml-file + [~,~,~] = rmdir(Sim_Path,'s'); + [~,~,~] = mkdir(Sim_Path); + WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + + % take a view at the "structure" + CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + + % define openEMS options and start simulation + openEMS_opts = ''; + RunOpenEMS( Sim_Path, Sim_CSX, openEMS_opts ); +end + +%% post processing +disp( ' ' ); +disp( ' ********************************************************** ' ); +disp( ' ' ); + +% calculate the far field at phi=0 degrees and at phi=90 degrees +thetaRange = 0:0.5:359; +disp( 'calculating far field at phi=[0 90] deg..' ); +nf2ff = CalcNF2FF( nf2ff, Sim_Path, f_max, thetaRange/180*pi, [0 pi/2], 'Mode', 1 ); +Prad = nf2ff.Prad; +Dmax = nf2ff.Dmax; + +theta_HPBW = interp1(nf2ff.E_norm{1}(find(thetaRange<90),1)/max(nf2ff.E_norm{1}(find(thetaRange<90),1)),thetaRange(find(thetaRange<90)),1/sqrt(2))*2; + +% display power and directivity +disp( ['radiated power: Prad = ' num2str(Prad)] ); +disp( ['directivity: Dmax = ' num2str(Dmax)] ); +disp( ['theta_HPBW = ' num2str(theta_HPBW) ' °']); + +% display polar plot for the e-field magnitude for phi = 0 & 90 deg +figure +polarFF(nf2ff,'xaxis','theta','param',[1 2]); + +%% calculate the far field at theta=90 degrees +phiRange = 0:2:359; +disp( 'calculating far field at theta=90 deg..' ); +nf2ff = CalcNF2FF( nf2ff, Sim_Path, f_max, 90/180*pi, phiRange/180*pi, 'Mode', 1 ); + +% display polar plot +figure +polarFF(nf2ff,'xaxis','phi','param',1); + +%% calculate 3D pattern +phiRange = 0:5:360; +thetaRange = 0:5:180; +disp( 'calculating 3D far field...' ); +nf2ff = CalcNF2FF( nf2ff, Sim_Path, f_max, thetaRange/180*pi, phiRange/180*pi, 'Mode', 1 ); +figure +plotFF3D(nf2ff) + +%% +E_far_normalized = nf2ff.E_norm{1} / max(nf2ff.E_norm{1}(:)); +DumpFF2VTK([Sim_Path '/FF_pattern.vtk'],E_far_normalized, thetaRange, phiRange); +disp(['view the farfield pattern "' Sim_Path '/FF_pattern.vtk" using paraview' ]); diff --git a/openEMS/matlab/examples/antennas/inverted_f.m b/openEMS/matlab/examples/antennas/inverted_f.m new file mode 100644 index 0000000..175f94c --- /dev/null +++ b/openEMS/matlab/examples/antennas/inverted_f.m @@ -0,0 +1,205 @@ +% +% EXAMPLE / antennas / inverted-f antenna (ifa) 2.4GHz +% +% This example demonstrates how to: +% - calculate the reflection coefficient of an ifa +% - calculate farfield of an ifa +% +% Tested with +% - Octave 3.7.5 +% - openEMS v0.0.30+ (git 10.07.2013) +% +% (C) 2013 Stefan Mahr + +close all +clear +clc + +%% setup the simulation +physical_constants; +unit = 1e-3; % all length in mm + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% substrate.width +% _______________________________________________ __ substrate. +% | A ifa.l |\ __ thickness +% | |ifa.e __________________________ | | +% | | | ___ _________________| w2 | | +% | | ifa.h | | || | | +% |_V_____________|___|___||______________________| | +% | .w1 .wf\ | | +% | |.fp| \ | | +% | | feed point | | +% | | | | substrate.length +% |<- substrate.width/2 ->| | | +% | | | +% |_______________________________________________| | +% \_______________________________________________\| +% +% Note: It's not checked whether your settings make sense, so check +% graphical output carefully. +% +substrate.width = 80; % width of substrate +substrate.length = 80; % length of substrate +substrate.thickness = 1.5; % thickness of substrate +substrate.cells = 4; % use 4 cells for meshing substrate + +ifa.h = 8; % height of short circuit stub +ifa.l = 22.5; % length of radiating element +ifa.w1 = 4; % width of short circuit stub +ifa.w2 = 2.5; % width of radiating element +ifa.wf = 1; % width of feed element +ifa.fp = 4; % position of feed element relative to short + % circuit stub +ifa.e = 10; % distance to edge + + +% substrate setup +substrate.epsR = 4.3; +substrate.kappa = 1e-3 * 2*pi*2.45e9 * EPS0*substrate.epsR; + +%setup feeding +feed.R = 50; %feed resistance + +%open AppCSXCAD and show ifa +show = 1; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% size of the simulation box +SimBox = [substrate.width*2 substrate.length*2 150]; + +%% setup FDTD parameter & excitation function +f0 = 2.5e9; % center frequency +fc = 1e9; % 20 dB corner frequency + +FDTD = InitFDTD('NrTS', 60000 ); +FDTD = SetGaussExcite( FDTD, f0, fc ); +BC = {'MUR' 'MUR' 'MUR' 'MUR' 'MUR' 'MUR'}; % boundary conditions +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +CSX = InitCSX(); + +%initialize the mesh with the "air-box" dimensions +mesh.x = [-SimBox(1)/2 SimBox(1)/2]; +mesh.y = [-SimBox(2)/2 SimBox(2)/2]; +mesh.z = [-SimBox(3)/2 SimBox(3)/2]; + +%% create substrate +CSX = AddMaterial( CSX, 'substrate'); +CSX = SetMaterialProperty( CSX, 'substrate', 'Epsilon',substrate.epsR, 'Kappa', substrate.kappa); +start = [-substrate.width/2 -substrate.length/2 0]; +stop = [ substrate.width/2 substrate.length/2 substrate.thickness]; +CSX = AddBox( CSX, 'substrate', 1, start, stop ); +% add extra cells to discretize the substrate thickness +mesh.z = [linspace(0,substrate.thickness,substrate.cells+1) mesh.z]; + +%% create ground plane +CSX = AddMetal( CSX, 'groundplane' ); % create a perfect electric conductor (PEC) +start = [-substrate.width/2 -substrate.length/2 substrate.thickness]; +stop = [ substrate.width/2 substrate.length/2-ifa.e substrate.thickness]; +CSX = AddBox(CSX, 'groundplane', 10, start,stop); + +%% create ifa +CSX = AddMetal( CSX, 'ifa' ); % create a perfect electric conductor (PEC) +tl = [0,substrate.length/2-ifa.e,substrate.thickness]; % translate +start = [0 0.5 0] + tl; +stop = start + [ifa.wf ifa.h-0.5 0]; +CSX = AddBox( CSX, 'ifa', 10, start, stop); % feed element +start = [-ifa.fp 0 0] + tl; +stop = start + [-ifa.w1 ifa.h 0]; +CSX = AddBox( CSX, 'ifa', 10, start, stop); % short circuit stub +start = [(-ifa.fp-ifa.w1) ifa.h 0] + tl; +stop = start + [ifa.l -ifa.w2 0]; +CSX = AddBox( CSX, 'ifa', 10, start, stop); % radiating element + +ifa_mesh = DetectEdges(CSX, [], 'SetProperty','ifa'); +mesh.x = [mesh.x SmoothMeshLines(ifa_mesh.x, 0.5)]; +mesh.y = [mesh.y SmoothMeshLines(ifa_mesh.y, 0.5)]; + +%% apply the excitation & resist as a current source +start = [0 0 0] + tl; +stop = start + [ifa.wf 0.5 0]; +[CSX port] = AddLumpedPort(CSX, 5 ,1 ,feed.R, start, stop, [0 1 0], true); + +%% finalize the mesh +% generate a smooth mesh with max. cell size: lambda_min / 20 +mesh = DetectEdges(CSX, mesh); +mesh = SmoothMesh(mesh, c0 / (f0+fc) / unit / 20); +CSX = DefineRectGrid(CSX, unit, mesh); + +%% add a nf2ff calc box; size is 3 cells away from MUR boundary condition +start = [mesh.x(4) mesh.y(4) mesh.z(4)]; +stop = [mesh.x(end-3) mesh.y(end-3) mesh.z(end-3)]; +[CSX nf2ff] = CreateNF2FFBox(CSX, 'nf2ff', start, stop); + +%% prepare simulation folder +Sim_Path = 'tmp_IFA'; +Sim_CSX = 'IFA.xml'; + +try confirm_recursive_rmdir(false,'local'); end + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +%% write openEMS compatible xml-file +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + +%% show the structure +if (show == 1) + CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +end + + +%% run openEMS +RunOpenEMS( Sim_Path, Sim_CSX); %RunOpenEMS( Sim_Path, Sim_CSX, '--debug-PEC -v'); + +%% postprocessing & do the plots +freq = linspace( max([1e9,f0-fc]), f0+fc, 501 ); +port = calcPort(port, Sim_Path, freq); + +Zin = port.uf.tot ./ port.if.tot; +s11 = port.uf.ref ./ port.uf.inc; +P_in = real(0.5 * port.uf.tot .* conj( port.if.tot )); % antenna feed power + +% plot feed point impedance +figure +plot( freq/1e6, real(Zin), 'k-', 'Linewidth', 2 ); +hold on +grid on +plot( freq/1e6, imag(Zin), 'r--', 'Linewidth', 2 ); +title( 'feed point impedance' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'impedance Z_{in} / Ohm' ); +legend( 'real', 'imag' ); + +% plot reflection coefficient S11 +figure +plot( freq/1e6, 20*log10(abs(s11)), 'k-', 'Linewidth', 2 ); +grid on +title( 'reflection coefficient S_{11}' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'reflection coefficient |S_{11}|' ); + +drawnow + +%% NFFF contour plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%find resonance frequncy from s11 +f_res_ind = find(s11==min(s11)); +f_res = freq(f_res_ind); + +%% +disp( 'calculating 3D far field pattern and dumping to vtk (use Paraview to visualize)...' ); +thetaRange = (0:2:180); +phiRange = (0:2:360) - 180; +nf2ff = CalcNF2FF(nf2ff, Sim_Path, f_res, thetaRange*pi/180, phiRange*pi/180,'Verbose',1,'Outfile','3D_Pattern.h5'); + +plotFF3D(nf2ff) + +% display power and directivity +disp( ['radiated power: Prad = ' num2str(nf2ff.Prad) ' Watt']); +disp( ['directivity: Dmax = ' num2str(nf2ff.Dmax) ' (' num2str(10*log10(nf2ff.Dmax)) ' dBi)'] ); +disp( ['efficiency: nu_rad = ' num2str(100*nf2ff.Prad./real(P_in(f_res_ind))) ' %']); + +E_far_normalized = nf2ff.E_norm{1} / max(nf2ff.E_norm{1}(:)) * nf2ff.Dmax; +DumpFF2VTK([Sim_Path '/3D_Pattern.vtk'],E_far_normalized,thetaRange,phiRange,1e-3); diff --git a/openEMS/matlab/examples/optimizer/optimizer_asco.m b/openEMS/matlab/examples/optimizer/optimizer_asco.m new file mode 100644 index 0000000..e405653 --- /dev/null +++ b/openEMS/matlab/examples/optimizer/optimizer_asco.m @@ -0,0 +1,36 @@ +% +% asco optimizer example -- optimize the turn number of a coil +% +% You need asco from http://asco.sf.net +% This is the main script. +% - optimizer_simfun.m starts the simulator with a parameter set from +% asco +% +% The goal is evaluated inside optimizer_simfun() to get as close to 2 uH. + +% clear +clear +close all +clc + +% setup the parameters +params = []; +params(end+1).name = 'turns'; +params(end).range = [1 30]; +params(end).value = 4; +params(end).step = 1; +params(end).active = 1; % this parameter is to be optimized + +% setup the simulation function +folder = fileparts( mfilename('fullpath') ); +options.simfun = [folder '/optimizer_simfun.m']; + +% additional options +% options.octave_exe = 'octave'; % must be newer than 3.2.4 (3.3.54 works) +options.clean = 1; + +% start the optimization +[params_opt,result] = optimize( 'opttmp', params, options, 'asco' ); + +% display best value +disp( ['ASCO found the optimum turn number: ' num2str(params_opt(1).value) ' result: ' num2str(result)] ); diff --git a/openEMS/matlab/examples/optimizer/optimizer_simfun.m b/openEMS/matlab/examples/optimizer/optimizer_simfun.m new file mode 100644 index 0000000..14152de --- /dev/null +++ b/openEMS/matlab/examples/optimizer/optimizer_simfun.m @@ -0,0 +1,134 @@ +function result = optimizer_simfun( folder, params ) +% +% simulation function +% +% the variable params contains the simulation parameters + +disp( [mfilename ': SIMULATING...'] ); + +if nargin == 0 + % visualize the structure if called without parameters + folder = 'tmp'; + params.turns = 10; +end + +oldpwd = pwd; +[a,a,a] = mkdir( folder ); +cd( folder ); + +% create the structure +f_max = 50e6; +structure( params, 'tmp.xml', f_max ); + +if nargin == 0 + % visualize the structure + CSXGeomPlot('tmp.xml'); + return; +end + +% start simulation +RunOpenEMS( '.', 'tmp.xml', '--engine=fastest' ); + +% postprocess the results +L = postproc( 'tmp.xml', f_max ); +disp( ['DONE. L = ' num2str(L(1)/1e-6) ' uH'] ); + +% calculate result +goal = 2e-6; % specify the goal: 2 uH +result = abs(goal - L(1)); % costs must not be negative + +% restore curent folder +cd( oldpwd ); + + + + +% ------------------------------------------------------------------------- +% ------------------------------------------------------------------------- + +function CSX = structure( params, filename, f_max ) +% CSX = structure( params, filename ) + +unit = 1e-3; % specify length in mm +lambda = 3e8/f_max; +resolution = lambda/15/unit; +mesh_size = 1.5; +radius = 10; +turns = params.turns; +height = 4 * turns; +feed_length = 10; + +CSX = InitCSX(); + +%% create coil +p1 = create_coil( radius, height, turns ); +p = p1(:,end) + [feed_length;0;0]; +p1 = [p1 p]; +p = p1(:,1) + [feed_length;0;0]; +p1 = [p p1]; +CSX = AddMetal(CSX,'PEC1'); +CSX = AddCurve(CSX, 'PEC1', 0, p1); + +%% create mesh +extraspace = 5*radius; +mesh.x = linspace(-radius,radius,ceil(2*radius/mesh_size)); +mesh.x = [mesh.x mesh.x(1)-extraspace mesh.x(end)+extraspace]; +mesh.x = [mesh.x p1(1,1) p1(1,1)-mesh_size p1(1,1)+mesh_size]; +mesh.x = SmoothMeshLines2( mesh.x, resolution ); +mesh.y = linspace(-radius,radius,ceil(2*radius/mesh_size)); +mesh.y = [mesh.y mesh.y(1)-extraspace mesh.y(end)+extraspace]; +mesh.y = SmoothMeshLines2( mesh.y, resolution ); +mesh.z = linspace(0,height,ceil(height/mesh_size)); +mesh.z = [mesh.z mesh.z(1)-extraspace mesh.z(end)+extraspace]; +% mesh.z = [mesh.z p1(3,1) p1(3,1)-mesh_size p1(3,1)+mesh_size]; +mesh.z = SmoothMeshLines2( mesh.z, resolution ); +CSX = DefineRectGrid(CSX, unit, mesh); + + +%% create port +[CSX,port] = AddCurvePort( CSX, 10, 1, 50, p1(:,1), p1(:,end), 'excite' ); + +if nargin > 1 + max_timesteps = 100000; + min_decrement = 1e-5; + FDTD = InitFDTD( max_timesteps, min_decrement ); + FDTD = SetGaussExcite( FDTD, 0, f_max ); + BC = {'PEC' 'PEC' 'PEC' 'PEC' 'PMC' 'PMC'}; + FDTD = SetBoundaryCond( FDTD, BC ); + + WriteOpenEMS( filename, FDTD, CSX ); +end + + +function p = create_coil(coil_rad,coil_length,coil_turns,coil_res,winding_direction,direction,offset,angle_offset) +if nargin < 8, angle_offset = 0; end +if nargin < 7, offset = [0; 0; 0]; end +if nargin < 6, direction = +1; end +if nargin < 5, winding_direction = +1; end +if nargin < 4, coil_res = 30; end +dt = 1/coil_res; +height = 0; + +p = []; +while abs(height) < coil_length + angle = height / (coil_length/coil_turns) * 2*pi; + p(1,end+1) = coil_rad * cos(angle*winding_direction+angle_offset); + p(2,end) = coil_rad * sin(angle*winding_direction+angle_offset); + p(3,end) = height * direction; + p(:,end) = p(:,end) + offset; + height = height + coil_length/coil_turns * dt; +end + + + +function L = postproc( filename, f_max ) +freq = linspace(0,f_max,201); +freq(1) = []; % delete DC component + +folder = fileparts(filename); +U = ReadUI( 'port_ut1', folder, freq ); +I = ReadUI( 'port_it1', folder, freq ); +Z = U.FD{1}.val ./ I.FD{1}.val; + +L = imag(Z) ./ (2*pi*freq); +L = reshape( L, 1, [] ); % row vector diff --git a/openEMS/matlab/examples/other/Helix.m b/openEMS/matlab/examples/other/Helix.m new file mode 100644 index 0000000..18e97c9 --- /dev/null +++ b/openEMS/matlab/examples/other/Helix.m @@ -0,0 +1,154 @@ +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +feed_length=10; +wire_rad = sqrt(1.4/pi); +mesh_size = wire_rad; +coil_rad = 10; +coil_length = 50; +coil_turns = 8; +coil_res = 10; +port_length = mesh_size; %coil_length/2; +port_resist = 1000; + +f_max = 100e6; +f_excite = 300e6; + +%% define openEMS options %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +openEMS_opts = ''; +% openEMS_opts = [openEMS_opts ' --debug-material']; +% openEMS_opts = [openEMS_opts ' --debug-boxes']; +% openEMS_opts = [openEMS_opts ' --debug-operator']; + +openEMS_opts = [openEMS_opts ' --disable-dumps --engine=fastest']; +% openEMS_opts = [openEMS_opts ' --engine=sse-compressed']; + +Sim_Path = 'tmp'; +Sim_CSX = 'helix.xml'; + +[status, message, messageid] = rmdir(Sim_Path,'s'); +[status,message,messageid] = mkdir(Sim_Path); + +%% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD(30000,1e-6); +FDTD = SetGaussExcite(FDTD,f_excite/2,f_excite/2); +BC = [1 1 1 1 1 1]; +FDTD = SetBoundaryCond(FDTD,BC); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +add_Lines = mesh_size * 1.5.^(1:10); +add_Lines = add_Lines(find(add_Lines<(3e8/f_excite)/10*1e3)); + +CSX = InitCSX(); +mesh.x = -coil_rad-mesh_size : mesh_size : coil_rad+mesh_size+feed_length; +mesh.x = [mesh.x(1)-add_Lines mesh.x mesh.x(end)+add_Lines ]; +mesh.y = -coil_rad-mesh_size : mesh_size : coil_rad+mesh_size; +mesh.y = [mesh.y(1)-add_Lines mesh.y mesh.y(end)+add_Lines ]; +mesh.z = -mesh_size : mesh_size : coil_length+mesh_size; +mesh.z = [mesh.z(1)-add_Lines mesh.z mesh.z(end)+add_Lines ]; +CSX = DefineRectGrid(CSX, 1e-3,mesh); + +%% build/define helix %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddMaterial(CSX,'copper'); +CSX = SetMaterialProperty(CSX,'copper','Kappa',56e6); + +dt = 1.0/coil_res; +height=0; +wire.Vertex = {}; +p(1,1) = coil_rad + feed_length; +p(2,1) = 0; +p(3,1) = 0.5*(coil_length-port_length); +p(1,2) = coil_rad + feed_length; +p(2,2) = 0; +p(3,2) = 0; +count=2; +for n=0:coil_turns-1 + for m=0:coil_res + count = count + 1; + p(1,count) = coil_rad * cos(2*pi*dt*m); + p(2,count) = coil_rad * sin(2*pi*dt*m); + p(3,count) = height + coil_length/coil_turns * dt*m; + end + height = height + coil_length/coil_turns; +end +p(1,count+1) = coil_rad + feed_length; +p(2,count+1) = 0; +p(3,count+1) = coil_length; +p(1,count+2) = coil_rad + feed_length; +p(2,count+2) = 0; +p(3,count+2) = 0.5*(coil_length+port_length); +CSX = AddWire(CSX, 'copper', 0, p, wire_rad); + +%% apply the excitation & resist as a current source%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddMaterial(CSX,'resist'); +kappa = port_length/port_resist/wire_rad^2/pi/1e-3; +CSX = SetMaterialProperty(CSX,'resist','Kappa',kappa); + +start=[coil_rad+feed_length 0 (coil_length-port_length)/2]; +stop=[coil_rad+feed_length 0 (coil_length+port_length)/2]; +%start(3)=(coil_length-port_length)/2;stop(3)=(coil_length+port_length)/2; +CSX = AddCylinder(CSX,'resist',5 ,start,stop,wire_rad); + +CSX = AddExcitation(CSX,'excite',0,[0 0 1]); +CSX = AddCylinder(CSX,'excite', 0 ,start,stop,wire_rad); + +%% define voltage calc boxes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%voltage calc +CSX = AddProbe(CSX,'ut1',0); +CSX = AddBox(CSX,'ut1', 0 ,stop,start); + +%current calc +CSX = AddProbe(CSX,'it1',1); +start(3) = coil_length/2+mesh_size;stop(3) = coil_length/2+mesh_size; +start(1) = start(1)-2;start(2) = start(2)-2; +stop(1) = stop(1)+2;stop(2) = stop(2)+2; +CSX = AddBox(CSX,'it1', 0 ,start,stop); + +%% define dump boxes... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddDump(CSX,'Et_'); +start = [mesh.x(1) , 0 , mesh.z(1)]; +stop = [mesh.x(end) , 0 , mesh.z(end)]; +CSX = AddBox(CSX,'Et_',0 , start,stop); + +CSX = AddDump(CSX,'Ht_','DumpType',1); +start = [mesh.x(1) , 0 , mesh.z(1)]; +stop = [mesh.x(end) , 0 , mesh.z(end)]; +CSX = AddBox(CSX,'Ht_',0 , start,stop); + +%% Write openEMS compatoble xml-file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + +%% run openEMS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +RunOpenEMS(Sim_Path, Sim_CSX, openEMS_opts); + +%% postproc & do the plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +U = ReadUI('ut1','tmp/'); +I = ReadUI('it1','tmp/'); + +Z = U.FD{1}.val./I.FD{1}.val; +f = U.FD{1}.f; +L = imag(Z)./(f*2*pi); +R = real(Z); +ind = find(f + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +f_max = 100e6; +f_excite = 300e6; +SimBox = 100; +mesh_size = 2; + +Lumped.R = 1000; +Lumped.C = 10e-12; + +% the parasitice inductance of the feeding has to be deduced with a R=0 +% simulation +parasitic_L = 63e-9; + +%% define openEMS options %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +openEMS_opts = ''; +% openEMS_opts = [openEMS_opts ' --debug-material']; +% openEMS_opts = [openEMS_opts ' --debug-boxes']; +% openEMS_opts = [openEMS_opts ' --debug-operator']; + +Sim_Path = 'tmp'; +Sim_CSX = 'lumped.xml'; + +[status, message, messageid] = rmdir(Sim_Path,'s'); +[status,message,messageid] = mkdir(Sim_Path); + +%% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD(30000,1e-6); +FDTD = SetGaussExcite(FDTD,f_excite/2,f_excite/2); +BC = [1 1 1 1 1 1]; +FDTD = SetBoundaryCond(FDTD,BC); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +mesh.x = SmoothMeshLines([-SimBox/2,+SimBox/2],mesh_size); +mesh.y = SmoothMeshLines([-SimBox/2,+SimBox/2],mesh_size); +mesh.z = SmoothMeshLines([-SimBox/2,+SimBox/2],mesh_size); +CSX = DefineRectGrid(CSX, 1e-3,mesh); + + +%% create structure +% insert curve port +start = [ 10 -10 0]; +stop = [ 10 10 0]; +CSX = AddCurvePort(CSX,0,1,100,start,stop,'excite'); + +% insert lumped element +CSX = AddLumpedElement( CSX, 'Capacitor', 1, 'C', Lumped.C, 'R', Lumped.R); +start = [ -14 -4 -4]; +stop = [ -6 4 4]; +CSX = AddBox( CSX, 'Capacitor', 0, start, stop ); + +% insert feeding wire +CSX = AddMetal(CSX,'metal'); +%first point +points(1,1) = -10; +points(2,1) = 4; +points(3,1) = 0; +%second point +points(1,2) = -10; +points(2,2) = 15; +points(3,2) = 0; +%3 point +points(1,end+1) = 10; +points(2,end) = 15; +points(3,end) = 0; +%4 point +points(1,end+1) = 10; +points(2,end) = 10; +points(3,end) = 0; +CSX = AddCurve(CSX,'metal', 10, points); + +points(2,:) = -1*points(2,:); +CSX = AddCurve(CSX,'metal', 10, points); + +%% Write openEMS compatoble xml-file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + +% CSXGeomPlot([Sim_Path '/' Sim_CSX]); + +%% run openEMS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +RunOpenEMS(Sim_Path, Sim_CSX, openEMS_opts); + +%% postproc & do the plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +f = linspace(1e6,f_max,1001); +w = 2*pi*f; +% read currents and voltages +U = ReadUI('port_ut1','tmp/',f); +I = ReadUI('port_it1','tmp/',f); + +% calculate analytic impedance +if (Lumped.R>=0) + Z_a = Lumped.R*(1-1i*w*Lumped.C*Lumped.R)./(1+(w*Lumped.C*Lumped.R).^2); +else + Z_a = -1i./(w*Lumped.C); +end + +% calculate numerical impedance +Z = U.FD{1}.val./I.FD{1}.val; + +% remove parasitic feeding effects +Z = Z - 1i*w*parasitic_L; + +L = imag(Z)./w; +C = -1./(w.*imag(Z)); +C(find(C<0)) = nan; +L(find(L<0)) = nan; +R = real(Z); + +subplot(2,1,1); +plot(f*1e-6,C*1e12,'Linewidth',2); +xlabel('frequency (MHz)'); +ylabel('capacitance (pF)'); +grid on; +subplot(2,1,2); +plot(f*1e-6,L*1e9,'Linewidth',2); +xlabel('frequency (MHz)'); +ylabel('inductance (nH)'); +grid on; + +figure(); +plot(f*1e-6,R,'Linewidth',2); +hold on +plot(f*1e-6,imag(Z),'r--','Linewidth',2); + +plot(f*1e-6,real(Z_a),'g-.','Linewidth',1); +plot(f*1e-6,imag(Z_a),'m--','Linewidth',1); + +xlabel('frequency (MHz)'); +ylabel('resistance (Ohm)'); +grid on; +legend( '\Re\{Z\}','\Im\{Z\}','\Re\{Z_{analytisch}\}','\Im\{Z_{analytisch}\}', 'location', 'northeast' ) + +figure(); +errorR = (R-real(Z_a))./R*100; +errorX = (imag(Z)-imag(Z_a))./imag(Z)*100; +plot(f*1e-6,errorR,'Linewidth',2); +hold on +grid on; +plot(f*1e-6,errorX,'r--','Linewidth',2); +xlabel('frequency (MHz)'); +ylabel('error (%)'); diff --git a/openEMS/matlab/examples/other/Metamaterial_PlaneWave_Drude.m b/openEMS/matlab/examples/other/Metamaterial_PlaneWave_Drude.m new file mode 100644 index 0000000..db72b3e --- /dev/null +++ b/openEMS/matlab/examples/other/Metamaterial_PlaneWave_Drude.m @@ -0,0 +1,147 @@ +%%%%%%%%%%%%%%%%%%%%%%% +% example demonstrating double drude meta-material +% +% tested with openEMS v0.0.28 +% +% author: Thorsten Liebig @ 2010,2012 +%%%%%%%%%%%%%%%%%%%%%%% + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +postproc_only = 0; %set to 1 if the simulation is already done + +Settings = []; +Settings.LogFile = 'openEMS.log'; + +pic_size = round([1400 1400/4]); %define the animation picture size + +%simulation domain setup (in mm) +length = 500; +width = 10; +mesh_res = 0.5; % mesh resolution +height = 3*mesh_res; % hight is ony 3 lines with PEC (top/bottom) --> quasi 2D + +%FDTD setup +f0 = 5e9; %center frequency +f_BW = f0/sqrt(2); %bandwidth +MTM.eps_R = 1; +MTM.mue_R = 1; +MTM.f0 = f0; %plasma frequency of the drude material +MTM.relaxTime = 5e-9; %relaxation time (smaller number results in greater losses, set to 0 to disable) +MTM.length = 250; %length of the metamaterial +N_TS = 5e4; %number of timesteps +endCriteria = 1e-5; %stop simulation if signal is at -50dB + +%constants +physical_constants + +%% define openEMS options %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +openEMS_opts = '-vvv'; + +Sim_Path = 'MTM_PW_Drude'; +Sim_CSX = 'MTM_PW_Drude.xml'; + +if (postproc_only==0) + + if (exist(Sim_Path,'dir')) + rmdir(Sim_Path,'s'); + end + mkdir(Sim_Path); + + %% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% + FDTD = InitFDTD(N_TS,endCriteria,'OverSampling',10); + FDTD = SetGaussExcite(FDTD,0,2*f0); + BC = [1 1 0 0 2 2]; + FDTD = SetBoundaryCond(FDTD,BC); + + %% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + CSX = InitCSX(); + mesh.x = -width/2 : mesh_res : width/2; + mesh.y = -height/2 : mesh_res : height/2; + mesh.z = -length/2 : mesh_res : length/2; + CSX = DefineRectGrid(CSX, 1e-3,mesh); + + %% apply the plane wave excitation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + start=[-width/2 -height/2 ,mesh.z(3)]; + stop=[width/2 height/2 mesh.z(3)]; + CSX = AddExcitation(CSX,'excite',0,[0 1 0]); % excite E_y + CSX = AddBox(CSX,'excite',0 ,start,stop); + + %% apply drude material %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + CSX = AddLorentzMaterial(CSX,'drude'); + CSX = SetMaterialProperty(CSX,'drude','Epsilon',MTM.eps_R,'EpsilonPlasmaFrequency',MTM.f0,'EpsilonRelaxTime',MTM.relaxTime); + CSX = SetMaterialProperty(CSX,'drude','Mue',MTM.mue_R,'MuePlasmaFrequency',MTM.f0,'MueRelaxTime',MTM.relaxTime); + start=[mesh.x(1) mesh.y(1) -MTM.length/2]; + stop =[mesh.x(end) mesh.y(end) MTM.length/2]; + CSX = AddBox(CSX,'drude', 10 ,start,stop); + + %% define dump boxes... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + CSX = AddDump(CSX,'Et','FileType',1,'SubSampling','10,10,1'); + start = [mesh.x(2) ,0 , mesh.z(1)]; + stop = [mesh.x(end-1) , 0 , mesh.z(end)]; + CSX = AddBox(CSX,'Et',0 , start,stop); + + %% Write openEMS compatoble xml-file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + + %% run openEMS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + RunOpenEMS(Sim_Path, Sim_CSX, openEMS_opts, Settings); + +end + +%% plot the drude type material dependency +f = linspace(0.1*f0,2*f0,501); +w = 2*pi*f; +epsr = MTM.eps_R * (1 - (2*pi*MTM.f0)^2./( w.^2 - 1j*w./MTM.relaxTime )); +muer = MTM.mue_R * (1 - (2*pi*MTM.f0)^2./( w.^2 - 1j*w./MTM.relaxTime )); +plot(f,real(epsr),'Linewidth',2); +hold on +grid on +plot(f,imag(epsr),'r--','Linewidth',2); +plot(f,real(muer),'c-.','Linewidth',2); +plot(f,imag(muer),'m-.','Linewidth',2); +ylim([-10 MTM.eps_R]) +% l=legend('\Re \epsilon_r','\Im \epsilon_r','\Re \mue_r','\Im \mue_r'); +l=legend('$\Re\{\varepsilon_r\}$','$\Im\{\varepsilon_r\}$','$\Re\{\mu_r\}$','$\Im\{\mu_r\}$'); +set(l,'Interpreter','latex','Fontsize',12) + +%% plot E-fields +freq = [f0/sqrt(2) f0 f0*sqrt(2)]; +field = ReadHDF5FieldData([Sim_Path '/Et.h5']); +mesh_h5 = ReadHDF5Mesh([Sim_Path '/Et.h5']); + +ET = ReadUI('et',Sim_Path); +ef = DFT_time2freq(ET.TD{1}.t,ET.TD{1}.val,freq); + +field_FD = GetField_TD2FD(field, freq); + +mesh.x = linspace(-500,500,numel(mesh_h5.lines{1})); %make animation wider... +mesh.y = mesh_h5.lines{2}; +mesh.z = mesh_h5.lines{3}; + +[X Z] = meshgrid(mesh.x,mesh.z); +X = X'; +Z = Z'; + +for n=1:numel(field_FD.FD.values) + Ec{n} = squeeze(field_FD.FD.values{n}/ef(n)); +end + +%% +figure('Position',[10 100 pic_size(1) pic_size(2)]); +phase = linspace(0,2*pi,21); +disp('press CTRL+C to stop animation'); +while (1) + for ph = phase(1:end-1) + for n=1:numel(Ec) + subplot(1,numel(Ec),n) + E = real(Ec{n}.*exp(1j*ph)); + surf(X,Z,E(:,:,2)); + title(['f_0 = ' num2str(freq(n)*1e-9) ' GHz']) + end + pause(0.1); + end +end diff --git a/openEMS/matlab/examples/other/PML_reflection_analysis.m b/openEMS/matlab/examples/other/PML_reflection_analysis.m new file mode 100644 index 0000000..f243a83 --- /dev/null +++ b/openEMS/matlab/examples/other/PML_reflection_analysis.m @@ -0,0 +1,196 @@ +% +% fake-PML parallel plate waveguide example +% +% this example analyzes the reflection coefficient of a vacuum-pml +% interface +% + +% +% currently this example uses a normal material with a certain conductivity +% profile and not a pml +% + +close all +% clear +clc + +physical_constants + + +postprocessing_only = 0; + + + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +drawingunit = 1e-6; % specify everything in um + +length = 10000; +epr = 1; + +mesh_res = [200 200 200]; +max_timesteps = 100000; +min_decrement = 1e-6; +f_max = 8e9; + +%% setup FDTD parameters & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD( max_timesteps, min_decrement ); +FDTD = SetGaussExcite( FDTD, f_max/2, f_max/2 ); +BC = [0 0 1 1 0 0]; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% mesh grading +N_pml = 8; +pml_delta = cumsum(mesh_res(1) * 1.0 .^ (1:N_pml)); +% pml_delta = cumsum([200 200 200 200 200]); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +mesh.x = 0 : mesh_res(1) : length; +mesh.x = [mesh.x(1) - fliplr(pml_delta), mesh.x]; +mesh.y = -2*mesh_res(2) : mesh_res(2) : 2*mesh_res(2); +mesh.z = 0 : mesh_res(3) : 4*mesh_res(3); +CSX = DefineRectGrid( CSX, drawingunit, mesh ); + +%% fake pml %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +g = 2; % 2..3 +R0 = 1e-6; % requested analytical reflection coefficient +Zm = sqrt(MUE0/(EPS0*epr)); % calculate reflection for substrate/pml interface +delta = pml_delta(end) * drawingunit; +deltal = mean(diff(pml_delta)) * drawingunit; +kappa0 = -log(R0)*log(g)/( 2*Zm*deltal*(g^(delta/deltal)-1) ); + +% kappa0 = 1.05; +CSX = AddMaterial( CSX, 'pml_xmin' ); +CSX = SetMaterialProperty( CSX, 'pml_xmin', 'Epsilon', epr ); +CSX = SetMaterialProperty( CSX, 'pml_xmin', 'Kappa', kappa0 ); +CSX = SetMaterialProperty( CSX, 'pml_xmin', 'Sigma', kappa0 * MUE0/(EPS0*epr) ); +CSX = SetMaterialWeight( CSX, 'pml_xmin', 'Kappa', [num2str(g) '^((abs(x-100)-' num2str(abs(mesh.x(N_pml+1))) ')/(' num2str(deltal) '/' num2str(drawingunit) '))'] ); % g^(rho/deltal)*kappa0 +CSX = SetMaterialWeight( CSX, 'pml_xmin', 'Sigma', [num2str(g) '^((abs(x-100)-' num2str(abs(mesh.x(N_pml+1))) ')/(' num2str(deltal) '/' num2str(drawingunit) '))'] ); +start = [mesh.x(1), mesh.y(1), mesh.z(1)]; +stop = [100, mesh.y(end), mesh.z(end)]; +CSX = AddBox( CSX, 'pml_xmin', 1, start, stop ); + +figure +x = [-fliplr(pml_delta) 50]; +plot( x, kappa0 * g.^((abs(x-50)-abs(mesh.x(N_pml+1)))./(deltal/drawingunit)) ,'x-'); +xlabel( 'x / m' ); +ylabel( 'kappa' ); +figure +title( 'conductivity profile inside the material' ); + +%% excitation +CSX = AddExcitation( CSX, 'excitation1', 0, [0 0 1]); +idx = interp1( mesh.x, 1:numel(mesh.x), length*2/3, 'nearest' ); +start = [mesh.x(idx), mesh.y(1), mesh.z(1)]; +stop = [mesh.x(idx), mesh.y(end), mesh.z(end)]; +CSX = AddBox( CSX, 'excitation1', 0, start, stop ); + +%% define dump boxes... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddDump( CSX, 'Et_', 'DumpMode', 2 ); +start = [mesh.x(1), mesh.y(1), mesh.z(3)]; +stop = [mesh.x(end), mesh.y(end), mesh.z(3)]; +CSX = AddBox( CSX, 'Et_', 0, start, stop ); + +CSX = AddDump( CSX, 'Ht_', 'DumpType', 1, 'DumpMode', 2 ); +CSX = AddBox( CSX, 'Ht_', 0, start, stop ); + +% hdf5 file +CSX = AddDump( CSX, 'E', 'DumpType', 0, 'DumpMode', 2, 'FileType', 1 ); +idx = interp1( mesh.x, 1:numel(mesh.x), length*1/3, 'nearest' ); +start = [mesh.x(idx), mesh.y(3), mesh.z(1)]; +stop = [mesh.x(idx), mesh.y(3), mesh.z(end)]; +CSX = AddBox( CSX, 'E', 0, start, stop ); + +% hdf5 file +CSX = AddDump( CSX, 'H', 'DumpType', 1, 'DumpMode', 2, 'FileType', 1 ); +idx = interp1( mesh.x, 1:numel(mesh.x), length*1/3, 'nearest' ); +start = [mesh.x(idx), mesh.y(1), mesh.z(3)]; +stop = [mesh.x(idx), mesh.y(end), mesh.z(3)]; +CSX = AddBox( CSX, 'H', 0, start, stop ); + +%% define openEMS options %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +openEMS_opts = ''; +% openEMS_opts = [openEMS_opts ' --disable-dumps']; +% openEMS_opts = [openEMS_opts ' --debug-material']; +% openEMS_opts = [openEMS_opts ' --debug-operator']; +% openEMS_opts = [openEMS_opts ' --debug-boxes']; +% openEMS_opts = [openEMS_opts ' --showProbeDiscretization']; +openEMS_opts = [openEMS_opts ' --engine=fastest']; + +Sim_Path = 'tmp'; +Sim_CSX = 'PML_reflection_analysis.xml'; + +if ~postprocessing_only + [~,~,~] = rmdir(Sim_Path,'s'); + [~,~,~] = mkdir(Sim_Path); +end + +%% Write openEMS compatible xml-file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + +%% cd to working dir and run openEMS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if ~postprocessing_only + savePath = pwd; + cd(Sim_Path); %cd to working dir + args = [Sim_CSX ' ' openEMS_opts]; + invoke_openEMS(args); + cd(savePath) +end + + +%% postproc & do the plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% E_coords = ReadHDF5Mesh( [Sim_Path '/E.h5'] ); +% H_coords = ReadHDF5Mesh( [Sim_Path '/H.h5'] ); +E = ReadHDF5FieldData( [Sim_Path '/E.h5'] ); +H = ReadHDF5FieldData( [Sim_Path '/H.h5'] ); +E_val = cellfun( @(x) squeeze(x(1,1,:,3)), E.values, 'UniformOutput', false ); +H_val = cellfun( @(x) squeeze(x(1,:,1,2)), H.values, 'UniformOutput', false ); +E_val = cell2mat(E_val); +H_val = cell2mat(H_val.'); + +% pick center point +Et = E_val(3,:); +Ht = H_val(:,3).'; + +delta_t_2 = H.time(1) - E.time(1); % half time-step (s) + +% create finer frequency resolution +f = linspace( 0, f_max, 1601 ); +Ef = DFT_time2freq( E.time, Et, f ); +Hf = DFT_time2freq( H.time, Ht, f ); +Hf = Hf .* exp(-1i*2*pi*f*delta_t_2); % compensate half time-step advance of H-field + +% H is now time interpolated, but the position is not corrected with +% respect to E + +% figure +% plot( E.time/1e-6, Et ); +% xlabel('time (us)'); +% ylabel('amplitude (V)'); +% grid on; +% title( 'Time domain voltage probe' ); +% +% figure +% plot( H.time/1e-6, Ht ); +% xlabel('time (us)'); +% ylabel('amplitude (A)'); +% grid on; +% title( 'Time domain current probe' ); + + +Z0 = sqrt(MUE0/EPS0); % line impedance +Z = Ef ./ Hf; % impedance at measurement plane +gamma = (Z - Z0) ./ (Z + Z0); + +plot( f/1e9, 20*log10(abs(gamma)),'Linewidth',2); +xlabel('frequency (GHz)'); +ylabel('reflection coefficient gamma (dB)'); +grid on; +title( 'Reflection Coefficient' ); + +if exist('ref_1','var') + hold on + plot( f/1e9, ref_1,'--','Linewidth',2, 'Color', [1 0 0]); + hold off +end +ref_1 = 20*log10(abs(gamma)); diff --git a/openEMS/matlab/examples/other/PlaneWave.m b/openEMS/matlab/examples/other/PlaneWave.m new file mode 100644 index 0000000..5e0d3e8 --- /dev/null +++ b/openEMS/matlab/examples/other/PlaneWave.m @@ -0,0 +1,69 @@ +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +length = 5000; +width = 300; +height = 200; +mesh_res = 15; +abs_length = mesh_res*10; + +EPS0 = 8.85418781762e-12; +MUE0 = 1.256637062e-6; + +%% define openEMS options %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +openEMS_opts = ''; +% openEMS_opts = [openEMS_opts ' --disable-dumps']; +% openEMS_opts = [openEMS_opts ' --debug-material']; +openEMS_opts = [openEMS_opts ' --engine=fastest']; + +Sim_Path = 'tmp'; +Sim_CSX = 'plane_wave.xml'; + +if (exist(Sim_Path,'dir')) + rmdir(Sim_Path,'s'); +end +mkdir(Sim_Path); + +%% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD(5000,1e-5,'OverSampling',10); +FDTD = SetGaussExcite(FDTD,0.5e9,0.5e9); +BC = [1 1 0 0 2 2]; +FDTD = SetBoundaryCond(FDTD,BC); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +mesh.x = -width/2 : mesh_res : width/2; +mesh.y = -height/2 : mesh_res : height/2; +mesh.z = 0 : mesh_res : length; +CSX = DefineRectGrid(CSX, 1e-3,mesh); + +%% apply the excitation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start=[-width/2 -height/2 mesh.z(3)]; +stop =[ width/2 height/2 mesh.z(3)]; +CSX = AddExcitation(CSX,'excite',0,[0 1 0]); +CSX = AddBox(CSX,'excite',0 ,start,stop); + +%% define dump boxes... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddDump(CSX,'Et','FileType',1,'SubSampling','4,4,4'); +start = [mesh.x(1) , mesh.y(1) , mesh.z(1)]; +stop = [mesh.x(end) , mesh.y(end) , mesh.z(end)]; +CSX = AddBox(CSX,'Et',0 , start,stop); + +CSX = AddDump(CSX,'Ht','DumpType',1,'FileType',1,'SubSampling','4,4,4','DumpMode',2); +CSX = AddBox(CSX,'Ht',0,start,stop); + +%% Write openEMS compatoble xml-file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + +%% run openEMS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +RunOpenEMS(Sim_Path, Sim_CSX, openEMS_opts); + +%% do the plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +PlotArgs.slice = {mesh.x(round(end/2)) mesh.y(round(end/2)) mesh.z(round(end/2))}; +PlotArgs.pauseTime=0.01; +PlotArgs.component=1; +PlotArgs.Limit = 'auto'; + +PlotHDF5FieldData('tmp/Ht.h5',PlotArgs) diff --git a/openEMS/matlab/examples/other/gauss_excitation_test.m b/openEMS/matlab/examples/other/gauss_excitation_test.m new file mode 100644 index 0000000..a7e166e --- /dev/null +++ b/openEMS/matlab/examples/other/gauss_excitation_test.m @@ -0,0 +1,72 @@ +% +% this script evaluates the same gaussian excitation function, as openEMS does +% + +clear +close all +clc + +f0 = 0e9; +fc = 10e9; +dT = 1e-12; % sample time-step + + +sigma = 1/sqrt(8/9)/pi/fc; +t0 = sqrt(18)/sqrt(8/9)/pi/fc; + +len = 2 * 9/(2*pi*fc) / dT; % gauss length + +for n=1:len + t_(n) = (n-1)*dT; + ex(n) = cos(2*pi*f0*((n-1)*dT - 9/(2*pi*fc))) .* exp(-((t_(n)-t0)/sigma)^2/2); +end + +plot(t_/1e-9,ex) +xlabel( 'time (ns)' ); +ylabel( 'amplitude' ); + + +disp( ['Amplitude at t=0: ' num2str(20*log10(abs(ex(1))/1)) ' dB'] ); + +val = DFT_time2freq( t_, ex, [f0-fc f0 f0+fc] ); +disp( ['Amplitude at f=f0-fc: ' num2str(20*log10(abs(val(1))/abs(val(2)))) ' dB'] ); +disp( ['Amplitude at f=f0+fc: ' num2str(20*log10(abs(val(3))/abs(val(2)))) ' dB'] ); + +% calculate frequency domain via slow DFT +freq = linspace(f0-fc,f0+fc,1000); +val = DFT_time2freq( t_, ex, freq ); +figure +plot( freq/1e9, abs(val) ) + +% overlay the FFT result +[f,val_fft] = FFT_time2freq( t_, ex ); +val_fft = val_fft((f0-fc<=f) & (f<=f0+fc)); +f = f((f0-fc<=f) & (f<=f0+fc)); +hold on +plot( f/1e9, abs(val_fft), 'r' ) +hold on + +if (f0==0) + Fw = sigma*sqrt(2*pi)*exp(-0.5*(sigma*2*pi*f).^2); + plot( f/1e9, 2*abs(Fw), 'g--' ) + legend('dft','fft','analytic') +else + legend('dft','fft') +end + +xlim([0 max(f)/1e9]) + +xlabel( 'frequency (GHz)' ); +ylabel( 'amplitude' ); + + +% dB +figure +val = val(freq>=0); +freq = freq(freq>=0); +plot( freq/1e9, 20*log10(abs(val)/max(abs(val))), 'r' ) +xlabel( 'frequency (GHz)' ); +ylabel( 'amplitude (dB)' ); + + + diff --git a/openEMS/matlab/examples/other/resistance_sheet.m b/openEMS/matlab/examples/other/resistance_sheet.m new file mode 100644 index 0000000..b63c00e --- /dev/null +++ b/openEMS/matlab/examples/other/resistance_sheet.m @@ -0,0 +1,207 @@ +% +% resistance "sheet" example +% +% this example calculates the reflection coefficient of a sheet resistance +% at the end of a parallel plate wave guide +% +% play around with the R and epr values +% + +close all +clear +clc + +physical_constants + + +postprocessing_only = 0; + + + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +epr = 1; % relative permittivity of the material inside the parallel plate waveguide + +% define the resistance +R = sqrt(MUE0/(EPS0*epr)); % matched load (no reflections) (vacuum: approx. 377 Ohm) +% R = 1e-10; % short circuit (reflection coefficient = -1) +% R = 1e10; % open circuit (reflection coefficient = 1) + + +drawingunit = 1e-6; % specify everything in um +length = 10000; +mesh_res = [200 200 200]; +max_timesteps = 100000; +min_decrement = 1e-6; +f_max = 1e9; + +%% setup FDTD parameters & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD( max_timesteps, min_decrement ); +FDTD = SetGaussExcite( FDTD, f_max/2, f_max/2 ); +BC = [1 2 1 1 0 0]; % 0:PEC 1:PMC 2:MUR-ABC +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +mesh.x = 0 : mesh_res(1) : length; +mesh.y = -2*mesh_res(2) : mesh_res(2) : 2*mesh_res(2); +mesh.z = 0 : mesh_res(3) : 4*mesh_res(3); +CSX = DefineRectGrid( CSX, drawingunit, mesh ); + +%% measurement plane & reference plane +meas_plane_xidx = interp1( mesh.x, 1:numel(mesh.x), length*1/3, 'nearest' ); +ref_plane_xidx = 3; + +%% fill the parallel plate waveguide with material +CSX = AddMaterial( CSX, 'm1' ); +CSX = SetMaterialProperty( CSX, 'm1', 'Epsilon', epr ); +start = [mesh.x(1), mesh.y(1), mesh.z(1)]; +stop = [mesh.x(end), mesh.y(end), mesh.z(end)]; +CSX = AddBox( CSX, 'm1', -1, start, stop ); + +%% excitation +CSX = AddExcitation( CSX, 'excitation1', 0, [0 0 1]); +idx = interp1( mesh.x, 1:numel(mesh.x), length*2/3, 'nearest' ); +start = [mesh.x(idx), mesh.y(1), mesh.z(1)]; +stop = [mesh.x(idx), mesh.y(end), mesh.z(end)]; +CSX = AddBox( CSX, 'excitation1', 0, start, stop ); + +%% define the sheet resistance +start = [mesh.x(ref_plane_xidx-1), mesh.y(1), mesh.z(1)]; +stop = [mesh.x(ref_plane_xidx), mesh.y(end), mesh.z(end)]; +l = abs(mesh.z(end) - mesh.z(1)) * drawingunit; % length of the "sheet" +A = abs(start(1) - stop(1)) * abs(mesh.y(end) - mesh.y(1)) * drawingunit^2; % area of the "sheet" +kappa = l/A / R; % [kappa] = S/m +CSX = AddMaterial( CSX, 'sheet_resistance' ); +CSX = SetMaterialProperty( CSX, 'sheet_resistance', 'Kappa', kappa ); +CSX = AddBox( CSX, 'sheet_resistance', 0, start, stop ); + +%% define dump boxes... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddDump( CSX, 'Et_', 'DumpMode', 2 ); +start = [mesh.x(1), mesh.y(1), mesh.z(3)]; +stop = [mesh.x(end), mesh.y(end), mesh.z(3)]; +CSX = AddBox( CSX, 'Et_', 0, start, stop ); + +CSX = AddDump( CSX, 'Ht_', 'DumpType', 1, 'DumpMode', 2 ); +CSX = AddBox( CSX, 'Ht_', 0, start, stop ); + +% hdf5 file +CSX = AddDump( CSX, 'E', 'DumpType', 0, 'DumpMode', 2, 'FileType', 1 ); +start = [mesh.x(meas_plane_xidx), mesh.y(3), mesh.z(1)]; +stop = [mesh.x(meas_plane_xidx), mesh.y(3), mesh.z(end)]; +CSX = AddBox( CSX, 'E', 0, start, stop ); + +% hdf5 file +CSX = AddDump( CSX, 'H', 'DumpType', 1, 'DumpMode', 2, 'FileType', 1 ); +start = [mesh.x(meas_plane_xidx), mesh.y(1), mesh.z(3)]; +stop = [mesh.x(meas_plane_xidx), mesh.y(end), mesh.z(3)]; +CSX = AddBox( CSX, 'H', 0, start, stop ); + +%% define openEMS options %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +openEMS_opts = ''; +% openEMS_opts = [openEMS_opts ' --disable-dumps']; +% openEMS_opts = [openEMS_opts ' --debug-material']; +% openEMS_opts = [openEMS_opts ' --debug-operator']; +% openEMS_opts = [openEMS_opts ' --debug-boxes']; +% openEMS_opts = [openEMS_opts ' --showProbeDiscretization']; +openEMS_opts = [openEMS_opts ' --engine=fastest']; + +Sim_Path = 'tmp'; +Sim_CSX = 'tmp.xml'; + +if ~postprocessing_only + [~,~,~] = rmdir(Sim_Path,'s'); + [~,~,~] = mkdir(Sim_Path); +end + +%% Write openEMS compatible xml-file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + +%% cd to working dir and run openEMS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if ~postprocessing_only + savePath = pwd; + cd(Sim_Path); %cd to working dir + args = [Sim_CSX ' ' openEMS_opts]; + invoke_openEMS(args); + cd(savePath) +end + + +%% postproc & do the plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% E_coords = ReadHDF5Mesh( [Sim_Path '/E.h5'] ); +% H_coords = ReadHDF5Mesh( [Sim_Path '/H.h5'] ); +E = ReadHDF5FieldData( [Sim_Path '/E.h5'] ); +H = ReadHDF5FieldData( [Sim_Path '/H.h5'] ); +E_val = cellfun( @(x) squeeze(x(1,1,:,3)), E.values, 'UniformOutput', false ); +H_val = cellfun( @(x) squeeze(x(1,:,1,2)), H.values, 'UniformOutput', false ); +E_val = cell2mat(E_val); +H_val = cell2mat(H_val.'); + +% pick center point +Et = E_val(3,:); +Ht = H_val(:,3).'; + +delta_t_2 = H.time(1) - E.time(1); % half time-step (s) + +% create finer frequency resolution +f = linspace( 0, f_max, 201 ); +Ef = DFT_time2freq( E.time, Et, f ); +Hf = DFT_time2freq( H.time, Ht, f ); +Hf = Hf .* exp(-1i*2*pi*f*delta_t_2); % compensate half time-step advance of H-field + +% H is now time interpolated, but the position is not corrected with +% respect to E + +% figure +% plot( E.time/1e-6, Et ); +% xlabel('time (us)'); +% ylabel('amplitude (V)'); +% grid on; +% title( 'Time domain voltage probe' ); +% +% figure +% plot( H.time/1e-6, Ht ); +% xlabel('time (us)'); +% ylabel('amplitude (A)'); +% grid on; +% title( 'Time domain current probe' ); + + +Z0 = sqrt(MUE0/(EPS0*epr)); % line impedance +Z = Ef ./ Hf; % impedance at measurement plane +gamma = (Z - Z0) ./ (Z + Z0); + +% reference plane shift +beta = 2*pi*f * sqrt(MUE0*(EPS0*epr)); % TEM wave +meas_plane_x = mesh.x(meas_plane_xidx); +ref_plane_x = mesh.x(ref_plane_xidx); +gamma_refplane = gamma .* exp(2i*beta* (meas_plane_x-ref_plane_x)*drawingunit); +Z_refplane = Z0 * (1+gamma_refplane)./(1-gamma_refplane); + +% smith chart +figure +if exist( 'smith', 'file' ) + % smith chart + % www.ece.rutgers.edu/~orfanidi/ewa + % or cmt toolbox from git.ate.uni-duisburg.de + smith +else + % poor man smith chart + plot( sin(0:0.01:2*pi), cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); + hold on +% plot( 0.25+0.75*sin(0:0.01:2*pi), 0.75*cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); + plot( 0.5+0.5*sin(0:0.01:2*pi), 0.5*cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); +% plot( 0.75+0.25*sin(0:0.01:2*pi), 0.25*cos(0:0.01:2*pi), 'Color', [.7 .7 .7] ); + plot( [-1 1], [0 0], 'Color', [.7 .7 .7] ); + axis equal +end +plot( real(gamma_refplane), imag(gamma_refplane), 'r*' ); +% plot( real(gamma), imag(gamma), 'k*' ); +title( 'reflection coefficient S11 at reference plane' ) + +figure +plot( f/1e9, [real(Z_refplane);imag(Z_refplane)],'Linewidth',2); +xlabel('frequency (GHz)'); +ylabel('impedance (Ohm)'); +grid on; +title( 'Impedance at reference plane' ); +legend( {'real','imag'} ); diff --git a/openEMS/matlab/examples/transmission_lines/CPW_Line.m b/openEMS/matlab/examples/transmission_lines/CPW_Line.m new file mode 100644 index 0000000..6dac636 --- /dev/null +++ b/openEMS/matlab/examples/transmission_lines/CPW_Line.m @@ -0,0 +1,125 @@ +% +% Tutorials / CPW_Line +% +% Describtion at: +% +% Tested with +% - Octave 3.8.1 +% - openEMS v0.0.32 +% +% (C) 2014 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants; +unit = 1e-6; % specify everything in um +CPW_length = 40000; +CPW_port_length = 10000; +CPW_width = 1000; +CPW_gap = 140; +substrate_thickness = 512; +substrate_width = 5000 +substrate_epr = 3.66; +f_max = 10e9; +air_spacing = 7000 + +% use a finite line CPW waveguide +if 1 + feed_R = 50; + pml_add_cells = [8 8 8 8 8 8]; + feed_shift_cells = 0; + x_spacing = air_spacing; +else % or use a waveguide with start/end in a pml + feed_R = inf; % CPW ends in a pml --> disable termination resitance + feed_shift_cells = 10; % CPW ends in an 8 cells thick pml --> shift feed 10 cells + pml_add_cells = [0 0 8 8 8 8]; % do not add air-space in x-direction + x_spacing = 0; % do not add air-space in x-direction +end + +%% setup FDTD parameters & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD('EndCriteria', 1e-4); +FDTD = SetGaussExcite( FDTD, f_max/2, f_max/2 ); +BC = [2 2 2 2 2 2]; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +resolution = c0/(f_max*sqrt(substrate_epr))/unit /30; % resolution of lambda/50 +edge_res = 40; +mesh.x = SmoothMeshLines( [0 CPW_length/2 CPW_length/2+x_spacing], resolution, 1.5 ,0 ); +mesh.x = unique(sort([-mesh.x mesh.x])); +mesh.y = SmoothMeshLines( [CPW_width/2+[-edge_res/3 +edge_res/3*2] CPW_gap+CPW_width/2+[-edge_res/3*2 +edge_res/3]], edge_res , 1.5 ,0); +mesh.y = SmoothMeshLines( [0 mesh.y], edge_res*2, 1.3 ,0); +mesh.y = SmoothMeshLines( [0 mesh.y substrate_width/2 substrate_width/2+air_spacing], resolution, 1.3 ,0); +mesh.y = unique(sort([-mesh.y mesh.y])); +mesh.z = SmoothMeshLines( [-air_spacing linspace(0,substrate_thickness,5) substrate_thickness+air_spacing], resolution ); + +mesh = AddPML(mesh, pml_add_cells); +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% substrate +CSX = AddMaterial( CSX, 'RO4350B' ); +CSX = SetMaterialProperty( CSX, 'RO4350B', 'Epsilon', substrate_epr ); +start = [-CPW_length/2, -substrate_width/2, 0]; +stop = [+CPW_length/2, +substrate_width/2, substrate_thickness]; +CSX = AddBox( CSX, 'RO4350B', 0, start, stop ); + +%% +CSX = AddMetal( CSX, 'CPW_PORT' ); + +%% CPW port, with the measurement plane at the end of each port +portstart = [ -CPW_length/2 , -CPW_width/2, substrate_thickness]; +portstop = [ -CPW_length/2+CPW_port_length, CPW_width/2, substrate_thickness]; +[CSX,port{1}] = AddCPWPort( CSX, 999, 1, 'CPW_PORT', portstart, portstop, CPW_gap, 'x', [0 1 0], 'ExcitePort', true, 'FeedShift', feed_shift_cells*resolution, 'MeasPlaneShift', CPW_port_length, 'Feed_R', feed_R); + +portstart = [ CPW_length/2 , -CPW_width/2, substrate_thickness]; +portstop = [ CPW_length/2-CPW_port_length, CPW_width/2, substrate_thickness]; +[CSX,port{2}] = AddCPWPort( CSX, 999, 2, 'CPW_PORT', portstart, portstop, CPW_gap, 'x', [0 1 0], 'MeasPlaneShift', CPW_port_length, 'Feed_R', feed_R); + +%% CPW +CSX = AddMetal( CSX, 'CPW'); +start = [ -CPW_length/2+CPW_port_length, -CPW_width/2, substrate_thickness]; +stop = [ +CPW_length/2-CPW_port_length, CPW_width/2, substrate_thickness]; +CSX = AddBox(CSX, 'CPW', 999, start, stop); + +%% CPW grounds +CSX = AddMetal( CSX, 'GND' ); +start = [-CPW_length/2, -CPW_width/2-CPW_gap, substrate_thickness]; +stop = [+CPW_length/2, -substrate_width/2 , substrate_thickness]; +CSX = AddBox(CSX, 'GND', 999, start, stop); + +start = [-CPW_length/2, +CPW_width/2+CPW_gap, substrate_thickness]; +stop = [+CPW_length/2, +substrate_width/2 , substrate_thickness]; +CSX = AddBox(CSX, 'GND', 999, start, stop); + +%% write/show/run the openEMS compatible xml-file +Sim_Path = 'tmp'; +Sim_CSX = 'CPW.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +RunOpenEMS( Sim_Path, Sim_CSX ); + +%% post-processing +close all +f = linspace( 1e6, f_max, 1601 ); +port = calcPort( port, Sim_Path, f, 'RefImpedance', 50); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; + +plot(f/1e9,20*log10(abs(s11)),'k-','LineWidth',2); +hold on; +grid on; +plot(f/1e9,20*log10(abs(s21)),'r--','LineWidth',2); +legend('S_{11}','S_{21}'); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (GHz) \rightarrow','FontSize',12); + + diff --git a/openEMS/matlab/examples/transmission_lines/Finite_Stripline.m b/openEMS/matlab/examples/transmission_lines/Finite_Stripline.m new file mode 100644 index 0000000..da2b4a3 --- /dev/null +++ b/openEMS/matlab/examples/transmission_lines/Finite_Stripline.m @@ -0,0 +1,91 @@ +% example demonstrating the use of a stripline terminated by a resistance +% (c) 2013 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants; +unit = 1e-6; % specify everything in um +SL_length = 50000; +SL_width = 520; +SL_height = 500; +substrate_thickness = SL_height; +substrate_epr = 3.66; +f_max = 7e9; + +Air_Spacer = 20000; + +%% setup FDTD parameters & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD(); +FDTD = SetGaussExcite( FDTD, f_max/2, f_max/2 ); +BC = {'MUR' 'MUR' 'MUR' 'MUR' 'MUR' 'MUR'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +resolution = c0/(f_max*sqrt(substrate_epr))/unit /50; % resolution of lambda/50 +mesh.x = SmoothMeshLines( [-SL_length/2 0 SL_length/2], resolution, 1.5 ,0 ); +mesh.y = SmoothMeshLines( [0 SL_width/2+[-resolution/3 +resolution/3*2]/4], resolution/4 , 1.5 ,0); +mesh.y = SmoothMeshLines( [-10*SL_width -mesh.y mesh.y 10*SL_width], resolution, 1.3 ,0); +mesh.z = linspace(0,substrate_thickness,5); +mesh.z = sort(unique([mesh.z -mesh.z])); + +%% substrate +CSX = AddMaterial( CSX, 'RO4350B' ); +CSX = SetMaterialProperty( CSX, 'RO4350B', 'Epsilon', substrate_epr ); +start = [mesh.x(1), mesh.y(1), mesh.z(1)]; +stop = [mesh.x(end), mesh.y(end), mesh.z(end)]; +CSX = AddBox( CSX, 'RO4350B', 0, start, stop ); + +%% add air spacer +mesh.x = [mesh.x mesh.x(1)-Air_Spacer mesh.x(end)+Air_Spacer]; +mesh.y = [mesh.y mesh.y(1)-Air_Spacer mesh.y(end)+Air_Spacer]; +mesh.z = [mesh.z mesh.z(1)-Air_Spacer mesh.z(end)+Air_Spacer]; +mesh = SmoothMesh(mesh, c0/f_max/unit/20); +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% SL port +CSX = AddMetal( CSX, 'PEC' ); +portstart = [ -SL_length/2, -SL_width/2, 0]; +portstop = [ 0, SL_width/2, 0]; +[CSX,port{1}] = AddStripLinePort( CSX, 999, 1, 'PEC', portstart, portstop, SL_height, 'x', [0 0 -1], 'ExcitePort', true, 'Feed_R', 50, 'MeasPlaneShift', SL_length/3); + +portstart = [+SL_length/2, -SL_width/2, 0]; +portstop = [0 , SL_width/2, 0]; +[CSX,port{2}] = AddStripLinePort( CSX, 999, 2, 'PEC', portstart, portstop, SL_height, 'x', [0 0 -1], 'MeasPlaneShift', SL_length/3, 'Feed_R', 50); + +% bottom PEC plane +CSX = AddBox(CSX, 'PEC', 999, [-SL_length/2 -10*SL_width -SL_height],[+SL_length/2 +10*SL_width -SL_height]); +% top PEC plane +CSX = AddBox(CSX, 'PEC', 999, [-SL_length/2 -10*SL_width SL_height],[+SL_length/2 +10*SL_width SL_height]); + +%% write/show/run the openEMS compatible xml-file +Sim_Path = ['tmp_' mfilename]; +Sim_CSX = 'stripline.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +RunOpenEMS( Sim_Path, Sim_CSX ); + +%% post-processing +close all +f = linspace( 1e6, f_max, 1601 ); +port = calcPort( port, Sim_Path, f, 'RefImpedance', 50); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; + +plot(f/1e9,20*log10(abs(s11)),'k-','LineWidth',2); +hold on; +grid on; +plot(f/1e9,20*log10(abs(s21)),'r--','LineWidth',2); +legend('S_{11}','S_{21}'); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (GHz) \rightarrow','FontSize',12); +ylim([-50 2]); + diff --git a/openEMS/matlab/examples/transmission_lines/MSL.m b/openEMS/matlab/examples/transmission_lines/MSL.m new file mode 100644 index 0000000..b6ec0b3 --- /dev/null +++ b/openEMS/matlab/examples/transmission_lines/MSL.m @@ -0,0 +1,185 @@ +% +% EXAMPLE / microstrip / MSL +% +% Microstrip line on air "substrate" in z-direction. +% +% This example demonstrates: +% - simple microstrip geometry +% - characteristic impedance +% - material grading function +% - geometric priority concept +% +% +% Tested with +% - Matlab 2009b +% - Octave 3.3.52 +% - openEMS v0.0.14 +% +% (C) 2010 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation +physical_constants; +unit = 1e-3; % all length in mm + +% geometry +abs_length = 100; % absorber length +length = 600; +width = 400; +height = 200; +MSL_width = 50; +MSL_height = 10; + +%% prepare simulation folder +Sim_Path = 'tmp'; +Sim_CSX = 'msl.xml'; +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +%% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +max_timesteps = 2000; +min_decrement = 1e-5; % equivalent to -50 dB +f0 = 2e9; % center frequency +fc = 1e9; % 10 dB corner frequency (in this case 1e9 Hz - 3e9 Hz) +FDTD = InitFDTD( max_timesteps, min_decrement ); +FDTD = SetGaussExcite( FDTD, f0, fc ); +BC = {'PMC' 'PMC' 'PEC' 'PMC' 'PEC' 'PEC'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh +% very simple mesh +CSX = InitCSX(); +resolution = c0/(f0+fc)/unit /15; % resolution of lambda/15 +mesh.x = SmoothMeshLines( [-width/2, width/2, -MSL_width/2, MSL_width/2], resolution ); % create smooth lines from fixed lines +mesh.y = SmoothMeshLines( [linspace(0,MSL_height,5) MSL_height+1 height], resolution ); +mesh.z = SmoothMeshLines( [0 length], resolution ); +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% create MSL +% attention! the skin effect is not simulated, because the MSL is +% discretized with only one cell! +CSX = AddMaterial( CSX, 'copper' ); +CSX = SetMaterialProperty( CSX, 'copper', 'Kappa', 56e6 ); +start = [-MSL_width/2, MSL_height, 0]; +stop = [ MSL_width/2, MSL_height+1, length]; +priority = 100; % the geometric priority is set to 100 +CSX = AddBox( CSX, 'copper', priority, start, stop ); + +%% add excitation below the strip +start = [-MSL_width/2, 0 , mesh.z(1)]; +stop = [ MSL_width/2, MSL_height, mesh.z(1)]; +CSX = AddExcitation( CSX, 'excite', 0, [0 -1 0] ); +CSX = AddBox( CSX, 'excite', 0, start, stop ); + +%% fake pml +% this "pml" is a normal material with graded losses +% electric and magnetic losses are related to give low reflection +% for normally incident TEM waves +finalKappa = 1/abs_length^2; +finalSigma = finalKappa*MUE0/EPS0; +CSX = AddMaterial( CSX, 'fakepml' ); +CSX = SetMaterialProperty( CSX, 'fakepml', 'Kappa', finalKappa ); +CSX = SetMaterialProperty( CSX, 'fakepml', 'Sigma', finalSigma ); +CSX = SetMaterialWeight( CSX, 'fakepml', 'Kappa', ['pow(z-' num2str(length-abs_length) ',2)'] ); +CSX = SetMaterialWeight( CSX, 'fakepml', 'Sigma', ['pow(z-' num2str(length-abs_length) ',2)'] ); +start = [mesh.x(1) mesh.y(1) length-abs_length]; +stop = [mesh.x(end) mesh.y(end) length]; +% the geometric priority is set to 0, which is lower than the priority +% of the MSL, thus the MSL (copper) has precendence +priority = 0; +CSX = AddBox( CSX, 'fakepml', priority, start, stop ); + +%% define dump boxes +start = [mesh.x(1), MSL_height/2, mesh.z(1)]; +stop = [mesh.x(end), MSL_height/2, mesh.z(end)]; +CSX = AddDump( CSX, 'Et_', 'DumpMode', 2 ); % cell interpolated +CSX = AddBox( CSX, 'Et_', 0, start, stop ); +CSX = AddDump( CSX, 'Ht_', 'DumpType', 1, 'DumpMode', 2 ); % cell interpolated +CSX = AddBox( CSX, 'Ht_', 0, start, stop ); + +%% define voltage calc box +% voltage calc boxes will automatically snap to the next mesh-line +CSX = AddProbe( CSX, 'ut1', 0 ); +zidx = interp1( mesh.z, 1:numel(mesh.z), length/2, 'nearest' ); +start = [0 MSL_height mesh.z(zidx)]; +stop = [0 0 mesh.z(zidx)]; +CSX = AddBox( CSX, 'ut1', 0, start, stop ); +% add a second voltage probe to compensate space offset between voltage and +% current +CSX = AddProbe( CSX, 'ut2', 0 ); +start = [0 MSL_height mesh.z(zidx+1)]; +stop = [0 0 mesh.z(zidx+1)]; +CSX = AddBox( CSX, 'ut2', 0, start, stop ); + +%% define current calc box +% current calc boxes will automatically snap to the next dual mesh-line +CSX = AddProbe( CSX, 'it1', 1 ); +xidx1 = interp1( mesh.x, 1:numel(mesh.x), -MSL_width/2, 'nearest' ); +xidx2 = interp1( mesh.x, 1:numel(mesh.x), MSL_width/2, 'nearest' ); +xdelta = diff(mesh.x); +yidx1 = interp1( mesh.y, 1:numel(mesh.y), MSL_height, 'nearest' ); +yidx2 = interp1( mesh.y, 1:numel(mesh.y), MSL_height+1, 'nearest' ); +ydelta = diff(mesh.y); +zdelta = diff(mesh.z); +start = [mesh.x(xidx1)-xdelta(xidx1-1)/2, mesh.y(yidx1)-ydelta(yidx1-1)/2, mesh.z(zidx)+zdelta(zidx)/2]; +stop = [mesh.x(xidx2)+xdelta(xidx2)/2, mesh.y(yidx2)+ydelta(yidx2)/2, mesh.z(zidx)+zdelta(zidx)/2]; +CSX = AddBox( CSX, 'it1', 0, start, stop ); + +%% write openEMS compatible xml-file +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); + +%% show the structure +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); + +%% run openEMS +openEMS_opts = ''; +openEMS_opts = [openEMS_opts ' --engine=fastest']; +% openEMS_opts = [openEMS_opts ' --debug-material']; +% openEMS_opts = [openEMS_opts ' --debug-boxes']; +RunOpenEMS( Sim_Path, Sim_CSX, openEMS_opts ); + +%% postprocess +freq = linspace( f0-fc, f0+fc, 501 ); +U = ReadUI( {'ut1','ut2','et'}, 'tmp/', freq ); % time domain/freq domain voltage +I = ReadUI( 'it1', 'tmp/', freq ); % time domain/freq domain current (half time step offset is corrected) + +% plot time domain voltage +figure +[ax,h1,h2] = plotyy( U.TD{1}.t/1e-9, U.TD{1}.val, U.TD{3}.t/1e-9, U.TD{3}.val ); +set( h1, 'Linewidth', 2 ); +set( h1, 'Color', [1 0 0] ); +set( h2, 'Linewidth', 2 ); +set( h2, 'Color', [0 0 0] ); +grid on +title( 'time domain voltage' ); +xlabel( 'time t / ns' ); +ylabel( ax(1), 'voltage ut1 / V' ); +ylabel( ax(2), 'voltage et / V' ); +% now make the y-axis symmetric to y=0 (align zeros of y1 and y2) +y1 = ylim(ax(1)); +y2 = ylim(ax(2)); +ylim( ax(1), [-max(abs(y1)) max(abs(y1))] ); +ylim( ax(2), [-max(abs(y2)) max(abs(y2))] ); + +% calculate characteristic impedance +% arithmetic mean of ut1 and ut2 -> voltage in the middle of ut1 and ut2 +U = (U.FD{1}.val + U.FD{2}.val) / 2; +Z = U ./ I.FD{1}.val; + +% plot characteristic impedance +figure +plot( freq/1e6, real(Z), 'k-', 'Linewidth', 2 ); +hold on +grid on +plot( freq/1e6, imag(Z), 'r--', 'Linewidth', 2 ); +title( 'characteristic impedance of MSL' ); +xlabel( 'frequency f / MHz' ); +ylabel( 'characteristic impedance Z / Ohm' ); +legend( 'real', 'imag' ); + +%% visualize electric and magnetic fields +% you will find vtk dump files in the simulation folder (tmp/) +% use paraview to visualize them diff --git a/openEMS/matlab/examples/transmission_lines/MSL_Losses.m b/openEMS/matlab/examples/transmission_lines/MSL_Losses.m new file mode 100644 index 0000000..95cad7b --- /dev/null +++ b/openEMS/matlab/examples/transmission_lines/MSL_Losses.m @@ -0,0 +1,102 @@ +% +% examples / microstrip / MSL_Losses +% +% This example demonstrates how to model sheet conductor losses +% +% Tested with +% - Matlab 2013a / Octave 3.8.1+ +% - openEMS v0.0.32 +% +% (C) 2012-2014 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants; +unit = 1e-6; % specify everything in um +MSL.length = 10000; +MSL.port_dist = 5000; +MSL.width = 225; +MSL.conductivity = 41e6; +MSL.thickness = 35e-6; + +substrate.thickness = 250; +substrate.epr = 9.8; + +f_start = 0e9; +f_stop = 25e9; + +lambda = c0/f_stop; + +%% setup FDTD parameters & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD('endCriteria',1e-4); +FDTD = SetGaussExcite(FDTD,0.5*(f_start+f_stop),0.5*(f_stop-f_start)); +BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PEC' 'PML_8'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +resolution = c0/(f_stop*sqrt(substrate.epr))/unit /20; +mesh.x = SmoothMeshLines( [-MSL.length*0.5-MSL.port_dist 0 MSL.length*0.5+MSL.port_dist], resolution, 1.3 ,0 ); +mesh.y = SmoothMeshLines2( [0 MSL.width/2], resolution/6 , 1.3); +mesh.y = SmoothMeshLines( [-0.5*lambda/unit -mesh.y mesh.y 0.5*lambda/unit], resolution, 1.4); +mesh.z = SmoothMeshLines( [linspace(0,substrate.thickness,10) 0.5*lambda/unit], resolution ); +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% substrate +CSX = AddMaterial( CSX, 'RO4350B' ); +CSX = SetMaterialProperty( CSX, 'RO4350B', 'Epsilon', substrate.epr ); +start = [mesh.x(1), mesh.y(1), 0]; +stop = [mesh.x(end), mesh.y(end), substrate.thickness]; +CSX = AddBox( CSX, 'RO4350B', 0, start, stop ); + +%% MSL ports and lossy line +CSX = AddConductingSheet( CSX, 'gold', MSL.conductivity, MSL.thickness ); +portstart = [ mesh.x(1), -MSL.width/2, substrate.thickness]; +portstop = [ mesh.x(1)+MSL.port_dist, MSL.width/2, 0]; +[CSX, port{1}] = AddMSLPort( CSX, 999, 1, 'gold', portstart, portstop, 0, [0 0 -1], 'ExcitePort', true, 'FeedShift', 10*resolution, 'MeasPlaneShift', MSL.port_dist); + +portstart = [mesh.x(end), -MSL.width/2, substrate.thickness]; +portstop = [mesh.x(end)-MSL.port_dist, MSL.width/2, 0]; +[CSX, port{2}] = AddMSLPort( CSX, 999, 2, 'gold', portstart, portstop, 0, [0 0 -1], 'MeasPlaneShift', MSL.port_dist ); + +start = [mesh.x(1)+MSL.port_dist, -MSL.width/2, substrate.thickness]; +stop = [mesh.x(end)-MSL.port_dist, MSL.width/2, substrate.thickness]; +CSX = AddBox(CSX,'gold',500,start,stop); + +%% write/show/run the openEMS compatible xml-file +Sim_Path = 'tmp'; +Sim_CSX = 'msl.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +RunOpenEMS( Sim_Path, Sim_CSX ,''); + +%% post-processing +close all +f = linspace( f_start, f_stop, 1601 ); +port = calcPort(port, Sim_Path, f, 'RefImpedance', 50); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; + +plot(f/1e9,-20*log10(abs(s21)),'r--','LineWidth',2); +grid on; +hold on; +ylabel('-|S_21| (dB)','Interpreter','None'); +xlabel('frequency (GHz)'); + +%% plot 35um thickness loss model curve +% values extracted from http://wcalc.sourceforge.net/cgi-bin/microstrip.cgi +model.f = [1 2 2.5 3 4 5 7.5 10 12.5 15 17.5 20 25 ]; % frequency in GHz +model.loss = [3.0 4.2 4.7 5.2 5.9 6.6 8.1 9.38 10.5 11.5 12.4 13.2 14.65]; % loss in db/m + +plot(model.f, model.loss * MSL.length * unit ,'k-','LineWidth',1); +legend('FDTD simulated attenuation','t=35um, loss model by E. Hammerstad & F. Bekkadal','Location','NorthWest'); + + diff --git a/openEMS/matlab/examples/transmission_lines/Stripline.m b/openEMS/matlab/examples/transmission_lines/Stripline.m new file mode 100644 index 0000000..71fd774 --- /dev/null +++ b/openEMS/matlab/examples/transmission_lines/Stripline.m @@ -0,0 +1,78 @@ +% example demonstrating the use of a stripline terminated by the pml +% (c) 2013 Thorsten Liebig + +close all +clear +clc + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants; +unit = 1e-6; % specify everything in um +SL_length = 50000; +SL_width = 520; +SL_height = 500; +substrate_thickness = SL_height; +substrate_epr = 3.66; +f_max = 7e9; + +%% setup FDTD parameters & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD(); +FDTD = SetGaussExcite( FDTD, f_max/2, f_max/2 ); +BC = {'PML_8' 'PML_8' 'PMC' 'PMC' 'PEC' 'PEC'}; +FDTD = SetBoundaryCond( FDTD, BC ); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +resolution = c0/(f_max*sqrt(substrate_epr))/unit /50; % resolution of lambda/50 +mesh.x = SmoothMeshLines( [-SL_length/2 0 SL_length/2], resolution, 1.5 ,0 ); +mesh.y = SmoothMeshLines( [0 SL_width/2+[-resolution/3 +resolution/3*2]/4], resolution/4 , 1.5 ,0); +mesh.y = SmoothMeshLines( [-10*SL_width -mesh.y mesh.y 10*SL_width], resolution, 1.3 ,0); +mesh.z = linspace(0,substrate_thickness,5); +mesh.z = sort(unique([mesh.z -mesh.z])); +CSX = DefineRectGrid( CSX, unit, mesh ); + +%% substrate +CSX = AddMaterial( CSX, 'RO4350B' ); +CSX = SetMaterialProperty( CSX, 'RO4350B', 'Epsilon', substrate_epr ); +start = [mesh.x(1), mesh.y(1), mesh.z(1)]; +stop = [mesh.x(end), mesh.y(end), mesh.z(end)]; +CSX = AddBox( CSX, 'RO4350B', 0, start, stop ); + +%% SL port +CSX = AddMetal( CSX, 'PEC' ); +portstart = [ mesh.x(1), -SL_width/2, 0]; +portstop = [ 0, SL_width/2, 0]; +[CSX,port{1}] = AddStripLinePort( CSX, 999, 1, 'PEC', portstart, portstop, SL_height, 'x', [0 0 -1], 'ExcitePort', true, 'FeedShift', 10*resolution, 'MeasPlaneShift', SL_length/3); + +portstart = [mesh.x(end), -SL_width/2, 0]; +portstop = [0 , SL_width/2, 0]; +[CSX,port{2}] = AddStripLinePort( CSX, 999, 2, 'PEC', portstart, portstop, SL_height, 'x', [0 0 -1], 'MeasPlaneShift', SL_length/3 ); + +%% write/show/run the openEMS compatible xml-file +Sim_Path = ['tmp_' mfilename]; +Sim_CSX = 'stripline.xml'; + +[status, message, messageid] = rmdir( Sim_Path, 's' ); % clear previous directory +[status, message, messageid] = mkdir( Sim_Path ); % create empty simulation folder + +WriteOpenEMS( [Sim_Path '/' Sim_CSX], FDTD, CSX ); +CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +RunOpenEMS( Sim_Path, Sim_CSX ); + +%% post-processing +close all +f = linspace( 1e6, f_max, 1601 ); +port = calcPort( port, Sim_Path, f, 'RefImpedance', 50); + +s11 = port{1}.uf.ref./ port{1}.uf.inc; +s21 = port{2}.uf.ref./ port{1}.uf.inc; + +plot(f/1e9,20*log10(abs(s11)),'k-','LineWidth',2); +hold on; +grid on; +plot(f/1e9,20*log10(abs(s21)),'r--','LineWidth',2); +legend('S_{11}','S_{21}'); +ylabel('S-Parameter (dB)','FontSize',12); +xlabel('frequency (GHz) \rightarrow','FontSize',12); +ylim([-50 2]); + diff --git a/openEMS/matlab/examples/transmission_lines/directional_coupler.m b/openEMS/matlab/examples/transmission_lines/directional_coupler.m new file mode 100644 index 0000000..8ba86f2 --- /dev/null +++ b/openEMS/matlab/examples/transmission_lines/directional_coupler.m @@ -0,0 +1,261 @@ +function directional_coupler +% +% EXAMPLE / microstrip / directional_coupler +% +% Stacked directional coupler in microstrip technology. +% +% This example demonstrates: +% - simple microstrip geometry +% - S-parameter calculation using the ypar-method +% - display of coupler parameters +% - display of S11 (smith chart) +% +% +% Tested with +% - Matlab 2010b +% - Octave 3.2.4 +% - openEMS v0.0.17 +% +% (C) 2010 Sebastian Held + +clear +close all +clc + +% sim settings +showStructure = 1; +runSimulation = 1; + +for n=1:4 + if n > 1, showStructure = 0; end + ports{n} = sim( n, showStructure, runSimulation ); +end +postprocess( ports ); + + + + +function ports = sim( simnr, showStructure, runSimulation ) +physical_constants + +% setup the simulation +drawingunit = 1e-6; % specify everything in um +Sim_Path = ['tmp' int2str(simnr)]; +Sim_CSX = 'tmp.xml'; +f_max = 100e6; +lambda = c0/f_max; + +% specify the coupler +pcb1.w = 147000; +pcb1.h = 54500; +pcb1.t = 1524; +pcb1.epr = 3; +msl1.w = 135000; +msl1.h = 2800; +pcb2.w = 107000; +pcb2.h = 14000; +pcb2.t = 1524; +pcb2.epr = 3; +msl2.w = 95000; +msl2.h = 4000; + + +CSX = InitCSX(); + +% create the mesh +mesh.x = [-pcb1.w/2 pcb1.w/2 -pcb2.w/2 pcb2.w/2 -msl1.w/2 msl1.w/2 -msl2.w/2 msl2.w/2]; +mesh.x = [mesh.x linspace(-msl2.w/2,-msl2.w/2+msl2.h, 5) linspace(msl2.w/2,msl2.w/2-msl2.h, 5)]; +mesh.y = [-pcb1.h/2 pcb1.h/2 -pcb2.h/2 pcb2.h/2 -msl1.h/2 msl1.h/2 -msl2.h/2 msl2.h/2]; +mesh.z = [linspace(0,pcb1.t,5) linspace(pcb1.t,pcb1.t+pcb2.t,5)]; +mesh.z = [mesh.z mesh.z(end)+10*(mesh.z(end)-mesh.z(1))]; % add space above pcb +res = lambda/sqrt(max([pcb1.epr,pcb2.epr])) / 20 / drawingunit; +mesh.x = SmoothMeshLines2(mesh.x,res); +mesh.y = SmoothMeshLines2(mesh.y,res); +mesh.z = SmoothMeshLines2(mesh.z,res); +mesh = AddPML( mesh, [8 8 8 8 8 8] ); % add space for PML +CSX = DefineRectGrid( CSX, drawingunit, mesh ); + +%% create the structure + +% microstrip +CSX = AddMetal( CSX, 'PEC' ); +start = [-msl1.w/2, -msl1.h/2, pcb1.t]; +stop = [ msl1.w/2, msl1.h/2, pcb1.t]; +priority = 100; % the geometric priority is set to 100 +CSX = AddBox( CSX, 'PEC', priority, start, stop ); + +% ground plane +CSX = AddMetal( CSX, 'PEC_ground' ); +start = [-pcb1.w/2, -pcb1.h/2, 0]; +stop = [ pcb1.w/2, pcb1.h/2, 0]; +CSX = AddBox( CSX, 'PEC_ground', priority, start, stop ); + +% substrate 1 +start = [-pcb1.w/2, -pcb1.h/2, 0]; +stop = [ pcb1.w/2, pcb1.h/2, pcb1.t]; +priority = 10; +CSX = AddMaterial( CSX, 'substrate1' ); +CSX = SetMaterialProperty( CSX, 'substrate1', 'Epsilon', pcb1.epr ); +CSX = AddBox( CSX, 'substrate1', priority, start, stop ); + +% substrate 2 +start = [-pcb2.w/2, -pcb2.h/2, pcb1.t]; +stop = [ pcb2.w/2, pcb2.h/2, pcb1.t+pcb2.t]; +priority = 10; +CSX = AddMaterial( CSX, 'substrate2' ); +CSX = SetMaterialProperty( CSX, 'substrate2', 'Epsilon', pcb2.epr ); +CSX = AddBox( CSX, 'substrate2', priority, start, stop ); + +% stripline +start = [-msl2.w/2, -msl2.h/2, pcb1.t+pcb2.t]; +stop = [ msl2.w/2, msl2.h/2, pcb1.t+pcb2.t]; +priority = 100; +CSX = AddBox( CSX, 'PEC', priority, start, stop ); + +% connections +start = [-msl2.w/2, -msl2.h/2, pcb1.t+pcb2.t]; +stop = [-msl2.w/2+msl2.h, -pcb2.h/2, pcb1.t+pcb2.t]; +priority = 100; +CSX = AddBox( CSX, 'PEC', priority, start, stop ); +start = [ msl2.w/2, -msl2.h/2, pcb1.t+pcb2.t]; +stop = [ msl2.w/2-msl2.h, -pcb2.h/2, pcb1.t+pcb2.t]; +priority = 100; +CSX = AddBox( CSX, 'PEC', priority, start, stop ); + +%% ports +% this project needs 4 simulations +for n=1:4 + portexcite{n} = []; +end +portexcite{simnr} = 'excite'; + +% port 1: input port +start = [-msl1.w/2, 0, pcb1.t]; +stop = [-msl1.w/2, 0, 0]; +[CSX ports{1}] = AddCurvePort( CSX, 999, 1, 50, start, stop, portexcite{1} ); +% port 2: output port +start = [msl1.w/2, 0, pcb1.t]; +stop = [msl1.w/2, 0, 0]; +[CSX ports{2}] = AddCurvePort( CSX, 999, 2, 50, start, stop, portexcite{2} ); +% port 3: coupled port +start = [-msl2.w/2+msl2.h/2, -pcb2.h/2, pcb1.t+pcb2.t]; +stop = [-msl2.w/2+msl2.h/2, -pcb2.h/2, 0]; +[CSX ports{3}] = AddCurvePort( CSX, 999, 3, 50, start, stop, portexcite{3} ); +% port 4: isolated port +start = [msl2.w/2-msl2.h/2, -pcb2.h/2, pcb1.t+pcb2.t]; +stop = [msl2.w/2-msl2.h/2, -pcb2.h/2, 0]; +[CSX ports{4}] = AddCurvePort( CSX, 999, 4, 50, start, stop, portexcite{4} ); + +%% setup FDTD parameters & excitation function +max_timesteps = 50000; +min_decrement = 1e-6; +FDTD = InitFDTD( max_timesteps, min_decrement ); +FDTD = SetGaussExcite( FDTD, 0, f_max ); +BC = {'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8' 'PML_8'}; +BC = {'MUR' 'MUR' 'MUR' 'MUR' 'MUR' 'MUR'}; % faster +FDTD = SetBoundaryCond( FDTD, BC ); + +%% Write openEMS compatible xml-file +if runSimulation + [dummy,dummy,dummy] = rmdir(Sim_Path,'s'); +end +[dummy,dummy,dummy] = mkdir(Sim_Path); +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + +if showStructure + CSXGeomPlot( [Sim_Path '/' Sim_CSX] ); +end + +%% run openEMS +openEMS_opts = ''; +openEMS_opts = [openEMS_opts ' --engine=fastest']; +% openEMS_opts = [openEMS_opts ' --debug-material']; +% openEMS_opts = [openEMS_opts ' --debug-boxes']; +if runSimulation + RunOpenEMS( Sim_Path, Sim_CSX, openEMS_opts ); +end + + + + +function postprocess( ports ) +f = linspace( 0, 100e6, 201 ); +Y = calc_ypar( f, ports{1}, 'tmp' ); +R = 50; +S = y2s(Y,R); + +% insertion loss +IL_dB = -20 * log10(abs(squeeze(S(2,1,:)))); + +% coupling factor +CF_dB = -20 * log10(abs(squeeze(S(3,1,:)))); + +% isolation +I_dB = -20 * log10(abs(squeeze(S(4,1,:)))); + +% directivity +D_dB = -20 * log10(abs(squeeze(S(4,1,:) ./ S(3,1,:)))); + +figure +plot( f, [IL_dB CF_dB I_dB D_dB] ); +legend( {'insertion loss','coupling factor','isolation','directivity'} ); +title( ['performance of the coupler for a termination resistance of R=' num2str(R)] ); +grid on + +smithchart +S11 = squeeze(S(1,1,:)); +plot( real(S11), imag(S11) ); +legend( 'S_{11}' ); +title( ['performance of the coupler for a termination resistance of R=' num2str(R)] ); +axis( [-1 1 -1 1] ); + + + +function smithchart +% smith chart +figure +if exist( 'smith', 'file' ) + % smith chart + % www.ece.rutgers.edu/~orfanidi/ewa + % or cmt toolbox from git.ate.uni-duisburg.de + smith +else + % poor man smith chart + color = [.6 .6 .6]; + h = plot( sin(0:0.01:2*pi), cos(0:0.01:2*pi), 'Color', color ); + hg = hggroup; + set( h,'Parent',hg ); + hold on + plot( hg, 0.25+0.75*sin(0:0.01:2*pi), 0.75*cos(0:0.01:2*pi), 'Color', color ); + plot( hg, 0.5+0.5*sin(0:0.01:2*pi), 0.5*cos(0:0.01:2*pi), 'Color', color ); + plot( hg, 0.75+0.25*sin(0:0.01:2*pi), 0.25*cos(0:0.01:2*pi), 'Color', color ); + plot( hg, [-1 1], [0 0], 'Color', color ); + axis equal + axis off +end + + +function s = y2s(y, ZL) +% S = y2s(Y, ZL) +% +% Admittance to Scattering transformation +% for square matrices at multiple frequencies +% +% ZL defaults to 50 Ohm + +if nargin < 2 + ZL = 50; +end + +if size(size(y),2) > 2 + nF = size(y,3); +else + nF = 1; +end + +I = diag(ones(1, size(y,2)))/ZL; + +for i=1:nF + %s(:,:,i) = inv(I+y(:,:,i)) * (I-y(:,:,i)); + s(:,:,i) = (I+y(:,:,i)) \ (I-y(:,:,i)); +end diff --git a/openEMS/matlab/examples/waveguide/Circ_Waveguide.m b/openEMS/matlab/examples/waveguide/Circ_Waveguide.m new file mode 100644 index 0000000..9ee860e --- /dev/null +++ b/openEMS/matlab/examples/waveguide/Circ_Waveguide.m @@ -0,0 +1,207 @@ +% +% EXAMPLE / waveguide / circular waveguide +% +% This example demonstrates how to: +% - setup a circular waveguide +% - use analytic functions for waveguide excitations and voltage/current +% calculations +% +% +% Tested with +% - Matlab 2009b +% - openEMS v0.0.17 +% +% (C) 2010 Thorsten Liebig + +close all +clear +clc + +%% switches & options... +postprocessing_only = 0; +use_pml = 0; % use pml boundaries instead of mur +openEMS_opts = ''; +% openEMS_opts = [openEMS_opts ' --disable-dumps']; + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +numTS = 1e5; %number of timesteps +length = 1000; %length of the waveguide +unit = 1e-3; %drawing unit used +rad = 300; %radius of the circular waveguide +mesh_res = [10 10 15]; %desired mesh resolution + +%excitation +f0 = 350e6; %center frequency +f0_BW = 25e6; %bandwidth: 10dB cut-off frequency + +physical_constants + +%% TE11 mode definitions (Pozar 3rd edition) +p11 = 1.841; +kc = p11 / rad /unit; +k = 2*pi*f0/C0; +fc = C0*kc/2/pi; +beta = sqrt(k^2 - kc^2); +n_eff = (beta/k); + +kc = kc*unit; %functions must be defined in drawing units +func_Er = [ num2str(-1/kc^2) '/rho*cos(a)*j1(' num2str(kc) '*rho)']; +func_Ea = [ num2str(1/kc) '*sin(a)*0.5*(j0(' num2str(kc) '*rho)-jn(2,' num2str(kc) '*rho))']; +func_Ex = ['(' func_Er '*cos(a) - ' func_Ea '*sin(a) )*(rho<' num2str(rad) ')']; +func_Ey = ['(' func_Er '*sin(a) + ' func_Ea '*cos(a) )*(rho<' num2str(rad) ')']; + +func_Ha = [ num2str(-1/kc^2,'%14.13f') '/rho*cos(a)*j1(' num2str(kc,'%14.13f') '*rho)']; +func_Hr = [ '-1*' num2str(1/kc,'%14.13f') '*sin(a)*0.5*(j0(' num2str(kc,'%14.13f') '*rho)-jn(2,' num2str(kc,'%14.13f') '*rho))']; +func_Hx = ['(' func_Hr '*cos(a) - ' func_Ha '*sin(a) )*(rho<' num2str(rad) ')']; +func_Hy = ['(' func_Hr '*sin(a) + ' func_Ha '*cos(a) )*(rho<' num2str(rad) ')']; + +%% define files and path %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Sim_Path = 'tmp'; +Sim_CSX = 'Circ_WG.xml'; + +if (postprocessing_only==0) + [status, message, messageid] = rmdir(Sim_Path,'s'); + [status, message, messageid] = mkdir(Sim_Path); +end + +%% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD(numTS,1e-6,'OverSampling',5); +FDTD = SetGaussExcite(FDTD,f0,f0_BW); +BC = {'PEC','PEC','PEC','PEC','PEC','MUR'}; +if (use_pml>0) + BC = {'PEC','PEC','PEC','PEC','PEC','PML_8'}; +end +FDTD = SetBoundaryCond(FDTD,BC,'MUR_PhaseVelocity',C0 / n_eff); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +mesh.x = -mesh_res(1)/2-rad:mesh_res(1):rad+mesh_res(1)/2; +mesh.y = -mesh_res(2)/2-rad:mesh_res(2):rad+mesh_res(2)/2; +mesh.z = 0 : mesh_res(3) : length; +CSX = DefineRectGrid(CSX, 1e-3,mesh); + +start = [0,0,0]; +stop = [0,0,length]; + +%%% fill everything with copper, priority 0 +CSX = AddMetal(CSX,'copper'); +% CSX = SetMaterialProperty(CSX,'copper','Kappa',56e6); +CSX = AddBox(CSX,'copper',0,[mesh.x(1) mesh.y(1) mesh.z(1)],[mesh.x(end) mesh.y(end) mesh.z(end)]); + +%%% cut out an air cylinder as circular waveguide... priority 5 +CSX = AddMaterial(CSX,'air'); +CSX = SetMaterialProperty(CSX,'air','Epsilon',1); +CSX = AddCylinder(CSX,'air', 5 ,start,stop,rad); + +CSX = AddExcitation(CSX,'excite',0,[1 1 0]); +weight{1} = func_Ex; +weight{2} = func_Ey; +weight{3} = 0; +CSX = SetExcitationWeight(CSX, 'excite', weight ); +CSX = AddCylinder(CSX,'excite', 5 ,[0 0 -0.1],[0 0 0.1],rad); + +%% define dump boxes... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddDump(CSX,'Et_','SubSampling','2,2,2','FileType',0,'DumpMode',2); +start = [mesh.x(1) , 0 , mesh.z(1)]; +stop = [mesh.x(end), 0 , mesh.z(end)]; +CSX = AddBox(CSX,'Et_',0 , start,stop); + +CSX = AddDump(CSX,'Ht_','SubSampling','2,2,2','DumpType',1,'FileType',0,'DumpMode',2); +CSX = AddBox(CSX,'Ht_',0,start,stop); + +%% define voltage calc boxes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%voltage calc +start = [mesh.x(1) mesh.y(1) mesh.z(10)]; +stop = [mesh.x(end) mesh.y(end) mesh.z(10)]; +CSX = AddProbe(CSX, 'ut1', 10, 1, [], 'ModeFunction',{func_Ex,func_Ey,0}); +CSX = AddBox(CSX, 'ut1', 0 ,start,stop); +CSX = AddProbe(CSX,'it1', 11, 1, [], 'ModeFunction',{func_Hx,func_Hy,0}); +CSX = AddBox(CSX,'it1', 0 ,start,stop); + +start = [mesh.x(1) mesh.y(1) mesh.z(end-10)]; +stop = [mesh.x(end) mesh.y(end) mesh.z(end-10)]; +CSX = AddProbe(CSX, 'ut2', 10, 1, [], 'ModeFunction',{func_Ex,func_Ey,0}); +CSX = AddBox(CSX, 'ut2', 0 ,start,stop); +CSX = AddProbe(CSX,'it2', 11, 1, [], 'ModeFunction',{func_Hx,func_Hy,0}); +CSX = AddBox(CSX,'it2', 0 ,start,stop); + +port_dist = mesh.z(end-10) - mesh.z(10); + +%% Write openEMS +if (postprocessing_only==0) + WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + + RunOpenEMS(Sim_Path, Sim_CSX, openEMS_opts); +end + +%% do the plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +freq = linspace(f0-f0_BW,f0+f0_BW,201); +U = ReadUI({'ut1','ut2'},[Sim_Path '/'],freq); +I = ReadUI({'it1','it2'},[Sim_Path '/'],freq); +Exc = ReadUI('et',Sim_Path,freq); + +k = 2*pi*freq/C0; +kc = p11 / rad /unit; +beta = sqrt(k.^2 - kc^2); + +ZL_a = Z0*k./beta ; + +uf1 = U.FD{1}.val./Exc.FD{1}.val; +uf2 = U.FD{2}.val./Exc.FD{1}.val; +if1 = I.FD{1}.val./Exc.FD{1}.val; +if2 = I.FD{2}.val./Exc.FD{1}.val; + +uf1_inc = 0.5 * ( uf1 + if1 .* ZL_a ); +if1_inc = 0.5 * ( if1 + uf1 ./ ZL_a ); +uf2_inc = 0.5 * ( uf2 + if2 .* ZL_a ); +if2_inc = 0.5 * ( if2 + uf2 ./ ZL_a ); + +uf1_ref = uf1 - uf1_inc; +if1_ref = if1 - if1_inc; +uf2_ref = uf2 - uf2_inc; +if2_ref = if2 - if2_inc; + +% plot s-parameter +figure +s11 = uf1_ref./uf1_inc; +s21 = uf2_inc./uf1_inc; +plot(freq,20*log10(abs(s11)),'Linewidth',2); +xlim([freq(1) freq(end)]); +xlabel('frequency (Hz)') +ylabel('s-para (dB)'); +% ylim([-40 5]); +grid on; +hold on; +plot(freq,20*log10(abs(s21)),'r','Linewidth',2); +legend('s11','s21','Location','SouthEast'); + +% plot line-impedance comparison +figure() +ZL = uf1./if1; +plot(freq,real(ZL),'Linewidth',2); +xlim([freq(1) freq(end)]); +xlabel('frequency (Hz)') +ylabel('line-impedance (\Omega)'); +grid on; +hold on; +plot(freq,imag(ZL),'r--','Linewidth',2); +plot(freq,ZL_a,'g-.','Linewidth',2); +legend('\Re\{ZL\}','\Im\{ZL\}','ZL-analytic','Location','Best'); + +% beta compare +figure() +da = angle(uf1_inc)-angle(uf2_inc); +da = mod(da,2*pi); +beta_12 = (da)/port_dist/unit; +plot(freq,beta_12,'Linewidth',2); +xlim([freq(1) freq(end)]); +xlabel('frequency (Hz)'); +ylabel('\beta (m^{-1})'); +grid on; +hold on; +plot(freq,beta,'g--','Linewidth',2); +legend('\beta-FDTD','\beta-analytic','Location','Best'); + +%% visualize electric & magnetic fields +disp('you will find vtk dump files in the simulation folder (tmp/)') +disp('use paraview to visulaize them'); diff --git a/openEMS/matlab/examples/waveguide/Circ_Waveguide_CylinderCoords.m b/openEMS/matlab/examples/waveguide/Circ_Waveguide_CylinderCoords.m new file mode 100644 index 0000000..a767c0a --- /dev/null +++ b/openEMS/matlab/examples/waveguide/Circ_Waveguide_CylinderCoords.m @@ -0,0 +1,204 @@ +% +% EXAMPLE / waveguide / circular waveguide cylindrical coordinates +% +% This example demonstrates how to: +% - use cylindrical coordinates +% - setup a circular waveguide defined by the boundary conditions of the +% cylindrical coordinate system +% - use analytic functions for waveguide excitations and voltage/current +% calculations +% +% +% Tested with +% - Matlab 2009b +% - openEMS v0.0.17 +% +% (C) 2010 Thorsten Liebig + +close all +clear +clc + +%% switches & options... +postprocessing_only = 0; +use_pml = 0; % use pml boundaries instead of mur +use_MultiGrid = 1; % disable multi-grid for this example +openEMS_opts = ''; +% openEMS_opts = [openEMS_opts ' --disable-dumps']; + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +numTS = 1e5; %number of timesteps +length = 1000; %length of the waveguide +unit = 1e-3; %drawing unit used +rad = 300; %radius of the circular waveguide +mesh_res = [10 nan 15]; %desired mesh resolution +N_alpha = 50; %mesh lines in azimuth direction + +MultiGrid_Level = [50]; % define multigrid radii (if enabled) + +%excitation +f0 = 350e6; %center frequency +f0_BW = 25e6; %bandwidth: 10dB cut-off frequency + +physical_constants + +%% TE11 mode definitions (Pozar 3rd edition) +p11 = 1.841; +kc = p11 / rad /unit; +k = 2*pi*f0/C0; +fc = C0*kc/2/pi; +beta = sqrt(k^2 - kc^2); +n_eff = (beta/k); + +kc = kc*unit; %functions must be defined in drawing units +func_Er = [ num2str(-1/kc^2,15) '/rho*cos(a)*j1(' num2str(kc,15) '*rho)']; +func_Ea = [ num2str(1/kc,15) '*sin(a)*0.5*(j0(' num2str(kc,15) '*rho)-jn(2,' num2str(kc,15) '*rho))']; +func_Ha = [ num2str(-1/kc^2,'%14.13f') '/rho*cos(a)*j1(' num2str(kc,'%14.13f') '*rho)']; +func_Hr = [ '-1*' num2str(1/kc,'%14.13f') '*sin(a)*0.5*(j0(' num2str(kc,'%14.13f') '*rho)-jn(2,' num2str(kc,'%14.13f') '*rho))']; + +%% define files and path %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Sim_Path = 'tmp'; +Sim_CSX = 'Circ_WG_CC.xml'; + +if (postprocessing_only==0) + [status, message, messageid] = rmdir(Sim_Path,'s'); + [status, message, messageid] = mkdir(Sim_Path); +end + +%% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if (use_MultiGrid==0) + FDTD = InitCylindricalFDTD(numTS,1e-5,'OverSampling',10); +else + mg_str = num2str(MultiGrid_Level,'%d,'); %create comma-separated string + N_alpha = round(N_alpha * 2^numel(MultiGrid_Level)); + FDTD = InitCylindricalFDTD(numTS,1e-5,'OverSampling',10,'MultiGrid',mg_str(1:end-1)); +end +FDTD = SetGaussExcite(FDTD,f0,f0_BW); +BC = {'PEC','PEC','PEC','PEC','PEC','MUR'}; +if (use_pml>0) + BC = {'PEC','PEC','PEC','PEC','PEC','PML_8'}; +end +FDTD = SetBoundaryCond(FDTD,BC,'MUR_PhaseVelocity',C0 / n_eff); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX('CoordSystem',1); +mesh.x = 0:mesh_res(1):rad; +%define an odd number of lines in alpha-direction +mesh.y = linspace(-pi,pi,N_alpha+mod(N_alpha+1,2))+pi/2; +mesh.z = 0 : mesh_res(3) : length; +CSX = DefineRectGrid(CSX, unit,mesh); + +%% apply the excitation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddExcitation(CSX,'excite',0,[1 1 0]); +weight{1} = func_Er; +weight{2} = func_Ea; +weight{3} = 0; +CSX = SetExcitationWeight(CSX, 'excite', weight ); +start = [mesh.x(1) mesh.y(1) mesh.z(1)]; +stop = [mesh.x(end) mesh.y(end) mesh.z(1)]; +CSX = AddBox(CSX,'excite', 5 ,start,stop); + +%% define dump boxes... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddDump(CSX,'Et_','FileType',0,'DumpMode',2,'SubSampling','2,2,2'); +start = [mesh.x(1) , 0 , mesh.z(1)]; +stop = [mesh.x(end), 0 , mesh.z(end)]; +CSX = AddBox(CSX,'Et_',0 , start,stop); + +CSX = AddDump(CSX,'Ht','FileType',0,'DumpType',1,'DumpMode',2,'SubSampling','2,2,2'); +CSX = AddBox(CSX,'Ht',0 , start,stop); + +%% define voltage calc boxes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +start = [mesh.x(1) mesh.y(1) mesh.z(10)]; +stop = [mesh.x(end) mesh.y(end) mesh.z(10)]; +CSX = AddProbe(CSX, 'ut1', 10, 1, [], 'ModeFunction',{func_Er,func_Ea,0}); +CSX = AddBox(CSX, 'ut1', 0 ,start,stop); +CSX = AddProbe(CSX,'it1', 11, 1, [], 'ModeFunction',{func_Hr,func_Ha,0}); +CSX = AddBox(CSX,'it1', 0 ,start,stop); + +start = [mesh.x(1) mesh.y(1) mesh.z(end-10)]; +stop = [mesh.x(end) mesh.y(end) mesh.z(end-10)]; +CSX = AddProbe(CSX, 'ut2', 10, 1, [], 'ModeFunction',{func_Er,func_Ea,0}); +CSX = AddBox(CSX, 'ut2', 0 ,start,stop); +CSX = AddProbe(CSX,'it2', 11, 1, [], 'ModeFunction',{func_Hr,func_Ha,0}); +CSX = AddBox(CSX,'it2', 0 ,start,stop); + +port_dist = mesh.z(end-10) - mesh.z(10); + +%% Write openEMS +if (postprocessing_only==0) + WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + + RunOpenEMS(Sim_Path, Sim_CSX, openEMS_opts); +end + +%% do the plots %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +freq = linspace(f0-f0_BW,f0+f0_BW,201); +U = ReadUI({'ut1','ut2'},[Sim_Path '/'],freq); +I = ReadUI({'it1','it2'},[Sim_Path '/'],freq); +Exc = ReadUI('et',Sim_Path,freq); + +k = 2*pi*freq/C0; +kc = p11 / rad /unit; +beta = sqrt(k.^2 - kc^2); + +ZL_a = Z0*k./beta ; + +uf1 = U.FD{1}.val./Exc.FD{1}.val; +uf2 = U.FD{2}.val./Exc.FD{1}.val; +if1 = I.FD{1}.val./Exc.FD{1}.val; +if2 = I.FD{2}.val./Exc.FD{1}.val; + +uf1_inc = 0.5 * ( uf1 + if1 .* ZL_a ); +if1_inc = 0.5 * ( if1 + uf1 ./ ZL_a ); +uf2_inc = 0.5 * ( uf2 + if2 .* ZL_a ); +if2_inc = 0.5 * ( if2 + uf2 ./ ZL_a ); + +uf1_ref = uf1 - uf1_inc; +if1_ref = if1 - if1_inc; +uf2_ref = uf2 - uf2_inc; +if2_ref = if2 - if2_inc; + +% plot s-parameter +figure +s11 = uf1_ref./uf1_inc; +s21 = uf2_inc./uf1_inc; +plot(freq,20*log10(abs(s11)),'Linewidth',2); +xlim([freq(1) freq(end)]); +xlabel('frequency (Hz)') +ylabel('s-para (dB)'); +% ylim([-40 5]); +grid on; +hold on; +plot(freq,20*log10(abs(s21)),'r','Linewidth',2); +legend('s11','s21','Location','SouthEast'); + +% plot line-impedance comparison +figure() +ZL = uf1./if1; +plot(freq,real(ZL),'Linewidth',2); +xlim([freq(1) freq(end)]); +xlabel('frequency (Hz)') +ylabel('line-impedance (\Omega)'); +grid on; +hold on; +plot(freq,imag(ZL),'r--','Linewidth',2); +plot(freq,ZL_a,'g-.','Linewidth',2); +legend('\Re\{ZL\}','\Im\{ZL\}','ZL-analytic','Location','Best'); + +%% beta compare +figure() +da = angle(uf1_inc)-angle(uf2_inc); +da = mod(da,2*pi); +beta_12 = (da)/port_dist/unit; +plot(freq,beta_12,'Linewidth',2); +xlim([freq(1) freq(end)]); +xlabel('frequency (Hz)'); +ylabel('\beta (m^{-1})'); +grid on; +hold on; +plot(freq,beta,'g--','Linewidth',2); +legend('\beta-FDTD','\beta-analytic','Location','Best'); + +%% visualize electric & magnetic fields +disp('you will find vtk dump files in the simulation folder (tmp/)') +disp('use paraview to visulaize them'); diff --git a/openEMS/matlab/examples/waveguide/Coax.m b/openEMS/matlab/examples/waveguide/Coax.m new file mode 100644 index 0000000..3db4d6a --- /dev/null +++ b/openEMS/matlab/examples/waveguide/Coax.m @@ -0,0 +1,120 @@ +% +% EXAMPLE / waveguide / coaxial cable +% +% This example demonstrates how to: +% - setup a coaxial waveguide +% - use analytic functions for waveguide excitations and voltage/current +% calculations +% +% +% Tested with +% - Matlab 2009b +% - openEMS v0.0.17 +% +% (C) 2010 Thorsten Liebig + +close all +clear +clc + +%% switches & options... +postprocessing_only = 0; +use_pml = 0; % use pml boundaries instead of mur +openEMS_opts = ''; +% openEMS_opts = [openEMS_opts ' --disable-dumps']; + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +numTS = 5000; %number of timesteps +length = 1000; %length of the waveguide +unit = 1e-3; %drawing unit used +coax_rad_i = 100; %inner radius +coax_rad_ai = 230; %inner radius of outer cladding +coax_rad_aa = 240; %outer radius of outer cladding +mesh_res = [5 5 5]; %desired mesh resolution + +physical_constants; + +%excitation +f0 = 0.5e9; +epsR = 1; + +%% create sim path %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Sim_Path = 'tmp'; +Sim_CSX = 'coax.xml'; + +if (postprocessing_only==0) + [status, message, messageid] = rmdir(Sim_Path,'s'); + [status, message, messageid] = mkdir(Sim_Path); +end + +%% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitFDTD(numTS,1e-5); +FDTD = SetGaussExcite(FDTD,f0,f0); +BC = {'PEC','PEC','PEC','PEC','MUR','MUR'}; +if (use_pml>0) + BC = {'PEC','PEC','PEC','PEC','PML_8','PML_8'}; +end +FDTD = SetBoundaryCond(FDTD,BC); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX(); +mesh.x = -coax_rad_aa : mesh_res(1) : coax_rad_aa; +mesh.y = mesh.x; +mesh.z = SmoothMeshLines([0 length], mesh_res(3)); +CSX = DefineRectGrid(CSX, unit, mesh); + +%%% coax +CSX = AddMetal(CSX,'copper'); +start = [0,0,0]; +stop = [0,0,length/2]; +[CSX,port{1}] = AddCoaxialPort( CSX, 10, 1, 'copper', '', start, stop, 'z', coax_rad_i, coax_rad_ai, coax_rad_aa, 'ExciteAmp', 1,'FeedShift', 10*mesh_res(1) ); + +start = [0,0,length/2]; +stop = [0,0,length]; +[CSX,port{2}] = AddCoaxialPort( CSX, 10, 2, 'copper', '', start, stop, 'z', coax_rad_i, coax_rad_ai, coax_rad_aa ); + +%% define dump boxes... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddDump(CSX,'Et_','DumpMode',2); +start = [mesh.x(1) , 0 , mesh.z(1)]; +stop = [mesh.x(end) , 0 , mesh.z(end)]; +CSX = AddBox(CSX,'Et_',0 , start,stop); + +CSX = AddDump(CSX,'Ht_','DumpType',1,'DumpMode',2); +CSX = AddBox(CSX,'Ht_',0,start,stop); + +%% Write openEMS +if (postprocessing_only==0) + WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + CSXGeomPlot([Sim_Path '/' Sim_CSX]); + RunOpenEMS(Sim_Path, Sim_CSX, openEMS_opts); +end + +%% +freq = linspace(0,2*f0,201); +port = calcPort(port, Sim_Path, freq); + +%% plot s-parameter +figure +s11 = port{1}.uf.ref./port{1}.uf.inc; +s21 = port{2}.uf.inc./port{1}.uf.inc; +plot(freq,20*log10(abs(s11)),'Linewidth',2); +hold on +grid on +plot(freq,20*log10(abs(s21)),'r--','Linewidth',2); +xlim([freq(1) freq(end)]); +xlabel('frequency (Hz)') +ylabel('s-para (dB)'); + +%% plot line-impedance comparison +figure() +ZL_a = ones(size(freq))*Z0/2/pi/sqrt(epsR)*log(coax_rad_ai/coax_rad_i); %analytic line-impedance of a coax +ZL = port{2}.uf.tot./port{2}.if.tot; +plot(freq,real(port{1}.ZL),'Linewidth',2); +xlim([freq(1) freq(end)]); +xlabel('frequency (Hz)') +ylabel('line-impedance (\Omega)'); +grid on; +hold on; +plot(freq,imag(port{1}.ZL),'r--','Linewidth',2); +plot(freq,ZL_a,'g-.','Linewidth',2); +legend('\Re\{ZL\}','\Im\{ZL\}','ZL-analytic','Location','Best'); diff --git a/openEMS/matlab/examples/waveguide/Coax_CylinderCoords.m b/openEMS/matlab/examples/waveguide/Coax_CylinderCoords.m new file mode 100644 index 0000000..5e4606c --- /dev/null +++ b/openEMS/matlab/examples/waveguide/Coax_CylinderCoords.m @@ -0,0 +1,190 @@ +% +% EXAMPLE / waveguide / coaxial cable using cylindrical coordinates +% +% This example demonstrates how to: +% - use cylindrical coordinates +% - setup a coaxial waveguide +% - use analytic functions for waveguide excitations and voltage/current +% calculations +% +% +% Tested with +% - Matlab 2009b +% - openEMS v0.0.17 +% +% (C) 2010 Thorsten Liebig + +close all +clear +clc + +%% switches & options... +postprocessing_only = 0; +use_pml = 0; % use pml boundaries instead of mur +openEMS_opts = ''; +% openEMS_opts = [openEMS_opts ' --disable-dumps']; + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +numTS = 1e5; %number of timesteps +length = 1000; %length of the waveguide +unit = 1e-3; %drawing unit used +coax_rad_i = 100; %inner radius +coax_rad_a = 230; %outer radius +mesh_res = [10 nan 10]; %desired mesh resolution +N_alpha = 71; %mesh lines in azimuth direction + +physical_constants; + +%excitation +f0 = 0.5e9; +epsR = 1; + +%% create sim path %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Sim_Path = 'tmp'; +Sim_CSX = 'coax.xml'; + +if (postprocessing_only==0) + [status, message, messageid] = rmdir(Sim_Path,'s'); + [status, message, messageid] = mkdir(Sim_Path); +end + +%% setup FDTD parameter & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%%% +FDTD = InitCylindricalFDTD(numTS,1e-5); +FDTD = SetGaussExcite(FDTD,f0,f0); +BC = {'PEC','PEC','PEC','PEC','PEC','MUR'}; +if (use_pml>0) + BC = {'PEC','PEC','PEC','PEC','PEC','PML_8'}; +end +FDTD = SetBoundaryCond(FDTD,BC); + +%% setup CSXCAD geometry & mesh %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = InitCSX('CoordSystem',1); +mesh.x = coax_rad_i : mesh_res(1) : coax_rad_a; +mesh.y = linspace(0,2*pi,N_alpha); +mesh.z = 0 : mesh_res(3) : length; +CSX = DefineRectGrid(CSX, unit, mesh); + +%% material +CSX = AddMaterial(CSX,'fill'); +CSX = SetMaterialProperty(CSX,'fill','Epsilon',epsR); +start = [mesh.x(1) mesh.y(1) 0]; +stop = [mesh.x(end) mesh.y(end) length]; +CSX = AddBox(CSX,'fill',0 ,start,stop); + +%% apply the excitation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddExcitation(CSX,'excite',0,[1 0 0]); +weight{1} = '1/rho'; +weight{2} = 0; +weight{3} = 0; +CSX = SetExcitationWeight(CSX, 'excite', weight ); +start = [coax_rad_i mesh.y(1) 0]; +stop = [coax_rad_a mesh.y(end) 0]; +CSX = AddBox(CSX,'excite',0 ,start,stop); + +%% define dump boxes... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CSX = AddDump(CSX,'Et_','DumpMode',0); +start = [mesh.x(1) , 0 , mesh.z(1)]; +stop = [mesh.x(end) , 0 , mesh.z(end)]; +CSX = AddBox(CSX,'Et_',0 , start,stop); + +CSX = AddDump(CSX,'Ht_','DumpType',1,'DumpMode',0); +CSX = AddBox(CSX,'Ht_',0,start,stop); + +%% define voltage calc boxes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%voltage calc +CSX = AddProbe(CSX,'ut1',0); +start = [ coax_rad_i 0 mesh.z(10) ]; +stop = [ coax_rad_a 0 mesh.z(10) ]; +CSX = AddBox(CSX,'ut1', 0 ,start,stop); +CSX = AddProbe(CSX,'ut2',0); +start = [ coax_rad_i 0 mesh.z(end-10)]; +stop = [ coax_rad_a 0 mesh.z(end-10)]; +CSX = AddBox(CSX,'ut2', 0 ,start,stop); + +%current calc, for each position there are two currents, which will get +%averaged to match the voltage position in between (!Yee grid!) +CSX = AddProbe(CSX,'it1a',1); +mid = 0.5*(coax_rad_i+coax_rad_a); +start = [ 0 mesh.z(1) mesh.z(9) ]; +stop = [ mid mesh.z(end) mesh.z(9) ]; +CSX = AddBox(CSX,'it1a', 0 ,start,stop); +CSX = AddProbe(CSX,'it1b',1); +start = [ 0 mesh.z(1) mesh.z(10) ]; +stop = [ mid mesh.z(end) mesh.z(10) ]; +CSX = AddBox(CSX,'it1b', 0 ,start,stop); + +CSX = AddProbe(CSX,'it2a',1); +start = [ 0 mesh.z(1) mesh.z(end-11) ]; +stop = [ mid mesh.z(end) mesh.z(end-11) ]; +CSX = AddBox(CSX,'it2a', 0 ,start,stop); +CSX = AddProbe(CSX,'it2b',1); +start = [ 0 mesh.z(1) mesh.z(end-10) ]; +stop = [ mid mesh.z(end) mesh.z(end-10) ]; +CSX = AddBox(CSX,'it2b', 0 ,start,stop); + +%% Write openEMS +if (postprocessing_only==0) + WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + RunOpenEMS(Sim_Path, Sim_CSX, openEMS_opts); +end + +%% +freq = linspace(0,2*f0,201); +U = ReadUI({'ut1','ut2'},[Sim_Path '/'],freq); +I = ReadUI({'it1a','it1b','it2a','it2b'},[Sim_Path '/'],freq); +Exc = ReadUI('et',Sim_Path,freq); + +%% plot voltages +figure +plot(U.TD{1}.t, U.TD{1}.val,'Linewidth',2); +hold on; +grid on; +plot(U.TD{2}.t, U.TD{2}.val,'r--','Linewidth',2); +xlabel('time (s)') +ylabel('voltage (V)') +legend('u_1(t)','u_2(t)') + +%% calculate incoming and reflected voltages & currents +ZL_a = ones(size(freq))*Z0/2/pi/sqrt(epsR)*log(coax_rad_a/coax_rad_i); %analytic line-impedance of a coax + +uf1 = U.FD{1}.val./Exc.FD{1}.val; +uf2 = U.FD{2}.val./Exc.FD{1}.val; +if1 = 0.5*(I.FD{1}.val+I.FD{2}.val)./Exc.FD{1}.val; +if2 = 0.5*(I.FD{3}.val+I.FD{4}.val)./Exc.FD{1}.val; + +uf1_inc = 0.5 * ( uf1 + if1 .* ZL_a ); +if1_inc = 0.5 * ( if1 + uf1 ./ ZL_a ); +uf2_inc = 0.5 * ( uf2 + if2 .* ZL_a ); +if2_inc = 0.5 * ( if2 + uf2 ./ ZL_a ); + +uf1_ref = uf1 - uf1_inc; +if1_ref = if1 - if1_inc; +uf2_ref = uf2 - uf2_inc; +if2_ref = if2 - if2_inc; + +% plot s-parameter +figure +s11 = uf1_ref./uf1_inc; +s21 = uf2_inc./uf1_inc; +plot(freq,20*log10(abs(s11)),'Linewidth',2); +xlim([freq(1) freq(end)]); +xlabel('frequency (Hz)') +ylabel('s-para (dB)'); +% ylim([-40 5]); +grid on; +hold on; +plot(freq,20*log10(abs(s21)),'r','Linewidth',2); +legend('s11','s21','Location','SouthEast'); + +% plot line-impedance comparison +figure() +ZL = uf1./if1; +plot(freq,real(ZL),'Linewidth',2); +xlim([freq(1) freq(end)]); +xlabel('frequency (Hz)') +ylabel('line-impedance (\Omega)'); +grid on; +hold on; +plot(freq,imag(ZL),'r--','Linewidth',2); +plot(freq,ZL_a,'g-.','Linewidth',2); +legend('\Re\{ZL\}','\Im\{ZL\}','ZL-analytic','Location','Best'); diff --git a/openEMS/matlab/examples/waveguide/Coax_Cylindrical_MG.m b/openEMS/matlab/examples/waveguide/Coax_Cylindrical_MG.m new file mode 100644 index 0000000..84a1668 --- /dev/null +++ b/openEMS/matlab/examples/waveguide/Coax_Cylindrical_MG.m @@ -0,0 +1,155 @@ +close all +clear +clc + +%example for an cylindrical mesh, modeling a coaxial cable +% this example is using a multi-grid approach + + +%% setup %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +Settings = []; +Settings.LogFile = 'openEMS.log'; + +physical_constants + +f0 = 0.5e9; +epsR = 1; %material filling + +length = 1000; +port_dist = length/2; +rad_i = 10; %inner radius +rad_a = 200; %outer radius +partial = 0.5; %e.g. 0.5 means only one half of a coax, should be <1 or change boundary cond. +max_mesh = 10 / sqrt(epsR); +max_alpha = max_mesh; +N_alpha = ceil(rad_a * 2*pi * partial / max_alpha); + +%make it even... +N_alpha = N_alpha + mod(N_alpha,2); +%make sure it is multiple of 4, needed for 2 multi-grid steps +N_alpha = ceil((N_alpha)/4) *4 + 1; + +openEMS_opts = ''; +% openEMS_opts = [openEMS_opts ' --disable-dumps']; +% openEMS_opts = [openEMS_opts ' --debug-material']; +% openEMS_opts = [openEMS_opts ' --numThreads=1']; + +def_refSimu = 0; % do a reference simulation without the multi-grid + +%% setup done %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +if (def_refSimu>0) + Sim_Path = 'tmp_ref'; +else + Sim_Path = 'tmp'; +end +Sim_CSX = 'coax.xml'; + +if (exist(Sim_Path,'dir')) + rmdir(Sim_Path,'s'); +end +mkdir(Sim_Path); + +%setup FDTD parameter +if (def_refSimu>0) + FDTD = InitCylindricalFDTD(1e5,1e-5,'OverSampling',5 ); +else + FDTD = InitCylindricalFDTD(1e5,1e-5,'OverSampling',5 ,'MultiGrid','60,120'); +end +FDTD = SetGaussExcite(FDTD,f0,f0); +BC = [0 0 1 1 2 2]; +FDTD = SetBoundaryCond(FDTD,BC); + +mesh_res = [max_mesh 2*pi*partial/N_alpha max_mesh]; + +%setup CSXCAD geometry +CSX = InitCSX(); +mesh.x = SmoothMeshLines([rad_i rad_a],mesh_res(1)); +mesh.y = linspace(-pi*partial,pi*partial,N_alpha); +mesh.z = SmoothMeshLines([0 port_dist length],mesh_res(3)); +CSX = DefineRectGrid(CSX, 1e-3,mesh); + +start = [rad_i mesh.y(1) mesh.z(3)]; +stop = [rad_a mesh.y(end) mesh.z(3)]; + +CSX = AddExcitation(CSX,'excite',0,[1 0 0]); +weight{1} = '1/rho'; +weight{2} = 0; +weight{3} = 0; +CSX = SetExcitationWeight(CSX, 'excite', weight ); +CSX = AddBox(CSX,'excite',0 ,start,stop); + + +start = [mesh.x(1) mesh.y(1) mesh.z(1)]; +stop = [mesh.x(end) mesh.y(end) mesh.z(end)]; +CSX = AddMaterial(CSX,'material'); +CSX = SetMaterialProperty(CSX,'material','Epsilon',epsR); +CSX = AddBox(CSX,'material',0 ,start,stop); + +%dump +CSX = AddDump(CSX,'Et_rz_','DumpMode',0); +start = [mesh.x(1) 0 mesh.z(1)]; +stop = [mesh.x(end) 0 mesh.z(end)]; +CSX = AddBox(CSX,'Et_rz_',0 , start,stop); + +CSX = AddDump(CSX,'Ht_rz_','DumpType',1,'DumpMode',0); +CSX = AddBox(CSX,'Ht_rz_',0 , start,stop); + +CSX = AddDump(CSX,'Et_','DumpType',0,'DumpMode',0); +start = [mesh.x(1) mesh.y(1) length/2]; +stop = [mesh.x(end) mesh.y(end) length/2]; +CSX = AddBox(CSX,'Et_',0,start,stop); + +CSX = AddDump(CSX,'Ht_','DumpType',1,'DumpMode',0); +start = [mesh.x(1) mesh.y(1) length/2]; +stop = [mesh.x(end) mesh.y(end) length/2]; +CSX = AddBox(CSX,'Ht_',0,start,stop); + +% voltage calc (take a voltage average to be at the same spot as the +% current calculation) +CSX = AddProbe(CSX,'ut1_1',0); +start = [ rad_i 0 port_dist ];stop = [ rad_a 0 port_dist ]; +CSX = AddBox(CSX,'ut1_1', 0 ,start,stop); +CSX = AddProbe(CSX,'ut1_2',0); +start = [ rad_i 0 port_dist+mesh_res(3) ];stop = [ rad_a 0 port_dist+mesh_res(3) ]; +CSX = AddBox(CSX,'ut1_2', 0 ,start,stop); + +% current calc +CSX = AddProbe(CSX,'it1',1); +mid = 75; +start = [ 0 mesh.y(1) port_dist+mesh_res(3)/2 ];stop = [ mid mesh.y(end) port_dist+mesh_res(3)/2 ]; +CSX = AddBox(CSX,'it1', 0 ,start,stop); + +%% Write openEMS compatoble xml-file %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +WriteOpenEMS([Sim_Path '/' Sim_CSX],FDTD,CSX); + +RunOpenEMS(Sim_Path, Sim_CSX, openEMS_opts, Settings) + +%% +close all +freq = linspace(0,2*f0,201); +UI = ReadUI({'ut1_1','ut1_2','it1'},Sim_Path,freq); +u_f = (UI.FD{1}.val + UI.FD{2}.val)/2; %averaging voltages to fit current +i_f = UI.FD{3}.val / partial; + +% plot(UI.TD{1}.t,UI.TD{1}.val); +% grid on; +% +% figure +% plot(UI.TD{3}.t,UI.TD{3}.val); +% grid on; + +%plot Z_L compare +figure +ZL = Z0/2/pi/sqrt(epsR)*log(rad_a/rad_i); %analytic line-impedance of a coax +plot(UI.FD{1}.f,ZL*ones(size(u_f)),'g','Linewidth',3); +hold on; +grid on; +Z = u_f./i_f; +plot(UI.FD{1}.f,real(Z),'k--','Linewidth',2); +plot(UI.FD{1}.f,imag(Z),'r-','Linewidth',2); +xlim([0 2*f0]); +legend('Z_L - analytic','\Re\{Z\} - FDTD','\Im\{Z\} - FDTD','Location','Best'); + + diff --git a/openEMS/matlab/examples/waveguide/Rect_Waveguide.m b/openEMS/matlab/examples/waveguide/Rect_Waveguide.m new file mode 100644 index 0000000..a9601ad --- /dev/null +++ b/openEMS/matlab/examples/waveguide/Rect_Waveguide.m @@ -0,0 +1,240 @@ +% +% EXAMPLE / waveguide / Rect_Waveguide +% +% This example demonstrates: +% - waveguide mode excitation +% - waveguide mode matching +% - pml absorbing boundaries +% +% +% Tested with +% - Matlab 2009b +% - openEMS v0.0.17 +% +% (C) 2010 Thorsten Liebig + +close all +clear +clc + +%% switches +postproc_only = 0; + +%% setup the simulation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +physical_constants; +unit = 1e-3; %drawing unit in mm +numTS = 50000; %max. number of timesteps + +% waveguide dimensions +length = 1000; +a = 1000; %waveguide width +b = 600; %waveguide heigth + +%waveguide TE-mode definition +m = 1; +n = 0; + +mesh_res = [10 10 10]; + +%% setup FDTD parameters & excitation function %%%%%%%%%%%%%%%%%%%%%%%%%%%% +f_start = 175e6; +f_stop = 500e6; + +% dump special frequencies to vtk, use paraview (www.paraview.org) to +% animate this dumps over phase +vtk_dump_freq = [200e6 300e6 500e6]; + +freq = linspace(f_start,f_stop,201); + +k = 2*pi*freq/c0; +kc = sqrt((m*pi/a/unit)^2 + (n*pi/b/unit)^2); +fc = c0*kc/2/pi; %cut-off frequency +beta = sqrt(k.^2 - kc^2); %waveguide phase-constant +ZL_a = k * Z0 ./ beta; %analytic waveguide impedance + +disp([' Cutoff frequencies for this mode and wavguide is: ' num2str(fc/1e6) ' MHz']); + +if (f_start +#include +#include "hdf5.h" + +// this special treatment is necessary because Win32-Octave ships with a very old hdf5 version (1.6.10) +void CloseH5Object(hid_t obj) +{ + H5Oclose(obj); +} + +DEFUN_DLD (h5readatt_octave, args, nargout, "h5readatt_octave(,,)") +{ + octave_value retval; + int nargin = args.length(); + if (nargin != 3) + { + print_usage(); + return retval; + } + if ((args(0).is_string()==false) || (args(1).is_string()==false) || (args(2).is_string()==false)) + { + print_usage(); + return retval; + } + + //suppress hdf5 error output + H5Eset_auto2(H5E_DEFAULT, NULL, NULL); + + hid_t file = H5Fopen( args(0).string_value().c_str(), H5F_ACC_RDONLY, H5P_DEFAULT ); + if (file==-1) + { + error("h5readatt_octave: opening the given File failed"); + return retval; + } + + hid_t obj = H5Oopen(file, args(1).string_value().c_str(), H5P_DEFAULT); + + if (obj==-1) + { + CloseH5Object(obj); + H5Fclose(file); + error("h5readatt_octave: opening the given Object failed"); + return retval; + } + + hid_t attr = H5Aopen_by_name(obj, ".", args(2).string_value().c_str(), H5P_DEFAULT, H5P_DEFAULT); + + if (attr==-1) + { + CloseH5Object(obj); + H5Fclose(file); + error("h5readatt_octave: opening the given Attribute failed"); + return retval; + } + + hid_t type = H5Aget_type(attr); + if (type<0) + { + H5Aclose(attr); + CloseH5Object(obj); + H5Fclose(file); + error("h5readatt_octave: dataset type error"); + return retval; + } + + if (H5Tget_class(type)!=H5T_FLOAT) + { + H5Aclose(attr); + CloseH5Object(obj); + H5Fclose(file); + error("h5readatt_octave: attribute type not supported"); + return retval; + } + + size_t numVal = H5Aget_storage_size(attr)/H5Tget_size(type); + double value[numVal]; + if (H5Tget_size(type)==sizeof(float)) + { + float f_value[numVal]; + if (H5Aread(attr, H5T_NATIVE_FLOAT, f_value)<0) + { + H5Aclose(attr); + CloseH5Object(obj); + H5Fclose(file); + error("h5readatt_octave: reading the given Attribute failed"); + return retval; + } + for (size_t n=0;n + +if isunix + harminv_exe = 'export LD_LIBRARY_PATH=; harminv'; +elseif ispc + m_filename = mfilename('fullpath'); + dir = fileparts( m_filename ); + harminv_exe = [ '"' dir '\..\harminv.exe"']; +else + error('openEMS:harminv','unknown/unsupported operating system...'); +end + +options = ['-t ' num2str(timestep)]; +tmpfile = tempname; + +% convert to column vector +if size(timeseries,2) > size(timeseries,1) + timeseries = timeseries.'; +end + +% harminv hangs if timeseries is zero only +if all(timeseries == 0) + disp( 'timeseries is 0' ); + return +end + +% write timeseries to temporary file +dlmwrite( tmpfile, timeseries ); + +command = [harminv_exe ' ' options ' '... + num2str(start_freq) '-' num2str(stop_freq) ' < "' tmpfile '"']; +[status,result] = system( command ); +if status ~= 0 + disp( 'error executing harminv:' ); + disp( command ); + disp( ['exit status: ' num2str(status)] ); + disp( ['output: ' result] ); + return +end + +%disp( command ) +%disp( result ) + +f = []; +decay = []; +Q = []; +amp = []; +phase = []; +err = []; + +lines = textscan( result, '%s', 'Delimiter', '\n'); + +for n=2:numel(lines{1}) + [C] = textscan( lines{1}{n}, '%f', 6, 'Delimiter', ','); + if isempty(C{1}), break; end + if C{1}(1) >= 0 + f = [f C{1}(1)]; + decay = [decay C{1}(2)]; + Q = [Q C{1}(3)]; + amp = [amp 2*C{1}(4)]; % neglecting negative frequencies => amplitude doubles + phase = [phase C{1}(5)]; + err = [err C{1}(6)]; + end +end diff --git a/openEMS/matlab/optimize.m b/openEMS/matlab/optimize.m new file mode 100644 index 0000000..78ef497 --- /dev/null +++ b/openEMS/matlab/optimize.m @@ -0,0 +1,203 @@ +function [params,result] = optimize( optimdir, params, options, algorithm ) +%params = optimize( optimdir, params, options, algorithm ) +% +% input: +% optimdir: folder where to optimize +% params: array of structures with parameters to optimize +% .name char string parameter name (e.g. 'length1') +% .value number +% .step number discretization of .value +% .range row vector range of .value (e.g. [1 10]) +% .active (0/1) 1=optimize this parameter +% options: structure +% .folder_matlabstart set the startup folder for matlab or octave +% .simfun char string with the simulation function name +% .octave_exe if this field is present, octave is used +% .clean clean the optimization folder before optimization start +% algorithm: 'asco' or 'simplex-downhill' +% +% output: +% params: optimal values +% result: optimization criterion for optimal values +% +% example: +% see openEMS/matlab/examples/optimizer +% +% notes: +% Create a file named 'STOP_OPTIMIZATION' in the optimdir folder to stop +% the optimization process (or press Ctrl+C). +% +% (C) 2010 Sebastian Held + +error( nargchk(3,4,nargin) ); + +% default to simplex-downhill +if nargin < 4 + algorithm = 'simplex-downhill'; +end +if ~strcmp( algorithm, 'asco' ) + algorithm = 'simplex-downhill'; +end + +optimdir = absolutepath( optimdir ); +if isfield(options,'clean') && (options.clean == 1) + [a,a,a] = rmdir( optimdir, 's' ); +end +[a,a,a] = mkdir( optimdir ); +oldfolder = cd( optimdir ); + +if strcmp( algorithm, 'asco' ) + % --------------------------------------------------------------------- + % selected algorithm: ASCO + % http://asco.sourceforge.net/ + +% if ~exist( 'asco', 'file' ) && ~exist( 'asco.exe', 'file' ) +% error 'asco was not found in PATH. Download from http://asco.sf.net/' +% end + + % create asco config file + fid = fopen( 'asco.cfg', 'wt' ); + fprintf( fid, '* asco configuration file\n' ); + fprintf( fid, '* http://asco.sourceforge.net/\n' ); + fprintf( fid, '* \n' ); + fprintf( fid, '* Optimization for openEMS\n\n' ); + fprintf( fid, '#Optimization Flow#\n' ); + fprintf( fid, 'Alter:no $do we want to do corner analysis?\n' ); + fprintf( fid, 'MonteCarlo:no $do we want to do MonteCarlo analysis?\n' ); + fprintf( fid, 'AlterMC cost:0.00 $point below which ALTER and/or MONTECARLO can start\n' ); + fprintf( fid, 'ExecuteRF:no $Execute or no the RF module to add RF parasitics?\n' ); + fprintf( fid, '#\n\n' ); + fprintf( fid, '#DE#\n' ); + fprintf( fid, 'choice of method:3\n' ); + fprintf( fid, 'maximum no. of iterations:50\n' ); + fprintf( fid, 'Output refresh cycle:2\n' ); + fprintf( fid, 'No. of parents NP:10\n' ); + fprintf( fid, 'Constant F:0.85\n' ); + fprintf( fid, 'Crossing Over factor CR:1\n' ); + fprintf( fid, 'Seed for pseudo random number generator:3\n' ); + fprintf( fid, 'Minimum Cost Variance:1e-6\n' ); + fprintf( fid, 'Cost objectives:10\n' ); + fprintf( fid, 'Cost constraints:100\n' ); + fprintf( fid, '#\n\n' ); + + fprintf( fid, '# Parameters #\n' ); + for n=1:numel(params) + if params(n).active == 1 + active = 'OPT'; + else + active = '---'; + end + value = params(n).value / params(n).step; + range = params(n).range / params(n).step; + fprintf( fid, 'description:#%s#:%i:%i:%i:LIN_INT:%s\n', params(n).name, value, range(1), range(2), active ); + end + fprintf( fid, '#\n\n' ); + + fprintf( fid, '# Measurements #\n' ); + fprintf( fid, 'value:---:MIN:0\n' ); + fprintf( fid, '#\n\n' ); + fclose(fid); + + % create extract file + [a,a,a]=mkdir( 'extract' ); + fid = fopen( 'extract/value', 'wt' ); + fprintf( fid, '# Info #\n' ); + fprintf( fid, 'Name:value\n' ); + fprintf( fid, 'Symbol:value\n' ); + fprintf( fid, '#\n\n' ); + fprintf( fid, '# Commands #\n' ); + fprintf( fid, '#\n\n' ); + fprintf( fid, '# Post Processing #\n' ); + fprintf( fid, 'MEASURE_VAR: #SYMBOL#: SEARCH_FOR:''value=''\n' ); + fprintf( fid, '#\n' ); + fclose(fid); + + % create matlab parameter file + fid = fopen( 'asco.txt', 'wt' ); + fprintf( fid, '%% this file is processed by asco and variables enclosed in ## are substituted\n' ); + fprintf( fid, 'params = [];\n' ); + for n=1:numel(params) + fprintf( fid, 'params.%s = #%s# * %i;\n', params(n).name, params(n).name, params(n).step ); + end + fclose(fid); + + % create shell script + folder_asco_helper = fileparts( mfilename('fullpath') ); + asco_sim_helper = 'optimizer_asco_sim'; + fid = fopen( 'general.sh', 'wt' ); + fprintf( fid, '#!/bin/sh\n' ); + fprintf( fid, 'rm "$2.out" 2> /dev/null\n' ); + fprintf( fid, 'mv "$1.txt" "$1.m"\n' ); + fprintf( fid, 'if [ -f STOP_OPTIMIZATION ]; then\n' ); + fprintf( fid, ' exit\n' ); + fprintf( fid, 'fi\n' ); + fprintf( fid, 'oldpwd=$PWD\n' ); + if isfield(options,'folder_matlabstart') + % this allows to start the new matlab process in a specific folder + % => startup.m is picked up here + fprintf( fid, 'cd "%s"\n', functions.folder_matlabstart ); + end + if ~isfield(options,'octave_exe') + % matlab + fprintf( fid, '%s/bin/matlab -nodesktop -nosplash -r "cd ''%s''; %s(''%s'',''$1'',''$2.out'',''%s''); exit"\n', matlabroot, folder_asco_helper, asco_sim_helper, optimdir, options.simfun ); + else + % octave + fprintf( fid, 'export LD_LIBRARY_PATH=\n' ); + fprintf( fid, '%s --silent --eval "cd ''%s''; %s(''%s'',''$1'',''$2.out'',''%s'');"\n', options.octave_exe, folder_asco_helper, asco_sim_helper, optimdir, options.simfun ); + end + fprintf( fid, 'cd "$oldpwd"\n' ); + fclose(fid); + fileattrib( 'general.sh', '+x' ); % make it executable + + % clean up old data + if exist( './best_result.mat', 'file' ), delete( 'best_result.mat' ); end + if exist( './STOP_OPTIMIZATION', 'file' ), delete( 'STOP_OPTIMIZATION' ); end + + % start asco + [status,result] = unix( 'asco -general asco.txt', '-echo' ); + + % get best result + best = load( 'best_result.mat' ); + best = best.best; + result = best.result; + for n=1:numel(params) + name = params(n).name; + if isfield(best.params,name) + params(n).value = best.params.(name); + end + end + +elseif strcmp( algorithm, 'simplex-downhill' ) + % --------------------------------------------------------------------- + % selected algorithm: simplex-downhill + % Thorsten Liebig + + error( 'not implemented yet' ); +end + +cd( oldfolder ); + + + + + +function folder = absolutepath( folder ) +%folder = absolutepath( folder ) +% make the path absolute +if isunix + % Unix + if folder(1) == '/' + return + end + folder = fullfile( pwd, folder ); +else + % Windows + folder = strrep( folder, '\', '/' ); + if strcmp( folder(2:3), ':/' ) || strcmp( folder(1:2), '//' ) || (folder(1) == '/') + return + end + if (folder(2) == ':') && (folder(3) ~= '/') + error( 'relative paths with drive specifier are not supported' ); + end + folder = fullfile( pwd, folder ); +end diff --git a/openEMS/matlab/optimizer_asco_sim.m b/openEMS/matlab/optimizer_asco_sim.m new file mode 100644 index 0000000..6f62ebf --- /dev/null +++ b/openEMS/matlab/optimizer_asco_sim.m @@ -0,0 +1,88 @@ +function optimizer_asco_sim( optimdir, inputfile, outputfile, simfun ) +%optimizer_asco_sim( optimdir, inputfile, outputfile, simfun ) +% +% This function is called from general.sh. Do not call it yourself. +% +% tasks: +% - set correct matlab path +% - evaluate inputfile +% - start simulation or get result from cache +% - postprocess simulation results +% - create output file (important: needs single \n at the first line and double \n at the last line!) + +error( nargchk(4,4,nargin) ); + +% add CSXCAD and openEMS to the matlab path +folder = fileparts( mfilename('fullpath') ); +addpath( folder ); +addpath( [folder '/../../CSXCAD/matlab'] ); + +% change to optimdir +olddir = pwd; +cd( optimdir ); + +% read parameters set by asco +if ~isempty( strfind(inputfile,'-') ) + % matlab cannot execute a file with dashes... + inputfile2 = strrep( inputfile,'-','_' ); + movefile( [inputfile '.m'], [inputfile2 '.m'] ); + run( inputfile2 ); + movefile( [inputfile2 '.m'], [inputfile '.m'] ); +end +% now a structure named 'params' is available + +% check cache +folder = create_folder_name( params ); +if exist( ['./' folder], 'dir' ) && exist( ['./' folder '/result.mat'], 'file' ) + % read cache + disp( 'CACHE HIT' ); + result = load( [folder '/result.mat'], 'result' ); + result = result.result; +else + % start simulation in folder + disp( ['starting simulation function ' simfun] ); + disp( [' simulation folder ' folder] ); + [simfun_folder,simfun] = fileparts(simfun); + oldpath = path; + addpath( simfun_folder ); + fhandle = str2func(simfun); % does not work for octave-3.2.4! + path( oldpath ); + mkdir( folder ); + result = fhandle(folder,params); + save( [folder '/result.mat'], 'result', '-mat' ); +end + +% write results for asco +fid = fopen( outputfile, 'wt' ); +fprintf( fid, '\nvalue= %e\n\n', result ); +fclose( fid ); + +% update best result +best = []; +best.result = result; +best.params = params; +if exist( [pwd '/best_result.mat'], 'file' ) + old = load( 'best_result.mat', 'best' ); + if old.best.result > best.result + save( 'best_result.mat', 'best', '-mat' ); + end +else + save( 'best_result.mat', 'best', '-mat' ); +end + +% restore old folder +cd( olddir ); + + + + + + + +function folder = create_folder_name( params ) +params = orderfields( params ); +folder = 'opt'; +fnames = fieldnames(params); +for n=1:numel(fnames) + folder = [folder '_' fnames{n} '=' num2str(params.(fnames{n}))]; +end diff --git a/openEMS/matlab/physical_constants.m b/openEMS/matlab/physical_constants.m new file mode 100644 index 0000000..cbb333e --- /dev/null +++ b/openEMS/matlab/physical_constants.m @@ -0,0 +1,12 @@ +% +% physical constants +% + +% Bronstein 3rd ed., 1997, pp. 945-946 +C0 = 299792458; % m/s +c0 = C0; %constans in capital letters, c0 for legacy support +MUE0 = 4e-7*pi; % N/A^2 +EPS0 = 1/(MUE0*C0^2); % F/m + +% free space wave impedance +Z0 = sqrt(MUE0/EPS0); % Ohm diff --git a/openEMS/matlab/plotFF3D.m b/openEMS/matlab/plotFF3D.m new file mode 100644 index 0000000..45950c8 --- /dev/null +++ b/openEMS/matlab/plotFF3D.m @@ -0,0 +1,91 @@ +function h = plotFF3D(nf2ff,varargin) +% h = plotFF3D(nf2ff,varargin) +% +% plot normalized 3D far field pattern +% +% input: +% nf2ff: output of CalcNF2FF +% +% variable input: +% 'freq_index': - use the given frequency index, see nf2ff.freq +% - default is 1 +% 'logscale': - if set, show farfield with logarithmic scale +% - set the dB value for point of origin +% - values below will be clamped +% 'normalize': - true/false, normalize linear plot +% - default is false, log-plot is always normalized! +% +% example: +% plotFF3D(nf2ff, 'freq_index', 2, 'logscale', -20) +% +% see examples/antennas/infDipol.m +% +% See also CalcNF2FF, plotFFdB, polarFF +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig, Stefan Mahr + +% defaults +logscale = []; +freq_index = 1; +normalize = 0; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'logscale')==1); + logscale = varargin{n+1}; + elseif (strcmp(varargin{n},'freq_index')==1); + freq_index = varargin{n+1}; + elseif (strcmp(varargin{n},'normalize')==1); + normalize = varargin{n+1}; + else + warning('openEMS:plotFF3D',['unknown argument key: ''' varargin{n} '''']); + end +end + +if ((normalize~=0) || ~isempty(logscale)) + E_far = nf2ff.E_norm{freq_index} / max(nf2ff.E_norm{freq_index}(:)); +else + E_far = nf2ff.E_norm{freq_index}; +end; + +if ~isempty(logscale) + E_far = 20*log10(E_far)/-logscale + 1; + E_far = E_far .* ( E_far > 0 ); + titletext = sprintf('electrical far field [dB] @ f = %e Hz',nf2ff.freq(freq_index)); +elseif (normalize==0) + titletext = sprintf('electrical far field [V/m] @ f = %e Hz',nf2ff.freq(freq_index)); +else + titletext = sprintf('normalized electrical far field @ f = %e Hz',nf2ff.freq(freq_index)); +end + +[theta,phi] = ndgrid(nf2ff.theta,nf2ff.phi); +x = E_far .* sin(theta) .* cos(phi); +y = E_far .* sin(theta) .* sin(phi); +z = E_far .* cos(theta); +%figure +h = surf( x,y,z, E_far ); +set(h,'EdgeColor','none'); +axis equal +axis off + +try + if (isOctave && (strcmp(graphics_toolkit,'gnuplot')==1)) + warning('openEMS:plotFF3D','Colorbar doesn''t work properly with octave and gnuplot. On problems, try ''colorbar off'''); + end +end + +if ~isempty(logscale) + colorbar('YTick', linspace(0,max(E_far(:)),9), ... + 'YTickLabel',num2str(linspace(logscale, 10*log10(nf2ff.Dmax(freq_index)),9)')); +else + colorbar; +end + +title( titletext ); + +if (nargout == 0) + clear h; +end + +end diff --git a/openEMS/matlab/plotFFdB.m b/openEMS/matlab/plotFFdB.m new file mode 100644 index 0000000..07e96e3 --- /dev/null +++ b/openEMS/matlab/plotFFdB.m @@ -0,0 +1,78 @@ +function h = plotFFdB(nf2ff,varargin) +% h = plotFFdB(nf2ff,varargin) +% +% plot far field pattern in dBi +% +% input: +% nf2ff: output of CalcNF2FF +% +% variable input: +% 'freq_index': - use the given frequency index, see nf2ff.freq +% - default is 1 +% 'xaxis': - 'phi' (default) or 'theta' +% 'param': - array positions of parametric plot +% - if xaxis='phi', theta is parameter, and vice versa +% - default is 1 +% +% example: +% plotFFdB(nf2ff, 'freq_index', 2, ... +% 'xaxis', 'phi', 'param', [1 46 91]) +% +% see examples/NF2FF/infDipol.m +% +% See also CalcNF2FF, plotFF3D, polarFF +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig, Stefan Mahr + +% defaults +freq_index = 1; +xaxis = 'phi'; +param = 1; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'freq_index')==1); + freq_index = varargin{n+1}; + elseif (strcmp(varargin{n},'xaxis')==1); + xaxis = varargin{n+1}; + elseif (strcmp(varargin{n},'param')==1); + param = varargin{n+1}; + else + warning('openEMS:plotFFdB',['unknown argument key: ''' varargin{n} '''']); + end +end + +D_log = nf2ff.E_norm{freq_index} / max(nf2ff.E_norm{freq_index}(:)); +D_log = 20*log10(D_log) + 10*log10(nf2ff.Dmax(freq_index)); + +if (strcmp(xaxis,'theta')==1); + xax = nf2ff.theta; + yax = D_log(:,param); + parval = nf2ff.phi(param); + param = 'phi'; +elseif (strcmp(xaxis,'phi')==1); + xax = nf2ff.phi; + yax = D_log(param,:); + parval = nf2ff.theta(param); + param = 'theta'; +else + error('openEMS:plotFFdB','unknown parameter to ''xaxis'''); +end + +%figure +h = plot( xax / pi * 180 , yax ); +xlabel( sprintf('%s (deg)',xaxis )); +ylabel( 'directivity (dBi)'); + +createlegend = @(d)sprintf('%s = %3.1f',param,d / pi * 180); +legendtext = arrayfun(createlegend,parval,'UniformOutput',0); +legend( legendtext ); +title( sprintf('far field pattern @ f = %e Hz',nf2ff.freq(freq_index)) ); +grid on; + +if (nargout == 0) + clear h; +end + +end diff --git a/openEMS/matlab/plotRefl.m b/openEMS/matlab/plotRefl.m new file mode 100644 index 0000000..5f88631 --- /dev/null +++ b/openEMS/matlab/plotRefl.m @@ -0,0 +1,145 @@ +function h = plotRefl(port, varargin) + +% h = plotRefl(port,varargin) +% +% plot the reflection coefficient of a port into a Smith chart. +% left and right facing triangles mark the lower and upper cutoff +% frequency of the pass bands. An asterisk marks the frequnecy with +% the lowest reflection. +% +% input: +% port: port data structure. Call calcPort with an appropriate +% frequency vector before calling this routine +% +% output: graphics handle for further modification of the plot. +% +% variable input: +% 'precision': - number of decimal places (floating point precision) +% for the frequency (always in MHz), default is 0 +% 'threshold': - Threshold value (in dB) for the upper and lower +% cutoff frequency, default is -3 +% example: +% myport = calcPort(myport, Sim_Path, linspace(f_0-f_c, f_0+f_c, 200)); +% plotRefl(myport); +% +% See also calcPort +% +% openEMS matlab interface +% ----------------------- +% author: Georg Michel + +%defaults +precision = 0; +threshold = -3; + + +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 + warning('openEMS:polarFF',['unknown argument key: ''' varargin{n} '''']); + end +end + + +if ~isfield(port, 'uf') + error('Cannot plot the reflection coefficient. Please call calcPort first.'); +end + +s11 = port.uf.ref ./ port.uf.inc; +ffmt = ['%.', num2str(precision), 'f']; + + + +figure; %new figure + +plot([-1, 1], [0, 0], 'k'); + + +axis ([-1.15, 1.15, -1.15, 1.15], "square"); +axis off; +hold on + +ReZ = [.2; .5; 1; 2]; +ImZ = 1i * [1 2 5 2]; +Z = bsxfun(@plus, ReZ, linspace(-ImZ, ImZ, 256)); +Gamma = (Z-1)./(Z+1); +plot(Gamma.', 'k'); + +ReZ = [.5 .5 1 1 2 2 5 5 10 10]; +ImZ = 1i * [-.2; .2; -.5; .5; -1; 1; -2; 2; -5; 5]; +Z = bsxfun(@plus, linspace(0, ReZ, 256), ImZ); +Gamma = (Z-1)./(Z+1); +plot(Gamma.', 'k'); + + +angle = linspace (0, 2 * pi, 256); ReZ = [0 5 10]; +center = ReZ ./ (ReZ + 1); +radius = 1 ./ (ReZ + 1); +plot(bsxfun(@plus, bsxfun(@times, radius, cos(angle.')), center), bsxfun(@times, radius, sin(angle.')), 'k'); + + +% resistance +ReZ = [0.2 0.5 1 2 5 10]; ImZ = zeros (1, length (ReZ)); +rho = (ReZ.^2 + ImZ.^2 - 1 + 2i * ImZ) ./ ((ReZ + 1).^2 + ImZ.^2); + +xoffset = [0.1 0.1 0.05 0.05 0.05 0.075]; +yoffset = -0.03; + +for idx = 1:length (ReZ) + text (real (rho(idx)) - xoffset(idx), ... + imag (rho(idx)) - yoffset, num2str (ReZ(idx))); +end + +% reactance +ReZ = [-0.06 -0.06 -0.06 -0.12 -0.5]; +ImZ = [0.2 0.5 1 2 5]; + + +rho = (ReZ.^2 + ImZ.^2 - 1 + 2i * ImZ) ./ ((ReZ + 1).^2 + ImZ.^2); + +for idx = 1:length (ImZ) + text (real (rho(idx)), imag (rho(idx)), [num2str(ImZ(idx)), "j"]); + text (real (rho(idx)), -imag (rho(idx)), [num2str(-ImZ(idx)), "j"]); end + +% zero +rho = (-0.05.^2 + 0.^2 - 1) ./ ((-0.05 + 1).^2 + 0.^2); + +text (real (rho), imag (rho), '0'); + +s11dB = 20*log10(abs(s11)); + +upperind = s11dB(1:end-1) < threshold & s11dB(2:end) > threshold; +lowerind = s11dB(1:end-1) > threshold & s11dB(2:end) < threshold; +minind = nthargout(2, @min, s11dB); +handle1 = plot(s11(lowerind),['<','b']); +handle2 = plot(s11(upperind),['>','b']); +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)}, ', '); + end +end + +if nnz(upperind) > 1 + for i= 2:nnz(upperind) + ulegend = strjoin({ulegend, num2str(port.f(upperind)(i)/1e6, ffmt)}, ', '); + end +end + +legend([handle1, handle2, handle3], {[llegend, " MHz"], ... + [ulegend, " MHz"], ... + [num2str(20*log10(abs(s11(minind))), "%4.0f"), ... + "dB @ ", num2str(port.f(minind)/1e6, ffmt), " MHz"]}); +h = plot(s11); + +if (nargout == 0) + clear h; +end + +end \ No newline at end of file diff --git a/openEMS/matlab/polarFF.m b/openEMS/matlab/polarFF.m new file mode 100644 index 0000000..96b97da --- /dev/null +++ b/openEMS/matlab/polarFF.m @@ -0,0 +1,172 @@ +function h = polarFF(nf2ff,varargin) +% h = polarFF(nf2ff,varargin) +% +% plot polar far field pattern +% +% input: +% nf2ff: output of CalcNF2FF +% +% variable input: +% 'freq_index': - use the given frequency index, see nf2ff.freq +% - default is 1 +% 'xaxis': - 'phi' (default) or 'theta' +% 'param': - array positions of parametric plot +% - if xaxis='phi', theta is parameter, and vice versa +% - default is 1 +% 'normalize': - true/false, normalize linear plot +% - default is false, log-plot is always normalized! +% 'logscale': - if set, plot logarithmic polar +% - set the dB value for point of origin if scalar +% - set point of origin and maximum if 2-element array +% - values below minimum will be clamped +% - default is -20 +% 'xtics': - set the number of tics for polar grid +% - default is 5 +% +% example: +% polarFF(nf2ff, 'freq_index', 2, ... +% 'xaxis', 'phi', 'param', [1 46 91] ); +% +% polarFF(..., 'normalize', true ); +% polarFF(..., 'logscale', -30 ); +% polarFF(..., 'logscale', [-30 10]); +% +% polarFF(..., 'xtics', 10); +% +% see examples/antenna/infDipol.m +% +% See also CalcNF2FF, plotFFdB, plotFF3D +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig, Stefan Mahr + +% defaults +freq_index = 1; +xaxis = 'phi'; +param = 1; +logscale = []; +xtics = 5; +normalize = 0; + +for n=1:2:numel(varargin) + if (strcmp(varargin{n},'freq_index')==1); + freq_index = varargin{n+1}; + elseif (strcmp(varargin{n},'xaxis')==1); + xaxis = varargin{n+1}; + elseif (strcmp(varargin{n},'param')==1); + param = varargin{n+1}; + elseif (strcmp(varargin{n},'normalize')==1); + normalize = varargin{n+1}; + elseif (strcmp(varargin{n},'logscale')==1); + logscale = varargin{n+1}; + elseif (strcmp(varargin{n},'xtics')==1); + xtics = varargin{n+1}; + else + warning('openEMS:polarFF',['unknown argument key: ''' varargin{n} '''']); + end +end + +E_far_max = max(nf2ff.E_norm{freq_index}(:)); +if ~isempty(logscale) + gridmin = logscale(1); + + Dmax = 10*log10(nf2ff.Dmax(freq_index)); + E_far_scale = Dmax - gridmin; + E_far = 20*log10(nf2ff.E_norm{freq_index}) - 20*log10(E_far_max) + E_far_scale; + E_far = E_far .* ( E_far > 0 ); + E_far = E_far ./ E_far_scale; + + titletext = sprintf('electrical far field [dBi] @ f = %e Hz',nf2ff.freq(freq_index)); + + if numel(logscale) == 2 % normalize to maximum grid + gridmax = logscale(2); + E_far = E_far .* E_far_scale/(gridmax-gridmin); + else + gridmax = Dmax; + end +elseif (normalize==0) + E_far = nf2ff.E_norm{freq_index}; + + titletext = sprintf('electrical far field [V/m] @ f = %e Hz',nf2ff.freq(freq_index)); + + gridmin = 0; + gridmax = E_far_max; +else % normalize == 1 + E_far = nf2ff.E_norm{freq_index} / E_far_max; + + titletext = sprintf('normalized electrical far field @ f = %e Hz',nf2ff.freq(freq_index)); + + gridmin = 0; + gridmax = 1; +end + + +if (strcmp(xaxis,'theta')==1); + xax = nf2ff.theta(:); + yax = E_far(:,param); + parval = nf2ff.phi(param); + param = 'phi'; +elseif (strcmp(xaxis,'phi')==1); + xax = nf2ff.phi(:); + yax = E_far(param,:)'; + parval = nf2ff.theta(param); + param = 'theta'; +else + error('openEMS:polarFF','unknown parameter to ''xaxis'''); +end + +if ~isempty(logscale) + scalegrid = 1; +else + scalegrid = gridmax; +end + +% workaround for polar plot +gridcolor = [0.85 0.85 0.85]; +% plot xtics circles +a=linspace(0,2*pi,60); +b=linspace(0,scalegrid,xtics+1); +b=repmat(b(2:end),numel(a),1)'; +a=repmat(a,size(b,1),1); +[x,y] = pol2cart(a,b); +h = plot(x',y'); +%h=polar(a,b,'-k'); +set(h,'Color',gridcolor); +set(h(end),'Color',gridcolor*0.8); +hold on; +% plot degree lines +a=bsxfun(@plus,[0:pi/6:pi-pi/6],[0 pi]'); +b=scalegrid.*ones(size(a)); +h=polar(a,b,'-k'); +set(h,'Color',gridcolor); +set(h([1 4]),'Color',gridcolor*0.8); +text(scalegrid*0.05,scalegrid*0.05,num2str(gridmin)) +text(scalegrid*1.05,scalegrid*0.05,num2str(gridmax)) + + +% draw far field +xax = repmat(xax,1,size(yax,2)); +[x,y] = pol2cart(xax,yax); +h = plot(x,y); +%h = polar( xax, yax ); + +% legend +ylabel( sprintf('%s / deg', xaxis) ); +title( titletext ); +createlegend = @(d)sprintf('%s = %3.1f',param,d / pi * 180); +legendtext = arrayfun(createlegend,parval,'UniformOutput',0); +legend( h, legendtext ,'location','southeast'); + +% workaround for polar plot +axis equal tight +axis ([-scalegrid scalegrid -scalegrid scalegrid]); +axis off +hold off +set(gcf,'Color','white'); + +if (nargout == 0) + clear h; +end + +end diff --git a/openEMS/matlab/private/ReadNF2FF.m b/openEMS/matlab/private/ReadNF2FF.m new file mode 100644 index 0000000..55f67f9 --- /dev/null +++ b/openEMS/matlab/private/ReadNF2FF.m @@ -0,0 +1,82 @@ +function nf2ff = ReadNF2FF(nf2ff) +% function nf2ff = ReadNF2FF(nf2ff) +% +% internal function to read calculated nf2ff data, use CalcNF2FF to read +% existing nf2ff data +% +% See also: CalcNF2FF, CreateNF2FFBox +% +% openEMS matlab interface +% ----------------------- +% author: Thorsten Liebig, 2012 + +file = nf2ff.hdf5; + +hdf_mesh = ReadHDF5Mesh(file); + +nf2ff.r = double(hdf_mesh.lines{1}); +nf2ff.theta = double(hdf_mesh.lines{2}); +nf2ff.phi = double(hdf_mesh.lines{3}); + +% read attributes +nf2ff.freq = ReadHDF5Attribute(file,'/nf2ff','Frequency'); +nf2ff.Prad = ReadHDF5Attribute(file,'/nf2ff','Prad'); +nf2ff.Dmax = ReadHDF5Attribute(file,'/nf2ff','Dmax'); + +try + nf2ff.Eps_r = ReadHDF5Attribute(file,'/nf2ff','Eps_r'); +catch + nf2ff.Eps_r = ones(size(nf2ff.freq)); +end +try + nf2ff.Mue_r = ReadHDF5Attribute(file,'/nf2ff','Mue_r'); +catch + nf2ff.Mue_r = ones(size(nf2ff.freq)); +end + +if isOctave + hdf = load( '-hdf5', file ); + for n=1:numel(nf2ff.freq) + nf2ff.E_theta{n} = double(hdf.nf2ff.E_theta.FD.(['f' int2str(n-1) '_real']) +1i*hdf.nf2ff.E_theta.FD.(['f' int2str(n-1) '_imag']) ); + nf2ff.E_phi{n} = double(hdf.nf2ff.E_phi.FD.(['f' int2str(n-1) '_real']) +1i*hdf.nf2ff.E_phi.FD.(['f' int2str(n-1) '_imag']) ); + nf2ff.E_norm{n} = double(sqrt(abs(nf2ff.E_theta{n}).^2+abs(nf2ff.E_phi{n}).^2)); + nf2ff.P_rad{n} = double(hdf.nf2ff.P_rad.FD.(['f' int2str(n-1)])); + end +else + % matlab compatibility to older versions + if verLessThan('matlab','7.12') + % read data + for n=1:numel(nf2ff.freq) + nf2ff.E_theta{n} = double(hdf5read(file,['/nf2ff/E_theta/FD/f' int2str(n-1) '_real']) + 1i*hdf5read(file,['/nf2ff/E_theta/FD/f' int2str(n-1) '_imag'])); + nf2ff.E_phi{n} = double(hdf5read(file,['/nf2ff/E_phi/FD/f' int2str(n-1) '_real']) + 1i*hdf5read(file,['/nf2ff/E_phi/FD/f' int2str(n-1) '_imag'])); + nf2ff.E_norm{n} = double(sqrt(abs(nf2ff.E_theta{n}).^2+abs(nf2ff.E_phi{n}).^2)); + nf2ff.P_rad{n} = double(hdf5read(file,['/nf2ff/P_rad/FD/f' int2str(n-1)])); + end + else + % read data + for n=1:numel(nf2ff.freq) + nf2ff.E_theta{n} = double(h5read(file,['/nf2ff/E_theta/FD/f' int2str(n-1) '_real']) + 1i*h5read(file,['/nf2ff/E_theta/FD/f' int2str(n-1) '_imag'])); + nf2ff.E_phi{n} = double(h5read(file,['/nf2ff/E_phi/FD/f' int2str(n-1) '_real']) + 1i*h5read(file,['/nf2ff/E_phi/FD/f' int2str(n-1) '_imag'])); + nf2ff.E_norm{n} = double(sqrt(abs(nf2ff.E_theta{n}).^2+abs(nf2ff.E_phi{n}).^2)); + nf2ff.P_rad{n} = double(h5read(file,['/nf2ff/P_rad/FD/f' int2str(n-1)])); + end + end +end + +% Calculation of right- and left-handed circular polarization +% adopted from +% 2012, Tim Pegg + +% cleanup (if exist) +nf2ff.E_cprh = []; +nf2ff.E_cplh = []; + +% Setup vectors for converting to LHCP and RHCP polarization senses +[THETHA PHI] = ndgrid(nf2ff.theta,nf2ff.phi); +cosphi = cos(PHI); +sinphi = sin(PHI); + +for f=1:numel(nf2ff.freq) + nf2ff.E_cprh{f} = (cosphi+1i*sinphi) .* (nf2ff.E_theta{f}+1i*nf2ff.E_phi{f})/sqrt(2); + nf2ff.E_cplh{f} = (cosphi-1i*sinphi) .* (nf2ff.E_theta{f}-1i*nf2ff.E_phi{f})/sqrt(2); +end diff --git a/openEMS/matlab/private/invoke_openEMS.m b/openEMS/matlab/private/invoke_openEMS.m new file mode 100644 index 0000000..afb2b46 --- /dev/null +++ b/openEMS/matlab/private/invoke_openEMS.m @@ -0,0 +1,47 @@ +function invoke_openEMS( opts, logfile, silent ) +% function invoke_openEMS( opts, logfile, silent ) +% +% internal method to invoke openEMS, use RunOpenEMS instead +% +% See also RunOpenEMS +% +% openEMS matlab interface +% ----------------------- +% author: Sebastian Held, Thorsten Liebig + +if nargin < 1 + error 'specify the xml file to simulate' +end +if nargin < 3 + silent = 0; +end +if (nargin < 2) || isempty(logfile) + if isunix + logfile = '/dev/null'; + else + logfile = 'nul:'; + end +end + +filename = mfilename('fullpath'); +dir = fileparts( filename ); + +if isunix + openEMS_bin = searchBinary('openEMS.sh', ... + {[dir filesep '..' filesep '..' filesep], ... % try devel path + [dir filesep '..' filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}); % try (default) install path +else % assume windows + openEMS_bin = searchBinary('openEMS.exe', [dir filesep '..' filesep '..' filesep]); +end + +command = [openEMS_bin ' ' opts]; + +if ~silent + if (isunix && nargin>1) + command = [command ' 2>&1 | tee ' logfile]; + end +else + command = [command ' > ' logfile ' 2>&1']; +end + +system(command); diff --git a/openEMS/matlab/queue_addProcess.m b/openEMS/matlab/queue_addProcess.m new file mode 100644 index 0000000..73d4e14 --- /dev/null +++ b/openEMS/matlab/queue_addProcess.m @@ -0,0 +1,22 @@ +function [pid,filenames] = queue_addProcess( command ) +% [pid,filenames] = queue_addProcess( command ) +% +% Sebastian Held +% 12.5.2010 + +if ~isunix + error 'your OS is not supported (Unix only)' +end + +if nargout > 1 + filenames.stdout = tempname; + filenames.stderr = tempname; +else + filenames.stdout = '/dev/null'; + filenames.stderr = '/dev/null'; +end + +cmd = ['(' command ') >' filenames.stdout ' 2>' filenames.stderr ' & echo $!' ]; +[~,result] = unix( cmd ); + +pid = str2double(result); diff --git a/openEMS/matlab/queue_checkProcess.m b/openEMS/matlab/queue_checkProcess.m new file mode 100644 index 0000000..878165a --- /dev/null +++ b/openEMS/matlab/queue_checkProcess.m @@ -0,0 +1,25 @@ +function [alive,stdout,stderr] = queue_checkProcess( pid, filenames ) +% [alive,stdout,stderr] = queue_checkProcess( pid ) +% +% Sebastian Held +% 12.5.2010 + +if ~isunix + error 'your OS is not supported (Unix only)' +end + +if nargout > 1 + fid = fopen( filenames.stdout ); + stdout = fread(fid, '*char')'; + fclose(fid); +end +if nargout > 2 + fid = fopen( filenames.stderr ); + stderr = fread(fid, '*char')'; + fclose(fid); +end + +cmd = ['ps --no-headers -p' num2str(pid) ]; +[status,~] = unix( cmd ); + +alive = (status == 0); diff --git a/openEMS/matlab/queue_delProcess.m b/openEMS/matlab/queue_delProcess.m new file mode 100644 index 0000000..39ab45c --- /dev/null +++ b/openEMS/matlab/queue_delProcess.m @@ -0,0 +1,40 @@ +function [stdout,stderr] = queue_delProcess( pid, filenames ) +% [stdout,stderr] = queue_delProcess( pid, filenames ) +% +% if pid == 0, do not kill a process, but clean up files +% +% Sebastian Held +% 12.5.2010 + +if ~isunix + error 'your OS is not supported (Unix only)' +end + +if pid ~= 0 + alive = queue_checkProcess( pid ); + + if alive + unix( ['kill ' num2str(pid)] ); + alive = queue_checkProcess( pid ); + end + if alive + pause(1) + unix( ['kill ' num2str(pid)] ); + alive = queue_checkProcess( pid ); + end + if alive + unix( ['kill -KILL ' num2str(pid)] ); + end +end + +if nargin > 1 + if nargout == 1 + [~,stdout] = queue_checkProcess( pid, filenames ); + end + if nargout == 2 + [~,stdout,stderr] = queue_checkProcess( pid, filenames ); + end + + delete( filenames.stdout ); + delete( filenames.stderr ); +end diff --git a/openEMS/matlab/setup.m b/openEMS/matlab/setup.m new file mode 100644 index 0000000..e208ad4 --- /dev/null +++ b/openEMS/matlab/setup.m @@ -0,0 +1,40 @@ +function setup() +% function setup() +% +% setup openEMS Matlab/octave interface +% +% openEMS matlab/octave interface +% ----------------------- +% author: Thorsten Liebig (2011-2017) + +disp('setting up openEMS matlab/octave interface') + +% cd to directory of this file and restore current path at the end +current_path = pwd; +dir = fileparts( mfilename('fullpath') ); +cd(dir); + +if isOctave() + disp('compiling oct files') + fflush(stdout); + if isunix + [res, fn_so] = unix('find /usr/lib -name libhdf5.so'); + [res, fn_h] = unix('find /usr/include -name hdf5.h'); + if length(fn_so)>0 && length(fn_h)>0 + [hdf5lib_dir, hdf5lib_fn] = fileparts(fn_so); + disp(["HDF5 library path found at: " hdf5lib_dir]) + + [hdf5inc_dir, hdf5inc_fn] = fileparts(fn_h); + disp(["HDF5 include path found at: " hdf5inc_dir]) + mkoctfile(["-L" hdf5lib_dir " -I" hdf5inc_dir],"-lhdf5", "h5readatt_octave.cc") + else + mkoctfile -lhdf5 h5readatt_octave.cc + end + else + mkoctfile -lhdf5 h5readatt_octave.cc + end +else + disp('Matlab does not need this function. It is Octave only.') +end + +cd(current_path); diff --git a/openEMS/nf2ff/CMakeLists.txt b/openEMS/nf2ff/CMakeLists.txt new file mode 100644 index 0000000..86811b4 --- /dev/null +++ b/openEMS/nf2ff/CMakeLists.txt @@ -0,0 +1,54 @@ + +# define build type +IF( DEFINED CMAKE_BUILD_TYPE ) + SET( CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Set to either \"Release\" or \"Debug\"" ) +ELSE() + SET( CMAKE_BUILD_TYPE Release CACHE STRING "Set to either \"Release\" or \"Debug\"" ) +ENDIF() + +PROJECT(nf2ff CXX) +cmake_minimum_required(VERSION 2.8) + +set(LIB_VERSION_MAJOR 0) +set(LIB_VERSION_MINOR 1) +set(LIB_VERSION_PATCH 0) +set(LIB_VERSION_STRING ${LIB_VERSION_MAJOR}.${LIB_VERSION_MINOR}.${LIB_VERSION_PATCH}) + +set(VERSION "v${LIB_VERSION_STRING}") + +set(SOURCES + nf2ff.cpp + nf2ff_calc.cpp + ../tools/array_ops.cpp + ../tools/useful.cpp + ../tools/hdf5_file_reader.cpp + ../tools/hdf5_file_writer.cpp +) + +#ADD_SUBDIRECTORY( ../tools ) +set(HEADERS + nf2ff.h + nf2ff_calc.h +) + +add_library( nf2ff SHARED ${SOURCES}) +set_target_properties(nf2ff PROPERTIES VERSION ${LIB_VERSION_STRING} SOVERSION ${LIB_VERSION_MAJOR}) + +TARGET_LINK_LIBRARIES( nf2ff + tinyxml + ${HDF5_LIBRARIES} + ${Boost_LIBRARIES} + ${MPI_LIBRARIES} +) + +ADD_EXECUTABLE( nf2ff_bin main.cpp ) +SET_TARGET_PROPERTIES(nf2ff_bin PROPERTIES OUTPUT_NAME nf2ff) +TARGET_LINK_LIBRARIES(nf2ff_bin nf2ff) + +INSTALL(TARGETS nf2ff_bin DESTINATION bin) +INSTALL(TARGETS nf2ff DESTINATION lib${LIB_SUFFIX}) + +INSTALL(FILES ${HEADERS} DESTINATION include/openEMS) + + +#TODO tarball, debug, release diff --git a/openEMS/nf2ff/main.cpp b/openEMS/nf2ff/main.cpp new file mode 100644 index 0000000..c8784f3 --- /dev/null +++ b/openEMS/nf2ff/main.cpp @@ -0,0 +1,44 @@ +/* +* Copyright (C) 2012-2014 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 . +*/ + +#include + +#include "nf2ff.h" + +using namespace std; + +int main(int argc, char *argv[]) +{ + cout << " ---------------------------------------------------------------------- " << endl; + cout << " | nf2ff, near-field to far-field transformation for openEMS " << endl; + cout << " | (C) 2012-2014 Thorsten Liebig GPL license" << endl; + cout << " ---------------------------------------------------------------------- " << endl; + + if (argc<=1) + { + cout << " Usage: nf2ff " << endl << endl; + cout << endl; + exit(-1); + } + + if (argc>=2) + { + return !nf2ff::AnalyseXMLFile(argv[argc-1]); + } + + return 0; +} diff --git a/openEMS/nf2ff/nf2ff.cpp b/openEMS/nf2ff/nf2ff.cpp new file mode 100644 index 0000000..62c9238 --- /dev/null +++ b/openEMS/nf2ff/nf2ff.cpp @@ -0,0 +1,661 @@ +/* +* Copyright (C) 2012-2014 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 . +*/ + +#include "nf2ff.h" +#include "nf2ff_calc.h" +#include "../tools/array_ops.h" +#include "../tools/useful.h" +#include "../tools/hdf5_file_reader.h" +#include "../tools/hdf5_file_writer.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//external libs +#include "tinyxml.h" + +using namespace std; + +nf2ff::nf2ff(vector freq, vector theta, vector phi, vector center, unsigned int numThreads) +{ + m_freq = freq; + + m_numTheta = theta.size(); + m_theta = new float[m_numTheta]; + for (size_t n=0;nSetNumThreads(numThreads); + } + m_radius = 1; + m_Verbose = 0; +} + +nf2ff::~nf2ff() +{ + m_freq.clear(); + for (size_t fn=0;fnSetRadius(radius); +} + +void nf2ff::SetPermittivity(vector permittivity) +{ + if (permittivity.size()==0) + return; + + m_permittivity = permittivity; + if (permittivity.size()==1) + { + for (size_t fn=0;fnSetPermittivity(permittivity.at(0)); + return; + } + + if (permittivity.size()!=m_freq.size()) + { + cerr << __func__ << ": Error, permittivity vector size must match number of set frequencies! skipping!" << endl; + return; + } + for (size_t fn=0;fnSetPermittivity(permittivity.at(fn)); +} + +void nf2ff::SetPermeability(vector permeability) +{ + if (permeability.size()==0) + return; + + m_permeability = permeability; + if (permeability.size()==1) + { + for (size_t fn=0;fnSetPermeability(permeability.at(0)); + return; + } + + if (permeability.size()!=m_freq.size()) + { + cerr << __func__ << ": Error, permeability vector size must match number of set frequencies! skipping!" << endl; + return; + } + for (size_t fn=0;fnSetPermeability(permeability.at(fn)); +} + +void nf2ff::SetMirror(int type, int dir, float pos) +{ + if (m_Verbose>0) + cerr << "Enable mirror of type: "<< type << " in direction: " << dir << " at: " << pos << endl; + for (size_t fn=0;fnSetMirror(type, dir, pos); +} + +bool nf2ff::AnalyseXMLNode(TiXmlElement* ti_nf2ff) +{ + if (ti_nf2ff==NULL) + return false; + + unsigned int numThreads=0; + int ihelp=0; + if (ti_nf2ff->QueryIntAttribute("NumThreads",&ihelp) == TIXML_SUCCESS) + { + numThreads = ihelp; + cerr << "nf2ff: Set number of threads to: " << numThreads << endl; + } + int Verbose=0; + if (ti_nf2ff->QueryIntAttribute("Verbose",&Verbose) == TIXML_SUCCESS) + cerr << "nf2ff: Set verbose level to " << Verbose << endl; + else + Verbose = 0; + + const char* attr = NULL; + attr = ti_nf2ff->Attribute("freq"); + if (attr==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read frequency inforamtions ... " << endl; + return false; + } + vector freq = SplitString2Float(attr); + + vector center; + attr = ti_nf2ff->Attribute("Center"); + if (attr!=NULL) + center = SplitString2Float(attr); + + attr = ti_nf2ff->Attribute("Outfile"); + if (attr==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read frequency inforamtions ... " << endl; + return false; + } + string outfile = string(attr); + if (outfile.empty()) + { + cerr << "nf2ff::AnalyseXMLNode: outfile is empty, skipping nf2ff... " << endl; + return false; + } + + TiXmlElement* ti_theta = ti_nf2ff->FirstChildElement("theta"); + if (ti_theta==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read theta values ... " << endl; + return false; + } + TiXmlNode* ti_theta_node = ti_theta->FirstChild(); + if (ti_theta_node==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read theta text child ... " << endl; + return false; + } + TiXmlText* ti_theta_text = ti_theta_node->ToText(); + if (ti_theta_text==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read theta text values ... " << endl; + return false; + } + vector theta = SplitString2Float(ti_theta_text->Value()); + + TiXmlElement* ti_phi = ti_nf2ff->FirstChildElement("phi"); + if (ti_phi==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read phi values ... " << endl; + return false; + } + TiXmlNode* ti_phi_node = ti_phi->FirstChild(); + if (ti_phi_node==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read phi text child ... " << endl; + return false; + } + TiXmlText* ti_phi_text = ti_phi_node->ToText(); + if (ti_phi_text==NULL) + { + cerr << "nf2ff::AnalyseXMLNode: Can't read phi text values ... " << endl; + return false; + } + vector phi = SplitString2Float(ti_phi_text->Value()); + + nf2ff* l_nf2ff = new nf2ff(freq,theta,phi,center,numThreads); + l_nf2ff->SetVerboseLevel(Verbose); + + attr = ti_nf2ff->Attribute("Eps_r"); + if (attr!=NULL) + l_nf2ff->SetPermittivity(SplitString2Float(attr)); + + attr = ti_nf2ff->Attribute("Mue_r"); + if (attr!=NULL) + l_nf2ff->SetPermeability(SplitString2Float(attr)); + + float radius = 1; + if (ti_nf2ff->QueryFloatAttribute("Radius",&radius) == TIXML_SUCCESS) + l_nf2ff->SetRadius(radius); + + // read mirrors + TiXmlElement* ti_Mirros = ti_nf2ff->FirstChildElement("Mirror"); + int dir=-1; + string type; + float pos=0.0; + while (ti_Mirros!=NULL) + { + type = string(ti_Mirros->Attribute("Type")); + if (ti_Mirros->QueryIntAttribute("Dir",&dir) != TIXML_SUCCESS) + dir = -1; + if (ti_Mirros->QueryFloatAttribute("Pos",&pos) != TIXML_SUCCESS) + dir = -1; + if ((dir>=0) && (strcmp(type.c_str(),"PEC")==0)) + l_nf2ff->SetMirror(MIRROR_PEC, dir, pos); + else if ((dir>=0) && (strcmp(type.c_str(),"PMC")==0)) + l_nf2ff->SetMirror(MIRROR_PMC, dir, pos); + ti_Mirros = ti_Mirros->NextSiblingElement("Mirror"); + } + + TiXmlElement* ti_Planes = ti_nf2ff->FirstChildElement("Planes"); + string E_name; + string H_name; + while (ti_Planes!=NULL) + { + E_name = string(ti_Planes->Attribute("E_Field")); + H_name = string(ti_Planes->Attribute("H_Field")); + if ((!E_name.empty()) && (!H_name.empty())) + { + if (l_nf2ff->AnalyseFile(E_name,H_name)==false) + { + cerr << "nf2ff::AnalyseXMLNode: Error, analysing Plane ... " << endl; + return false; + } + } + else + { + cerr << "nf2ff::AnalyseXMLNode: Error, invalid plane entry ... " << endl; + return false; + } + ti_Planes = ti_Planes->NextSiblingElement("Planes"); + } + l_nf2ff->Write2HDF5(outfile); + delete l_nf2ff; + return true; +} + +bool nf2ff::AnalyseXMLFile(string filename) +{ + TiXmlDocument doc(filename.c_str()); + if (!doc.LoadFile()) + { + cerr << "nf2ff::AnalyseXMLFile: Error loading xml-file failed!!! File: " << filename << endl; + return false; + } + TiXmlElement* ti_nf2ff = doc.FirstChildElement("nf2ff"); + if (ti_nf2ff==NULL) + { + cerr << "nf2ff::AnalyseXMLFile: Can't read nf2ff ... " << endl; + return false; + } + + return AnalyseXMLNode(ti_nf2ff); +} + +bool nf2ff::AnalyseFile(string E_Field_file, string H_Field_file) +{ + HDF5_File_Reader E_file(E_Field_file); + HDF5_File_Reader H_file(H_Field_file); + + if (m_Verbose>0) + cerr << "nf2ff: Reading planes: " << E_Field_file << " & " << H_Field_file << endl; + + // read E-mesh + float* E_lines[3]={NULL,NULL,NULL}; + unsigned int E_numLines[3]; + int E_meshType; + if (E_file.ReadMesh(E_lines, E_numLines, E_meshType) == false) + { + cerr << "nf2ff::AnalyseFile: Error reading E-field mesh..." << endl; + return false; + } + + // read H-mesh + float* H_lines[3]={NULL,NULL,NULL}; + unsigned int H_numLines[3]; + int H_meshType; + if (H_file.ReadMesh(H_lines, H_numLines, H_meshType) == false) + { + cerr << "nf2ff::AnalyseFile: Error reading H-Field mesh..." << endl; + for (int n=0;n<3;++n) + delete[] E_lines[n]; + return false; + } + + // compare E/H meshs + if (E_meshType!=H_meshType) + { + cerr << "nf2ff::AnalyseFile: Error mesh types don't agree" << endl; + for (int n=0;n<3;++n) + { + delete[] H_lines[n]; + delete[] E_lines[n]; + } + return false; + } + if ((E_numLines[0]!=H_numLines[0]) || (E_numLines[1]!=H_numLines[1]) || (E_numLines[2]!=H_numLines[2])) + { + cerr << "nf2ff::AnalyseFile: Error mesh dimensions don't agree" << endl; + for (int n=0;n<3;++n) + { + delete[] H_lines[n]; + delete[] E_lines[n]; + } + return false; + } + for (int n=0;n<3;++n) + for (unsigned int m=0;m0) + cerr << "nf2ff: Data-Size: " << E_numLines[0] << "x" << E_numLines[1] << "x" << E_numLines[2] << endl; + + // test if FD data available or fallback to TD is necessary + bool fallBack_TD=false; + vector FD_freq; + if (E_file.ReadFrequencies(FD_freq)==false) + fallBack_TD = true; + if (FD_freq.size()>0) + { + vector H_freq; + if (H_file.ReadFrequencies(H_freq)==false) + { + cerr << "nf2ff::AnalyseFile: Error, number of FD data mismatch, fallback to TD data..." << endl; + fallBack_TD = true; + } + else + { + for (size_t nf=0;nf FD_index; + if (fallBack_TD==false) + { + FD_index.resize(FD_freq.size(),-1); + + for (size_t n=0;n****> E_fd_data; + vector****> H_fd_data; + + if (m_Verbose>1) + cerr << "nf2ff: calculate dft..." << endl; + + unsigned int data_size[4]; + if (E_file.CalcFDVectorData(m_freq,E_fd_data,data_size)==false) + { + for (int n=0;n<3;++n) + delete[] E_lines[n]; + return false; + } + if ((data_size[0]!=E_numLines[0]) || (data_size[1]!=E_numLines[1]) || (data_size[2]!=E_numLines[2]) ) + { + for (size_t fn=0;fn >(E_fd_data.at(fn),data_size); + } + for (int n=0;n<3;++n) + delete[] E_lines[n]; + return false; + } + + if (H_file.CalcFDVectorData(m_freq,H_fd_data,data_size)==false) + { + for (size_t fn=0;fn >(E_fd_data.at(fn),data_size); + for (int n=0;n<3;++n) + delete[] E_lines[n]; + return false; + } + if ((data_size[0]!=E_numLines[0]) || (data_size[1]!=E_numLines[1]) || (data_size[2]!=E_numLines[2]) ) + { + for (size_t fn=0;fn >(E_fd_data.at(fn),data_size); + Delete_N_3DArray >(H_fd_data.at(fn),data_size); + } + for (int n=0;n<3;++n) + delete[] E_lines[n]; + return false; + } + + if (m_Verbose>0) + cerr << "nf2ff: Analysing far-field for " << m_nf2ff.size() << " frequencies. " << endl; + + for (size_t fn=0;fn1) + cerr << "nf2ff: f = " << m_freq.at(fn) << "Hz (" << fn+1 << "/" << m_freq.size() << ") ..."; + m_nf2ff.at(fn)->AddPlane(E_lines, E_numLines, E_fd_data.at(fn), H_fd_data.at(fn),E_meshType); + if (m_Verbose>1) + cerr << " done." << endl; + } + + } + else + { + complex**** E_fd_data; + complex**** H_fd_data; + unsigned int data_size[4]; + for (size_t n=0;n >(E_fd_data,data_size); + for (int n=0;n<3;++n) + delete[] E_lines[n]; + return false; + } + + H_fd_data = H_file.GetFDVectorData(FD_index.at(n),data_size); + if ((data_size[0]!=E_numLines[0]) || (data_size[1]!=E_numLines[1]) || (data_size[2]!=E_numLines[2]) ) + { + cerr << data_size[0] << "," << data_size[1] << "," << data_size[2] << endl; + cerr << "nf2ff::AnalyseFile: FD data size mismatch... " << endl; + Delete_N_3DArray >(H_fd_data,data_size); + Delete_N_3DArray >(E_fd_data,data_size); + for (int n=0;n<3;++n) + delete[] E_lines[n]; + return false; + } + + if ((E_fd_data==NULL) || (H_fd_data==NULL)) + { + cerr << "nf2ff::AnalyseFile: Reaing FD data failed... " << endl; + Delete_N_3DArray >(E_fd_data,data_size); + Delete_N_3DArray >(H_fd_data,data_size); + for (int n=0;n<3;++n) + delete[] E_lines[n]; + return false; + } + if (m_Verbose>1) + cerr << "nf2ff: f = " << m_freq.at(n) << "Hz (" << n+1 << "/" << m_freq.size() << ") ..."; + m_nf2ff.at(n)->AddPlane(E_lines, E_numLines, E_fd_data, H_fd_data,E_meshType); + if (m_Verbose>1) + cerr << " done." << endl; + } + } + + for (int n=0;n<3;++n) + delete[] E_lines[n]; + + return true; +} + +bool nf2ff::Write2HDF5(string filename) +{ + HDF5_File_Writer hdf_file(filename); + + //write mesh information + hdf_file.SetCurrentGroup("/Mesh"); + size_t meshsize[1]={m_numTheta}; + if (hdf_file.WriteData(string("theta"),m_theta,1,meshsize)==false) + return false; + meshsize[0]=m_numPhi; + if (hdf_file.WriteData(string("phi"),m_phi,1,meshsize)==false) + return false; + meshsize[0]=1; + float rad[1]={m_radius}; + if (hdf_file.WriteData(string("r"),rad,1,meshsize)==false) + return false; + + float attr_value = 2; + hdf_file.WriteAtrribute("/Mesh", "MeshType", &attr_value, 1); + + //write field data + size_t dim = 2; + size_t pos = 0; + size_t datasize[2]={m_numPhi,m_numTheta}; + size_t size = datasize[0]*datasize[1]; + double* buffer = new double[size]; + complex** field_data; + string field_names[2]={"E_theta", "E_phi"}; + for (int n=0;n<2;++n) + { + hdf_file.SetCurrentGroup("/nf2ff/" + field_names[n] + "/FD"); + for (size_t fn=0;fn0) + { + buffer = new double[m_permittivity.size()]; + for (size_t n=0;n0) + { + buffer = new double[m_permeability.size()]; + for (size_t n=0;n. +*/ + +#ifndef NF2FF_H +#define NF2FF_H + +#include +#include +#include +#include +#include +#include "nf2ff_calc.h" + +using namespace std; + +class TiXmlElement; + +class nf2ff +{ +public: + nf2ff(vector freq, vector theta, vector phi, vector center, unsigned int numThreads=0); + ~nf2ff(); + + bool AnalyseFile(string E_Field_file, string H_Field_file); + + void SetRadius(float radius); + void SetPermittivity(vector permittivity); + void SetPermeability(vector permeability); + + void SetMirror(int type, int dir, float pos); + + double GetTotalRadPower(size_t f_idx) const {return m_nf2ff.at(f_idx)->GetTotalRadPower();} + double GetMaxDirectivity(size_t f_idx) const {return m_nf2ff.at(f_idx)->GetMaxDirectivity();} + + complex** GetETheta(size_t f_idx) const {return m_nf2ff.at(f_idx)->GetETheta();} + complex** GetEPhi(size_t f_idx) const {return m_nf2ff.at(f_idx)->GetEPhi();} + double** GetRadPower(size_t f_idx) const {return m_nf2ff.at(f_idx)->GetRadPower();} + + //! Write results to a hdf5 file + bool Write2HDF5(string filename); + + void SetVerboseLevel(int level) {m_Verbose=level;} + + static bool AnalyseXMLNode(TiXmlElement* ti_nf2ff); + static bool AnalyseXMLFile(string filename); + +protected: + vector m_freq; + vector m_permittivity; + vector m_permeability; + unsigned int m_numTheta; + unsigned int m_numPhi; + float* m_theta; + float* m_phi; + float m_radius; + int m_Verbose; + vector m_nf2ff; +}; + +#endif // NF2FF_H diff --git a/openEMS/nf2ff/nf2ff_calc.cpp b/openEMS/nf2ff/nf2ff_calc.cpp new file mode 100644 index 0000000..335dd9a --- /dev/null +++ b/openEMS/nf2ff/nf2ff_calc.cpp @@ -0,0 +1,513 @@ +/* +* Copyright (C) 2012-2014 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 . +*/ + +#include "nf2ff_calc.h" +#include "../tools/array_ops.h" +#include "../tools/useful.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +nf2ff_calc_thread::nf2ff_calc_thread(nf2ff_calc* nfc, unsigned int start, unsigned int stop, unsigned int threadID, nf2ff_data &data) +{ + m_nf_calc = nfc; + m_start = start; + m_stop = stop; + m_threadID = threadID; + m_data = data; +} + +void nf2ff_calc_thread::operator()() +{ + m_nf_calc->m_Barrier->wait(); // start + + int ny = m_data.ny; + int nP = (ny+1)%3; + int nPP = (ny+2)%3; + + unsigned int* numLines = m_data.numLines; + float* normDir = m_data.normDir; + float **lines = m_data.lines; + float* edge_length_P = m_data.edge_length_P; + float* edge_length_PP = m_data.edge_length_PP; + + unsigned int pos[3]; + unsigned int pos_t=0; + unsigned int num_t=m_stop-m_start+1; + + + complex**** Js=m_data.Js; + complex**** Ms=m_data.Ms; + complex**** E_field=m_data.E_field; + complex**** H_field=m_data.H_field; + + int mesh_type = m_data.mesh_type; + + // calc Js and Ms (eq. 8.15a/b) + pos[ny]=0; + for (pos_t=0; pos_t** m_Nt=m_data.m_Nt; + complex** m_Np=m_data.m_Np; + complex** m_Lt=m_data.m_Lt; + complex** m_Lp=m_data.m_Lp; + + float center[3] = {m_nf_calc->m_centerCoord[0],m_nf_calc->m_centerCoord[1],m_nf_calc->m_centerCoord[2]}; + if (mesh_type==1) + { + center[0] = m_nf_calc->m_centerCoord[0]*cos(m_nf_calc->m_centerCoord[1]); + center[1] = m_nf_calc->m_centerCoord[0]*sin(m_nf_calc->m_centerCoord[1]); + } + // calc local Nt,Np,Lt and Lp + float area; + float cosT_cosP,cosP_sinT; + float cosT_sinP,sinT_sinP; + float sinT,sinP; + float cosP,cosT; + float r_cos_psi; + float k = 2*M_PI*m_nf_calc->m_freq/__C0__*sqrt(m_nf_calc->m_permittivity*m_nf_calc->m_permeability); + complex exp_jkr; + complex _I_(0,1); + for (unsigned int tn=0;tnm_numTheta;++tn) + for (unsigned int pn=0;pnm_numPhi;++pn) + { + sinT = sin(m_nf_calc->m_theta[tn]); + sinP = sin(m_nf_calc->m_phi[pn]); + cosT = cos(m_nf_calc->m_theta[tn]); + cosP = cos(m_nf_calc->m_phi[pn]); + cosT_cosP = cosT*cosP; + cosT_sinP = cosT*sinP; + cosP_sinT = cosP*sinT; + sinT_sinP = sinP*sinT; + + for (pos_t=0; pos_tm_Barrier->wait(); //combine all thread local Nt,Np,Lt and Lp + + m_nf_calc->m_Barrier->wait(); //wait for termination +} + + +/***********************************************************************/ + + +nf2ff_calc::nf2ff_calc(float freq, vector theta, vector phi, vector center) +{ + m_freq = freq; + m_permittivity = 1; + m_permeability = 1; + + m_numTheta = theta.size(); + m_theta = new float[m_numTheta]; + for (size_t n=0;n >(numLines); + m_E_phi = Create2DArray >(numLines); + m_H_theta = Create2DArray >(numLines); + m_H_phi = Create2DArray >(numLines); + m_P_rad = Create2DArray(numLines); + + if (center.size()==3) + { + m_centerCoord[0]=center.at(0); + m_centerCoord[1]=center.at(1); + m_centerCoord[2]=center.at(2); + } + else if (center.size()>0) + { + cerr << "nf2ff_calc::nf2ff_calc: Warning: Center coordinates error, ignoring!" << endl; + m_centerCoord[0]=m_centerCoord[1]=m_centerCoord[2]=0.0; + } + else + m_centerCoord[0]=m_centerCoord[1]=m_centerCoord[2]=0.0; + + m_radPower = 0; + m_maxDir = 0; + m_radius = 1; + + for (int n=0;n<3;++n) + { + m_MirrorType[n] = MIRROR_OFF; + m_MirrorPos[n] = 0.0; + } + + m_Barrier = NULL; + m_numThreads = boost::thread::hardware_concurrency(); +} + +nf2ff_calc::~nf2ff_calc() +{ + delete[] m_phi; + m_phi = NULL; + delete[] m_theta; + m_theta = NULL; + + unsigned int numLines[2] = {m_numTheta, m_numPhi}; + Delete2DArray(m_E_theta,numLines); + m_E_theta = NULL; + Delete2DArray(m_E_phi,numLines); + m_E_phi = NULL; + Delete2DArray(m_H_theta,numLines); + m_H_theta = NULL; + Delete2DArray(m_H_phi,numLines); + m_H_phi = NULL; + Delete2DArray(m_P_rad,numLines); + m_P_rad = NULL; + + delete m_Barrier; + m_Barrier = NULL; +} + +int nf2ff_calc::GetNormalDir(unsigned int* numLines) +{ + int ny = -1; + int nP,nPP; + for (int n=0;n<3;++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + if ((numLines[n]==1) && (numLines[nP]>2) && (numLines[nPP]>2)) + ny=n; + } + return ny; +} + +void nf2ff_calc::SetMirror(int type, int dir, float pos) +{ + if ((dir<0) || (dir>3)) + { + cerr << "nf2ff_calc::SetMirror: Error, invalid direction!" << endl; + return; + } + if ((type!=MIRROR_PEC) && (type!=MIRROR_PMC)) + { + cerr << "nf2ff_calc::SetMirror: Error, invalid type!" << endl; + return; + } + m_MirrorType[dir] = type; + m_MirrorPos[dir] = pos; +} + +bool nf2ff_calc::AddMirrorPlane(int n, float **lines, unsigned int* numLines, complex**** E_field, complex**** H_field, int MeshType) +{ + float E_factor[3] = {1,1,1}; + float H_factor[3] = {1,1,1}; + + int nP = (n+1)%3; + int nPP = (n+2)%3; + + // mirror in ny direction + for (unsigned int i=0;iAddSinglePlane(lines, numLines, E_field, H_field, MeshType); +} + +bool nf2ff_calc::AddPlane(float **lines, unsigned int* numLines, complex**** E_field, complex**** H_field, int MeshType) +{ + this->AddSinglePlane(lines, numLines, E_field, H_field, MeshType); + + for (int n=0;n<3;++n) + { + int nP = (n+1)%3; + int nPP = (n+2)%3; + // check if a single mirror plane is on + 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); + break; + } + //check if two planes are on + else if ((m_MirrorType[n]==MIRROR_OFF) && (m_MirrorType[nP]!=MIRROR_OFF) && (m_MirrorType[nPP]!=MIRROR_OFF)) + { + 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); + break; + } + } + // check if all planes are on + if ((m_MirrorType[0]!=MIRROR_OFF) && (m_MirrorType[1]!=MIRROR_OFF) && (m_MirrorType[2]!=MIRROR_OFF)) + { + 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); + this->AddMirrorPlane(2, lines, numLines, E_field, H_field, MeshType); + 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); + } + + //cleanup E- & H-Fields + Delete_N_3DArray(E_field,numLines); + Delete_N_3DArray(H_field,numLines); + return true; +} + +bool nf2ff_calc::AddSinglePlane(float **lines, unsigned int* numLines, complex**** E_field, complex**** H_field, int MeshType) +{ + //find normal direction + int ny = this->GetNormalDir(numLines); + if (ny<0) + { + cerr << "nf2ff_calc::AddPlane: Error can't determine normal direction..." << endl; + return false; + } + int nP = (ny+1)%3; + int nPP = (ny+2)%3; + + complex**** Js = Create_N_3DArray >(numLines); + complex**** Ms = Create_N_3DArray >(numLines); + + float normDir[3]= {0,0,0}; + if (lines[ny][0]>=m_centerCoord[ny]) + normDir[ny]=1; + else + normDir[ny]=-1; + unsigned int pos[3]; + + float edge_length_P[numLines[nP]]; + for (unsigned int n=1;n power = 0; + double area; + for (pos[0]=0; pos[0] jpt = AssignJobs2Threads(numLines[nP], m_numThreads, true); + m_numThreads = jpt.size(); + nf2ff_data thread_data[m_numThreads]; + m_Barrier = new boost::barrier(m_numThreads+1); // numThread workers + 1 controller + unsigned int start=0; + unsigned int stop=jpt.at(0)-1; + for (unsigned int n=0; n >(numAngles); + thread_data[n].m_Np=Create2DArray >(numAngles); + thread_data[n].m_Lt=Create2DArray >(numAngles); + thread_data[n].m_Lp=Create2DArray >(numAngles); + + boost::thread *t = new boost::thread( nf2ff_calc_thread(this,start,stop,n,thread_data[n]) ); + + m_thread_group.add_thread( t ); + + start = stop+1; + if (nwait(); //start + + // threads: calc Js and Ms (eq. 8.15a/b) + // threads calc their local Nt,Np,Lt and Lp + + m_Barrier->wait(); //combine all thread local Nt,Np,Lt and Lp + + complex** Nt = Create2DArray >(numAngles); + complex** Np = Create2DArray >(numAngles); + complex** Lt = Create2DArray >(numAngles); + complex** Lp = Create2DArray >(numAngles); + + for (unsigned int n=0; nwait(); //wait for termination + m_thread_group.join_all(); // wait for termination + delete m_Barrier; + m_Barrier = NULL; + + //cleanup Js & Ms + Delete_N_3DArray(Js,numLines); + Delete_N_3DArray(Ms,numLines); + + // calc equations 8.23a/b and 8.24a/b + float k = 2*M_PI*m_freq/__C0__*sqrt(m_permittivity*m_permeability); + complex factor(0,k/4.0/M_PI/m_radius); + complex f_exp(0,-1*k*m_radius); + factor *= exp(f_exp); + float fZ0 = __Z0__ * sqrt(m_permeability/m_permittivity); + complex Z0 = fZ0; + float P_max = 0; + for (unsigned int tn=0;tnP_max) + P_max = m_P_rad[tn][pn]; + } + + //cleanup Nx and Lx + Delete2DArray(Nt,numAngles); + Delete2DArray(Np,numAngles); + Delete2DArray(Lt,numAngles); + Delete2DArray(Lp,numAngles); + + m_maxDir = 4*M_PI*P_max / m_radPower; + + return true; +} diff --git a/openEMS/nf2ff/nf2ff_calc.h b/openEMS/nf2ff/nf2ff_calc.h new file mode 100644 index 0000000..ab46e5e --- /dev/null +++ b/openEMS/nf2ff/nf2ff_calc.h @@ -0,0 +1,136 @@ +/* +* Copyright (C) 2012-2014 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 . +*/ + +#ifndef NF2FF_CALC_H +#define NF2FF_CALC_H + +#include +#include +#include +#include +#include +#include + +class nf2ff_calc; + +#define MIRROR_OFF 0 +#define MIRROR_PEC 1 +#define MIRROR_PMC 2 + +// data structure to exchange data between thread-controller and worker-threads +typedef struct +{ + //local working data IN + int ny; + int mesh_type; + float* normDir; + unsigned int* numLines; + float **lines; + float* edge_length_P; + float* edge_length_PP; + + std::complex**** E_field; + std::complex**** H_field; + std::complex**** Js; + std::complex**** Ms; + + //local working data OUT + std::complex** m_Nt; + std::complex** m_Np; + std::complex** m_Lt; + std::complex** m_Lp; + +} nf2ff_data; + +class nf2ff_calc_thread +{ +public: + nf2ff_calc_thread(nf2ff_calc* nfc, unsigned int start, unsigned int stop, unsigned int threadID, nf2ff_data &data); + void operator()(); + +protected: + unsigned int m_start, m_stop, m_threadID; + nf2ff_calc *m_nf_calc; + + nf2ff_data m_data; +}; + +class nf2ff_calc +{ + // allow full data access to nf2ff_calc_thread class + friend class nf2ff_calc_thread; +public: + nf2ff_calc(float freq, std::vector theta, std::vector phi, std::vector center); + ~nf2ff_calc(); + + void SetRadius(float radius) {m_radius=radius;} + void SetPermittivity(float permittivity) {m_permittivity=permittivity;} + void SetPermeability(float permeability) {m_permeability=permeability;} + + double GetTotalRadPower() const {return m_radPower;} + double GetMaxDirectivity() const {return m_maxDir;} + + std::complex** GetETheta() const {return m_E_theta;} + std::complex** GetEPhi() const {return m_E_phi;} + double** GetRadPower() const {return m_P_rad;} + + unsigned int GetNumThreads() const {return m_numThreads;} + void SetNumThreads(unsigned int n) {m_numThreads=n;} + + void SetMirror(int type, int dir, float pos); + + bool AddPlane(float **lines, unsigned int* numLines, std::complex**** E_field, std::complex**** H_field, int MeshType=0); + +protected: + float m_freq; + float m_radius; + + float m_permittivity; //relative electric permittivity + float m_permeability; //relative magnetic permeability + + double m_radPower; + double m_maxDir; + + std::complex** m_E_theta; + std::complex** m_E_phi; + std::complex** m_H_theta; + std::complex** m_H_phi; + double** m_P_rad; + + float m_centerCoord[3]; + unsigned int m_numTheta; + unsigned int m_numPhi; + float* m_theta; + float* m_phi; + + //mirror settings + bool m_EnableMirror; + int m_MirrorType[3]; + float m_MirrorPos[3]; + + int GetNormalDir(unsigned int* numLines); + bool AddSinglePlane(float **lines, unsigned int* numLines, std::complex**** E_field, std::complex**** H_field, int MeshType=0); + bool AddMirrorPlane(int n, float **lines, unsigned int* numLines, std::complex**** E_field, std::complex**** H_field, int MeshType=0); + + //boost multi-threading + unsigned int m_numThreads; + boost::thread_group m_thread_group; + boost::barrier *m_Barrier; +}; + + +#endif // NF2FF_CALC_H diff --git a/openEMS/openEMS.sh b/openEMS/openEMS.sh new file mode 100755 index 0000000..fe5e5e1 --- /dev/null +++ b/openEMS/openEMS.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +#clear LD_LIBRARY_PATH +export LD_LIBRARY_PATH= + +#get path to openEMS +openEMS_PATH=`dirname $0` + +#execute openEMS +exec $openEMS_PATH/openEMS $@ + diff --git a/openEMS/openEMS_MPI.sh b/openEMS/openEMS_MPI.sh new file mode 100755 index 0000000..c46f0fa --- /dev/null +++ b/openEMS/openEMS_MPI.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +#clear LD_LIBRARY_PATH +export LD_LIBRARY_PATH= + +#get path to openEMS +openEMS_PATH=`dirname $0` + +#execute openEMS +exec mpirun -l -n 2 $openEMS_PATH/openEMS $@ + diff --git a/openEMS/openems.cpp b/openEMS/openems.cpp new file mode 100644 index 0000000..1d08ef7 --- /dev/null +++ b/openEMS/openems.cpp @@ -0,0 +1,1232 @@ +/* +* Copyright (C) 2010-2015 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 . +*/ + +#include "openems.h" +#include +#include +#include +#include "tools/array_ops.h" +#include "tools/useful.h" +#include "FDTD/operator_cylinder.h" +#include "FDTD/operator_cylindermultigrid.h" +#include "FDTD/engine_multithread.h" +#include "FDTD/operator_multithread.h" +#include "FDTD/extensions/operator_ext_excitation.h" +#include "FDTD/extensions/operator_ext_tfsf.h" +#include "FDTD/extensions/operator_ext_mur_abc.h" +#include "FDTD/extensions/operator_ext_upml.h" +#include "FDTD/extensions/operator_ext_lorentzmaterial.h" +#include "FDTD/extensions/operator_ext_conductingsheet.h" +#include "FDTD/extensions/operator_ext_steadystate.h" +#include "FDTD/extensions/engine_ext_steadystate.h" +#include "FDTD/engine_interface_fdtd.h" +#include "FDTD/engine_interface_cylindrical_fdtd.h" +#include "Common/processvoltage.h" +#include "Common/processcurrent.h" +#include "Common/processfieldprobe.h" +#include "Common/processmodematch.h" +#include "Common/processfields_td.h" +#include "Common/processfields_fd.h" +#include "Common/processfields_sar.h" +#include // only for H5get_libversion() +#include // only for BOOST_LIB_VERSION +#include + +//external libs +#include "tinyxml.h" +#include "ContinuousStructure.h" +#include "CSPropProbeBox.h" +#include "CSPropDumpBox.h" + +using namespace std; + +double CalcDiffTime(timeval t1, timeval t2) +{ + double s_diff = t1.tv_sec - t2.tv_sec; + s_diff += (t1.tv_usec-t2.tv_usec)*1e-6; + return s_diff; +} + +openEMS::openEMS() +{ + FDTD_Op=NULL; + FDTD_Eng=NULL; + Eng_Ext_SSD=NULL; + m_CSX=NULL; + PA=NULL; + CylinderCoords = false; + Enable_Dumps = true; + DebugMat = false; + DebugOp = false; + m_debugCSX = false; + m_debugBox = m_debugPEC = m_no_simulation = false; + m_DumpStats = false; + endCrit = 1e-6; + m_OverSampling = 4; + m_CellConstantMaterial=false; + + m_engine = EngineType_Multithreaded; //default engine type + m_engine_numThreads = 0; + + m_Abort = false; + m_Exc = 0; + + m_TS_method=3; + m_TS=0; + m_TS_fac=1.0; + m_maxTime=0.0; + + for (int n=0;n<6;++n) + { + m_BC_type[n] = 0; + m_PML_size[n] = 8; + m_Mur_v_ph[n] = 0; + } +} + +openEMS::~openEMS() +{ + Reset(); +} + +void openEMS::Reset() +{ + if (PA) PA->DeleteAll(); + delete PA; + PA=0; + delete FDTD_Eng; + FDTD_Eng=0; + delete FDTD_Op; + FDTD_Op=0; + delete m_CSX; + m_CSX=0; + delete m_Exc; + m_Exc=0; +} + +void openEMS::showUsage() +{ + cout << " Usage: openEMS [...]" << endl << endl; + cout << " " << endl; + cout << "\t--disable-dumps\t\tDisable all field dumps for faster simulation" << endl; + cout << "\t--debug-material\tDump material distribution to a vtk file for debugging" << endl; + cout << "\t--debug-PEC\t\tDump metal distribution to a vtk file for debugging" << endl; + cout << "\t--debug-operator\tDump operator to vtk file for debugging" << endl; + cout << "\t--debug-boxes\t\tDump e.g. probe boxes to vtk file for debugging" << endl; + cout << "\t--debug-CSX\t\tWrite CSX geometry file to debugCSX.xml" << endl; + cout << "\t--engine=\t\tChoose engine type" << endl; + cout << "\t\t--engine=fastest\t\tfastest available engine (default)" << endl; + cout << "\t\t--engine=basic\t\t\tbasic FDTD engine" << endl; + cout << "\t\t--engine=sse\t\t\tengine using sse vector extensions" << endl; + cout << "\t\t--engine=sse-compressed\t\tengine using compressed operator + sse vector extensions" << endl; +#ifdef MPI_SUPPORT + cout << "\t\t--engine=MPI\t\t\tengine using compressed operator + sse vector extensions + MPI parallel processing" << endl; + cout << "\t\t--engine=multithreaded\t\tengine using compressed operator + sse vector extensions + MPI + multithreading" << endl; +#else + cout << "\t\t--engine=multithreaded\t\tengine using compressed operator + sse vector extensions + multithreading" << endl; +#endif + cout << "\t--numThreads=\tForce use n threads for multithreaded engine (needs: --engine=multithreaded)" << endl; + cout << "\t--no-simulation\t\tonly run preprocessing; do not simulate" << endl; + cout << "\t--dump-statistics\tdump simulation statistics to '" << __OPENEMS_RUN_STAT_FILE__ << "' and '" << __OPENEMS_STAT_FILE__ << "'" << endl; + cout << "\n\t Additional global arguments " << endl; + g_settings.ShowArguments(cout,"\t"); + cout << endl; +} + +//! \brief processes a command line argument +//! \return true if argument is known +//! \return false if argument is unknown +bool openEMS::parseCommandLineArgument( const char *argv ) +{ + if (!argv) + return false; + + if (strcmp(argv,"--disable-dumps")==0) + { + cout << "openEMS - disabling all field dumps" << endl; + SetEnableDumps(false); + return true; + } + else if (strcmp(argv,"--debug-material")==0) + { + cout << "openEMS - dumping material to 'material_dump.vtk'" << endl; + DebugMaterial(); + return true; + } + else if (strcmp(argv,"--debug-operator")==0) + { + cout << "openEMS - dumping operator to 'operator_dump.vtk'" << endl; + DebugOperator(); + return true; + } + else if (strcmp(argv,"--debug-boxes")==0) + { + cout << "openEMS - dumping boxes to 'box_dump*.vtk'" << endl; + DebugBox(); + return true; + } + else if (strcmp(argv,"--debug-PEC")==0) + { + cout << "openEMS - dumping PEC info to 'PEC_dump.vtk'" << endl; + m_debugPEC = true; + return true; + } + else if (strcmp(argv,"--debug-CSX")==0) + { + cout << "openEMS - dumping CSX geometry to 'debugCSX.xml'" << endl; + m_debugCSX = true; + return true; + } + else if (strcmp(argv,"--engine=basic")==0) + { + cout << "openEMS - enabled basic engine" << endl; + m_engine = EngineType_Basic; + return true; + } + else if (strcmp(argv,"--engine=sse")==0) + { + cout << "openEMS - enabled sse engine" << endl; + m_engine = EngineType_SSE; + return true; + } + else if (strcmp(argv,"--engine=sse-compressed")==0) + { + cout << "openEMS - enabled compressed sse engine" << endl; + m_engine = EngineType_SSE_Compressed; + return true; + } + else if (strcmp(argv,"--engine=multithreaded")==0) + { + cout << "openEMS - enabled multithreading" << endl; + m_engine = EngineType_Multithreaded; + return true; + } + else if (strncmp(argv,"--numThreads=",13)==0) + { + m_engine_numThreads = atoi(argv+13); + cout << "openEMS - fixed number of threads: " << m_engine_numThreads << endl; + return true; + } + else if (strcmp(argv,"--engine=fastest")==0) + { + cout << "openEMS - enabled multithreading engine" << endl; + m_engine = EngineType_Multithreaded; + return true; + } + else if (strcmp(argv,"--no-simulation")==0) + { + cout << "openEMS - disabling simulation => preprocessing only" << endl; + m_no_simulation = true; + return true; + } + else if (strcmp(argv,"--dump-statistics")==0) + { + cout << "openEMS - dump simulation statistics to '" << __OPENEMS_RUN_STAT_FILE__ << "' and '" << __OPENEMS_STAT_FILE__ << "'" << endl; + m_DumpStats = true; + return true; + } + + return false; +} + +string openEMS::GetExtLibsInfo(string prefix) +{ + stringstream str; + + str << prefix << "Used external libraries:" << endl; + str << prefix << "\t" << ContinuousStructure::GetInfoLine(true) << endl; + + // libhdf5 + unsigned int major, minor, release; + if (H5get_libversion( &major, &minor, &release ) >= 0) + { + str << prefix << "\t" << "hdf5 -- Version: " << major << '.' << minor << '.' << release << endl; + str << prefix << "\t" << " compiled against: " H5_VERS_INFO << endl; + } + + // tinyxml + str << prefix << "\t" << "tinyxml -- compiled against: " << TIXML_MAJOR_VERSION << '.' << TIXML_MINOR_VERSION << '.' << TIXML_PATCH_VERSION << endl; + + // fparser + str << prefix << "\t" << "fparser" << endl; + + // boost + str << prefix << "\t" << "boost -- compiled against: " << BOOST_LIB_VERSION << endl; + + //vtk + str << prefix << "\t" << "vtk -- Version: " << vtkVersion::GetVTKMajorVersion() << "." << vtkVersion::GetVTKMinorVersion() << "." << vtkVersion::GetVTKBuildVersion() << endl; + str << prefix << "\t" << " compiled against: " << VTK_VERSION << endl; + + return str.str(); +} + +void openEMS::WelcomeScreen() +{ +#if defined(_LP64) || defined(_WIN64) + string bits = "64bit"; +#else + string bits = "32bit"; +#endif + + cout << " ---------------------------------------------------------------------- " << endl; + cout << " | openEMS " << bits << " -- version " GIT_VERSION << endl; + cout << " | (C) 2010-2016 Thorsten Liebig GPL license" << endl; + cout << " ---------------------------------------------------------------------- " << endl; + cout << openEMS::GetExtLibsInfo("\t") << endl; +} + +bool openEMS::SetupBoundaryConditions() +{ + FDTD_Op->SetBoundaryCondition(m_BC_type); //operator only knows about PEC and PMC, everything else is defined by extensions (see below) + + /**************************** create all operator/engine extensions here !!!! **********************************/ + for (int n=0; n<6; ++n) + { + FDTD_Op->SetBCSize(n, 0); + if (m_BC_type[n]==2) //Mur-ABC + { + FDTD_Op->SetBCSize(n, 1); + Operator_Ext_Mur_ABC* op_ext_mur = new Operator_Ext_Mur_ABC(FDTD_Op); + op_ext_mur->SetDirection(n/2,n%2); + if (m_Mur_v_ph[n]>0) + op_ext_mur->SetPhaseVelocity(m_Mur_v_ph[n]); + FDTD_Op->AddExtension(op_ext_mur); + } + if (m_BC_type[n]==3) + FDTD_Op->SetBCSize(n, m_PML_size[n]); + } + + + //create the upml + Operator_Ext_UPML::Create_UPML(FDTD_Op, m_BC_type, m_PML_size, string()); + + return true; +} + +Engine_Interface_FDTD* openEMS::NewEngineInterface(int multigridlevel) +{ + Operator_CylinderMultiGrid* op_cyl_mg = dynamic_cast(FDTD_Op); + while (op_cyl_mg && multigridlevel>0) + { + int mgl = op_cyl_mg->GetMultiGridLevel(); + if (mgl==multigridlevel) + { + if (g_settings.GetVerboseLevel()>0) + cout << __func__ << ": Operator with requested multi-grid level found." << endl; + return new Engine_Interface_Cylindrical_FDTD(op_cyl_mg); + } + Operator_Cylinder* op_cyl_inner = op_cyl_mg->GetInnerOperator(); + op_cyl_mg = dynamic_cast(op_cyl_inner); + if (op_cyl_mg==NULL) //inner most operator reached + { + if (g_settings.GetVerboseLevel()>0) + cout << __func__ << ": Operator with highest multi-grid level chosen." << endl; + return new Engine_Interface_Cylindrical_FDTD(op_cyl_inner); + } + // try next level + } + Operator_Cylinder* op_cyl = dynamic_cast(FDTD_Op); + if (op_cyl) + return new Engine_Interface_Cylindrical_FDTD(op_cyl); + Operator_sse* op_sse = dynamic_cast(FDTD_Op); + if (op_sse) + return new Engine_Interface_SSE_FDTD(op_sse); + return new Engine_Interface_FDTD(FDTD_Op); +} + +void openEMS::SetVerboseLevel(int level) +{ + g_settings.SetVerboseLevel(level); +} + +bool openEMS::SetupProcessing() +{ + //*************** setup processing ************// + if (g_settings.GetVerboseLevel()>0) + cout << "Setting up processing..." << endl; + + unsigned int Nyquist = FDTD_Op->GetExcitationSignal()->GetNyquistNum(); + PA = new ProcessingArray(Nyquist); + + double start[3]; + double stop[3]; + bool l_MultiBox = false; + vector Probes = m_CSX->GetPropertyByType(CSProperties::PROBEBOX); + for (size_t i=0; iGetQtyPrimitives()>1); + + for (size_t nb=0; nbGetQtyPrimitives(); ++nb) + { + CSPrimitives* prim = Probes.at(i)->GetPrimitive(nb); + if (prim!=NULL) + { + double bnd[6] = {0,0,0,0,0,0}; + prim->GetBoundBox(bnd,true); + start[0]= bnd[0]; + start[1]=bnd[2]; + start[2]=bnd[4]; + stop[0] = bnd[1]; + stop[1] =bnd[3]; + stop[2] =bnd[5]; + CSPropProbeBox* pb = Probes.at(i)->ToProbeBox(); + ProcessIntegral* proc = NULL; + if (pb) + { + if (pb->GetProbeType()==0) + { + ProcessVoltage* procVolt = new ProcessVoltage(NewEngineInterface()); + proc=procVolt; + } + else if (pb->GetProbeType()==1) + { + ProcessCurrent* procCurr = new ProcessCurrent(NewEngineInterface()); + proc=procCurr; + } + else if (pb->GetProbeType()==2) + proc = new ProcessFieldProbe(NewEngineInterface(),0); + else if (pb->GetProbeType()==3) + proc = new ProcessFieldProbe(NewEngineInterface(),1); + else if ((pb->GetProbeType()==10) || (pb->GetProbeType()==11)) + { + ProcessModeMatch* pmm = new ProcessModeMatch(NewEngineInterface()); + pmm->SetFieldType(pb->GetProbeType()-10); + pmm->SetModeFunction(0,pb->GetAttributeValue("ModeFunctionX")); + pmm->SetModeFunction(1,pb->GetAttributeValue("ModeFunctionY")); + pmm->SetModeFunction(2,pb->GetAttributeValue("ModeFunctionZ")); + proc = pmm; + } + else + { + cerr << "openEMS::SetupFDTD: Warning: Probe type " << pb->GetProbeType() << " of property '" << pb->GetName() << "' is unknown..." << endl; + continue; + } + if (CylinderCoords) + proc->SetMeshType(Processing::CYLINDRICAL_MESH); + if ((pb->GetProbeType()==1) || (pb->GetProbeType()==3)) + { + proc->SetDualTime(true); + proc->SetDualMesh(true); + } + if (pb->GetProbeType()==11) + proc->SetDualTime(true); + proc->SetProcessInterval(Nyquist/m_OverSampling); + if (pb->GetStartTime()>0 || pb->GetStopTime()>0) + proc->SetProcessStartStopTime(pb->GetStartTime(), pb->GetStopTime()); + proc->AddFrequency(pb->GetFDSamples()); + proc->GetNormalDir(pb->GetNormalDir()); + if (l_MultiBox==false) + proc->SetName(pb->GetName()); + else + proc->SetName(pb->GetName(),nb); + proc->DefineStartStopCoord(start,stop); + if (g_settings.showProbeDiscretization()) + proc->ShowSnappedCoords(); + proc->SetWeight(pb->GetWeighting()); + PA->AddProcessing(proc); + prim->SetPrimitiveUsed(true); + } + else + delete proc; + } + } + } + + vector DumpProps = m_CSX->GetPropertyByType(CSProperties::DUMPBOX); + for (size_t i=0; iGetQtyPrimitives()>1); + + for (size_t nb=0; nbGetQtyPrimitives(); ++nb) + { + + CSPrimitives* prim = DumpProps.at(i)->GetPrimitive(nb); + if (prim!=NULL) + { + double bnd[6] = {0,0,0,0,0,0}; + prim->GetBoundBox(bnd,true); + start[0]= bnd[0]; + start[1]=bnd[2]; + start[2]=bnd[4]; + stop[0] = bnd[1]; + stop[1] =bnd[3]; + stop[2] =bnd[5]; + CSPropDumpBox* db = DumpProps.at(i)->ToDumpBox(); + if (db) + { + if ((db->GetDumpType()>=0) && (db->GetDumpType()<=3)) + ProcField = new ProcessFieldsTD(NewEngineInterface(db->GetMultiGridLevel())); + else if ((db->GetDumpType()>=10) && (db->GetDumpType()<=13)) + ProcField = new ProcessFieldsFD(NewEngineInterface(db->GetMultiGridLevel())); + else if ( ((db->GetDumpType()>=20) && (db->GetDumpType()<=22)) || (db->GetDumpType()==29) ) + { + ProcessFieldsSAR* procSAR = new ProcessFieldsSAR(NewEngineInterface(db->GetMultiGridLevel())); + ProcField = procSAR; + string method = db->GetAttributeValue("SAR_Method"); + if (!method.empty()) + procSAR->SetSARAveragingMethod(method); + // use (center)-cell based conductivity only + procSAR->SetUseCellConductivity(true); + } + else + cerr << "openEMS::SetupFDTD: unknown dump box type... skipping!" << endl; + if (ProcField) + { + ProcField->SetEnable(Enable_Dumps); + ProcField->SetProcessInterval(Nyquist/m_OverSampling); + if (db->GetStopTime()>0 || db->GetStartTime()>0) + ProcField->SetProcessStartStopTime(db->GetStartTime(), db->GetStopTime()); + if ((db->GetDumpType()==1) || (db->GetDumpType()==11)) + { + ProcField->SetDualTime(true); + //make dualMesh the default mesh for h-field dumps, maybe overwritten by interpolation type (node-interpolation) + ProcField->SetDualMesh(true); + } + if (db->GetDumpType()>=10) + { + ProcField->AddFrequency(db->GetFDSamples()); + ProcField->SetDumpType((ProcessFields::DumpType)(db->GetDumpType()-10)); + } + else + ProcField->SetDumpType((ProcessFields::DumpType)db->GetDumpType()); + + if (db->GetDumpType()==20) + ProcField->SetDumpType(ProcessFields::SAR_LOCAL_DUMP); + if (db->GetDumpType()==21) + ProcField->SetDumpType(ProcessFields::SAR_1G_DUMP); + if (db->GetDumpType()==22) + ProcField->SetDumpType(ProcessFields::SAR_10G_DUMP); + if (db->GetDumpType()==29) + ProcField->SetDumpType(ProcessFields::SAR_RAW_DATA); + + //SetupMaterialStorages() has previewed storage needs... refresh here to prevent cleanup!!! + if ( ProcField->NeedConductivity() && Enable_Dumps ) + FDTD_Op->SetMaterialStoreFlags(1,true); + + ProcField->SetDumpMode((Engine_Interface_Base::InterpolationType)db->GetDumpMode()); + ProcField->SetFileType((ProcessFields::FileType)db->GetFileType()); + if (CylinderCoords) + ProcField->SetMeshType(Processing::CYLINDRICAL_MESH); + if (db->GetSubSampling()) + for (int n=0; n<3; ++n) + ProcField->SetSubSampling(db->GetSubSampling(n),n); + if (db->GetOptResolution()) + for (int n=0; n<3; ++n) + ProcField->SetOptResolution(db->GetOptResolution(n),n); + + if (l_MultiBox==false) + ProcField->SetName(db->GetName()); + else + ProcField->SetName(db->GetName(),nb); + + ProcField->SetFileName(ProcField->GetName()); + ProcField->DefineStartStopCoord(start,stop); + if (g_settings.showProbeDiscretization()) + ProcField->ShowSnappedCoords(); + PA->AddProcessing(ProcField); + prim->SetPrimitiveUsed(true); + } + } + } + } + } + + return true; +} + +bool openEMS::SetupMaterialStorages() +{ + vector DumpProps = m_CSX->GetPropertyByType(CSProperties::DUMPBOX); + for (size_t i=0; iToDumpBox(); + if (!db) + continue; + if (db->GetQtyPrimitives()==0) + continue; + //check for current density dump types + if ( ((db->GetDumpType()==2) || (db->GetDumpType()==12) || // current density storage + (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 + } + return true; +} + +void openEMS::SetupCylinderMultiGrid(std::string val) +{ + m_CC_MultiGrid.clear(); + m_CC_MultiGrid = SplitString2Double(val,','); +} + +bool openEMS::SetupOperator() +{ + if (CylinderCoords) + { + if (m_CC_MultiGrid.size()>0) + { + FDTD_Op = Operator_CylinderMultiGrid::New(m_CC_MultiGrid, m_engine_numThreads); + if (FDTD_Op==NULL) + FDTD_Op = Operator_Cylinder::New(m_engine_numThreads); + } + else + FDTD_Op = Operator_Cylinder::New(m_engine_numThreads); + } + else if (m_engine == EngineType_SSE) + { + FDTD_Op = Operator_sse::New(); + } + else if (m_engine == EngineType_SSE_Compressed) + { + FDTD_Op = Operator_SSE_Compressed::New(); + } + else if (m_engine == EngineType_Multithreaded) + { + FDTD_Op = Operator_Multithread::New(m_engine_numThreads); + } + else + { + FDTD_Op = Operator::New(); + } + return true; +} + +void openEMS::Set_BC_Type(int idx, int type) +{ + if ((idx<0) || (idx>5)) + return; + m_BC_type[idx] = type; +} + +int openEMS::Get_BC_Type(int idx) +{ + if ((idx<0) || (idx>5)) + return -1; + return m_BC_type[idx]; +} + +void openEMS::Set_BC_PML(int idx, unsigned int size) +{ + if ((idx<0) || (idx>5)) + return; + m_BC_type[idx] = 3; + m_PML_size[idx] = size; +} + +int openEMS::Get_PML_Size(int idx) +{ + if ((idx<0) || (idx>5)) + return -1; + if (m_BC_type[idx]!=3) + return -1; // return -1 if BC was *not* a PML + return m_PML_size[idx]; +} + +void openEMS::Set_Mur_PhaseVel(int idx, double val) +{ + if ((idx<0) || (idx>5)) + return; + m_Mur_v_ph[idx] = val; +} + +bool openEMS::ParseFDTDSetup(std::string file) +{ + Reset(); + + if (g_settings.GetVerboseLevel()>0) + cout << "Read openEMS xml file: " << file << " ..." << endl; + + TiXmlDocument doc(file); + if (!doc.LoadFile()) + { + cerr << "openEMS: Error File-Loading failed!!! File: " << file << endl; + exit(-1); + } + + if (g_settings.GetVerboseLevel()>0) + cout << "Read openEMS Settings..." << endl; + TiXmlElement* openEMSxml = doc.FirstChildElement("openEMS"); + if (openEMSxml==NULL) + { + cerr << "Can't read openEMS ... " << endl; + exit(-1); + } + TiXmlElement* FDTD_Opts = openEMSxml->FirstChildElement("FDTD"); + + if (FDTD_Opts==NULL) + { + cerr << "Can't read openEMS FDTD Settings... " << endl; + exit(-1); + } + + if (g_settings.GetVerboseLevel()>0) + cout << "Read Geometry..." << endl; + ContinuousStructure* csx = new ContinuousStructure(); + string EC(csx->ReadFromXML(openEMSxml)); + if (EC.empty()==false) + cerr << EC << endl; + this->SetCSX(csx); + + + return this->Parse_XML_FDTDSetup(FDTD_Opts); +} + +bool openEMS::Parse_XML_FDTDSetup(TiXmlElement* FDTD_Opts) +{ + double dhelp=0; + FDTD_Opts->QueryDoubleAttribute("NumberOfTimesteps",&dhelp); + if (dhelp<0) + this->SetNumberOfTimeSteps(0); + else + this->SetNumberOfTimeSteps((unsigned int)dhelp); + + int ihelp = 0; + FDTD_Opts->QueryIntAttribute("CylinderCoords",&ihelp); + if (ihelp==1) + { + this->SetCylinderCoords(true); + const char* cchelp = FDTD_Opts->Attribute("MultiGrid"); + if (cchelp!=NULL) + this->SetupCylinderMultiGrid(string(cchelp)); + } + + dhelp = 0; + FDTD_Opts->QueryDoubleAttribute("endCriteria",&dhelp); + if (dhelp==0) + this->SetEndCriteria(1e-6); + else + this->SetEndCriteria(dhelp); + + ihelp = 0; + FDTD_Opts->QueryIntAttribute("OverSampling",&ihelp); + if (ihelp>1) + this->SetOverSampling(ihelp); + + // check for cell constant material averaging + if (FDTD_Opts->QueryIntAttribute("CellConstantMaterial",&ihelp)==TIXML_SUCCESS) + this->SetCellConstantMaterial(ihelp==1); + + TiXmlElement* BC = FDTD_Opts->FirstChildElement("BoundaryCond"); + if (BC==NULL) + { + cerr << "Can't read openEMS boundary cond Settings... " << endl; + exit(-3); + } + +// const char* tmp = BC->Attribute("PML_Grading"); +// string pml_gradFunc; +// if (tmp) +// pml_gradFunc = string(tmp); + + string bound_names[] = {"xmin","xmax","ymin","ymax","zmin","zmax"}; + string s_bc; + for (int n=0; n<6; ++n) + { + int EC = BC->QueryIntAttribute(bound_names[n].c_str(),&ihelp); + if (EC==TIXML_SUCCESS) + { + this->Set_BC_Type(n, ihelp); + continue; + } + if (EC==TIXML_WRONG_TYPE) + { + const char* tmp = BC->Attribute(bound_names[n].c_str()); + if (tmp) + s_bc = string(tmp); + else + cerr << "openEMS::SetupBoundaryConditions: Warning, boundary condition for \"" << bound_names[n] << "\" unknown... set to PEC " << endl; + if (s_bc=="PEC") + this->Set_BC_Type(n, 0); + else if (s_bc=="PMC") + this->Set_BC_Type(n, 1); + else if (s_bc=="MUR") + this->Set_BC_Type(n, 2); + else if (strncmp(s_bc.c_str(),"PML_=",4)==0) + this->Set_BC_PML(n, atoi(s_bc.c_str()+4)); + else + cerr << "openEMS::SetupBoundaryConditions: Warning, boundary condition for \"" << bound_names[n] << "\" unknown... set to PEC " << endl; + } + else + cerr << "openEMS::SetupBoundaryConditions: Warning, boundary condition for \"" << bound_names[n] << "\" not found... set to PEC " << endl; + } + + //read general mur phase velocity + if (BC->QueryDoubleAttribute("MUR_PhaseVelocity",&dhelp) == TIXML_SUCCESS) + for (int n=0;n<6;++n) + this->Set_Mur_PhaseVel(n, dhelp); + + string mur_v_ph_names[6] = {"MUR_PhaseVelocity_xmin", "MUR_PhaseVelocity_xmax", "MUR_PhaseVelocity_ymin", "MUR_PhaseVelocity_ymax", "MUR_PhaseVelocity_zmin", "MUR_PhaseVelocity_zmax"}; + for (int n=0; n<6; ++n) + if (BC->QueryDoubleAttribute(mur_v_ph_names[n].c_str(),&dhelp) == TIXML_SUCCESS) + this->Set_Mur_PhaseVel(n, dhelp); + + TiXmlElement* m_Excite_Elem = FDTD_Opts->FirstChildElement("Excitation"); + if (!m_Excite_Elem) + { + cerr << "Excitation::setupExcitation: Error, can't read openEMS excitation settings... " << endl; + return false; + } + + Excitation* exc = this->InitExcitation(); + double f0=0, fc=0, f_max=0; + ihelp = -1; + m_Excite_Elem->QueryIntAttribute("Type",&ihelp); + switch (ihelp) + { + case Excitation::GaissianPulse: + m_Excite_Elem->QueryDoubleAttribute("f0",&f0); + m_Excite_Elem->QueryDoubleAttribute("fc",&fc); + exc->SetupGaussianPulse(f0, fc); + break; + case Excitation::Sinusoidal: // sinusoidal excite + m_Excite_Elem->QueryDoubleAttribute("f0",&f0); + exc->SetupSinusoidal(f0); + break; + case Excitation::DiracPulse: + FDTD_Opts->QueryDoubleAttribute("f_max",&f_max); + exc->SetupDiracPulse(f_max); + break; + case Excitation::Step: + FDTD_Opts->QueryDoubleAttribute("f_max",&f_max); + exc->SetupStepExcite(f_max); + break; + case Excitation::CustomExcite: + m_Excite_Elem->QueryDoubleAttribute("f0",&f0); + FDTD_Opts->QueryDoubleAttribute("f_max",&f_max); + exc->SetupCustomExcite(m_Excite_Elem->Attribute("Function"), f0, f_max); + break; + } + + if (FDTD_Opts->QueryIntAttribute("TimeStepMethod",&ihelp)==TIXML_SUCCESS) + this->SetTimeStepMethod(ihelp); + if (FDTD_Opts->QueryDoubleAttribute("TimeStep",&dhelp)==TIXML_SUCCESS) + this->SetTimeStep(dhelp); + if (FDTD_Opts->QueryDoubleAttribute("TimeStepFactor",&dhelp)==TIXML_SUCCESS) + this->SetTimeStepFactor(dhelp); + return true; +} + +void openEMS::SetGaussExcite(double f0, double fc) +{ + this->InitExcitation(); + m_Exc->SetupGaussianPulse(f0, fc); +} + +Excitation* openEMS::InitExcitation() +{ + delete m_Exc; + m_Exc = new Excitation(); + return m_Exc; +} + +void openEMS::SetCSX(ContinuousStructure* csx) +{ + delete m_CSX; + m_CSX = csx; +} + +int openEMS::SetupFDTD() +{ + timeval startTime; + gettimeofday(&startTime,NULL); + + if (m_CSX==NULL) + { + cerr << "openEMS::SetupFDTD: Error: CSXCAD is not set!" << endl; + return 3; + } + if (m_CSX==NULL) + { + cerr << "openEMS::SetupFDTD: Error: CSXCAD is not set!" << endl; + return 3; + } + std::string ec = m_CSX->Update(); + if (!ec.empty()) + cerr << ec << endl; + if (g_settings.GetVerboseLevel()>2) + m_CSX->ShowPropertyStatus(cerr); + + if (CylinderCoords) + if (m_CSX->GetCoordInputType()!=CYLINDRICAL) + { + cerr << "openEMS::SetupFDTD: Warning: Coordinate system found in the CSX file is not a cylindrical. Forcing to cylindrical coordinate system!" << endl; + m_CSX->SetCoordInputType(CYLINDRICAL); //tell CSX to use cylinder-coords + } + + if (m_debugCSX) + m_CSX->Write2XML("debugCSX.xml"); + + //*************** setup operator ************// + if (SetupOperator()==false) + return 2; + + // default material averaging is quarter cell averaging + FDTD_Op->SetQuarterCellMaterialAvg(); + + if (m_CellConstantMaterial) + { + FDTD_Op->SetCellConstantMaterial(); + if (g_settings.GetVerboseLevel()>0) + cout << "Enabling constant cell material assumption." << endl; + } + + if (m_Exc==NULL) + { + cerr << "openEMS::SetupFDTD: Error, excitation is not defined! Abort!" << endl; + return 3; + } + + FDTD_Op->SetExcitationSignal(m_Exc); + FDTD_Op->AddExtension(new Operator_Ext_Excitation(FDTD_Op)); + if (!CylinderCoords) + FDTD_Op->AddExtension(new Operator_Ext_TFSF(FDTD_Op)); + + if (FDTD_Op->SetGeometryCSX(m_CSX)==false) return(2); + + SetupBoundaryConditions(); + + FDTD_Op->SetTimeStepMethod(m_TS_method); + + if (m_TS>0) + FDTD_Op->SetTimestep(m_TS); + if (m_TS_fac<1) + FDTD_Op->SetTimestepFactor(m_TS_fac); + + // Is a steady state detection requested + Operator_Ext_SteadyState* Op_Ext_SSD = NULL; + if (m_Exc->GetSignalPeriod()>0) + { + cout << "Create a steady state detection using a period of " << m_Exc->GetSignalPeriod() << " s" << endl; + Op_Ext_SSD = new Operator_Ext_SteadyState(FDTD_Op, m_Exc->GetSignalPeriod()); + unsigned int pos[3]; + for (int p=0;p<3;++p) + pos[p] = FDTD_Op->GetNumberOfLines(p)/2; + Op_Ext_SSD->Add_E_Probe(pos, 0); + Op_Ext_SSD->Add_E_Probe(pos, 1); + Op_Ext_SSD->Add_E_Probe(pos, 2); + + for (int n=0;n<3;++n) + { + for (int p=0;p<3;++p) + pos[p] = FDTD_Op->GetNumberOfLines(p)/2; + + pos[n] *= 1/4; + Op_Ext_SSD->Add_E_Probe(pos, 0); + Op_Ext_SSD->Add_E_Probe(pos, 1); + Op_Ext_SSD->Add_E_Probe(pos, 2); + + pos[n] *= 3/4; + Op_Ext_SSD->Add_E_Probe(pos, 0); + Op_Ext_SSD->Add_E_Probe(pos, 1); + Op_Ext_SSD->Add_E_Probe(pos, 2); + } + FDTD_Op->AddExtension(Op_Ext_SSD); + } + + if ((m_CSX->GetQtyPropertyType(CSProperties::LORENTZMATERIAL)>0) || (m_CSX->GetQtyPropertyType(CSProperties::DEBYEMATERIAL)>0)) + FDTD_Op->AddExtension(new Operator_Ext_LorentzMaterial(FDTD_Op)); + if (m_CSX->GetQtyPropertyType(CSProperties::CONDUCTINGSHEET)>0) + FDTD_Op->AddExtension(new Operator_Ext_ConductingSheet(FDTD_Op, m_Exc->GetMaxFreq())); + + //check all properties to request material storage during operator creation... + SetupMaterialStorages(); + + /******************* create the EC-FDTD operator *****************************/ + Operator::DebugFlags debugFlags = Operator::None; + if (DebugMat) + debugFlags |= Operator::debugMaterial; + if (DebugOp) + debugFlags |= Operator::debugOperator; + if (m_debugPEC) + debugFlags |= Operator::debugPEC; + + FDTD_Op->CalcECOperator( debugFlags ); + /*******************************************************************************/ + + //reset flags for material storage, if no dump-box resets it to true, it will be cleaned up... + FDTD_Op->SetMaterialStoreFlags(0,false); + FDTD_Op->SetMaterialStoreFlags(1,false); + FDTD_Op->SetMaterialStoreFlags(2,false); + FDTD_Op->SetMaterialStoreFlags(3,false); + + unsigned int maxTime_TS = (unsigned int)(m_maxTime/FDTD_Op->GetTimestep()); + if ((m_maxTime>0) && (maxTime_TSbuildExcitationSignal(NrTS)) + exit(2); + m_Exc->DumpVoltageExcite("et"); + m_Exc->DumpCurrentExcite("ht"); + + timeval OpDoneTime; + gettimeofday(&OpDoneTime,NULL); + + if (g_settings.GetVerboseLevel()>0) + { + FDTD_Op->ShowStat(); + FDTD_Op->ShowExtStat(); + cout << "Creation time for operator: " << CalcDiffTime(OpDoneTime,startTime) << " s" << endl; + } + cout << "FDTD simulation size: " << FDTD_Op->GetNumberOfLines(0) << "x" << FDTD_Op->GetNumberOfLines(1) << "x" << FDTD_Op->GetNumberOfLines(2) << " --> " << FDTD_Op->GetNumberCells() << " FDTD cells " << endl; + cout << "FDTD timestep is: " <GetTimestep() << " s; Nyquist rate: " << m_Exc->GetNyquistNum() << " timesteps @" << CalcNyquistFrequency(m_Exc->GetNyquistNum(),FDTD_Op->GetTimestep()) << " Hz" << endl; + if (m_Exc->GetNyquistNum()>1000) + cerr << "openEMS::SetupFDTD: Warning, the timestep seems to be very small --> long simulation. Check your mesh!?" << endl; + + if (m_Exc->GetSignalPeriod()==0) + { + cout << "Excitation signal length is: " << m_Exc->GetLength() << " timesteps (" << m_Exc->GetLength()*FDTD_Op->GetTimestep() << "s)" << endl; + cout << "Max. number of timesteps: " << NrTS << " ( --> " << (double)NrTS/(double)(m_Exc->GetLength()) << " * Excitation signal length)" << endl; + if ( ((double)NrTS/(double)m_Exc->GetLength() < 3) && (m_Exc->GetExciteType()==0)) + cerr << "openEMS::SetupFDTD: Warning, max. number of timesteps is smaller than three times the excitation. " << endl << \ + "\tYou may want to choose a higher number of max. timesteps... " << endl; + } + else + { + int p = int(m_Exc->GetSignalPeriod()/FDTD_Op->GetTimestep()); + cout << "Excitation signal period is: " << p << " timesteps (" << m_Exc->GetSignalPeriod() << "s)" << endl; + cout << "Max. number of timesteps: " << NrTS << " ( --> " << (double)NrTS/(double)(m_Exc->GetLength()) << " * Excitation signal period)" << endl; + if (NrTS/p < 3) + cerr << "openEMS::SetupFDTD: Warning, max. number of timesteps is smaller than three times the excitation signal period. " << endl << \ + "\tYou may want to choose a higher number of max. timesteps... " << endl; + } + + if (m_no_simulation) + { + // simulation was disabled (to generate debug output only) + return 1; + } + + //create FDTD engine + FDTD_Eng = FDTD_Op->CreateEngine(); + + if (Op_Ext_SSD) + { + Eng_Ext_SSD = dynamic_cast(Op_Ext_SSD->GetEngineExtention()); + Eng_Ext_SSD->SetEngineInterface(this->NewEngineInterface()); + } + + //setup all processing classes + if (SetupProcessing()==false) + return 2; + + // Cleanup all unused material storages... + FDTD_Op->CleanupMaterialStorage(); + + //check and warn for unused properties and primitives + m_CSX->WarnUnusedPrimitves(cerr); + + // dump all boxes (voltage, current, fields, ...) + if (m_debugBox) + { + PA->DumpBoxes2File("box_dump_"); + } + + return 0; +} + +string FormatTime(int sec) +{ + stringstream ss; + if (sec<60) + { + ss << setw(9) << sec << "s"; + return ss.str(); + } + if (sec<3600) + { + ss << setw(6) << sec/60 << "m" << setw(2) << setfill('0') << sec%60 << "s"; + return ss.str(); + } + ss << setw(3) << sec/3600 << "h" << setw(2) << setfill('0') << (sec%3600)/60 << "m" << setw(2) << setfill('0') << sec%60 << "s"; + return ss.str(); +} + +bool openEMS::CheckAbortCond() +{ + if (m_Abort) //abort was set externally + return true; + + //check whether the file "ABORT" exist in current working directory + ifstream ifile("ABORT"); + if (ifile) + { + ifile.close(); + cerr << "openEMS::CheckAbortCond(): Found file \"ABORT\", aborting simulation..." << endl; + return true; + } + + return false; +} + +void openEMS::RunFDTD() +{ + cout << "Running FDTD engine... this may take a while... grab a cup of coffee?!?" << endl; + + //special handling of a field processing, needed to realize the end criteria... + ProcessFields* ProcField = new ProcessFields(NewEngineInterface()); + PA->AddProcessing(ProcField); + double maxE=0,currE=0; + + //init processings + PA->InitAll(); + + //add all timesteps to end-crit field processing with max excite amplitude + unsigned int maxExcite = FDTD_Op->GetExcitationSignal()->GetMaxExcitationTimestep(); +// for (unsigned int n=0; nExc->Volt_Count; ++n) +// ProcField->AddStep(FDTD_Op->Exc->Volt_delay[n]+maxExcite); + ProcField->AddStep(maxExcite); + + double change=1; + int prevTS=0,currTS=0; + double numCells = FDTD_Op->GetNumberCells(); + double speed = 0; + double t_diff; + double t_run; + + timeval currTime; + gettimeofday(&currTime,NULL); + timeval startTime = currTime; + timeval prevTime= currTime; + + if (m_DumpStats) + InitRunStatistics(__OPENEMS_RUN_STAT_FILE__); + //*************** simulate ************// + + PA->PreProcess(); + int step=PA->Process(); + if ((step<0) || (step>(int)NrTS)) step=NrTS; + while ((FDTD_Eng->GetNumberOfTimesteps()endCrit) && !CheckAbortCond()) + { + FDTD_Eng->IterateTS(step); + step=PA->Process(); + + if ((Eng_Ext_SSD==NULL) && ProcField->CheckTimestep()) + { + currE = ProcField->CalcTotalEnergyEstimate(); + if (currE>maxE) + maxE=currE; + } + +// cout << " do " << step << " steps; current: " << eng.GetNumberOfTimesteps() << endl; + currTS = FDTD_Eng->GetNumberOfTimesteps(); + if ((step<0) || (step>(int)(NrTS - currTS))) step=NrTS - currTS; + + gettimeofday(&currTime,NULL); + + t_diff = CalcDiffTime(currTime,prevTime); + + if (t_diff>4) + { + t_run = CalcDiffTime(currTime,startTime); + speed = numCells*(currTS-prevTS)/t_diff; + cout << "[@" << FormatTime(t_run) << "] Timestep: " << setw(12) << currTS ; + cout << " || Speed: " << setw(6) << setprecision(1) << std::fixed << speed*1e-6 << " MC/s (" << setw(4) << setprecision(3) << std::scientific << t_diff/(currTS-prevTS) << " s/TS)" ; + if (Eng_Ext_SSD==NULL) + { + currE = ProcField->CalcTotalEnergyEstimate(); + if (currE>maxE) + maxE=currE; + if (maxE) + change = currE/maxE; + cout << " || Energy: ~" << setw(6) << setprecision(2) << std::scientific << currE << " (-" << setw(5) << setprecision(2) << std::fixed << fabs(10.0*log10(change)) << "dB)" << endl; + } + else + { + change = Eng_Ext_SSD->GetLastDiff(); + cout << " || SteadyState: " << setw(6) << setprecision(2) << std::fixed << 10.0*log10(change) << " dB" << endl; + } + prevTime=currTime; + prevTS=currTS; + + PA->FlushNext(); + + if (m_DumpStats) + DumpRunStatistics(__OPENEMS_RUN_STAT_FILE__, t_run, currTS, speed, currE); + } + } + if ((change>endCrit) && (FDTD_Op->GetExcitationSignal()->GetExciteType()==0)) + cerr << "RunFDTD: Warning: Max. number of timesteps was reached before the end-criteria of -" << fabs(10.0*log10(endCrit)) << "dB was reached... " << endl << \ + "\tYou may want to choose a higher number of max. timesteps... " << endl; + + gettimeofday(&currTime,NULL); + t_diff = CalcDiffTime(currTime,startTime); + + cout << "Time for " << FDTD_Eng->GetNumberOfTimesteps() << " iterations with " << FDTD_Op->GetNumberCells() << " cells : " << t_diff << " sec" << endl; + cout << "Speed: " << numCells*(double)FDTD_Eng->GetNumberOfTimesteps()/t_diff*1e-6 << " MCells/s " << endl; + + if (m_DumpStats) + DumpStatistics(__OPENEMS_STAT_FILE__, t_diff); + + //*************** postproc ************// + PA->PostProcess(); +} + +bool openEMS::DumpStatistics(const string& filename, double time) +{ + ofstream stat_file; + stat_file.open(filename.c_str()); + + if (!stat_file.is_open()) + { + cerr << "openEMS::DumpStatistics: Error, opening file failed..." << endl; + return false; + } + stat_file << std::setprecision( 16 ); + stat_file << FDTD_Op->GetNumberCells() << "\t% number of cells" << endl; + stat_file << FDTD_Op->GetTimestep() << "\t% timestep (s)" << endl; + stat_file << FDTD_Eng->GetNumberOfTimesteps() << "\t% number of iterations" << endl; + stat_file << FDTD_Eng->GetNumberOfTimesteps()*FDTD_Op->GetTimestep() << "\t% total numercial time (s)" << endl; + stat_file << time << "\t% simulation time (s)" << endl; + stat_file << (double)FDTD_Op->GetNumberCells()*(double)FDTD_Eng->GetNumberOfTimesteps()/time << "\t% speed (cells/s)" << endl; + + stat_file.close(); + return true; +} + +bool openEMS::InitRunStatistics(const string& filename) +{ + ofstream stat_file; + stat_file.open(filename.c_str(), ios_base::out); + + if (!stat_file.is_open()) + { + cerr << "openEMS::InitRunStatistics: Error, opening file failed..." << endl; + return false; + } + stat_file << "%time\ttimestep\tspeed\tenergy" << endl; + stat_file.close(); + return true; +} + +bool openEMS::DumpRunStatistics(const string& filename, double time, unsigned int ts, double speed, double energy) +{ + ofstream stat_file; + stat_file.open(filename.c_str(), ios_base::app); + + if (!stat_file.is_open()) + { + cerr << "openEMS::DumpRunStatistics: Error, opening file failed..." << endl; + return false; + } + stat_file << time << "\t" << ts << "\t" << speed << "\t" << energy << endl; + stat_file.close(); + return true; +} diff --git a/openEMS/openems.h b/openEMS/openems.h new file mode 100644 index 0000000..d194050 --- /dev/null +++ b/openEMS/openems.h @@ -0,0 +1,167 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef OPENEMS_H +#define OPENEMS_H + +#include +#include +#include +#include + +#define __OPENEMS_STAT_FILE__ "openEMS_stats.txt" +#define __OPENEMS_RUN_STAT_FILE__ "openEMS_run_stats.txt" + +class Operator; +class Engine; +class Engine_Interface_FDTD; +class ProcessingArray; +class TiXmlElement; +class ContinuousStructure; +class Engine_Interface_FDTD; +class Excitation; +class Engine_Ext_SteadyState; + +double CalcDiffTime(timeval t1, timeval t2); +std::string FormatTime(int sec); + +class openEMS +{ +public: + openEMS(); + virtual ~openEMS(); + + virtual bool parseCommandLineArgument( const char *argv ); + static void showUsage(); + + bool ParseFDTDSetup(std::string file); + virtual bool Parse_XML_FDTDSetup(TiXmlElement* openEMSxml); + virtual int SetupFDTD(); + virtual void RunFDTD(); + + void Reset(); + + void SetNumberOfTimeSteps(unsigned int val) {NrTS=val;} + void SetEnableDumps(bool val) {Enable_Dumps=val;} + void SetEndCriteria(double val) {endCrit=val;} + void SetOverSampling(int val) {m_OverSampling=val;} + void SetCellConstantMaterial(bool val) {m_CellConstantMaterial=val;} + + void SetCylinderCoords(bool val) {CylinderCoords=val;} + void SetupCylinderMultiGrid(std::vector val) {m_CC_MultiGrid=val;} + void SetupCylinderMultiGrid(std::string val); + + void SetTimeStepMethod(int val) {m_TS_method=val;} + void SetTimeStep(double val) {m_TS=val;} + void SetTimeStepFactor(double val) {m_TS_fac=val;} + void SetMaxTime(double val) {m_maxTime=val;} + + void DebugMaterial() {DebugMat=true;} + void DebugOperator() {DebugOp=true;} + void DebugBox() {m_debugBox=true;} + + 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); + + //! Get informations about external libs used by openEMS + static std::string GetExtLibsInfo(std::string prefix="\t"); + + //! Get welcome screen for openEMS + static void WelcomeScreen(); + + //! Set this to about FDTD iteration process + void SetAbort(bool val) {m_Abort=val;} + //! Check for abort conditions + bool CheckAbortCond(); + + void SetGaussExcite(double f0, double fc); + Excitation* InitExcitation(); + + void SetCSX(ContinuousStructure* csx); + + Engine_Interface_FDTD* NewEngineInterface(int multigridlevel = 0); + + void SetVerboseLevel(int level); + +protected: + bool CylinderCoords; + std::vector m_CC_MultiGrid; + + ContinuousStructure* m_CSX; + + //! Number of Timesteps + unsigned int NrTS; + int m_TS_method; + double m_TS; + double m_TS_fac; + double m_maxTime; + + // some command line flags + bool Enable_Dumps; + bool DebugMat; + bool DebugOp; + bool m_debugCSX; + bool m_DumpStats; + bool m_debugBox, m_debugPEC, m_no_simulation; + + double endCrit; + int m_OverSampling; + bool m_CellConstantMaterial; + Operator* FDTD_Op; + Engine* FDTD_Eng; + Engine_Ext_SteadyState* Eng_Ext_SSD; + ProcessingArray* PA; + + Excitation* m_Exc; + + bool m_Abort; + +#ifdef MPI_SUPPORT + enum EngineType {EngineType_Basic, EngineType_SSE, EngineType_SSE_Compressed, EngineType_Multithreaded, EngineType_MPI}; +#else + enum EngineType {EngineType_Basic, EngineType_SSE, EngineType_SSE_Compressed, EngineType_Multithreaded}; +#endif + EngineType m_engine; + unsigned int m_engine_numThreads; + + //! Setup an operator matching the requested engine + virtual bool SetupOperator(); + + //! Read boundary conditions from xml element and apply to FDTD operator + bool SetupBoundaryConditions(); + int m_BC_type[6]; + unsigned int m_PML_size[6]; + double m_Mur_v_ph[6]; + + //! Check whether or not the FDTD-Operator has to store material data. + bool SetupMaterialStorages(); + + //! Setup all processings. + virtual bool SetupProcessing(); + + //! Dump statistics to file + virtual bool DumpStatistics(const std::string& filename, double time); + + //! Dump run statistivs to file + virtual bool InitRunStatistics(const std::string& filename); + virtual bool DumpRunStatistics(const std::string& filename, double time, unsigned int ts, double speed, double energy); +}; + +#endif // OPENEMS_H diff --git a/openEMS/tools/AdrOp.cpp b/openEMS/tools/AdrOp.cpp new file mode 100644 index 0000000..228f8de --- /dev/null +++ b/openEMS/tools/AdrOp.cpp @@ -0,0 +1,554 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "AdrOp.h" + +using namespace std; + +AdrOp::AdrOp(unsigned int muiImax, unsigned int muiJmax, unsigned int muiKmax, unsigned int muiLmax) +{ + //error-handling... + error = new ErrorMsg(9); + if (error==NULL) + { + fprintf(stderr,"Memory allocation failed!! exiting..."); + exit(1); + } + error->SetMsg(1,"Adress Operator: Memory allocation failed!! exiting..."); + error->SetMsg(2,"Adress Operator: Invalid Adress requested!! exiting..."); + error->SetMsg(3,"Adress Operator: Invalid Position set!! exiting..."); + error->SetMsg(4,"Adress Operator: Invalid jump or passing end of iteration!! exiting..."); + error->SetMsg(5,"Adress Operator: 4D not yet implemented!! exiting..."); + error->SetMsg(6,"Adress Operator: Position not set!! exiting..."); + error->SetMsg(7,"Adress Operator: Cells not added to Adress Operator!! exiting..."); + error->SetMsg(8,"Adress Operator: Invalid Node!! exiting..."); + error->SetMsg(9,"Adress Operator: Grid invalid!! exiting..."); + + //if (muiImax<0) muiImax=0; + //if (muiJmax<0) muiJmax=0; + //if (muiKmax<0) muiKmax=0; + //if (muiLmax<0) muiLmax=0; + + uiDimension=0; + if (muiImax>0) uiDimension++; + else exit(-1); + if (muiJmax>0) uiDimension++; + else exit(-2); + if (muiKmax>0) uiDimension++; + if ( (muiLmax>0) && (muiKmax>0) ) uiDimension++; +// cout << "\n-----Adress Operator created: Dimension: " << uiDimension << "----" <Error(5); + iIshift=iJshift=iKshift=0; + reflect=false; + uiTypeOffset=0; + clCellAdr=NULL; + dGrid[0]=NULL; + dGrid[1]=NULL; + dGrid[2]=NULL; + dGrid[3]=NULL; + dDeltaUnit=1; + bDebug=false; +} + +AdrOp::AdrOp(AdrOp* origOP) +{ + clCellAdr=NULL; + error=NULL; // has to be done!!! + + uiDimension=origOP->uiDimension; + uiSize=origOP->uiSize; + uiImax=origOP->uiImax; + uiJmax=origOP->uiJmax; + uiKmax=origOP->uiKmax; + uiLmax=origOP->uiLmax; + uiIpos=origOP->uiIpos; + uiJpos=origOP->uiJpos; + uiKpos=origOP->uiKpos; + uiLpos=origOP->uiLpos; + for (int ii=0; ii<4; ++ii) dGrid[ii]=origOP->dGrid[ii]; + dDeltaUnit=origOP->dDeltaUnit; + iIshift=origOP->iIshift; + iJshift=origOP->iJshift; + iKshift=origOP->iKshift; + for (int ii=0; ii<3; ++ii) iCellShift[ii]=origOP->iCellShift[ii]; + i=origOP->i; + j=origOP->j; + k=origOP->k; + l=origOP->l; + reflect=origOP->reflect; + uiTypeOffset=origOP->uiTypeOffset; + + bPosSet=origOP->bPosSet; + bDebug=origOP->bDebug; +// return; + if (origOP->clCellAdr!=NULL) clCellAdr= new AdrOp(origOP->clCellAdr); +} + +AdrOp::~AdrOp() +{ +// cerr << "\n------Adress Operator deconstructed-----\n" << endl; + delete error; + error=NULL; + delete clCellAdr; + clCellAdr=NULL; +} + +unsigned int AdrOp::SetPos(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos, unsigned int muiLpos) +{ + if (bDebug) fprintf(stderr,"AdrOp Debug:: SetPos(%d,%d,%d,%d) Max(%d,%d,%d,%d) \n",muiIpos,muiJpos,muiKpos,muiLpos,uiImax,uiJmax,uiKmax,uiLmax); + bPosSet=false; + if (muiIposError(3); + if (muiJposError(3); + if ((muiKpos>=uiKmax) && (uiDimension>2)) error->Error(3); + else if (uiDimension>2) uiKpos=muiKpos; + if ((muiLpos>=uiLmax) && (uiDimension>3)) error->Error(3); + else if (uiDimension>3) uiLpos=muiLpos; + bPosSet=true; +// cerr << "Position i:" << uiIpos << " j: " << uiJpos << " k: " << uiKpos << " l: " << 0 << " MAX: i:" << uiImax << " j: " << uiJmax << " k: " << uiKmax << endl; //debug + ADRESSEXPENSE(0,0,0,0,uiDimension+1,18) + return GetPos(); +} + +bool AdrOp::SetPosChecked(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos, unsigned int muiLpos) +{ + bPosSet=true; + if (muiIpos=uiKmax) && (uiDimension>2)) bPosSet=false; + else if (uiDimension>2) uiKpos=muiKpos; + if ((muiLpos>=uiLmax) && (uiDimension>3)) bPosSet=false; + else if (uiDimension>3) uiLpos=muiLpos; + ADRESSEXPENSE(0,0,0,0,uiDimension+1,18) + return bPosSet; +} + +void AdrOp::SetGrid(double *gridI,double *gridJ,double *gridK,double *gridL) +{ + dGrid[0]=gridI; + dGrid[1]=gridJ; + dGrid[2]=gridK; + dGrid[3]=gridL; + ADRESSEXPENSE(0,0,0,0,4,0) +} + +bool AdrOp::CheckPos(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos, unsigned int muiLpos) +{ + bPosSet=true; + if ((muiIpos>=uiImax)) bPosSet=false; + if ((muiJpos>=uiJmax)) bPosSet=false; + if ((muiKpos>=uiKmax) && (uiDimension>2)) bPosSet=false; + if ((muiLpos>=uiLmax) && (uiDimension>3)) bPosSet=false; + ADRESSEXPENSE(0,0,0,0,uiDimension+1,18) + return bPosSet; +} + +bool AdrOp::CheckRelativePos(int muiIrel,int muiJrel,int muiKrel, int muiLrel) +{ + bPosSet=true; + if ((muiIrel+(int)uiIpos<0) || (muiIrel+(int)uiIpos>=(int)uiImax)) bPosSet=false; + if ((muiJrel+(int)uiJpos<0) || (muiJrel+(int)uiJpos>=(int)uiJmax)) bPosSet=false; + if (((muiKrel+(int)uiKpos<0) || (muiKrel+(int)uiKpos>=(int)uiKmax)) && (uiDimension>2)) bPosSet=false; + if (((muiLrel+(int)uiLpos<0) || (muiLrel+(int)uiLpos>=(int)uiLmax)) && (uiDimension>3)) bPosSet=false; + ADRESSEXPENSE(2*uiDimension,0,0,0,uiDimension+1,18) + return bPosSet; +} + +unsigned int AdrOp::GetPos(int muiIrel, int muiJrel, int muiKrel, int /*muiLrel*/) +{ + if (bPosSet==false) error->Error(6); + if (reflect) + { +#if EXPENSE_LOG==1 + if (muiIrel+(int)uiIpos<0) ADRESSEXPENSE(2,1,0,0,1,0) + if (muiIrel+(int)uiIpos>(int)uiImax-1) ADRESSEXPENSE(4,1,0,0,1,0) + if (muiJrel+(int)uiJpos<0) ADRESSEXPENSE(2,1,0,0,1,0) + if (muiJrel+(int)uiJpos>(int)uiJmax-1) ADRESSEXPENSE(4,1,0,0,1,0) + if (muiKrel+(int)uiKpos<0) ADRESSEXPENSE(2,1,0,0,1,0) + if (muiKrel+(int)uiKpos>(int)uiKmax-1) ADRESSEXPENSE(4,1,0,0,1,0) +#endif + + if (muiIrel+(int)uiIpos<0) muiIrel=-2*uiIpos-muiIrel-uiTypeOffset; + if (muiIrel+(int)uiIpos>(int)uiImax-1) muiIrel=2*(uiImax-1-uiIpos)-muiIrel+uiTypeOffset; + if (muiJrel+(int)uiJpos<0) muiJrel=-2*uiJpos-muiJrel-uiTypeOffset; + if (muiJrel+(int)uiJpos>(int)uiJmax-1) muiJrel=2*(uiJmax-1-uiJpos)-muiJrel+uiTypeOffset; + if (muiKrel+(int)uiKpos<0) muiKrel=-2*uiKpos-muiKrel-uiTypeOffset; + if (muiKrel+(int)uiKpos>(int)uiKmax-1) muiKrel=2*(uiKmax-1-uiKpos)-muiKrel+uiTypeOffset; + } + if (uiDimension==2) + { + ADRESSEXPENSE(7,1,0,0,0,7) + if ( (muiIrel+uiIposError(2); + return 0; + } + else if (uiDimension==3) + { + ADRESSEXPENSE(9,3,0,0,0,11) + if ( (muiIrel+uiIposError(2); + return 0; + } + else return 0; +} + +unsigned int AdrOp::GetPosFromNode(int ny, unsigned int uiNode) +{ + while (ny<0) ny+=uiDimension; + ny=ny%uiDimension; + unsigned int help=uiNode,i=0,j=0,k=0,l=0; + i=help%uiImax; + help=help/uiImax; + j=help%uiJmax; + help=help/uiJmax; + if (uiKmax>0) + { + k=help%uiKmax; + help=help/uiKmax; + l=help; + } + if (!CheckPos(i,j,k,l)) error->Error(8); + ADRESSEXPENSE(0,7,0,0,13,4) + switch (ny) + { + case 0: + { + return i; + break; + } + case 1: + { + return j; + break; + } + case 2: + { + return k; + break; + } + case 3: + { + return l; + break; + } + } + return 0; +} + +double AdrOp::GetNodeVolume(unsigned int uiNode) +{ + for (unsigned int n=0; nError(9); + double dVol=1; + unsigned int uiMax[4]={uiImax,uiJmax,uiKmax,uiLmax}; + unsigned int uiPos[4]={GetPosFromNode(0,uiNode),GetPosFromNode(1,uiNode),GetPosFromNode(2,uiNode),GetPosFromNode(3,uiNode)}; + for (unsigned int n=0; n0) && (uiPos[n]0) && (uiPos[n]==uiMax[n]-1)) + { + dVol*=dDeltaUnit*(dGrid[n][uiPos[n]]-dGrid[n][uiPos[n]-1]); + ADRESSEXPENSE(3,0,1,2,0,4) + } + } + return dVol; +} + +double AdrOp::GetIndexWidth(int ny, int index) +{ + for (unsigned int n=0; nError(9); + double width=0; + while (ny<0) ny+=uiDimension; + ny=ny%uiDimension; + unsigned int uiMax[4]={uiImax,uiJmax,uiKmax,uiLmax}; + if ((index>0) && (index<(int)uiMax[ny]-1)) width= (dGrid[ny][index+1]-dGrid[ny][index-1])/2*dDeltaUnit; + else if ((index==0) && (index<(int)uiMax[ny]-1)) width=(dGrid[ny][index+1]-dGrid[ny][index])*dDeltaUnit; + else if ((index>0) && (index==(int)uiMax[ny]-1)) width=(dGrid[ny][index]-dGrid[ny][index-1])*dDeltaUnit; + else width= 0; + return width; +} + +double AdrOp::GetIndexCoord(int ny, int index) +{ + for (unsigned int n=0; nError(9); + while (ny<0) ny+=uiDimension; + ny=ny%uiDimension; + unsigned int uiMax[4]={uiImax,uiJmax,uiKmax,uiLmax}; + if (index<0) index=0; + if (index>=(int)uiMax[ny]) index=uiMax[ny]-1; + return dGrid[ny][index]*dDeltaUnit; +} + +double AdrOp::GetIndexDelta(int ny, int index) +{ + if (index<0) return GetIndexCoord(ny, 0) - GetIndexCoord(ny, 1); + unsigned int uiMax[4]={uiImax,uiJmax,uiKmax,uiLmax}; + if (index>=(int)uiMax[ny]-1) return GetIndexCoord(ny, (int)uiMax[ny]-2) - GetIndexCoord(ny, (int)uiMax[ny]-1); + return GetIndexCoord(ny, index+1) - GetIndexCoord(ny, index); +} + + +unsigned int AdrOp::Shift(int ny, int step) +{ + if (bPosSet==false) error->Error(6); + while (ny<0) ny+=uiDimension; + ny=ny%uiDimension; + switch (ny) + { + case 0: + { + iIshift=step; +// if ((int)uiIpos+step<0) iIshift=-2*uiIpos-iIshift; +// else if ((int)uiIpos+step>=(int)uiImax) iIshift=-1*iIshift+2*(uiImax-1-uiIpos); + break; + } + case 1: + { + iJshift=step; +// if ((int)uiJpos+iJshift<0) iJshift=-2*uiJpos-iJshift; +// else if ((int)uiJpos+iJshift>=(int)uiJmax) iJshift=-1*iJshift+2*(uiJmax-1-uiJpos); + break; + } + case 2: + { + iKshift=step; +// if ((int)uiKpos+iKshift<0) iKshift=-2*uiKpos-iKshift; +// else if ((int)uiKpos+iKshift>=(int)uiKmax) iKshift=-1*iKshift+2*(uiKmax-1-uiKpos); + break; + } + } + ADRESSEXPENSE(1,1,0,0,2,3) + return GetPos(iIshift,iJshift,iKshift); +} + +bool AdrOp::CheckShift(int ny, int step) +{ + while (ny<0) ny+=uiDimension; + ny=ny%uiDimension; + int shift[3]={0,0,0}; + shift[ny]=step; + if (this->CheckPos(uiIpos+shift[0],uiJpos+shift[1],uiKpos+shift[2])) + { + this->Shift(ny,step); + return true; + } + else return false; +} + +unsigned int AdrOp::GetShiftedPos(int ny, int step) +{ + if ((ny<0) || (ny>2)) + return GetPos(iIshift,iJshift,iKshift); + int pos[3] = {iIshift, iJshift, iKshift}; + pos[ny]+=step; + return GetPos(pos[0],pos[1],pos[2]); +} + +void AdrOp::ResetShift() +{ + iIshift=iJshift=iKshift=0; +} + +unsigned int AdrOp::Iterate(int jump) +{ + if (abs(jump)>=(int)uiImax) error->Error(4); + i=uiIpos+jump; + if (i>=uiImax) + { + i=i-uiImax; + j=uiJpos+1; + if (j>=uiJmax) + { + j=0; + if (uiDimension==3) + { + k=uiKpos+1; + if (k>=uiKmax) k=0; + uiKpos=k; + } + } + uiIpos=i; + uiJpos=j; + return GetPos(); + } + else + { + uiIpos=i; + return GetPos(); + } +} + +unsigned int AdrOp::GetSize() +{ + return uiSize; +} + + +void AdrOp::SetReflection2Node() +{ + reflect=true; + uiTypeOffset=0; +} + +void AdrOp::SetReflection2Cell() +{ + reflect=true; + uiTypeOffset=1; +} + +void AdrOp::SetReflectionOff() +{ + reflect=false; +} + +AdrOp* AdrOp::AddCellAdrOp() +{ + if (clCellAdr!=NULL) return clCellAdr; + if (uiDimension==3) clCellAdr = new AdrOp(uiImax-1,uiJmax-1,uiKmax-1); + else if (uiDimension==2) clCellAdr = new AdrOp(uiImax-1,uiJmax-1); + else clCellAdr=NULL; + if (clCellAdr!=NULL) + { + clCellAdr->SetPos(0,0,0); + clCellAdr->SetReflection2Cell(); + } + iCellShift[0]=iCellShift[1]=iCellShift[2]=0; + return clCellAdr; +} + +AdrOp* AdrOp::DeleteCellAdrOp() +{ + delete clCellAdr; + clCellAdr=NULL; + return NULL; +} + +unsigned int AdrOp::ShiftCell(int ny, int step) +{ + if (clCellAdr==NULL) error->Error(7); + while (ny<0) ny+=uiDimension; + ny=ny%uiDimension; + iCellShift[ny]=step; + ADRESSEXPENSE(3,1,0,0,1,2) + return clCellAdr->GetPos(uiIpos+iCellShift[0],uiJpos+iCellShift[1],uiKpos+iCellShift[2]); +} + +bool AdrOp::ShiftCellCheck(int ny, int step) +{ + return clCellAdr->CheckShift(ny,step); +} + +void AdrOp::ResetCellShift() +{ + if (clCellAdr==NULL) error->Error(7); + iCellShift[0]=iCellShift[1]=iCellShift[2]=0; +} + +unsigned int AdrOp::GetCellPos(bool incShift) +{ + if (bPosSet==false) error->Error(6); + if (clCellAdr==NULL) error->Error(7); +#if EXPENSE_LOG==1 + if (incShift) ADRESSEXPENSE(3,0,0,0,0,2) +#endif + if (incShift) return clCellAdr->GetPos(uiIpos+iCellShift[0],uiJpos+iCellShift[1],uiKpos+iCellShift[2]); + else return clCellAdr->GetPos(uiIpos,uiJpos,uiKpos); +} + +unsigned int AdrOp::GetCellPos(int i, int j, int k) +{ + if (bPosSet==false) error->Error(6); + return clCellAdr->GetPos(uiIpos+i,uiJpos+j,uiKpos+k); +} + + +double AdrOp::GetShiftCellVolume(int ny, int step) +{ + for (unsigned int n=0; nError(9); + int uiMax[4]={(int)uiImax-1,(int)uiJmax-1,(int)uiKmax-1,(int)uiLmax-1}; + while (ny<0) ny+=uiDimension; + ny=ny%uiDimension; + iCellShift[ny]=step; + int uiPos[4]={(int)uiIpos+iCellShift[0],(int)uiJpos+iCellShift[1],(int)uiKpos+iCellShift[2]}; + double dVol=1; + for (unsigned int n=0; n0) + { + while ((uiPos[n]<0) || (uiPos[n]>=uiMax[n])) + { + if (uiPos[n]<0) uiPos[n]=-1*uiPos[n]-1; + else if (uiPos[n]>=uiMax[n]) uiPos[n]=uiMax[n]-(uiPos[n]-uiMax[n]+1); + } + dVol*=(dGrid[n][uiPos[n]+1]-dGrid[n][uiPos[n]])*dDeltaUnit; + } + } + return dVol; +} + + +deltaAdrOp::deltaAdrOp(unsigned int max) +{ + uiMax=max; +} + +deltaAdrOp::~deltaAdrOp() +{ +} + +void deltaAdrOp::SetMax(unsigned int max) +{ + uiMax=max; +} + +unsigned int deltaAdrOp::GetAdr(int pos) +{ + if (uiMax==1) return 0; + if (pos<0) pos=pos*-1; + else if (pos>(int)uiMax-1) pos=2*(uiMax-1)-pos+1; + if ((pos<0) || (pos>(int)uiMax-1)) + { + fprintf(stderr," Error exiting... "); + getchar(); + exit(-1); + } + return pos; +} + + diff --git a/openEMS/tools/AdrOp.h b/openEMS/tools/AdrOp.h new file mode 100644 index 0000000..e4a690b --- /dev/null +++ b/openEMS/tools/AdrOp.h @@ -0,0 +1,149 @@ +/* +* Copyright (C) 2010 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 . +*/ + +/*! +\class AdrOp +\author Thorsten Liebig +\version $Revision: 1.10 $ +\date $Date: 2006/10/29 18:50:44 $ +*/ + +#ifndef ADROP_H +#define ADROP_H + +#include +#include +#include +#include +#include "ExpenseLog.h" +#include "ErrorMsg.h" + +class AdrOp +{ +public: + ///Constructor, define dimension/size here + AdrOp(unsigned int muiImax, unsigned int muiYmax, unsigned int muiKmax=0, unsigned int muiLmax=0); + ///Copy-Constructor + AdrOp(AdrOp* origOP); + ///Deconstructor + virtual ~AdrOp(); + ///Set the current n-dim position, get 1-dim array position as return value + /*!A position has to be set or all other methodes will case error! \n The methode will exit with error message if invalid position is set! \sa ErrorMsg */ + unsigned int SetPos(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos=0, unsigned int muiLpos=0); + + bool SetPosChecked(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos=0, unsigned int muiLpos=0); + + void SetGrid(double *gridI,double *gridJ,double *gridK=NULL,double *gridL=NULL); + void SetGridDelta(double delta) {this->dDeltaUnit=delta;}; + + bool CheckPos(unsigned int muiIpos, unsigned int muiJpos, unsigned int muiKpos=0, unsigned int muiLpos=0); + bool CheckRelativePos(int muiIrel=0,int muiJrel=0,int muiKrel=0, int muiLrel=0); + ///will return current 1-dim position, in addition to a relative n-dim shift + /*!In case of crossing the boundaries, activate reflection or an error will be invoked\sa SetReflection2Node \sa SetReflection2Cell \sa SetReflectionOff */ + unsigned int GetPos(int muiIrel=0,int muiJrel=0,int muiKrel=0, int muiLrel=0); + + double GetNodeVolume(unsigned int uiNode); + + double GetIndexWidth(int ny, int index); + double GetIndexCoord(int ny, int index); + ///Get the gird delta at the given index of direction ny. (if index<0 return negative value as index=0 would give, if index>=max-1 returns negative value as index=max-2 would give) + double GetIndexDelta(int ny, int index); + +// double GetCellVolume(unsigned int uiCell); + + unsigned int GetPosFromNode(int ny, unsigned int uiNode); + ///Set a shift in ny direction (e.g. 0 for i-direction) + /*!Shift set by this methode will be ignored by methode GetPos*/ + unsigned int Shift(int ny, int step); + ///Set a checked shift in ny direction (e.g. 0 for i-direction) + /*!Shift set by this methode will be ignored by methode GetPos*/ + bool CheckShift(int ny, int step); + ///Returns the current 1-dim position including shift by methode "Shift" + additional (transitory) shift + unsigned int GetShiftedPos(int ny=-1, int step=0); + ///Reset shift set by "Shift"-methode + void ResetShift(); + ///Iterates through AdrOp; --- obsolete --- + unsigned int Iterate(int jump=1); + ///Retruns size of array + unsigned int GetSize(); + ///Set mode to reflect by node + /*!1D-example (6 nodes): \image html node_reflect.PNG order: 0,1,2,3,4,5,4,3,...*/ + void SetReflection2Node(); + ///Set mode to reflect by cell + /*!1D-example (5 cells): \image html cell_reflect.PNG order: 0,1,2,3,4,4,3,...*/ + void SetReflection2Cell(); + ///Deactivate reflection (default) + void SetReflectionOff(); + ///Add a cell adress operator (dimensions: i-1 j-1 k-1 l-1) + /*!\image html cells_nodes.png */ + AdrOp* AddCellAdrOp(); + + AdrOp* GetCellAdrOp() {return clCellAdr;}; + + ///Deconstructed cell adress operator if no longer needed + AdrOp* DeleteCellAdrOp(); + ///Shift cell in ny dircetion; cell reflection is active + unsigned int ShiftCell(int ny, int step); + ///Shift cell in ny dircetion; cell reflection is active; return check + bool ShiftCellCheck(int ny, int step); + ///Reset cell shift + void ResetCellShift(); + ///Get current cell position from cell adress operator + unsigned int GetCellPos(bool incShift=true); + ///Get cell position from cell adress operator + unsigned int GetCellPos(int i, int j, int k=0); + //get volume of cell; incl shift + double GetShiftCellVolume(int ny, int step); + + + void SetDebugOn() {this->bDebug=true;}; + void SetDebugOff() {this->bDebug=false;}; + +protected: + AdrOp *clCellAdr; + unsigned int uiDimension; + unsigned int uiSize; + unsigned int uiImax,uiJmax,uiKmax,uiLmax; + unsigned int uiIpos, uiJpos, uiKpos, uiLpos; + double *dGrid[4]; + double dDeltaUnit; + int iIshift, iJshift, iKshift; + int iCellShift[3]; + unsigned int i,j,k,l; + bool reflect; + unsigned int uiTypeOffset; + + bool bPosSet; + bool bDebug; + ErrorMsg *error; +}; + + +class deltaAdrOp +{ +public: + deltaAdrOp(unsigned int max=0); + virtual ~deltaAdrOp(); + void SetMax(unsigned int max); + unsigned int GetAdr(int pos); + +protected: + unsigned int uiMax; +}; + + +#endif // ADROP_H diff --git a/openEMS/tools/CMakeLists.txt b/openEMS/tools/CMakeLists.txt new file mode 100644 index 0000000..8b62b8a --- /dev/null +++ b/openEMS/tools/CMakeLists.txt @@ -0,0 +1,28 @@ + +set(SOURCES + ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/AdrOp.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ErrorMsg.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/array_ops.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/global.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/hdf5_file_reader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/hdf5_file_writer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/sar_calculation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/useful.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/vtk_file_writer.cpp + PARENT_SCOPE +) + +#set(HEADERS +# constants.h +# array_ops.h +# global.h +# useful.h +# aligned_allocator.h +# hdf5_file_reader.h +# hdf5_file_writer.h +#) + +# tools lib +#add_library(tools STATIC ${SOURCES} ) + diff --git a/openEMS/tools/ErrorMsg.cpp b/openEMS/tools/ErrorMsg.cpp new file mode 100644 index 0000000..9a1974c --- /dev/null +++ b/openEMS/tools/ErrorMsg.cpp @@ -0,0 +1,98 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include +#include +#include +#include "ErrorMsg.h" + +ErrorMsg::ErrorMsg(unsigned int NoMessage) +{ + NoMsg=NoMessage; + if (NoMsg>0) Msg = new char*[NoMsg]; + if (Msg==NULL) + { + fprintf(stderr,"Memory allocation failed!! exiting..."); + exit(1); + } + for (unsigned int i=0; iNoMsg) || (Message==NULL)) ownError(); + Msg[nr-1] = new char[strlen(Message)+1]; + if (Msg[nr-1]==NULL) + { + fprintf(stderr,"Memory allocation failed!! exiting..."); + exit(1); + } + Msg[nr-1]=strcpy(Msg[nr-1],Message); +} + +void ErrorMsg::Error(unsigned int nr,char *chAddMsg) +{ + if ((nr>0) && (nr<=NoMsg)) + { + if (Msg[nr-1]!=NULL) fprintf(stderr,"%s",Msg[nr-1]); + else fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + if (chAddMsg!=NULL) fprintf(stderr,"%s",chAddMsg); + getchar(); + exit(nr); + } + else + { + fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + getchar(); + exit(nr); + } +} + +void ErrorMsg::Error(unsigned int nr,int addNr) +{ + if ((nr>0) && (nr<=NoMsg)) + { + if (Msg[nr-1]!=NULL) fprintf(stderr,"%s",Msg[nr-1]); + else fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + fprintf(stderr,"%d",addNr); + getchar(); + exit(nr); + } + else + { + fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + getchar(); + exit(nr); + } +} + +void ErrorMsg::ownError(void) +{ + fprintf(stdout," Error occured by using Error Message class!! ... exiting..."); + exit(-1); +} diff --git a/openEMS/tools/ErrorMsg.h b/openEMS/tools/ErrorMsg.h new file mode 100644 index 0000000..fa63c93 --- /dev/null +++ b/openEMS/tools/ErrorMsg.h @@ -0,0 +1,50 @@ +/* +* Copyright (C) 2010 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 . +*/ + +/*! +\class ErrorMsg +\author Thorsten Liebig +\version $Revision: 1.2 $ +\date $Date: 2006/01/25 11:47:07 $ +*/ + +#ifndef _ERRORMSG_H_ +#define _ERRORMSG_H_ + +class ErrorMsg +{ +public: + ///Constructor defines number of error messages + ErrorMsg(unsigned int NoMessage=0); + ///Deconstructor + virtual ~ErrorMsg(); + ///Methode for defining error messages + /*! \param nr Number of defining error message \param *Message Set error message string \sa Error */ + void SetMsg(unsigned int nr, const char *Message); + ///Call an error message. Will exit the program! + /*! \param nr Number of called error message. default is 0 \sa SetMsg*/ + void Error(unsigned int nr=0,char *chAddMsg=0); + + void Error(unsigned int nr,int addNr); + +protected: + void ownError(void); + unsigned int NoMsg; + char **Msg; +}; + +#endif //_ERRORMSG_H_ diff --git a/openEMS/tools/ExpenseLog.cpp b/openEMS/tools/ExpenseLog.cpp new file mode 100644 index 0000000..95a0d4c --- /dev/null +++ b/openEMS/tools/ExpenseLog.cpp @@ -0,0 +1,145 @@ +#include "ExpenseLog.h" + +ExpenseModule::ExpenseModule(const char* moduleName) +{ + chModuleName=moduleName; + uiDoubleAdditions=uiDoubleMultiplications=uiIntAdditions=uiIntMultiplications=uiAssignments=uiBoolOp=0; + uiMrdDA=uiMrdDM=uiMrdIA=uiMrdIM=uiMrdAssign=uiMrdBO=0; +} + +ExpenseModule::~ExpenseModule() {}; + +void ExpenseModule::Clear() +{ + uiDoubleAdditions=uiDoubleMultiplications=uiIntAdditions=uiIntMultiplications=uiAssignments=uiBoolOp=0; + uiMrdDA=uiMrdDM=uiMrdIA=uiMrdIM=uiMrdAssign=uiMrdBO=0; +} + +void ExpenseModule::AddDoubleAdditons(unsigned int number) +{ + uiDoubleAdditions+=number; + if (uiDoubleAdditions>=MRD) + { + uiDoubleAdditions-=MRD; + ++uiMrdDA; + } +} + +void ExpenseModule::AddDoubleMultiplications(unsigned int number) +{ + uiDoubleMultiplications+=number; + if (uiDoubleMultiplications>=MRD) + { + uiDoubleMultiplications-=MRD; + ++uiMrdDM; + } +} + +void ExpenseModule::AddIntAdditons(unsigned int number) +{ + uiIntAdditions+=number; + if (uiIntAdditions>=MRD) + { + uiIntAdditions-=MRD; + ++uiMrdIA; + } +} + +void ExpenseModule::AddIntMultiplications(unsigned int number) +{ + uiIntMultiplications+=number; + if (uiIntMultiplications>=MRD) + { + uiIntMultiplications-=MRD; + ++uiMrdIM; + } +} + +void ExpenseModule::AddAssignments(unsigned int number) +{ + uiAssignments+=number; + if (uiAssignments>=MRD) + { + uiAssignments-=MRD; + ++uiMrdAssign; + } +} + +void ExpenseModule::AddBoolOperations(unsigned int number) +{ + uiBoolOp+=number; + if (uiBoolOp>=MRD) + { + uiBoolOp-=MRD; + ++uiMrdBO; + } +} + +void ExpenseModule::AddOperations(unsigned int IntAdd, unsigned int IntMul, unsigned int DoubleAdd, unsigned int DoubleMul, unsigned int Assigns, unsigned int BoolOp) +{ + this->AddIntAdditons(IntAdd); + this->AddIntMultiplications(IntMul); + this->AddDoubleAdditons(DoubleAdd); + this->AddDoubleMultiplications(DoubleMul); + this->AddAssignments(Assigns); + this->AddBoolOperations(BoolOp); +} + +void ExpenseModule::PrintfSelf(FILE* file) +{ + fprintf(file,"\n***********\n Module: %s\n Additions:\n Double: %3.0d%9d\tInteger: %3.0d%9d",chModuleName,uiMrdDA,uiDoubleAdditions,uiMrdIA,uiIntAdditions); + fprintf(file,"\n\n Multiplications:\n Double: %3.0d%9d\tInteger: %3.0d%9d\n",uiMrdDM,uiDoubleMultiplications,uiMrdIM,uiIntMultiplications); + fprintf(file,"\n Assignments: %3.0d%9d\tBool Operations: %3.0d%9d\n",uiMrdAssign,uiAssignments,uiMrdBO,uiBoolOp); + fprintf(file,"\n***********\n"); +} + + + + +/***********************************************************************************************************************/ + +ExpenseLog::ExpenseLog(void) +{ +} + +ExpenseLog::~ExpenseLog(void) +{ + for (size_t i=0; iuiIntAdditions+(double)vModules.at(i)->uiDoubleAdditions) + 1e9*((double)vModules.at(i)->uiMrdIA+(double)vModules.at(i)->uiMrdIA); + totalMul+=((double)vModules.at(i)->uiIntMultiplications+(double)vModules.at(i)->uiDoubleMultiplications) + 1e9*(double)(vModules.at(i)->uiMrdIM+vModules.at(i)->uiMrdIM); + totalBool+=(double)vModules.at(i)->uiBoolOp + 1e9*(double)vModules.at(i)->uiMrdBO; + totalAssign+=(double)vModules.at(i)->uiAssignments + 1e9*(double)vModules.at(i)->uiMrdAssign; + vModules.at(i)->PrintfSelf(file); + } + fprintf(stderr," Total:\n Additions: %e Multiplications: %e\n Bool Operations: %e Assignments: %e\n",totalAdd,totalMul,totalBool,totalAssign); + fprintf(stderr,"\n ----------------\n"); +} + +void ExpenseLog::ClearAll() +{ + for (size_t i=0; iClear(); + } +} + diff --git a/openEMS/tools/ExpenseLog.h b/openEMS/tools/ExpenseLog.h new file mode 100644 index 0000000..f8cc1ba --- /dev/null +++ b/openEMS/tools/ExpenseLog.h @@ -0,0 +1,92 @@ +#pragma once +#include +#include +#include + +using namespace std; + +#define EXPENSE_LOG 0 +#define MRD 1000000000 + +#if EXPENSE_LOG==1 + +#define EXPENSE_DEFINE \ +ExpenseLog EL; \ +ExpenseModule* EngineExpense=EL.AddModule("Static Engine Expenses"); \ +ExpenseModule* PPExpense=EL.AddModule("Static Post Processing"); \ +ExpenseModule* AdrOpExpense=EL.AddModule("Adress Operator"); +#define EXTERN_EXPENSE_DEFINE extern ExpenseLog EL; +#define ENGINEEXPENSE_DEFINE extern ExpenseModule* EngineExpense; +#define POSTPROCEXPENSE_DEFINE extern ExpenseModule* PPExpense; +#define ADREXPENSE_DEFINE extern ExpenseModule* AdrOpExpense; +#define ENGINEEXPENSE(IA,IM,DA,DM,AS,BO) EngineExpense->AddOperations((IA),(IM),(DA),(DM),(AS),(BO)); +#define POSTPROCEXPENSE(IA,IM,DA,DM,AS,BO) PPExpense->AddOperations((IA),(IM),(DA),(DM),(AS),(BO)); +#define ADRESSEXPENSE(IA,IM,DA,DM,AS,BO) AdrOpExpense->AddOperations((IA),(IM),(DA),(DM),(AS),(BO)); +#define EXPENSEPRINT EL.PrintAll(stderr); +#define EXPENSECLEAR EL.ClearAll(); +#else + +#define EXPENSE_DEFINE +#define EXTERN_EXPENSE_DEFINE +#define ENGINEEXPENSE_DEFINE +#define POSTPROCEXPENSE_DEFINE +#define ADREXPENSE_DEFINE +#define ENGINEEXPENSE(IA,IM,DA,DM,AS,BO) +#define POSTPROCEXPENSE(IA,IM,DA,DM,AS,BO) +#define ADRESSEXPENSE(IA,IM,DA,DM,AS,BO) +#define EXPENSEPRINT +#define EXPENSECLEAR +#endif + +class ExpenseModule +{ + friend class ExpenseLog; +public: + ExpenseModule(const char* moduleName); + ~ExpenseModule(); + + void Clear(); + + void AddDoubleAdditons(unsigned int number); + void AddDoubleMultiplications(unsigned int number); + + void AddIntAdditons(unsigned int number); + void AddIntMultiplications(unsigned int number); + + void AddAssignments(unsigned int number); + void AddBoolOperations(unsigned int number); + + void AddOperations(unsigned int IntAdd, unsigned int IntMul, unsigned int DoubleAdd, unsigned int DoubleMul, unsigned int Assigns, unsigned int BoolOp); + + void PrintfSelf(FILE* file=stdout); + +protected: + const char* chModuleName; + unsigned int uiDoubleAdditions; + unsigned int uiDoubleMultiplications; + unsigned int uiIntAdditions; + unsigned int uiIntMultiplications; + unsigned int uiAssignments; + unsigned int uiBoolOp; + unsigned int uiMrdDA; + unsigned int uiMrdDM; + unsigned int uiMrdIA; + unsigned int uiMrdIM; + unsigned int uiMrdAssign; + unsigned int uiMrdBO; +}; + +class ExpenseLog +{ +public: + ExpenseLog(void); + ~ExpenseLog(void); + + ExpenseModule* AddModule(const char* name); + void PrintAll(FILE *file=stdout); + void ClearAll(); +protected: + vector vModules; +}; + + diff --git a/openEMS/tools/aligned_allocator.h b/openEMS/tools/aligned_allocator.h new file mode 100644 index 0000000..efabe7d --- /dev/null +++ b/openEMS/tools/aligned_allocator.h @@ -0,0 +1,173 @@ +/* +* Copyright (C) 2010 Sebastian Held (sebastian.held@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 . +*/ + +// based on http://blogs.msdn.com/b/vcblog/archive/2008/08/28/the-aligned_allocator.aspx +// from Stephan T. Lavavej + + +// The following headers are required for all allocators. +#include // Required for size_t and ptrdiff_t and NULL +#include // Required for placement new and std::bad_alloc +#include // Required for std::length_error + + +#ifdef WIN32 +#define __MSVCRT_VERSION__ 0x0700 +#include +#define MEMALIGN( array, alignment, size ) !(*array = _aligned_malloc( size, alignment )) +#define FREE( array ) _aligned_free( array ) +#else +#define MEMALIGN( array, alignment, size ) posix_memalign( array, alignment, size ) +#define FREE( array ) free( array ) +#endif + + +template class aligned_allocator +{ +public: + // The following will be the same for virtually all allocators. + typedef T * pointer; + typedef const T * const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + T * address(T& r) const + { + return &r; + } + + const T * address(const T& s) const + { + return &s; + } + + size_t max_size() const + { + // The following has been carefully written to be independent of + // the definition of size_t and to avoid signed/unsigned warnings. + return (static_cast(0) - static_cast(1)) / sizeof(T); + } + + // The following must be the same for all allocators. + template struct rebind + { + typedef aligned_allocator other; + }; + + bool operator!=(const aligned_allocator& other) const + { + return !(*this == other); + } + + void construct(T * const p, const T& t) const + { + void * const pv = static_cast(p); + new (pv) T(t); + } + + void destroy(T * const p) const; // Defined below. + + // Returns true if and only if storage allocated from *this + // can be deallocated from other, and vice versa. + // Always returns true for stateless allocators. + bool operator==(const aligned_allocator& other) const + { + return true; + } + + // Default constructor, copy constructor, rebinding constructor, and destructor. + // Empty for stateless allocators. + aligned_allocator() { } + aligned_allocator(const aligned_allocator&) { } + template aligned_allocator(const aligned_allocator&) { } + ~aligned_allocator() { } + + // The following will be different for each allocator. + T * allocate(const size_t n) const + { +// std::cout << "Allocating " << n << (n == 1 ? " object" : "objects") << " of size " << sizeof(T) << "." << std::endl; + // The return value of allocate(0) is unspecified. + // aligned_allocator returns NULL in order to avoid depending + // on malloc(0)'s implementation-defined behavior + // (the implementation can define malloc(0) to return NULL, + // in which case the bad_alloc check below would fire). + // All allocators can return NULL in this case. + if (n == 0) + { + return NULL; + } + + // All allocators should contain an integer overflow check. + // The Standardization Committee recommends that std::length_error + // be thrown in the case of integer overflow. + if (n > max_size()) + { + throw std::length_error("aligned_allocator::allocate() - Integer overflow."); + } + + // Allocators should throw std::bad_alloc in the case of memory allocation failure. + void * pv; + if (MEMALIGN( &pv, 16, n * sizeof(T))) + throw std::bad_alloc(); + + return static_cast(pv); + } + + void deallocate(T * const p, const size_t n) const + { +// std::cout << "Deallocating " << n << (n == 1 ? " object" : "objects") << " of size " << sizeof(T) << "." << std::endl; + // aligned_allocator wraps free(). + UNUSED(n); + FREE(p); + } + + // The following will be the same for all allocators that ignore hints. + template T * allocate(const size_t n, const U * /* const hint */) const + { + return allocate(n); + } + + // Allocators are not required to be assignable, so + // all allocators should have a private unimplemented + // assignment operator. Note that this will trigger the + // off-by-default (enabled under /Wall) warning C4626 + // "assignment operator could not be generated because a + // base class assignment operator is inaccessible" within + // the STL headers, but that warning is useless. + +private: + aligned_allocator& operator=(const aligned_allocator&); +}; + +// A compiler bug causes it to believe that p->~T() doesn't reference p. +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4100) // unreferenced formal parameter +#endif + +// The definition of destroy() must be the same for all allocators. +template void aligned_allocator::destroy(T * const p) const +{ + p->~T(); +} + +#ifdef _MSC_VER +#pragma warning(pop) +#endif diff --git a/openEMS/tools/array_ops.cpp b/openEMS/tools/array_ops.cpp new file mode 100644 index 0000000..8710b3c --- /dev/null +++ b/openEMS/tools/array_ops.cpp @@ -0,0 +1,144 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "array_ops.h" +#include + +using namespace std; + +#ifdef WIN32 +#define __MSVCRT_VERSION__ 0x0700 +#include +//(void**)&array, 16, sizeof(typeof(f4vector**))*numLines[0] +#define MEMALIGN( array, alignment, size ) !(*array = _aligned_malloc( size, alignment )) +#define FREE( array ) _aligned_free( array ) +#else +#define MEMALIGN( array, alignment, size ) posix_memalign( array, alignment, size ) +#define FREE( array ) free( array ) +#endif + +void Delete1DArray_v4sf(f4vector* array) +{ + if (array==NULL) return; + FREE( array ); +} + + +void Delete3DArray_v4sf(f4vector*** array, const unsigned int* numLines) +{ + if (array==NULL) return; + unsigned int pos[3]; + for (pos[0]=0; pos[0]. +*/ + +#ifndef ARRAY_OPS_H +#define ARRAY_OPS_H + +#ifdef __SIZEOF_FLOAT__ +#if __SIZEOF_FLOAT__ != 4 +#error wrong size of float +#endif +#endif + +#include +#include +#include +#include +#include +#include "constants.h" + +typedef float v4sf __attribute__ ((vector_size (16))); // vector of four single floats +typedef int v4si __attribute__ ((vector_size (4*sizeof(int)))); // vector of four single ints + +union f4vector +{ + v4sf v; + float f[4]; +}; + +void Delete1DArray_v4sf(f4vector* array); +void Delete3DArray_v4sf(f4vector*** array, const unsigned int* numLines); +void Delete_N_3DArray_v4sf(f4vector**** array, const unsigned int* numLines); +f4vector* Create1DArray_v4sf(const unsigned int numLines); +f4vector*** Create3DArray_v4sf(const unsigned int* numLines); +f4vector**** Create_N_3DArray_v4sf(const unsigned int* numLines); + +// ************************************************************************************* +// templates +// ************************************************************************************* +template +T** Create2DArray(const unsigned int* numLines) +{ + T** array=NULL; + unsigned int pos[3]; + array = new T*[numLines[0]]; + for (pos[0]=0; pos[0] +void Delete2DArray(T** array, const unsigned int* numLines) +{ + if (array==NULL) return; + unsigned int pos[3]; + for (pos[0]=0; pos[0] +inline T& Access_N_3DArray(T**** array, unsigned int n, unsigned int* pos) +{ + return array[n][pos[0]][pos[1]][pos[2]]; +} + +template +inline T& Access_N_3DArray(T**** array, unsigned int n, unsigned int x, unsigned int y, unsigned int z ) +{ + return array[n][x][y][z]; +} + +template +T*** Create3DArray(const unsigned int* numLines) +{ + T*** array=NULL; + unsigned int pos[3]; + array = new T**[numLines[0]]; + for (pos[0]=0; pos[0] +T*** Copy3DArray(T*** array_in, T*** array_out, const unsigned int* numLines) +{ + if (array_out==NULL) + array_out = Create3DArray(numLines); + unsigned int pos[3]; + for (pos[0]=0; pos[0] +T**** Create_N_3DArray(const unsigned int* numLines) +{ + T**** array=NULL; + array = new T***[3]; + for (int n=0; n<3; ++n) + { + array[n]=Create3DArray( numLines ); + } + return array; +} + +template +T**** Copy_N_3DArray(T**** array_in, T**** array_out, const unsigned int* numLines) +{ + if (array_out==NULL) + array_out = Create_N_3DArray(numLines); + for (int n=0; n<3; ++n) + array_out[n]=Copy3DArray( array_in[n], array_out[n], numLines); + return array_out; +} + +template +void Delete3DArray(T*** array, const unsigned int* numLines) +{ + if (!array) return; + unsigned int pos[3]; + for (pos[0]=0; pos[0] +void Delete_N_3DArray(T**** array, const unsigned int* numLines) +{ + if (!array) return; + for (int n=0; n<3; ++n) + { + Delete3DArray(array[n],numLines); + } + delete[] array; +} + +template +void Dump_N_3DArray2File(std::ostream &file, T**** array, const unsigned int* numLines) +{ + unsigned int pos[3]; + for (pos[0]=0; pos[0]. +*/ + +#ifndef CONSTANTS_H +#define CONSTANTS_H + +#define FDTD_FLOAT float + +#define __EPS0__ 8.85418781762e-12 +#define __MUE0__ 1.256637062e-6 +#define __C0__ 299792458 +#define __Z0__ 376.730313461 +#define PI 3.141592653589793238462643383279 + +#endif // CONSTANTS_H diff --git a/openEMS/tools/global.cpp b/openEMS/tools/global.cpp new file mode 100644 index 0000000..3e97fac --- /dev/null +++ b/openEMS/tools/global.cpp @@ -0,0 +1,78 @@ +/* +* Copyright (C) 2010 Sebastian Held +* +* 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 . +*/ + +#include +#include +#include "global.h" + +using namespace std; + +// create global object +Global g_settings; + +Global::Global() +{ + m_showProbeDiscretization = false; + m_nativeFieldDumps = false; + m_VerboseLevel = 0; +} + +void Global::ShowArguments(ostream& ostr, string front) +{ + ostr << front << "--showProbeDiscretization\tShow probe discretization information" << endl; + ostr << front << "--nativeFieldDumps\t\tDump all fields using the native field components" << endl; + ostr << front << "-v,-vv,-vvv\t\t\tSet debug level: 1 to 3" << endl; +} + +//! \brief This function initializes the object +bool Global::parseCommandLineArgument( const char *argv ) +{ + if (!argv) + return false; + + if (strcmp(argv,"--showProbeDiscretization")==0) + { + cout << "openEMS - showing probe discretization information" << endl; + m_showProbeDiscretization = true; + return true; + } + else if (strcmp(argv,"--nativeFieldDumps")==0) + { + cout << "openEMS - dumping all fields using the native field components" << endl; + m_nativeFieldDumps = true; + return true; + } + else if (strcmp(argv,"-v")==0) + { + cout << "openEMS - verbose level 1" << endl; + m_VerboseLevel = 1; + return true; + } + else if (strcmp(argv,"-vv")==0) + { + cout << "openEMS - verbose level 2" << endl; + m_VerboseLevel = 2; + return true; + } + else if (strcmp(argv,"-vvv")==0) + { + cout << "openEMS - verbose level 3" << endl; + m_VerboseLevel = 3; + return true; + } + return false; +} diff --git a/openEMS/tools/global.h b/openEMS/tools/global.h new file mode 100644 index 0000000..c3bb524 --- /dev/null +++ b/openEMS/tools/global.h @@ -0,0 +1,65 @@ +/* +* Copyright (C) 2010 Sebastian Held +* +* 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 . +*/ + +#ifndef GLOBAL_H +#define GLOBAL_H + +#include + +#define UNUSED(x) (void)(x); + +class Global +{ +public: + Global(); + + //! Show all possible (global) command line arguments + void ShowArguments(std::ostream& ostr, std::string front=std::string()); + + //! Parse the given command line arguments + bool parseCommandLineArgument( const char *argv ); + + bool showProbeDiscretization() const {return m_showProbeDiscretization;} + + //! Returns true if native field dumps are requested... + bool NativeFieldDumps() const {return m_nativeFieldDumps;} + //! Set dumps to use native fields. + void SetNativeFieldDumps(bool val) {m_nativeFieldDumps=val;} + + //! Set the verbose level + void SetVerboseLevel(int level) {m_VerboseLevel=level;m_SavedVerboseLevel=level;} + //! Get the verbose level + int GetVerboseLevel() const {return m_VerboseLevel;} + + //! Set a new verbose level temporarily, restore it with RestoreVerboseLevel() + void SetTempVerboseLevel(int level) {m_SavedVerboseLevel=m_VerboseLevel;m_VerboseLevel=level;} + //! Restore the temporarily overwritten verbose level + void RestoreVerboseLevel() {m_VerboseLevel=m_SavedVerboseLevel;} + +protected: + bool m_showProbeDiscretization; + bool m_nativeFieldDumps; + int m_VerboseLevel; + int m_SavedVerboseLevel; +}; + +extern Global g_settings; + +// declare a parameter as unused +#define UNUSED(x) (void)(x); + +#endif // GLOBAL_H diff --git a/openEMS/tools/hdf5_file_reader.cpp b/openEMS/tools/hdf5_file_reader.cpp new file mode 100644 index 0000000..a6e1359 --- /dev/null +++ b/openEMS/tools/hdf5_file_reader.cpp @@ -0,0 +1,689 @@ +/* +* Copyright (C) 2011 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 . +*/ + +#include "hdf5_file_reader.h" +#include "../tools/array_ops.h" +#include + +#include +#include +#include + +using namespace std; + +HDF5_File_Reader::HDF5_File_Reader(string filename) +{ + m_filename = filename; + //suppress hdf5 error output + //H5Eset_auto(NULL, NULL); +} + +HDF5_File_Reader::~HDF5_File_Reader() +{ +} + +bool HDF5_File_Reader::IsValid() +{ + htri_t val = H5Fis_hdf5(m_filename.c_str()); + if (val<0) + { + cerr << "HDF5_File_Reader::IsValid: the given file """ << m_filename << """ is not accessible..." << endl; + return false; + } + if (val==0) + { + cerr << "HDF5_File_Reader::IsValid: the given file """ << m_filename << """ is invalid..." << endl; + return false; + } + if (val==0) + cerr << "HDF5_File_Reader::IsValid: the given file """ << m_filename << """ is valid..." << endl; + return true; +} + +bool HDF5_File_Reader::OpenGroup(hid_t &file, hid_t &group, string groupName) +{ + file = H5Fopen( m_filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT ); + if (file==-1) + { + cerr << "HDF5_File_Reader::OpenGroup: opening the given file """ << m_filename << """ failed" << endl; + return 0; + } + if (H5Lexists(file, groupName.c_str(), H5P_DEFAULT)<=0) + { + H5Fclose(file); + return 0; + } + + group = H5Gopen(file, groupName.c_str(), H5P_DEFAULT ); + if (group<0) + { + cerr << "HDF5_File_Reader::OpenGroup: can't open group """ << groupName << """" << endl; + H5Fclose(file); + return 0; + } + return true; +} + +bool HDF5_File_Reader::ReadAttribute(string grp_name, string attr_name, vector &attr_values) +{ + vector d_attr_values; + if (ReadAttribute(grp_name, attr_name, d_attr_values)==false) + return false; + attr_values.resize(d_attr_values.size(),0); + for (size_t n=0;n &attr_values) +{ + attr_values.clear(); + + hid_t hdf5_file = H5Fopen( m_filename.c_str(), H5F_ACC_RDONLY, H5P_DEFAULT ); + if (hdf5_file==-1) + { + cerr << "HDF5_File_Reader::OpenGroup: opening the given file """ << m_filename << """ failed" << endl; + return 0; + } + + if (H5Lexists(hdf5_file, grp_name.c_str(), H5P_DEFAULT)<=0) + { + H5Fclose(hdf5_file); + return false; + } + + hid_t attr = H5Aopen_by_name(hdf5_file, grp_name.c_str(), attr_name.c_str(), H5P_DEFAULT, H5P_DEFAULT); + if (attr==-1) + { + cerr << "HDF5_File_Reader::ReadAttribute: Opening the given Attribute: """ << attr_name << """ failed" << endl; + H5Fclose(hdf5_file); + return false; + } + + hid_t type = H5Aget_type(attr); + if (type<0) + { + cerr << "HDF5_File_Reader::ReadAttribute: Dataset type error" << endl; + H5Aclose(attr); + H5Fclose(hdf5_file); + return false; + } + + attr_values.clear(); + if (H5Tget_class(type)==H5T_FLOAT) + { + size_t numVal = H5Aget_storage_size(attr)/H5Tget_size(type); + hid_t datatype=-1; + void *value=NULL; + float *f_value=NULL; + double *d_value=NULL; + if (H5Tget_size(type)==sizeof(float)) + { + f_value = new float[numVal]; + value = f_value; + datatype = H5T_NATIVE_FLOAT; + } + if (H5Tget_size(type)==sizeof(double)) + { + d_value = new double[numVal]; + value = d_value; + datatype = H5T_NATIVE_DOUBLE; + } + if (H5Aread(attr, datatype, value)<0) + { + cerr << "HDF5_File_Reader::ReadAttribute: Reading the given Attribute failed" << endl; + H5Aclose(attr); + H5Fclose(hdf5_file); + return false; + } + if (f_value) + for (size_t n=0;n Mesh_Names; + if (H5Lexists(hdf5_file, "/Mesh/x", H5P_DEFAULT) && H5Lexists(hdf5_file, "/Mesh/y", H5P_DEFAULT) && H5Lexists(hdf5_file, "/Mesh/z", H5P_DEFAULT)) + { + meshType = 0; + Mesh_Names.push_back("/Mesh/x"); + Mesh_Names.push_back("/Mesh/y"); + Mesh_Names.push_back("/Mesh/z"); + } + else if (H5Lexists(hdf5_file, "/Mesh/rho", H5P_DEFAULT) && H5Lexists(hdf5_file, "/Mesh/alpha", H5P_DEFAULT) && H5Lexists(hdf5_file, "/Mesh/z", H5P_DEFAULT)) + { + meshType = 1; + Mesh_Names.push_back("/Mesh/rho"); + Mesh_Names.push_back("/Mesh/alpha"); + Mesh_Names.push_back("/Mesh/z"); + } + else + { + cerr << "HDF5_File_Reader::ReadMesh: no falid mesh information found" << endl; + H5Fclose(hdf5_file); + return false; + } + + for (int n=0;n<3;++n) + { + hsize_t nDim; + hsize_t* dims=NULL; + float* data=NULL; + ReadDataSet(Mesh_Names.at(n), nDim, dims, data); + if (nDim!=1) + { + cerr << "HDF5_File_Reader::ReadMesh: mesh dimension error" << endl; + delete[] dims; + delete[] data; + H5Fclose(hdf5_file); + return false; + } + numLines[n]=dims[0]; + delete[] dims; + lines[n]=data; + } + H5Fclose(hdf5_file); + return true; +} + +unsigned int HDF5_File_Reader::GetNumTimeSteps() +{ + if (IsValid()==false) + return false; + + hid_t hdf5_file; + hid_t TD_grp; + if (OpenGroup(hdf5_file, TD_grp, "/FieldData/TD")==false) + return false; + + hsize_t numObj; + if (H5Gget_num_objs(TD_grp,&numObj)<0) + { + cerr << "HDF5_File_Reader::GetNumTimeSteps: can't read number of datasets" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return 0; + } + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return numObj; +} + +bool HDF5_File_Reader::ReadTimeSteps(vector ×tep, vector &names) +{ + if (IsValid()==false) + return false; + + hid_t hdf5_file; + hid_t TD_grp; + if (OpenGroup(hdf5_file, TD_grp, "/FieldData/TD")==false) + return false; + + hsize_t numObj; + if (H5Gget_num_objs(TD_grp,&numObj)<0) + { + cerr << "HDF5_File_Reader::ReadTimeSteps: can't read number of datasets" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return false; + } + char name[100]; + timestep.clear(); + timestep.resize(numObj,0); + names.clear(); + names.resize(numObj); + for (hsize_t n=0;n> num) + { + timestep.at(n)=num; + names.at(n)=name; + } + else + { + cerr << "HDF5_File_Reader::ReadTimeSteps: invalid timestep format found!" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return false; + } + } + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return true; +} + +float**** HDF5_File_Reader::GetTDVectorData(size_t idx, float &time, unsigned int data_size[]) +{ + if (IsValid()==false) + return NULL; + + hid_t hdf5_file; + hid_t TD_grp; + if (OpenGroup(hdf5_file, TD_grp, "/FieldData/TD")==false) + return NULL; + + hsize_t numObj; + if (H5Gget_num_objs(TD_grp,&numObj)<0) + { + cerr << "HDF5_File_Reader::GetTDVectorData: can't read number of datasets" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + if (idx>=numObj) + { + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + + if (H5Gget_objtype_by_idx(TD_grp, idx) != H5G_DATASET) + { + cerr << "HDF5_File_Reader::GetTDVectorData: invalid timestep found!" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + + char name[100]; + H5Gget_objname_by_idx(TD_grp, idx, name, 100 ); + string ds_name = "/FieldData/TD/" + string(name); + + hid_t attr = H5Aopen_by_name(hdf5_file, ds_name.c_str(), "time", H5P_DEFAULT, H5P_DEFAULT); + if (attr<0) + { + cerr << "HDF5_File_Reader::GetTDVectorData: time attribute not found!" << endl; + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + if (H5Aread(attr, H5T_NATIVE_FLOAT, &time)<0) + { + cerr << "HDF5_File_Reader::GetTDVectorData: can't read time attribute!" << endl; + H5Aclose(attr); + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + + hsize_t nDim; + hsize_t* dims=NULL; + double* data=NULL; + ReadDataSet(ds_name, nDim, dims, data); + if (nDim!=4) + { + cerr << "HDF5_File_Reader::GetTDVectorData: data dimension invalid" << endl; + delete[] dims; + H5Aclose(attr); + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + if (dims[0]!=3) + { + cerr << "HDF5_File_Reader::GetTDVectorData: vector data dimension invalid" << endl; + delete[] dims; + H5Aclose(attr); + H5Gclose(TD_grp); + H5Fclose(hdf5_file); + return NULL; + } + data_size[0]=dims[3]; + data_size[1]=dims[2]; + data_size[2]=dims[1]; + delete[] dims; + data_size[3]=3; + size_t pos = 0; + float**** field = Create_N_3DArray(data_size); + for (unsigned int d=0;d<3;++d) + for (unsigned int k=0;k frequencies; + if (ReadFrequencies(frequencies)==false) + return 0; + return frequencies.size(); +} + +bool HDF5_File_Reader::ReadFrequencies(vector &frequencies) +{ + if (IsValid()==false) + return false; + + return ReadAttribute("/FieldData/FD","frequency",frequencies); +} + +bool HDF5_File_Reader::ReadFrequencies(vector &frequencies) +{ + if (IsValid()==false) + return false; + + return ReadAttribute("/FieldData/FD","frequency",frequencies); +} + + +complex**** HDF5_File_Reader::GetFDVectorData(size_t idx, unsigned int data_size[]) +{ + hsize_t nDim; + hsize_t* dims=NULL; + double* data=NULL; + stringstream ds_name; + + // read real values + ds_name << "/FieldData/FD/f" << idx << "_real"; + if (ReadDataSet(ds_name.str(), nDim, dims, data) == false) + return NULL; + if (nDim!=4) + { + cerr << "HDF5_File_Reader::GetFDVectorData: data dimension invalid" << endl; + delete[] dims; + delete[] data; + return NULL; + } + if (dims[0]!=3) + { + cerr << "HDF5_File_Reader::GetFDVectorData: vector data dimension invalid" << endl; + delete[] dims; + delete[] data; + return NULL; + } + data_size[0]=dims[3]; + data_size[1]=dims[2]; + data_size[2]=dims[1]; + delete[] dims; + data_size[3]=3; + size_t pos = 0; + complex**** field = Create_N_3DArray >(data_size); + for (unsigned int d=0;d<3;++d) + for (unsigned int k=0;k >(field, data_size); + return NULL; + } + if (nDim!=4) + { + cerr << "HDF5_File_Reader::GetFDVectorData: data dimension invalid" << endl; + delete[] dims; + delete[] data; + Delete_N_3DArray >(field, data_size); + return NULL; + } + if (dims[0]!=3) + { + cerr << "HDF5_File_Reader::GetFDVectorData: vector data dimension invalid" << endl; + delete[] dims; + delete[] data; + Delete_N_3DArray >(field, data_size); + return NULL; + } + if ((data_size[0]!=dims[3]) || (data_size[1]!=dims[2]) || (data_size[2]!=dims[1])) + { + cerr << "HDF5_File_Reader::GetFDVectorData: data dimension mismatch" << endl; + delete[] dims; + delete[] data; + Delete_N_3DArray >(field, data_size); + return NULL; + } + delete[] dims; + + pos = 0; + complex I(0,1); + for (unsigned int d=0;d<3;++d) + for (unsigned int k=0;k &frequencies, vector****> &FD_data, unsigned int data_size[4]) +{ + FD_data.clear(); + + if (GetNumTimeSteps()<=0) + { + cerr << "HDF5_File_Reader::CalcFDVectorData: error, no TD data found..." << endl; + return false; + } + + float time; + //read first TD data + float**** field = this->GetTDVectorData(0,time,data_size); + if (field==NULL) + { + cerr << "HDF5_File_Reader::CalcFDVectorData: error, no TD data found..." << endl; + return false; + } + + //init + FD_data.resize(frequencies.size(), NULL); + for (size_t fn=0;fn >(data_size); + + size_t ts=0; + unsigned int pos[3]; + complex PI_2_I(0.0,-2.0*M_PI); + complex exp_jwt_2_dt; + float time_diff=0; + float time_old =0; + complex**** field_fd = NULL; + while (field) + { + if ((ts>1) && abs(time_diff - (time - time_old))>1e15) + { + cerr << "HDF5_File_Reader::CalcFDVectorData: time interval error..." << endl; + for (size_t fn=0;fn)(PI_2_I * frequencies.at(fn) * time) ); + field_fd = FD_data.at(fn); + for (pos[0]=0; pos[0]GetTDVectorData(ts,time,data_size); + } + + // finalize data + time_diff*=2; + for (size_t fn=0;fn. +*/ + +#ifndef HDF5_FILE_READER_H +#define HDF5_FILE_READER_H + +#include +#include +#include +#include + +class HDF5_File_Reader +{ +public: + HDF5_File_Reader(std::string filename); + virtual ~HDF5_File_Reader(); + + bool ReadMesh(float** lines, unsigned int* numLines, int &meshType); + + //! Get the number of timesteps stored at /FieldData/TD/ + unsigned int GetNumTimeSteps(); + bool ReadTimeSteps(std::vector ×tep, std::vector &names); + + /*! + Get time-domain data stored at /FieldData/TD/ + \param[in] idx time step index to extract + \param[out] time time attribute for the given timestep + \param[out] data_size data size found + \return field data found in given timestep, caller must delete array, returns NULL if timestep was not found + */ + float**** GetTDVectorData(size_t idx, float &time, unsigned int data_size[4]); + + unsigned int GetNumFrequencies(); + bool ReadFrequencies(std::vector &frequencies); + bool ReadFrequencies(std::vector &frequencies); + + /*! + Get frequency-domain data stored at "/FieldData/FD/f_real" and "/FieldData/FD/f_imag" + \param[in] idx frequency index to extract + \param[out] data_size data size found + \return complex field data found for the given frequency, caller must delete array, returns NULL if frequency was not found + */ + std::complex**** GetFDVectorData(size_t idx, unsigned int data_size[4]); + + /*! + Calculate + */ + bool CalcFDVectorData(std::vector &frequencies, std::vector****> &FD_data, unsigned int data_size[4]); + + bool ReadAttribute(std::string grp_name, std::string attr_name, std::vector &attr_values); + bool ReadAttribute(std::string grp_name, std::string attr_name, std::vector &attr_values); + + bool IsValid(); + +protected: + std::string m_filename; + + bool ReadDataSet(std::string ds_name, hsize_t &nDim, hsize_t* &dims, double* &data); + bool ReadDataSet(std::string ds_name, hsize_t &nDim, hsize_t* &dims, float* &data); + + bool OpenGroup(hid_t &file, hid_t &group, std::string groupName); +}; + +#endif // HDF5_FILE_READER_H diff --git a/openEMS/tools/hdf5_file_writer.cpp b/openEMS/tools/hdf5_file_writer.cpp new file mode 100644 index 0000000..e3a2113 --- /dev/null +++ b/openEMS/tools/hdf5_file_writer.cpp @@ -0,0 +1,515 @@ +/* +* Copyright (C) 2011 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 . +*/ + +using namespace std; + +#include "hdf5_file_writer.h" +#include +#include + +#include +#include +#include + +HDF5_File_Writer::HDF5_File_Writer(string filename) +{ + m_filename = filename; + m_Group = "/"; + hid_t hdf5_file = H5Fcreate(m_filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + if (hdf5_file<0) + { + cerr << "HDF5_File_Writer::HDF5_File_Writer: Error, creating the given file """ << m_filename << """ failed" << endl; + } + H5Fclose(hdf5_file); +} + +HDF5_File_Writer::~HDF5_File_Writer() +{ +} + +hid_t HDF5_File_Writer::OpenGroup(hid_t hdf5_file, string group) +{ + if (hdf5_file<0) + { + cerr << "HDF5_File_Writer::CreateGroup: Error, invalid file id" << endl; + return -1; + } + + vector results; + boost::split(results, group, boost::is_any_of("/")); + + hid_t grp=H5Gopen(hdf5_file,"/", H5P_DEFAULT); + if (grp<0) + { + cerr << "HDF5_File_Writer::OpenGroup: Error, opening root group " << endl; + return -1; + } + + for (size_t n=0;n0)) //check for theta/phi-direction + array[i] = discLines[n][i]; + else + array[i] = discLines[n][i] * scaling; + } + if (H5Dwrite(dataset, H5T_NATIVE_FLOAT, space, H5P_DEFAULT, H5P_DEFAULT, array)) + { + cerr << "HDF5_File_Writer::WriteRectMesh: Error, writing to dataset failed" << endl; + delete[] array; + H5Dclose(dataset); + H5Sclose(space); + H5Gclose(mesh_grp); + H5Fclose(hdf5_file); + return false; + } + delete[] array; + H5Dclose(dataset); + H5Sclose(space); + } + H5Gclose(mesh_grp); + H5Fclose(hdf5_file); + return true; +} + +bool HDF5_File_Writer::WriteScalarField(std::string dataSetName, float const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]; + size_t n_size[3]={datasize[2],datasize[1],datasize[0]}; + float* buffer = new float[size]; + for (size_t k=0;k const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]; + size_t n_size[3]={datasize[2],datasize[1],datasize[0]}; + float* buffer = new float[size]; + for (size_t k=0;k const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]; + size_t n_size[3]={datasize[2],datasize[1],datasize[0]}; + double* buffer = new double[size]; + for (size_t k=0;k const* const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]*3; + size_t n_size[4]={3,datasize[2],datasize[1],datasize[0]}; + float* buffer = new float[size]; + for (int n=0;n<3;++n) + for (size_t k=0;k const* const* const* const* field, size_t datasize[3]) +{ + size_t pos = 0; + size_t size = datasize[0]*datasize[1]*datasize[2]*3; + size_t n_size[4]={3,datasize[2],datasize[1],datasize[0]}; + double* buffer = new double[size]; + for (int n=0;n<3;++n) + for (size_t k=0;k values) +{ + float val[values.size()]; + for (size_t n=0;n values) +{ + double val[values.size()]; + for (size_t n=0;n. +*/ + +#ifndef HDF5_FILE_WRITER_H +#define HDF5_FILE_WRITER_H + +#include +#include +#include +#include + +class HDF5_File_Writer +{ +public: + HDF5_File_Writer(std::string filename); + ~HDF5_File_Writer(); + + bool WriteRectMesh(unsigned int const* numLines, double const* const* discLines, int MeshType=0, double scaling=1); + bool WriteRectMesh(unsigned int const* numLines, float const* const* discLines, int MeshType=0, float scaling=1); + + bool WriteScalarField(std::string dataSetName, float const* const* const* field, size_t datasize[3]); + bool WriteScalarField(std::string dataSetName, double const* const* const* field, size_t datasize[3]); + + bool WriteScalarField(std::string dataSetName, std::complex const* const* const* field, size_t datasize[3]); + bool WriteScalarField(std::string dataSetName, std::complex const* const* const* field, size_t datasize[3]); + + bool WriteVectorField(std::string dataSetName, float const* const* const* const* field, size_t datasize[3]); + bool WriteVectorField(std::string dataSetName, double const* const* const* const* field, size_t datasize[3]); + + bool WriteVectorField(std::string dataSetName, std::complex const* const* const* const* field, size_t datasize[3]); + bool WriteVectorField(std::string dataSetName, std::complex const* const* const* const* field, size_t datasize[3]); + + bool WriteData(std::string dataSetName, float const* field_buf, size_t dim, size_t* datasize); + bool WriteData(std::string dataSetName, double const* field_buf, size_t dim, size_t* datasize); + + bool WriteAtrribute(std::string locName, std::string attr_name, void const* value, hsize_t size, hid_t mem_type); + bool WriteAtrribute(std::string locName, std::string attr_name, float const* value, hsize_t size); + bool WriteAtrribute(std::string locName, std::string attr_name, double const* value, hsize_t size); + bool WriteAtrribute(std::string locName, std::string attr_name, std::vector values); + bool WriteAtrribute(std::string locName, std::string attr_name, std::vector values); + bool WriteAtrribute(std::string locName, std::string attr_name, float value); + bool WriteAtrribute(std::string locName, std::string attr_name, double value); + + void SetCurrentGroup(std::string group, bool createGrp=true); + +protected: + std::string m_filename; + std::string m_Group; + + hid_t OpenGroup(hid_t hdf5_file, std::string group); + bool WriteData(std::string dataSetName, hid_t mem_type, void const* field_buf, size_t dim, size_t* datasize); +}; + +#endif // HDF5_FILE_WRITER_H diff --git a/openEMS/tools/sar_calculation.cpp b/openEMS/tools/sar_calculation.cpp new file mode 100644 index 0000000..343aa07 --- /dev/null +++ b/openEMS/tools/sar_calculation.cpp @@ -0,0 +1,656 @@ +/* +* Copyright (C) 2012 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 . +*/ + + +#include "sar_calculation.h" +#include "cfloat" +#include "array_ops.h" +#include "global.h" + +using namespace std; + +SAR_Calculation::SAR_Calculation() +{ + m_Vx_Used = NULL; + m_Vx_Valid = NULL; + m_DebugLevel = 0; + SetAveragingMethod(SIMPLE, true); + Reset(); +} + +void SAR_Calculation::Reset() +{ + Delete3DArray(m_Vx_Used,m_numLines); + m_Vx_Used = NULL; + Delete3DArray(m_Vx_Valid,m_numLines); + m_Vx_Valid = NULL; + + m_avg_mass = 0; + m_numLines[0]=m_numLines[1]=m_numLines[2]=0; + m_cellWidth[0]=m_cellWidth[1]=m_cellWidth[2]=NULL; + + m_cell_volume = NULL; + m_cell_density = NULL; + m_cell_conductivity = NULL; + m_E_field = NULL; + m_J_field = NULL; + + Delete3DArray(m_Vx_Used,m_numLines); + m_Vx_Used = NULL; + Delete3DArray(m_Vx_Valid,m_numLines); + m_Vx_Valid = NULL; +} + +void SAR_Calculation::SetAveragingMethod(string method, bool silent) +{ + if (method.compare("IEEE_C95_3")==0) + return SetAveragingMethod(IEEE_C95_3, silent); + if (method.compare("IEEE_62704")==0) + return SetAveragingMethod(IEEE_62704, silent); + if (method.compare("Simple")==0) + return SetAveragingMethod(SIMPLE, silent); + + cerr << __func__ << ": Error, """ << method << """ is an unknown averaging method..." << endl; + // unknown method, fallback to simple + SetAveragingMethod(SIMPLE, false); +} + +void SAR_Calculation::SetAveragingMethod(SARAveragingMethod method, bool silent) +{ + if (method==IEEE_62704) + { + m_massTolerance = 0.0001; + m_maxMassIterations = 100; + m_maxBGRatio = 0.1; + m_markPartialAsUsed = false; + m_UnusedRelativeVolLimit = 1.05; + m_IgnoreFaceValid = false; + if (!silent) + cerr << __func__ << ": Setting averaging method to IEEE_62704" << endl; + return; + } + else if (method==IEEE_C95_3) + { + m_massTolerance = 0.05; + m_maxMassIterations = 100; + m_maxBGRatio = 1; + m_markPartialAsUsed = true; + m_UnusedRelativeVolLimit = 1; + m_IgnoreFaceValid = false; + if (!silent) + cerr << __func__ << ": Setting averaging method to IEEE_C95_3" << endl; + return; + } + else if (method==SIMPLE) + { + m_massTolerance = 0.05; + m_maxMassIterations = 100; + m_maxBGRatio = 1; + m_markPartialAsUsed = true; + m_UnusedRelativeVolLimit = 1; + m_IgnoreFaceValid = true; + if (!silent) + cerr << __func__ << ": Setting averaging method to SIMPLE" << endl; + return; + } + + cerr << __func__ << ": Error, unknown averaging method..." << endl; + // unknown method, fallback to simple + SetAveragingMethod(SIMPLE, false); +} + +void SAR_Calculation::SetNumLines(unsigned int numLines[3]) +{ + Delete3DArray(m_Vx_Used,m_numLines); + m_Vx_Used = NULL; + Delete3DArray(m_Vx_Valid,m_numLines); + m_Vx_Valid = NULL; + + for (int n=0;n<3;++n) + m_numLines[n]=numLines[n]; +} + +void SAR_Calculation::SetCellWidth(float* cellWidth[3]) +{ + for (int n=0;n<3;++n) + m_cellWidth[n]=cellWidth[n]; +} + +float*** SAR_Calculation::CalcSAR(float*** SAR) +{ + if (CheckValid()==false) + { + cerr << "SAR_Calculation::CalcSAR: SAR calculation is invalid due to missing values... Abort..." << endl; + return NULL; + } + if (m_avg_mass<=0) + return CalcLocalSAR(SAR); + return CalcAveragedSAR(SAR); +} + +bool SAR_Calculation::CheckValid() +{ + for (int n=0;n<3;++n) + if (m_cellWidth[n]==NULL) + return false; + if (m_E_field==NULL) + return false; + if ((m_J_field==NULL) && (m_cell_conductivity==NULL)) + return false; + if (m_cell_density==NULL) + return false; + if (m_avg_mass<0) + return false; + return true; +} + +double SAR_Calculation::CalcSARPower() +{ + if (CheckValid()==false) + { + cerr << "SAR_Calculation::CalcSARPower: SAR calculation is invalid due to missing values... Abort..." << endl; + return 0; + } + double power=0; + unsigned int pos[3]; + for (pos[0]=0; pos[0]0) + { + ++m_Valid; + SAR[pos[0]][pos[1]][pos[2]] = CalcLocalPowerDensity(pos)/m_cell_density[pos[0]][pos[1]][pos[2]]; + } + else + { + ++m_AirVoxel; + SAR[pos[0]][pos[1]][pos[2]] = 0; + } + } + } + } + return SAR; +} + +int SAR_Calculation::FindFittingCubicalMass(unsigned int pos[3], float 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, bool ignoreFaceValid) +{ + unsigned int mass_iterations = 0; + double old_mass=0; + double old_box_size=0; + bool face_valid; + bool mass_valid; + bool voxel_valid; + + //iterate over cubical sizes to find fitting volume to mass + while (mass_iterations increasing the box will not yield a valid cube + return 1; + } + else if ((face_valid==false || bg_ratio>=m_maxBGRatio) && (mass_valid)) + { + // this is an invalid cube with a valid total mass + if (ignoreFaceValid) + return 0; + return 2; + } + if (voxel_valid) + { + // valid cube found + return 0; + } + + // if no valid or finally invalid cube is found, calculate an alternaive cube size + if (mass_iterations==0) + { + // on first interation, try a relative resize + old_box_size=box_size; + box_size*=pow(m_avg_mass/mass,1.0/3.0); + } + else + { + // on later interations, try a newton approach + float new_box_size = box_size - (mass-m_avg_mass)/(mass-old_mass)*(box_size-old_box_size); + old_box_size = box_size; + box_size = new_box_size; + } + old_mass=mass; + + ++mass_iterations; + } + + // m_maxMassIterations iterations are exhausted... + return -1; +} + +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)) + { + cerr << "SAR_Calculation::GetCubicalMass: critical error: invalid averaging box size!! EXIT" << endl; + exit(-1); + } + bool face_valid=true; + for (int n=0;n<3;++n) + { + // check start position + start[n]=pos[n]; + partial_start[n]=1; + float dist=m_cellWidth[n][pos[n]]/2; + if (disabledFace==2*n) + dist=box_size; + else + { + while (dist=0) + { + mass += CellMass(f_pos)*weight[0]*weight[1]*weight[2]; + power_mass += CalcLocalPowerDensity(f_pos) * CellVolume(f_pos)*weight[0]*weight[1]*weight[2]; + } + } + } + } + float vx_SAR = power_mass/mass; + if (SAR==NULL) + return vx_SAR; + + SAR[pos[0]][pos[1]][pos[2]]=vx_SAR; + + if (assignUsed==false) + return vx_SAR; + + // assign SAR to all used voxel + bool is_partial[3]; + for (f_pos[0]=start[0];f_pos[0]<=stop[0];++f_pos[0]) + { + if ( ((f_pos[0]==start[0]) && (partial_start[0]!=1)) || ((f_pos[0]==stop[0]) && (partial_stop[0]!=1)) ) + is_partial[0]=true; + else + is_partial[0]=false; + + for (f_pos[1]=start[1];f_pos[1]<=stop[1];++f_pos[1]) + { + if ( ((f_pos[1]==start[1]) && (partial_start[1]!=1)) || ((f_pos[1]==stop[1]) && (partial_stop[1]!=1)) ) + is_partial[1]=true; + else + is_partial[1]=false; + + for (f_pos[2]=start[2];f_pos[2]<=stop[2];++f_pos[2]) + { + if ( ((f_pos[2]==start[2]) && (partial_start[2]!=1)) || ((f_pos[2]==stop[2]) && (partial_stop[2]!=1)) ) + is_partial[2]=true; + else + is_partial[2]=false; + + if ( (!is_partial[0] && !is_partial[1] && !is_partial[2]) || m_markPartialAsUsed) + { + if (!m_Vx_Valid[f_pos[0]][f_pos[1]][f_pos[2]] && (m_cell_density[f_pos[0]][f_pos[1]][f_pos[2]]>0)) + { + m_Vx_Used[f_pos[0]][f_pos[1]][f_pos[2]]=true; + SAR[f_pos[0]][f_pos[1]][f_pos[2]]=max(SAR[f_pos[0]][f_pos[1]][f_pos[2]], vx_SAR); + } + } + } + } + } + return vx_SAR; +} + + +float*** SAR_Calculation::CalcAveragedSAR(float*** SAR) +{ + unsigned int pos[3]; + m_Vx_Used = Create3DArray(m_numLines); + m_Vx_Valid = Create3DArray(m_numLines); + + double voxel_volume; + double total_mass; + unsigned int start[3]; + unsigned int stop[3]; + float partial_start[3]; + float partial_stop[3]; + double bg_ratio; + int EC=0; + + // debug counter + unsigned int cnt_case1=0; + unsigned int cnt_case2=0; + unsigned int cnt_NoConvergence=0; + + m_Valid=0; + m_Used=0; + m_Unused=0; + m_AirVoxel=0; + + for (pos[0]=0; pos[0]0) + { + cerr << "SAR_Calculation::CalcAveragedSAR: Warning, for some voxel a valid averaging cube could not be found (no convergence)... " << endl; + } + if (m_DebugLevel>0) + { + cerr << "Number of invalid cubes (case 1): " << cnt_case1 << endl; + cerr << "Number of invalid cubes (case 2): " << cnt_case2 << endl; + cerr << "Number of invalid cubes (failed to converge): " << cnt_NoConvergence << endl; + } + + // count all used and unused etc. + special handling of unused voxels!! + m_Used=0; + m_Unused=0; + for (pos[0]=0;pos[0]0) && !m_Vx_Valid[pos[0]][pos[1]][pos[2]] && !m_Vx_Used[pos[0]][pos[1]][pos[2]]) + { + ++m_Unused; + + SAR[pos[0]][pos[1]][pos[2]] = 0; + double unused_volumes[6]; + float unused_SAR[6]; + + double min_Vol=FLT_MAX; + + // special handling of unused voxels: + for (int n=0;n<6;++n) + { + EC = FindFittingCubicalMass(pos, pow(m_avg_mass/m_cell_density[pos[0]][pos[1]][pos[2]],1.0/3.0)/2, start, stop, + partial_start, partial_stop, total_mass, unused_volumes[n], bg_ratio, n, true); + if ((EC!=0) && (EC!=2)) + { + // this should not happen + cerr << "SAR_Calculation::CalcAveragedSAR: Error handling unused voxels, can't find fitting cubical averaging volume' " << endl; + unused_SAR[n]=0; + } + else + { + unused_SAR[n]=CalcCubicalSAR(NULL, pos, start, stop, partial_start, partial_stop, false); + min_Vol = min(min_Vol,unused_volumes[n]); + } + } + for (int n=0;n<6;++n) + { + if (unused_volumes[n]<=m_UnusedRelativeVolLimit*min_Vol) + SAR[pos[0]][pos[1]][pos[2]] = max(SAR[pos[0]][pos[1]][pos[2]],unused_SAR[n]); + } + } + } + } + } + + if (m_Valid+m_Used+m_Unused+m_AirVoxel!=m_numLines[0]*m_numLines[1]*m_numLines[2]) + { + cerr << "SAR_Calculation::CalcAveragedSAR: critical error, mismatch in voxel status count... EXIT" << endl; + exit(1); + } + + if (m_DebugLevel>0) + cerr << "SAR_Calculation::CalcAveragedSAR: Stats: Valid=" << m_Valid << " Used=" << m_Used << " Unused=" << m_Unused << " Air-Voxel=" << m_AirVoxel << endl; + + return SAR; +} + +double SAR_Calculation::CellVolume(unsigned int pos[3]) +{ + if (m_cell_volume) + return m_cell_volume[pos[0]][pos[1]][pos[2]]; + + double volume=1; + for (int n=0;n<3;++n) + volume*=m_cellWidth[n][pos[n]]; + return volume; +} + +double SAR_Calculation::CellMass(unsigned int pos[3]) +{ + return m_cell_density[pos[0]][pos[1]][pos[2]]*CellVolume(pos); +} + diff --git a/openEMS/tools/sar_calculation.h b/openEMS/tools/sar_calculation.h new file mode 100644 index 0000000..58d9ab8 --- /dev/null +++ b/openEMS/tools/sar_calculation.h @@ -0,0 +1,122 @@ +/* +* Copyright (C) 2012 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 . +*/ + +#ifndef SAR_CALCULATION_H +#define SAR_CALCULATION_H + +#include + +class SAR_Calculation +{ +public: + SAR_Calculation(); + + enum SARAveragingMethod { IEEE_C95_3, IEEE_62704, SIMPLE}; + + //! Reset and initialize all values (will keep all SAR settings) + void Reset(); + + //! Set the debug level + void SetDebugLevel(int level) {m_DebugLevel=level;} + + //! Set the used averaging method + void SetAveragingMethod(SARAveragingMethod method, bool silent=false); + + //! Set the used averaging method + void SetAveragingMethod(std::string method, bool silent=false); + + //! Set number of lines in all direcitions. (mandatory information) + void SetNumLines(unsigned int numLines[3]); + //! Set cell width in all direcitions. (mandatory information for averaging) + void SetCellWidth(float* cellWidth[3]); + + //! Set the averaging mash. (mandatory information for averaging) + void SetAveragingMass(float mass) {m_avg_mass=mass;} + + //! Set the cell volumes (optional for speedup) + void SetCellVolumes(float*** cell_volume) {m_cell_volume=cell_volume;} + + //! Set the cell densities (mandatory information) + void SetCellDensities(float*** cell_density) {m_cell_density=cell_density;} + + //! Set the cell conductivities (mandatory if no current density field is given) + void SetCellCondictivity(float*** cell_conductivity) {m_cell_conductivity=cell_conductivity;} + + //! Set the electric field (mandatory information) + void SetEField(std::complex**** field) {m_E_field=field;} + //! Set the current density field (mandatory if no conductivity distribution is given) + void SetJField(std::complex**** field) {m_J_field=field;} + + //! Calculate the SAR, requires a preallocated 3D array + float*** CalcSAR(float*** SAR); + + //! Calculate the total power dumped + double CalcSARPower(); + +protected: + unsigned int m_numLines[3]; + float* m_cellWidth[3]; + + float m_avg_mass; + float*** m_cell_volume; + float*** m_cell_density; + float*** m_cell_conductivity; + std::complex**** m_E_field; + std::complex**** m_J_field; + + bool*** m_Vx_Used; + bool*** m_Vx_Valid; + + unsigned int m_Valid; + unsigned int m_Used; + unsigned int m_Unused; + unsigned int m_AirVoxel; + + int m_DebugLevel; + + /*********** SAR calculation parameter and settings ***********/ + float m_massTolerance; + unsigned int m_maxMassIterations; + float m_maxBGRatio; + bool m_markPartialAsUsed; + float m_UnusedRelativeVolLimit; + bool m_IgnoreFaceValid; + + /*********** SAR calculations methods ********/ + double CalcLocalPowerDensity(unsigned int pos[3]); + + //! Calculate the local SAR + float*** CalcLocalSAR(float*** SAR); + + /****** start SAR averaging and all necessary methods ********/ + //! Calculate the averaged SAR + float*** CalcAveragedSAR(float*** SAR); + + int FindFittingCubicalMass(unsigned int pos[3], float 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=-1, bool ignoreFaceValid=false); + bool 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=-1); + + float CalcCubicalSAR(float*** SAR, unsigned int pos[3], unsigned int start[3], unsigned int stop[3], float partial_start[3], float partial_stop[3], bool assignUsed=false); + /****** end SAR averaging and all necessary methods ********/ + + bool CheckValid(); + double CellVolume(unsigned int pos[3]); + double CellMass(unsigned int pos[3]); +}; + +#endif // SAR_CALCULATION_H diff --git a/openEMS/tools/useful.cpp b/openEMS/tools/useful.cpp new file mode 100644 index 0000000..50aacfb --- /dev/null +++ b/openEMS/tools/useful.cpp @@ -0,0 +1,185 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#include "useful.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +unsigned int CalcNyquistNum(double fmax, double dT) +{ + if (fmax==0) return UINT_MAX; + if (dT==0) return 1; + double T0 = 1/fmax; + return floor(T0/2/dT); +} + +double CalcNyquistFrequency(unsigned int nyquist, double dT) +{ + if (nyquist==0) return 0; + if (dT==0) return 0; + return floor(1/(double)nyquist/2/dT); +} + +std::vector AssignJobs2Threads(unsigned int jobs, unsigned int nrThreads, bool RemoveEmpty) +{ + std::vector jpt; //jobs per thread + + unsigned int ui_jpt = jobs/nrThreads; + for (unsigned int n=0; n0) + { + ++jpt.at(n); + --jobs; + } + } + + if (jobs>0) + std::cerr << "AssignJobs2Threads: Error, " << jobs << " remain to be assigned, this should not have happend..." << std::endl; + + if (RemoveEmpty) + { + while (jpt.back()==0) + jpt.pop_back(); + } + + return jpt; +} + +std::vector SplitString2Float(std::string str, std::string delimiter) +{ + std::vector v_f; + std::vector results; + boost::split(results, str, boost::is_any_of(delimiter)); + + for (size_t n=0;n> num) + v_f.push_back(num); + } + return v_f; +} + +std::vector SplitString2Double(std::string str, std::string delimiter) +{ + std::vector v_f; + std::vector results; + boost::split(results, str, boost::is_any_of(delimiter)); + + for (size_t n=0;n> num) + v_f.push_back(num); + } + return v_f; +} + +bool CrossProd(const double *v1, const double *v2, double* out) +{ + int nP,nPP; + for (int n=0;n<3;++n) + { + nP = (n+1)%3; + nPP = (n+2)%3; + out[n] = v1[nP]*v2[nPP] - v1[nPP]*v2[nP]; + } + return ((out[0]+out[1]+out[2])>0); +} + +double ScalarProd(const double *v1, const double *v2) +{ + double out=0; + for (int n=0;n<3;++n) + out+=v1[n]*v2[n]; + return out; +} + +double Determinant(const double *mat) +{ + return mat[0]*mat[4]*mat[8]+mat[1]*mat[5]*mat[6]+mat[2]*mat[3]*mat[7]-mat[2]*mat[4]*mat[6]-mat[1]*mat[3]*mat[8]-mat[0]*mat[5]*mat[7]; +} + +double* Invert(const double* in, double* out) +{ + double det = Determinant(in); + out[0] = (in[4]*in[8]-in[5]*in[7])/det; + out[1] = (in[2]*in[7]-in[1]*in[8])/det; + out[2] = (in[1]*in[5]-in[2]*in[4])/det; + out[3] = (in[5]*in[6]-in[3]*in[8])/det; + out[4] = (in[0]*in[8]-in[2]*in[6])/det; + out[5] = (in[2]*in[3]-in[0]*in[5])/det; + out[6] = (in[3]*in[7]-in[4]*in[6])/det; + out[7] = (in[1]*in[6]-in[0]*in[7])/det; + out[8] = (in[0]*in[4]-in[1]*in[3])/det; + return out; +} + +int LinePlaneIntersection(const double *p0, const double *p1, const double *p2, const double *l_start, const double *l_stop, double* is_point, double &dist) +{ + dist = 0; + double mat[9]; + for (int n=0;n<3;++n) + { + is_point[n] = 0; + mat[3*n] = l_start[n]-l_stop[n]; + mat[3*n+1] = p1[n]-p0[n]; + mat[3*n+2] = p2[n]-p0[n]; + } + double det = Determinant(mat); + if (fabs(det)<1e-50) + return -1; + + double inv_mat[9]; + Invert(mat, inv_mat); + + double t=0,u=0,v=0; + for (int n=0;n<3;++n) + { + t+=inv_mat[n]*(l_start[n]-p0[n]); + u+=inv_mat[3+n]*(l_start[n]-p0[n]); + v+=inv_mat[6+n]*(l_start[n]-p0[n]); + } + dist = t; + + for (int n=0;n<3;++n) + is_point[n] = l_start[n]*(1-dist) + l_stop[n]*dist; + + if ((u<0) || (u>1) || (v<0) || (v>1)) + return 1; + if ((t<0) || (t>1)) + return 2; + + return 0; +} diff --git a/openEMS/tools/useful.h b/openEMS/tools/useful.h new file mode 100644 index 0000000..dec13ab --- /dev/null +++ b/openEMS/tools/useful.h @@ -0,0 +1,44 @@ +/* +* Copyright (C) 2010 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 . +*/ + +#ifndef USEFUL_H +#define USEFUL_H + +#include +#include + +//! Calc the nyquist number of timesteps for a given frequency and timestep +unsigned int CalcNyquistNum(double fmax, double dT); + +//! Calc the highest frequency allowed for a given nyquist number of timesteps and timestep +double CalcNyquistFrequency(unsigned int nyquist, double dT); + +//! Calculate an optimal job distribution to a given number of threads. Will return a vector with the jobs for each thread. +std::vector AssignJobs2Threads(unsigned int jobs, unsigned int nrThreads, bool RemoveEmpty=false); + +std::vector SplitString2Float(std::string str, std::string delimiter=","); +std::vector SplitString2Double(std::string str, std::string delimiter=","); + +bool CrossProd(const double* v1, const double* v2, double* out); +double ScalarProd(const double* v1, const double* v2); + +double Determinant(const double* mat); +double* Invert(const double* in, double* out); + +int LinePlaneIntersection(const double *p0, const double* p1, const double* p2, const double* l_start, const double* l_stop, double* is_point, double &dist); + +#endif // USEFUL_H diff --git a/openEMS/tools/vtk_file_writer.cpp b/openEMS/tools/vtk_file_writer.cpp new file mode 100644 index 0000000..79c40f3 --- /dev/null +++ b/openEMS/tools/vtk_file_writer.cpp @@ -0,0 +1,340 @@ +/* +* Copyright (C) 2011,2012 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 . +*/ + +using namespace std; + +#include "vtk_file_writer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +VTK_File_Writer::VTK_File_Writer(string filename, int meshType) +{ + SetFilename(filename); + m_MeshType = meshType; + m_NativeDump = false; + m_Binary = true; + m_Compress = true; + m_AppendMode = false; + m_ActiveTS = false; + + if (m_MeshType==0) //cartesian mesh + m_GridData = vtkRectilinearGrid::New(); + else if (m_MeshType==1) //cylindrical mesh + m_GridData = vtkStructuredGrid::New(); + else + { + cerr << "VTK_File_Writer::VTK_File_Writer: Error, unknown mesh type: " << m_MeshType << endl; + m_GridData=NULL; + } +} + +VTK_File_Writer::~VTK_File_Writer() +{ + if (m_GridData) + m_GridData->Delete(); + m_GridData = NULL; +} + +void VTK_File_Writer::SetMeshLines(double const* const* lines, unsigned int const* count, double scaling) +{ + if (m_MeshType==0) //cartesian mesh + { + vtkRectilinearGrid* RectGrid = dynamic_cast(m_GridData); + if (RectGrid==NULL) + { + cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happend! " << endl; + exit(1); + } + RectGrid->SetDimensions(count[0],count[1],count[2]); + vtkDoubleArray *Coords[3]; + for (int n=0;n<3;++n) + { + m_MeshLines[n].clear(); + m_MeshLines[n].reserve(count[n]); + Coords[n] = vtkDoubleArray::New(); + for (unsigned int i=0; iInsertNextValue(lines[n][i]*scaling); + m_MeshLines[n].push_back(lines[n][i]*scaling); + } + } + RectGrid->SetXCoordinates(Coords[0]); + RectGrid->SetYCoordinates(Coords[1]); + RectGrid->SetZCoordinates(Coords[2]); + for (int n=0;n<3;++n) + Coords[n]->Delete(); + } + else if (m_MeshType==1) //cylindrical mesh + { + vtkStructuredGrid* StructGrid = dynamic_cast(m_GridData); + if (StructGrid==NULL) + { + cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happend! " << endl; + exit(1); + } + + for (int n=0;n<3;++n) + { + m_MeshLines[n].clear(); + m_MeshLines[n].reserve(count[n]); + double scale=1; + if (n!=1) + scale*=scaling; + for (unsigned int i=0; iSetDimensions(count[0],count[1],count[2]); + vtkPoints *points = vtkPoints::New(); + points->SetNumberOfPoints(count[0]*count[1]*count[2]); + double r[3]; + int id=0; + for (unsigned int k=0; kSetPoint(id++,r); + } + StructGrid->SetPoints(points); + points->Delete(); + } + else + { + cerr << "VTK_File_Writer::SetMeshLines: Error, unknown mesh type: " << m_MeshType << endl; + } +} + +void VTK_File_Writer::AddScalarField(string fieldname, double const* const* const* field) +{ + vtkDoubleArray* array = vtkDoubleArray::New(); + array->SetNumberOfTuples(m_MeshLines[0].size()*m_MeshLines[1].size()*m_MeshLines[2].size()); + array->SetName(fieldname.c_str()); + int id=0; + for (unsigned int k=0;kSetTuple1(id++,field[i][j][k]); + } + } + } + m_GridData->GetPointData()->AddArray(array); + array->Delete(); +} + +void VTK_File_Writer::AddScalarField(string fieldname, float const* const* const* field) +{ + vtkFloatArray* array = vtkFloatArray::New(); + array->SetNumberOfTuples(m_MeshLines[0].size()*m_MeshLines[1].size()*m_MeshLines[2].size()); + array->SetName(fieldname.c_str()); + int id=0; + for (unsigned int k=0;kSetTuple1(id++,field[i][j][k]); + } + } + } + m_GridData->GetPointData()->AddArray(array); + array->Delete(); +} + +void VTK_File_Writer::AddVectorField(string fieldname, double const* const* const* const* field) +{ + vtkDoubleArray* array = vtkDoubleArray::New(); + array->SetNumberOfComponents(3); + array->SetNumberOfTuples(m_MeshLines[0].size()*m_MeshLines[1].size()*m_MeshLines[2].size()); + array->SetName(fieldname.c_str()); + int id=0; + double out[3]; + for (unsigned int k=0;kSetTuple3(id++,field[0][i][j][k],field[1][i][j][k],field[2][i][j][k]); + else + { + out[0] = field[0][i][j][k] * cos_a - field[1][i][j][k] * sin_a; + out[1] = field[0][i][j][k] * sin_a + field[1][i][j][k] * cos_a; + out[2] = field[2][i][j][k]; + array->SetTuple3(id++,out[0],out[1],out[2]); + } + } + } + } + m_GridData->GetPointData()->AddArray(array); + array->Delete(); +} + +void VTK_File_Writer::AddVectorField(string fieldname, float const* const* const* const* field) +{ + vtkFloatArray* array = vtkFloatArray::New(); + array->SetNumberOfComponents(3); + array->SetNumberOfTuples(m_MeshLines[0].size()*m_MeshLines[1].size()*m_MeshLines[2].size()); + array->SetName(fieldname.c_str()); + int id=0; + float out[3]; + for (unsigned int k=0;kSetTuple3(id++,field[0][i][j][k],field[1][i][j][k],field[2][i][j][k]); + else + { + out[0] = field[0][i][j][k] * cos_a - field[1][i][j][k] * sin_a; + out[1] = field[0][i][j][k] * sin_a + field[1][i][j][k] * cos_a; + out[2] = field[2][i][j][k]; + array->SetTuple3(id++,out[0],out[1],out[2]); + } + } + } + } + m_GridData->GetPointData()->AddArray(array); + array->Delete(); +} + + +int VTK_File_Writer::GetNumberOfFields() const +{ + return m_GridData->GetPointData()->GetNumberOfArrays(); +} + +void VTK_File_Writer::ClearAllFields() +{ + while (m_GridData->GetPointData()->GetNumberOfArrays()>0) + { + const char* name = m_GridData->GetPointData()->GetArrayName(0); + m_GridData->GetPointData()->RemoveArray(name); + } +} + +bool VTK_File_Writer::Write() +{ + return WriteXML(); +} + +string VTK_File_Writer::GetTimestepFilename(int pad_length) const +{ + if (m_ActiveTS==false) + return m_filename; + + stringstream ss; + ss << m_filename << "_" << std::setw( pad_length ) << std::setfill( '0' ) << m_timestep; + + return ss.str(); +} + + +bool VTK_File_Writer::WriteASCII() +{ + vtkDataWriter* writer = NULL; + if (m_MeshType==0) //cartesian mesh + writer = vtkRectilinearGridWriter::New(); + else if (m_MeshType==1) //cylindrical mesh + writer = vtkStructuredGridWriter::New(); + else + { + cerr << "VTK_File_Writer::WriteASCII: Error, unknown mesh type: " << m_MeshType << endl; + return false; + } + + writer->SetHeader(m_header.c_str()); +#if VTK_MAJOR_VERSION>=6 + writer->SetInputData(m_GridData); +#else + writer->SetInput(m_GridData); +#endif + + string filename = GetTimestepFilename() + ".vtk"; + writer->SetFileName(filename.c_str()); + if (m_Binary) + writer->SetFileTypeToBinary(); + else + writer->SetFileTypeToASCII(); + + writer->Write(); + writer->Delete(); + return true; +} + +bool VTK_File_Writer::WriteXML() +{ + vtkXMLStructuredDataWriter* writer = NULL; + if (m_MeshType==0) //cartesian mesh + writer = vtkXMLRectilinearGridWriter::New(); + else if (m_MeshType==1) //cylindrical mesh + writer = vtkXMLStructuredGridWriter::New(); + else + { + cerr << "VTK_File_Writer::WriteXML: Error, unknown mesh type: " << m_MeshType << endl; + return false; + } + +#if VTK_MAJOR_VERSION>=6 + writer->SetInputData(m_GridData); +#else + writer->SetInput(m_GridData); +#endif + + string filename = GetTimestepFilename() + "." + writer->GetDefaultFileExtension(); + writer->SetFileName(filename.c_str()); + if (m_Compress) + writer->SetCompressor(vtkZLibDataCompressor::New()); + else + writer->SetCompressor(NULL); + + if (m_Binary) + writer->SetDataModeToBinary(); + else + writer->SetDataModeToAscii(); + + writer->Write(); + writer->Delete(); + return true; +} diff --git a/openEMS/tools/vtk_file_writer.h b/openEMS/tools/vtk_file_writer.h new file mode 100644 index 0000000..428d859 --- /dev/null +++ b/openEMS/tools/vtk_file_writer.h @@ -0,0 +1,94 @@ +/* +* Copyright (C) 2011,2012 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 . +*/ + +#ifndef VTK_FILE_WRITER_H +#define VTK_FILE_WRITER_H + +#include +#include +#include +#include +#include +#include + +class vtkDataSet; + +class VTK_File_Writer +{ +public: + VTK_File_Writer(std::string filename, int meshType=0); + virtual ~VTK_File_Writer(); + + //! Set the filename + virtual void SetFilename(std::string filename) {m_filename=filename;} + //! Set the header information. May not be supported by all file types or setting. + virtual void SetHeader(std::string header) {m_header=header;} + + //! Tell write to append data. May fail if filename has changed or filetype doesn't support this. + virtual void SetAppendMode(bool val) {m_AppendMode=val;} + //! Set binary flag (if the file type supports it) + virtual void SetBinary(bool val) {m_Binary=val;} + //! Set compression flag (if the file type supports it) + virtual void SetCompress(bool val) {m_Compress=val;} + + void SetNativeDump(bool val) {m_NativeDump=val;} + + virtual void SetMeshLines(double const* const* lines, unsigned int const* count, double scaling=1); + + virtual void AddScalarField(std::string fieldname, double const* const* const* field); + virtual void AddScalarField(std::string fieldname, float const* const* const* field); + virtual void AddVectorField(std::string fieldname, double const* const* const* const* field); + virtual void AddVectorField(std::string fieldname, float const* const* const* const* field); + + virtual int GetNumberOfFields() const; + virtual void ClearAllFields(); + + //! Get if timestep file series is active. \sa SetTimestepActive + virtual bool GetTimestepActive() {return m_ActiveTS;} + //! Set the timestep file series flag. \sa GetTimestepActive \sa SetTimestep + virtual void SetTimestepActive(bool val) {m_ActiveTS = val;} + //! Set the current timestep, this will set the timestep flag to true. \sa SetTimestepActive + virtual void SetTimestep(unsigned int ts) {m_timestep=ts;SetTimestepActive(true);} + + virtual bool Write(); + + virtual bool WriteASCII(); + virtual bool WriteXML(); + +protected: + std::string m_filename; + std::string m_header; + + //timestep properties + bool m_ActiveTS; + unsigned int m_timestep; + + vtkDataSet* m_GridData; + + //mesh information + int m_MeshType; + std::vector m_MeshLines[3]; + bool m_NativeDump; + + bool m_AppendMode; + bool m_Binary; + bool m_Compress; + + virtual std::string GetTimestepFilename(int pad_length=10) const; +}; + +#endif // VTK_FILE_Writer_H diff --git a/other/openEMS.png b/other/openEMS.png new file mode 100644 index 0000000..b8ff168 Binary files /dev/null and b/other/openEMS.png differ diff --git a/other/openEMS.svg b/other/openEMS.svg new file mode 100644 index 0000000..24b5387 --- /dev/null +++ b/other/openEMS.svg @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + EMS + open + + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..8c0ad29 --- /dev/null +++ b/readme.md @@ -0,0 +1,79 @@ + ![openEMS](https://raw.github.com/thliebig/openEMS-Project/master/other/openEMS.png "openEMS")
+openEMS is a free and open electromagnetic field solver using the FDTD method. Matlab or Octave are used as an easy and flexible scripting interface.
+ +**Website**: [http://openEMS.de](http://openEMS.de)
+**Forum**: [http://openEMS.de/forum](http://openEMS.de/forum)
+**Wiki**: [http://openems.de/index.php](http://openems.de/index.php)
+**Github**: [https://github.com/thliebig/openEMS-Project](https://github.com/thliebig/openEMS-Project)
+ +# openEMS Features: ++ fully 3D Cartesian and cylindrical coordinates graded mesh. ++ Multi-threading, SIMD (SSE) and MPI support for high speed FDTD. ++ Octave and Matlab-Interface ++ Dispersive material (Drude/Lorentz/Debye type) ++ Field dumps in time and frequency domain as vtk or hdf5 file format ++ Flexible post-processing routines in Octave/Matlab ++ and [many more](http://openems.de/index.php/OpenEMS#Features) + +# Install Instruction + +## Requirements + +### Ubuntu ++ Install all necessary dependencies, e.g. on *Ubuntu 14.04 and above*:
+```bash +sudo apt-get install build-essential cmake git libhdf5-dev libvtk5-dev libboost-all-dev libcgal-dev libtinyxml-dev libqt4-dev libvtk5-qt4-dev +``` +**Note for Ubuntu 16.04:** Due to a bug in CGAL the package "libcgal-qt5-dev" may be required + ++ Optional: Install [octave](http://www.gnu.org/software/octave/) and octave devel packages:
+```bash +sudo apt-get install octave liboctave-dev +``` + ++ Optional: For the package [hyp2mat](https://github.com/koendv/hyp2mat) you need additonal dependencies:
+```bash +sudo apt-get install gengetopt help2man groff pod2pdf bison flex libhpdf-dev libtool +``` + ++ Optional: For MPI support:
+```bash +sudo apt-get install libopenmpi-dev +``` + +## Clone, build and install ++ Clone this repository, build openEMS and install e.g. to "~/opt/openEMS":
+```bash +git clone --recursive https://github.com/thliebig/openEMS-Project.git +cd openEMS-Project +./update_openEMS.sh ~/opt/openEMS +``` +or including [hyp2mat](https://github.com/koendv/hyp2mat) and [CTB](https://github.com/thliebig/CTB) and MPI:
+```bash +./update_openEMS.sh ~/opt/openEMS --with-hyp2mat --with-CTB --with-MPI +``` + ++ Add the given paths to your Octave/Matlab environment (e.g.):
+```Matlab +addpath('~/opt/openEMS/share/openEMS/matlab'); +addpath('~/opt/openEMS/share/CSXCAD/matlab'); +``` + ++ Add the optional packages to your Octave/Matlab environment (e.g.):
+```Matlab +addpath('~/opt/openEMS/share/hyp2mat/matlab'); +addpath('~/opt/openEMS/share/CTB/matlab'); +``` + +For more informations and other platforms see: +[http://www.openems.de/index.php/OpenEMS#Installation](http://www.openems.de/index.php/OpenEMS#Installation)
+ +## Update Instruction: ++ Perform an update in case of a new release + +**Note:** Changes you may have made (e.g. to the tutorials or examples) may be overwritten!
+```bash +cd openEMS-Project +git pull +./update_openEMS.sh ~/opt/openEMS +``` diff --git a/update_openEMS.sh b/update_openEMS.sh new file mode 100755 index 0000000..4acbf0e --- /dev/null +++ b/update_openEMS.sh @@ -0,0 +1,160 @@ +#!/bin/bash + +# Compiling OpenEMS may require installing the following packages: +# apt-get install cmake qt4-qmake libtinyxml-dev libcgal-dev libvtk5-qt4-dev +# Compiling hyp2mat may require installing the following packages: +# apt-get install gengetopt help2man groff pod2pdf bison flex libhpdf-dev libtool + +if [ $# -lt 1 ] +then + echo "Usage: `basename $0` []" + echo "" + echo " options:" + echo " --with-hyp2mat: enable hyp2mat build" + echo " --with-CTB enable circuit toolbox" + echo " --disable-GUI disable GUI build (AppCSXCAD)" + echo " --with-MPI enable MPI" + exit $E_BADARGS +fi + +# defaults +BUILD_HYP2MAT=0 +BUILD_CTB=0 +BUILD_GUI="YES" +WITH_MPI=0 + +# parse arguments +for varg in ${@:2:$#} +do + case "$varg" in + "--with-hyp2mat") + echo "enabling hyp2mat build" + BUILD_HYP2MAT=1 + ;; + "--with-CTB") + echo "enabling CTB build" + BUILD_CTB=1 + ;; + "--disable-GUI") + echo "disabling AppCSXCAD build" + BUILD_GUI="NO" + ;; + "--with-MPI") + echo "enabling MPI" + WITH_MPI=1 + ;; + *) + echo "error, unknown argumennt: $varg" + exit 1 + ;; + esac +done + +basedir=$(pwd) +INSTALL_PATH=${1%/} +LOG_FILE=$basedir/build_$(date +%Y%m%d_%H%M%S).log + +echo "setting install path to: $INSTALL_PATH" +echo "logging build output to: $LOG_FILE" + +function build { +cd $1 +make clean &> /dev/null + +if [ -f bootstrap.sh ]; then + echo "bootstrapping $1 ... please wait" + sh ./bootstrap.sh >> $LOG_FILE + if [ $? -ne 0 ]; then + echo "bootstrap for $1 failed" + cd .. + exit 1 + fi +fi + +if [ -f configure ]; then + echo "configuring $1 ... please wait" + ./configure $2 >> $LOG_FILE + if [ $? -ne 0 ]; then + echo "configure for $1 failed" + cd .. + exit 1 + fi +fi + +echo "compiling $1 ... please wait" +make -j4 >> $LOG_FILE +if [ $? -ne 0 ]; then + echo "make for $1 failed" + cd .. + exit 1 +fi +cd .. +} + +function install { +cd $1 +echo "installing $1 ... please wait" +make ${@:2:$#} install >> $LOG_FILE +if [ $? -ne 0 ]; then + echo "make install for $1 failed" + cd .. + exit 1 +fi +cd .. +} + +##### build openEMS and dependencies #### +tmpdir=`mktemp -d` && cd $tmpdir +echo "running cmake in tmp dir: $tmpdir" +cmake -DBUILD_APPCSXCAD=$BUILD_GUI -DCMAKE_INSTALL_PREFIX=$INSTALL_PATH -DWITH_MPI=$WITH_MPI $basedir >> $LOG_FILE +if [ $? -ne 0 ]; then + echo "cmake failed" + cd $basedir + echo "build incomplete, cleaning up tmp dir ..." + rm -rf $tmpdir + exit 1 +fi +echo "build openEMS and dependencies ... please wait" +make >> $LOG_FILE 2>&1 +if [ $? -ne 0 ]; then + echo "make failed, build incomplete, please see logfile for more details..." + cd $basedir + echo "build incomplete, cleaning up tmp dir ..." + rm -rf $tmpdir + exit 1 +fi +echo "build successful, cleaning up tmp dir ..." +rm -rf $tmpdir +cd $basedir + +##### addtional packages #### + +if [ $BUILD_HYP2MAT -eq 1 ]; then + #build hyp2mat + build hyp2mat --prefix=$INSTALL_PATH + install hyp2mat +fi + +if [ $BUILD_CTB -eq 1 ]; then + #install circuit toolbox (CTB) + install CTB PREFIX=$INSTALL_PATH +fi + +##### + +echo " -------- " +echo "openEMS and all modules have been updated successfully..." +echo "" +echo "% add the required paths to Octave/Matlab:" +echo "addpath('$INSTALL_PATH/share/openEMS/matlab')" +echo "addpath('$INSTALL_PATH/share/CSXCAD/matlab')" +echo "" +echo "% optional additional pckages:" +if [ $BUILD_HYP2MAT -eq 1 ]; then + echo "addpath('$INSTALL_PATH/share/hyp2mat/matlab'); % hyp2mat package" +fi +if [ $BUILD_CTB -eq 1 ]; then + echo "addpath('$INSTALL_PATH/share/CTB/matlab'); % circuit toolbox" +fi +echo "" +echo "Have fun using openEMS" -- cgit v1.2.3 From 933f19315c4bef9e6fdd1cb546b372755e486558 Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Wed, 6 Jul 2016 18:24:09 +0200 Subject: Fix path to binaries for Debian Gbp-Pq: Name 0001-Fix-path-to-binaries-for-Debian.patch --- CSXCAD/matlab/CSXGeomPlot.m | 16 +++++++++------- openEMS/matlab/CalcNF2FF.m | 15 ++++++++------- openEMS/matlab/private/invoke_openEMS.m | 16 +++++++++------- 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/CSXCAD/matlab/CSXGeomPlot.m b/CSXCAD/matlab/CSXGeomPlot.m index df33c94..034f1a1 100644 --- a/CSXCAD/matlab/CSXGeomPlot.m +++ b/CSXCAD/matlab/CSXGeomPlot.m @@ -27,13 +27,15 @@ end filename = mfilename('fullpath'); dir = fileparts( filename ); -if isunix - AppCSXCAD_bin = searchBinary('AppCSXCAD.sh', ... - {[dir filesep '..' filesep '..' filesep 'AppCSXCAD' filesep], ... - [dir filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}); -else % assume windows - AppCSXCAD_bin = searchBinary('AppCSXCAD.exe',[dir filesep '..' filesep]); -end +%if isunix +% AppCSXCAD_bin = searchBinary('AppCSXCAD.sh', ... +% {[dir filesep '..' filesep '..' filesep 'AppCSXCAD' filesep], ... +% [dir filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}); +%else % assume windows +% AppCSXCAD_bin = searchBinary('AppCSXCAD.exe',[dir filesep '..' filesep]); +%end + +AppCSXCAD_bin = '/usr/bin/AppCSXCAD'; command = [AppCSXCAD_bin ' --disableEdit ' args_string ' ' CSX_filename]; disp( ['invoking AppCSXCAD, exit to continue script...'] ); diff --git a/openEMS/matlab/CalcNF2FF.m b/openEMS/matlab/CalcNF2FF.m index c80b52e..07cc849 100644 --- a/openEMS/matlab/CalcNF2FF.m +++ b/openEMS/matlab/CalcNF2FF.m @@ -98,13 +98,14 @@ struct_2_xml(nf2ff.xml,nf2ff_xml,'nf2ff'); m_filename = mfilename('fullpath'); dir_name = fileparts( m_filename ); -if isunix - nf2ff_bin = searchBinary('nf2ff', ... - {[dir_name filesep '..' filesep 'nf2ff' filesep], ... - [dir_name filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}, 0); -else - nf2ff_bin = searchBinary('nf2ff.exe',[dir_name filesep '..' filesep], 0); -end +%if isunix +% nf2ff_bin = searchBinary('nf2ff', ... +% {[dir_name filesep '..' filesep 'nf2ff' filesep], ... +% [dir_name filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}, 0); +%else +% nf2ff_bin = searchBinary('nf2ff.exe',[dir_name filesep '..' filesep], 0); +%end +nf2ff_bin = '/usr/bin/nf2ff'; if ((exist(nf2ff.hdf5,'file') && (mode==0)) || (mode==2)) disp('CalcNF2FF: Reading nf2ff data only...') diff --git a/openEMS/matlab/private/invoke_openEMS.m b/openEMS/matlab/private/invoke_openEMS.m index afb2b46..8c4d79b 100644 --- a/openEMS/matlab/private/invoke_openEMS.m +++ b/openEMS/matlab/private/invoke_openEMS.m @@ -26,13 +26,15 @@ end filename = mfilename('fullpath'); dir = fileparts( filename ); -if isunix - openEMS_bin = searchBinary('openEMS.sh', ... - {[dir filesep '..' filesep '..' filesep], ... % try devel path - [dir filesep '..' filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}); % try (default) install path -else % assume windows - openEMS_bin = searchBinary('openEMS.exe', [dir filesep '..' filesep '..' filesep]); -end +%if isunix +% openEMS_bin = searchBinary('openEMS.sh', ... +% {[dir filesep '..' filesep '..' filesep], ... % try devel path +% [dir filesep '..' filesep '..' filesep '..' filesep '..' filesep 'bin' filesep]}); % try (default) install path +%else % assume windows +% openEMS_bin = searchBinary('openEMS.exe', [dir filesep '..' filesep '..' filesep]); +%end + +openEMS_bin = '/usr/bin/openEMS'; command = [openEMS_bin ' ' opts]; -- cgit v1.2.3 From fe640c36dd4705854882cbe81768d8369b21de68 Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Sat, 9 Jul 2016 11:12:02 +0200 Subject: Spelling fixes Gbp-Pq: Name 0002-Spelling-fixes.patch --- CSXCAD/src/CSPrimPolyhedron.cpp | 4 ++-- CSXCAD/src/CSPrimPolyhedronReader.cpp | 2 +- CSXCAD/src/CSRectGrid.cpp | 4 ++-- QCSXCAD/QCSGridEditor.cpp | 2 +- QCSXCAD/QCSXCAD.cpp | 8 ++++---- QCSXCAD/QVTKStructure.cpp | 2 +- openEMS/Common/processmodematch.cpp | 2 +- openEMS/FDTD/extensions/operator_ext_upml.cpp | 2 +- openEMS/FDTD/operator.cpp | 6 +++--- openEMS/tools/AdrOp.cpp | 22 +++++++++++----------- openEMS/tools/ErrorMsg.cpp | 10 +++++----- openEMS/tools/ExpenseLog.h | 2 +- openEMS/tools/useful.cpp | 2 +- openEMS/tools/vtk_file_writer.cpp | 4 ++-- 14 files changed, 36 insertions(+), 36 deletions(-) diff --git a/CSXCAD/src/CSPrimPolyhedron.cpp b/CSXCAD/src/CSPrimPolyhedron.cpp index 7eac505..9583b7e 100644 --- a/CSXCAD/src/CSPrimPolyhedron.cpp +++ b/CSXCAD/src/CSPrimPolyhedron.cpp @@ -183,11 +183,11 @@ bool CSPrimPolyhedron::BuildTree() { m_Dimension = 2; - //if structure is not closed due to invalud faces, mark it as 3D + //if structure is not closed due to invalid faces, mark it as 3D if (m_InvalidFaces>0) { m_Dimension = 3; - std::cerr << "CSPrimPolyhedron::BuildTree: Warning, found polyhedron has invalud faces and is not a closed surface, setting to 3D solid anyway!" << std::endl; + std::cerr << "CSPrimPolyhedron::BuildTree: Warning, found polyhedron has invalid faces and is not a closed surface, setting to 3D solid anyway!" << std::endl; } } diff --git a/CSXCAD/src/CSPrimPolyhedronReader.cpp b/CSXCAD/src/CSPrimPolyhedronReader.cpp index ed224fd..c88c67e 100644 --- a/CSXCAD/src/CSPrimPolyhedronReader.cpp +++ b/CSXCAD/src/CSPrimPolyhedronReader.cpp @@ -77,7 +77,7 @@ bool CSPrimPolyhedronReader::Write2XML(TiXmlElement &elem, bool parameterised) elem.SetAttribute("FileType","PLY"); break; default: - elem.SetAttribute("FileType","Unkown"); + elem.SetAttribute("FileType","Unknown"); break; } return CSPrimitives::Write2XML(elem,parameterised); diff --git a/CSXCAD/src/CSRectGrid.cpp b/CSXCAD/src/CSRectGrid.cpp index 50f2947..5b36dc2 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 } fParse.Parse(DistFunction,dirVar); if (fParse.GetParseErrorType()!=FunctionParser::FP_NO_ERROR) - return std::string("An error occured parsing f(") + dirVar + std::string(") - Parser message:\n") + std::string(fParse.ErrorMsg()); + return std::string("An error occurred parsing f(") + dirVar + std::string(") - Parser message:\n") + std::string(fParse.ErrorMsg()); double dValue=0; bool error=false; @@ -88,7 +88,7 @@ std::string CSRectGrid::AddDiscLines(int direct, int numLines, double* vals, std if (fParse.EvalError()!=0) error=true; AddDiscLine(direct,dValue); } - if (error) return std::string("An error occured evaluation the grid function f(") + dirVar + std::string(")!"); + if (error) return std::string("An error occurred evaluation the grid function f(") + dirVar + std::string(")!"); } return ""; } diff --git a/QCSXCAD/QCSGridEditor.cpp b/QCSXCAD/QCSGridEditor.cpp index 4e2210c..17d8ffe 100644 --- a/QCSXCAD/QCSGridEditor.cpp +++ b/QCSXCAD/QCSGridEditor.cpp @@ -237,7 +237,7 @@ void QCSGridEditor::BuildInHomogenDisc() // if (fParse.EvalError()!=0) error=true; // clGrid->AddDiscLine(i,dValue); // } -// if (error) QMessageBox::warning(HomogenDisc,tr("Error evaluation grid function!"),QString(tr("An error occured evaluation the grid function f(%1)!").arg(coordVars.at(i)))); +// if (error) QMessageBox::warning(HomogenDisc,tr("Error evaluation grid function!"),QString(tr("An error occurred evaluation the grid function f(%1)!").arg(coordVars.at(i)))); // } // clGrid->Sort(i); // } diff --git a/QCSXCAD/QCSXCAD.cpp b/QCSXCAD/QCSXCAD.cpp index 4cd4a74..b9ef094 100644 --- a/QCSXCAD/QCSXCAD.cpp +++ b/QCSXCAD/QCSXCAD.cpp @@ -299,7 +299,7 @@ bool QCSXCAD::ReadNode(TiXmlNode* root) if (root==NULL) return false; clear(); QString msg(ReadFromXML(root)); - if (msg.isEmpty()==false) QMessageBox::warning(this,tr("Geometry read error"),tr("An geometry read error occured!!\n\n")+msg,QMessageBox::Ok,QMessageBox::NoButton); + if (msg.isEmpty()==false) QMessageBox::warning(this,tr("Geometry read error"),tr("An geometry read error occurred!!\n\n")+msg,QMessageBox::Ok,QMessageBox::NoButton); CSTree->UpdateTree(); CSTree->expandAll(); setModified(); @@ -336,7 +336,7 @@ bool QCSXCAD::ReadFile(QString filename) // QString msg(ReadFromXML(filename.toLatin1().constData())); QString msg(ReadFromXML(root)); if (msg.isEmpty()==false) - QMessageBox::warning(this,tr("Geometry read error"),tr("An geometry read error occured!!\n\n")+msg,QMessageBox::Ok,QMessageBox::NoButton); + QMessageBox::warning(this,tr("Geometry read error"),tr("An geometry read error occurred!!\n\n")+msg,QMessageBox::Ok,QMessageBox::NoButton); CSTree->UpdateTree(); CSTree->expandAll(); @@ -720,7 +720,7 @@ void QCSXCAD::ExportGeometry() if (qFilename==NULL) return; if (!qFilename.endsWith(".xml")) qFilename+=".xml"; - if (Write2XML(qFilename.toLatin1().data())==false) QMessageBox::warning(this,tr("Geometry Export"),tr("Unknown error occured! Geometry Export failed"),1,0); + if (Write2XML(qFilename.toLatin1().data())==false) QMessageBox::warning(this,tr("Geometry Export"),tr("Unknown error occurred! Geometry Export failed"),1,0); } void QCSXCAD::ExportGeometry_Povray() @@ -802,7 +802,7 @@ void QCSXCAD::ExportGeometry(QString dirname, int type) StructureVTK->ExportProperty2PLY(uID,filename,clGrid.GetDeltaUnit()); break; default: - QMessageBox::warning(this, "Export Dialog","Unkown export type, skipping..."); + QMessageBox::warning(this, "Export Dialog","Unknown export type, skipping..."); return; break; } diff --git a/QCSXCAD/QVTKStructure.cpp b/QCSXCAD/QVTKStructure.cpp index 9482dde..8eea1e8 100644 --- a/QCSXCAD/QVTKStructure.cpp +++ b/QCSXCAD/QVTKStructure.cpp @@ -295,7 +295,7 @@ void QVTKStructure::RenderGridDir(int dir, unsigned int plane_pos) uiQty[n]=CSGrid->GetQtyLines(n); if ((int)plane_pos>=uiQty[dir]) { - cerr << "QVTKStructure::RenderGridDir: requested plane postion is out of range, resetting to max value!" << endl; + cerr << "QVTKStructure::RenderGridDir: requested plane position is out of range, resetting to max value!" << endl; plane_pos = uiQty[dir]-1; } diff --git a/openEMS/Common/processmodematch.cpp b/openEMS/Common/processmodematch.cpp index 620257d..7cd22f8 100644 --- a/openEMS/Common/processmodematch.cpp +++ b/openEMS/Common/processmodematch.cpp @@ -123,7 +123,7 @@ void ProcessModeMatch::InitProcess() int res = m_ModeParser[n]->Parse(m_ModeFunction[ny], "x,y,z,rho,a,r,t"); if (res >= 0) { - cerr << "ProcessModeMatch::InitProcess(): Warning, an error occured parsing the mode matching function (see below) ..." << endl; + cerr << "ProcessModeMatch::InitProcess(): Warning, an error occurred parsing the mode matching function (see below) ..." << endl; cerr << m_ModeFunction[ny] << "\n" << string(res, ' ') << "^\n" << m_ModeParser[n]->ErrorMsg() << "\n"; SetEnable(false); Reset(); diff --git a/openEMS/FDTD/extensions/operator_ext_upml.cpp b/openEMS/FDTD/extensions/operator_ext_upml.cpp index fc46d85..d64c21c 100644 --- a/openEMS/FDTD/extensions/operator_ext_upml.cpp +++ b/openEMS/FDTD/extensions/operator_ext_upml.cpp @@ -280,7 +280,7 @@ bool Operator_Ext_UPML::SetGradingFunction(string func) int res = m_GradingFunction->Parse(m_GradFunc.c_str(), "D,dl,W,Z,N"); if (res < 0) return true; - cerr << "Operator_Ext_UPML::SetGradingFunction: Warning, an error occured parsing the pml grading function (see below) ..." << endl; + cerr << "Operator_Ext_UPML::SetGradingFunction: Warning, an error occurred parsing the pml grading function (see below) ..." << endl; cerr << func << "\n" << string(res, ' ') << "^\n" << m_GradingFunction->ErrorMsg() << "\n"; return false; } diff --git a/openEMS/FDTD/operator.cpp b/openEMS/FDTD/operator.cpp index a7582aa..2dec2d3 100644 --- a/openEMS/FDTD/operator.cpp +++ b/openEMS/FDTD/operator.cpp @@ -450,7 +450,7 @@ Grid_Path Operator::FindPath(double start[], double stop[]) currPos[minDir]+=-1; minPos[minDir]-=1; } - //check validity of current postion + //check validity of current position for (int n=0;n<3;++n) if (currPos[n]>=numLines[n]) { @@ -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])) { - 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; cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << "," << pos[2] << endl; exit(0); } @@ -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])) { - 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; cerr << ny << "@" << n << " : " << pos[0] << "," << pos[1] << "," << pos[2] << endl; exit(0); } diff --git a/openEMS/tools/AdrOp.cpp b/openEMS/tools/AdrOp.cpp index 228f8de..23a7e87 100644 --- a/openEMS/tools/AdrOp.cpp +++ b/openEMS/tools/AdrOp.cpp @@ -28,15 +28,15 @@ AdrOp::AdrOp(unsigned int muiImax, unsigned int muiJmax, unsigned int muiKmax, u fprintf(stderr,"Memory allocation failed!! exiting..."); exit(1); } - error->SetMsg(1,"Adress Operator: Memory allocation failed!! exiting..."); - error->SetMsg(2,"Adress Operator: Invalid Adress requested!! exiting..."); - error->SetMsg(3,"Adress Operator: Invalid Position set!! exiting..."); - error->SetMsg(4,"Adress Operator: Invalid jump or passing end of iteration!! exiting..."); - error->SetMsg(5,"Adress Operator: 4D not yet implemented!! exiting..."); - error->SetMsg(6,"Adress Operator: Position not set!! exiting..."); - error->SetMsg(7,"Adress Operator: Cells not added to Adress Operator!! exiting..."); - error->SetMsg(8,"Adress Operator: Invalid Node!! exiting..."); - error->SetMsg(9,"Adress Operator: Grid invalid!! exiting..."); + error->SetMsg(1,"Address Operator: Memory allocation failed!! exiting..."); + error->SetMsg(2,"Address Operator: Invalid Address requested!! exiting..."); + error->SetMsg(3,"Address Operator: Invalid Position set!! exiting..."); + error->SetMsg(4,"Address Operator: Invalid jump or passing end of iteration!! exiting..."); + error->SetMsg(5,"Address Operator: 4D not yet implemented!! exiting..."); + error->SetMsg(6,"Address Operator: Position not set!! exiting..."); + error->SetMsg(7,"Address Operator: Cells not added to Address Operator!! exiting..."); + error->SetMsg(8,"Address Operator: Invalid Node!! exiting..."); + error->SetMsg(9,"Address Operator: Grid invalid!! exiting..."); //if (muiImax<0) muiImax=0; //if (muiJmax<0) muiJmax=0; @@ -50,7 +50,7 @@ AdrOp::AdrOp(unsigned int muiImax, unsigned int muiJmax, unsigned int muiKmax, u else exit(-2); if (muiKmax>0) uiDimension++; if ( (muiLmax>0) && (muiKmax>0) ) uiDimension++; -// cout << "\n-----Adress Operator created: Dimension: " << uiDimension << "----" <0) && (nr<=NoMsg)) { if (Msg[nr-1]!=NULL) fprintf(stderr,"%s",Msg[nr-1]); - else fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + else fprintf(stderr,"unknown error occurred!! Error code: %d exiting...",nr); if (chAddMsg!=NULL) fprintf(stderr,"%s",chAddMsg); getchar(); exit(nr); } else { - fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + fprintf(stderr,"unknown error occurred!! Error code: %d exiting...",nr); getchar(); exit(nr); } @@ -78,14 +78,14 @@ void ErrorMsg::Error(unsigned int nr,int addNr) if ((nr>0) && (nr<=NoMsg)) { if (Msg[nr-1]!=NULL) fprintf(stderr,"%s",Msg[nr-1]); - else fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + else fprintf(stderr,"unknown error occurred!! Error code: %d exiting...",nr); fprintf(stderr,"%d",addNr); getchar(); exit(nr); } else { - fprintf(stderr,"unkown error occured!! Error code: %d exiting...",nr); + fprintf(stderr,"unknown error occurred!! Error code: %d exiting...",nr); getchar(); exit(nr); } @@ -93,6 +93,6 @@ void ErrorMsg::Error(unsigned int nr,int addNr) void ErrorMsg::ownError(void) { - fprintf(stdout," Error occured by using Error Message class!! ... exiting..."); + fprintf(stdout," Error occurred by using Error Message class!! ... exiting..."); exit(-1); } diff --git a/openEMS/tools/ExpenseLog.h b/openEMS/tools/ExpenseLog.h index f8cc1ba..8aa1438 100644 --- a/openEMS/tools/ExpenseLog.h +++ b/openEMS/tools/ExpenseLog.h @@ -14,7 +14,7 @@ using namespace std; ExpenseLog EL; \ ExpenseModule* EngineExpense=EL.AddModule("Static Engine Expenses"); \ ExpenseModule* PPExpense=EL.AddModule("Static Post Processing"); \ -ExpenseModule* AdrOpExpense=EL.AddModule("Adress Operator"); +ExpenseModule* AdrOpExpense=EL.AddModule("Address Operator"); #define EXTERN_EXPENSE_DEFINE extern ExpenseLog EL; #define ENGINEEXPENSE_DEFINE extern ExpenseModule* EngineExpense; #define POSTPROCEXPENSE_DEFINE extern ExpenseModule* PPExpense; diff --git a/openEMS/tools/useful.cpp b/openEMS/tools/useful.cpp index 50aacfb..8e548f0 100644 --- a/openEMS/tools/useful.cpp +++ b/openEMS/tools/useful.cpp @@ -63,7 +63,7 @@ std::vector AssignJobs2Threads(unsigned int jobs, unsigned int nrT } if (jobs>0) - std::cerr << "AssignJobs2Threads: Error, " << jobs << " remain to be assigned, this should not have happend..." << std::endl; + std::cerr << "AssignJobs2Threads: Error, " << jobs << " remain to be assigned, this should not have happened..." << std::endl; if (RemoveEmpty) { diff --git a/openEMS/tools/vtk_file_writer.cpp b/openEMS/tools/vtk_file_writer.cpp index 79c40f3..be6586f 100644 --- a/openEMS/tools/vtk_file_writer.cpp +++ b/openEMS/tools/vtk_file_writer.cpp @@ -70,7 +70,7 @@ void VTK_File_Writer::SetMeshLines(double const* const* lines, unsigned int cons vtkRectilinearGrid* RectGrid = dynamic_cast(m_GridData); if (RectGrid==NULL) { - cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happend! " << endl; + cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happened! " << endl; exit(1); } RectGrid->SetDimensions(count[0],count[1],count[2]); @@ -97,7 +97,7 @@ void VTK_File_Writer::SetMeshLines(double const* const* lines, unsigned int cons vtkStructuredGrid* StructGrid = dynamic_cast(m_GridData); if (StructGrid==NULL) { - cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happend! " << endl; + cerr << "VTK_File_Writer::SetMeshLines: Error, grid invalid, this should not have happened! " << endl; exit(1); } -- cgit v1.2.3 From 26c6dc91941d1b78d4b53171e8713c08032af0af Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Sun, 20 Nov 2016 22:01:42 +0000 Subject: More things to fix build Gbp-Pq: Name 0003-More-things-to-fix-build.patch --- CSXCAD/CMakeLists.txt | 4 ++-- openEMS/CMakeLists.txt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CSXCAD/CMakeLists.txt b/CSXCAD/CMakeLists.txt index 9d516d5..d7670c1 100644 --- a/CSXCAD/CMakeLists.txt +++ b/CSXCAD/CMakeLists.txt @@ -90,9 +90,9 @@ INCLUDE_DIRECTORIES( ${fparser_INCLUDE_DIR} ) find_package(TinyXML REQUIRED) ADD_DEFINITIONS( -DTIXML_USE_STL ) -find_package(HDF5 1.8 COMPONENTS C HL REQUIRED) +find_package(HDF5 1.8 COMPONENTS CXX HL REQUIRED) INCLUDE_DIRECTORIES (${HDF5_INCLUDE_DIRS}) -link_directories(${HDF5_LIBRARY_DIRS}) +link_directories(${HDF5_LIBRARIES}) # hdf5 compat ADD_DEFINITIONS( -DH5_USE_16_API ) diff --git a/openEMS/CMakeLists.txt b/openEMS/CMakeLists.txt index 898f280..5504590 100644 --- a/openEMS/CMakeLists.txt +++ b/openEMS/CMakeLists.txt @@ -108,7 +108,7 @@ find_package(TinyXML REQUIRED) ADD_DEFINITIONS( -DTIXML_USE_STL ) # hdf5 -find_package(HDF5 1.8 COMPONENTS C HL REQUIRED) +find_package(HDF5 1.8 COMPONENTS CXX HL REQUIRED) INCLUDE_DIRECTORIES (${HDF5_INCLUDE_DIRS}) link_directories(${HDF5_LIBRARIES}) -- cgit v1.2.3 From 882d9c7698ca5986f6e4fe8deea8c41858142901 Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Sun, 20 Nov 2016 22:40:17 +0000 Subject: link more Gbp-Pq: Name 0004-link-more.patch --- AppCSXCAD/CMakeLists.txt | 1 + openEMS/CMakeLists.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/AppCSXCAD/CMakeLists.txt b/AppCSXCAD/CMakeLists.txt index d5a72c9..2d4b11b 100644 --- a/AppCSXCAD/CMakeLists.txt +++ b/AppCSXCAD/CMakeLists.txt @@ -157,6 +157,7 @@ TARGET_LINK_LIBRARIES( AppCSXCAD ${HDF5_HL_LIBRARIES} ${QT_LIBRARIES} ${vtk_LIBS} + hdf5_serial_hl ) # diff --git a/openEMS/CMakeLists.txt b/openEMS/CMakeLists.txt index 5504590..794a498 100644 --- a/openEMS/CMakeLists.txt +++ b/openEMS/CMakeLists.txt @@ -184,6 +184,7 @@ TARGET_LINK_LIBRARIES( openEMS ${Boost_LIBRARIES} ${vtk_LIBS} ${MPI_LIBRARIES} + hdf5_serial_hl ) # main program -- cgit v1.2.3 From c46e7ef0380b20e28fec3114abbffab557062bba Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Mon, 21 Nov 2016 00:08:20 +0100 Subject: Deletede CVS dir (lintian) Gbp-Pq: Name 0005-Deletede-CVS-dir-lintian.patch --- QCSXCAD/images/CVS/Entries | 40 ---------------------------------------- QCSXCAD/images/CVS/Repository | 1 - QCSXCAD/images/CVS/Root | 1 - 3 files changed, 42 deletions(-) delete mode 100644 QCSXCAD/images/CVS/Entries delete mode 100644 QCSXCAD/images/CVS/Repository delete mode 100644 QCSXCAD/images/CVS/Root diff --git a/QCSXCAD/images/CVS/Entries b/QCSXCAD/images/CVS/Entries deleted file mode 100644 index 3593808..0000000 --- a/QCSXCAD/images/CVS/Entries +++ /dev/null @@ -1,40 +0,0 @@ -/GeoEdit.png/1.1/Mon Oct 20 07:11:47 2003/-kb/ -/ParaSetup.png/1.1/Mon Oct 20 07:11:13 2003/-kb/ -/Thumbs.db/1.2/Tue Jun 27 14:51:16 2006/-kb/ -/accept.png/1.1/Mon Aug 29 14:17:00 2005/-kb/ -/bulb.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/bulb_off.png/1.1/Wed Oct 11 20:48:27 2006/-kb/ -/cancel.png/1.1/Mon Oct 20 07:16:21 2003/-kb/ -/close.png/1.1/Mon Oct 20 07:16:25 2003/-kb/ -/configure.png/1.1/Mon Oct 10 19:03:03 2005/-kb/ -/down.png/1.1/Mon Oct 10 19:03:03 2005/-kb/ -/edit.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/edit_add.png/1.1/Mon Oct 20 07:16:24 2003/-kb/ -/edit_remove.png/1.1/Mon Oct 20 07:16:25 2003/-kb/ -/editcopy.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/exit.png/1.1/Mon Oct 20 07:16:26 2003/-kb/ -/failed.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/filenew.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/fileopen.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/filesave.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/filesaveas.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/folder.png/1.1/Fri Apr 4 12:47:44 2003/-kb/ -/funct.png/1.1/Mon Oct 20 07:16:30 2003/-kb/ -/hourglass.png/1.1/Wed Sep 28 17:56:00 2005/-kb/ -/icon.gif/1.1/Sun Aug 28 21:13:00 2005/-kb/ -/launch.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/qt-logo.png/1.1/Wed Dec 14 17:02:26 2005/-kb/ -/reload.png/1.1/Mon Dec 16 23:41:14 2002/-kb/ -/result_small.png/1.1/Mon Oct 20 07:16:29 2003/-kb/ -/results.png/1.1/Mon Oct 20 07:11:58 2003/-kb/ -/setup.png/1.1/Sun Aug 14 17:45:15 2005/-kb/ -/simulation.png/1.1/Fri Jan 6 12:43:58 2006/-kb/ -/simulation_icon.png/1.1/Fri Jan 6 14:24:45 2006/-kb/ -/simulation_small.png/1.1/Thu Jun 29 20:43:26 2006/-kb/ -/simulation_tr.png/1.1/Fri Jan 6 14:23:52 2006/-kb/ -/up.png/1.1/Mon Oct 10 19:03:03 2005/-kb/ -/viewmag+.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/viewmag-.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/viewmagfit.png/1.1/Fri Apr 4 12:47:42 2003/-kb/ -/window_icon2.png/1.1/Mon Aug 29 14:17:00 2005/-kb/ -/work.png/1.1/Mon Oct 20 07:14:09 2003/-kb/ diff --git a/QCSXCAD/images/CVS/Repository b/QCSXCAD/images/CVS/Repository deleted file mode 100644 index d336c21..0000000 --- a/QCSXCAD/images/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -StaticSimulator/images diff --git a/QCSXCAD/images/CVS/Root b/QCSXCAD/images/CVS/Root deleted file mode 100644 index 800d2fc..0000000 --- a/QCSXCAD/images/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:extssh:coft@atex.ate.uni-duisburg.de:/srv/CVS -- cgit v1.2.3 From b3b93600fd920e40233fe32cb673ac06467a65f9 Mon Sep 17 00:00:00 2001 From: Ruben Undheim Date: Mon, 21 Nov 2016 00:45:35 +0100 Subject: Don't exit from library Gbp-Pq: Name 0006-Don-t-exit-from-library.patch --- openEMS/tools/array_ops.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openEMS/tools/array_ops.cpp b/openEMS/tools/array_ops.cpp index 8710b3c..7100f9a 100644 --- a/openEMS/tools/array_ops.cpp +++ b/openEMS/tools/array_ops.cpp @@ -73,7 +73,7 @@ f4vector* Create1DArray_v4sf(const unsigned int numLines) if (MEMALIGN( (void**)&array, 16, sizeof(typeof(f4vector))*numLines )) { cerr << "cannot allocate aligned memory" << endl; - exit(3); + return 0; } for (unsigned int pos=0; pos