pax_global_header00006660000000000000000000000064141134356740014522gustar00rootroot0000000000000052 comment=df65b1282ea89ad40d2cb6565983f7e633ccce31 dune-common-2.8.0/000077500000000000000000000000001411343567400137525ustar00rootroot00000000000000dune-common-2.8.0/.gitignore000066400000000000000000000002471411343567400157450ustar00rootroot00000000000000# ignore all build folders /build*/ # ignore backup files *~ # ignore Python files *.pyc # ignore files generated during python setup.py sdist MANIFEST _skbuild/ dist dune-common-2.8.0/.gitlab-ci.yml000066400000000000000000000044701411343567400164130ustar00rootroot00000000000000--- include: - project: 'core/ci-config' ref: master file: 'config/common/master.yml' - project: 'core/ci-config' ref: master file: 'jobs/common/master.yml' before_script: - . /duneci/bin/duneci-init-job variables: DUNECI_TEST_LABELS: quick DUNE_TEST_EXPECTED_VC_IMPLEMENTATION: SSE2 debian:10 gcc-7-17--expensive: # This image has Vc image: registry.dune-project.org/docker/ci/debian:10 script: duneci-standard-test stage: test # allow expensive tests variables: DUNECI_CXXFLAGS: -mavx DUNECI_TEST_LABELS: "" DUNECI_TOOLCHAIN: gcc-7-17 DUNE_TEST_EXPECTED_VC_IMPLEMENTATION: AVX # require AVX to properly test Vc tags: [duneci, "iset:avx"] # allowed to fail to e.g. do no hold up a merge when a runner supporting avx # is unavailable allow_failure: true debian-11-gcc-9-17-python: image: registry.dune-project.org/docker/ci/debian:11 script: duneci-standard-test stage: test variables: DUNECI_TOOLCHAIN: gcc-9-17 # so we need some variables to build the dune-py module during execution of the first python test: # we need to find the dune mdoule DUNE_CONTROL_PATH: /duneci/modules:$CI_PROJECT_DIR # the position for the dune-py module DUNE_PY_DIR: /duneci/modules/dune-py # during dune-py build this variable is used - do know a way to access # the CMAKE_FLAGS used to build the modules... DUNE_CMAKE_FLAGS: "CC=gcc-9 CXX=g++-9 -DCMAKE_CXX_FLAGS='-std=c++17 -O2 -g -Wall -fdiagnostics-color=always' -DDUNE_ENABLE_PYTHONBINDINGS=ON -DDUNE_MAX_TEST_CORES=4 -DBUILD_SHARED_LIBS=TRUE -DDUNE_PYTHON_INSTALL_LOCATION=none -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE -DCMAKE_DISABLE_FIND_PACKAGE_LATEX=TRUE -DCMAKE_DISABLE_FIND_PACKAGE_Alberta=TRUE -DCMAKE_DISABLE_FIND_PACKAGE_Vc=TRUE -DCMAKE_DISABLE_DOCUMENTATION=TRUE" # cmake flags we use for all dune moudle - important is that build shared libs is set (need some better way of doing this) DUNECI_CMAKE_FLAGS: $DUNE_CMAKE_FLAGS # finally set the python path to all modules PYTHONPATH: $CI_PROJECT_DIR/build-cmake/python tags: [duneci] system-test: stage: downstream variables: CI_BUILD_REF_NAME: $CI_COMMIT_REF_NAME DUNECI_TEST_LABELS: "" trigger: project: infrastructure/dune-nightly-test branch: core strategy: depend allow_failure: true dune-common-2.8.0/.mailmap000066400000000000000000000001571411343567400153760ustar00rootroot00000000000000Benjamin Bykowski Convex Function <329364@wright.mathepool.rwth-aachen.de> dune-common-2.8.0/CHANGELOG.md000066400000000000000000000344631411343567400155750ustar00rootroot00000000000000# Release 2.8 - Set minimal required CMake version in cmake to >= 3.13. - Python bindings have been moved from `dune-python` to the respective core modules. `dune-python` is now obsolete. To activate Python bindings the CMake flag `DUNE_ENABLE_PYTHONBINDINGS` needs to be turned on (default is off). Furthermore, flags for either shared library or position independent code need to be used. - Add `instance` method to MPIHelper that does not expect arguments for access to the singleton object after initialization. - Remove the cmake check for `HAVE_MPROTECT` and also do not define this variable in the `config.h` file. It is defined only inside the header `debugallocator.hh`. - Remove deprecated type-traits `has_nan`, `is_indexable`, and `is_range`, use the CamelCase versions instead. - Deprecate fallback implementations `Dune::Std::apply`, `Dune::Std::bool_constant`, and `Dune::Std::make_array` in favor of std c++ implementations. - Deprecate type traits `Dune::Std::to_false_type`, `Dune::Std::to_true_type`. `Dune::AlwaysFalse` and `Dune::AlwaysTrue` (from header `dune/common/typetraits.hh`) now inherit from `std::true_type` and `std::false_type` and are therefore exact replacements for these two type traits. - Deprecate fallback implementation `Dune::Std::conjunction`, `Dune::Std::disjunction`, and `Dune::Std::negation`. Use std c++17 implementations. - Deprecate fallback implementations `Dune::Std::is_callable` and `Dune::Std::is_invocable`. Use C++17 std implementation `std::is_invocable` instead. Be aware that `Dune::Std::is_callable` and `std::is_invocable` are slightly different concepts, since `std::is_invocable` also covers invocation of pointers to member functions and pointers to data members. To additionally constrain for that case, there is now `Dune::IsCallable` (in `dune/common/typetraits.hh`) - Added `Dune::IsCallable` (in `dune/common/typetraits.hh`) which is an improved version of the deprecated `Dune::Std::is_callable` and allows for checking if a type is a function object type, i.e. has a ()-operator than can be invoked with the given argument types and returns a specified return type. - Remove c++ feature tests in cmake for existing c++-17 standards. Add default defines for `DUNE_HAVE_CXX_BOOL_CONSTANT`, `DUNE_HAVE_CXX_EXPERIMENTAL_BOOL_CONSTANT`, `DUNE_HAVE_HEADER_EXPERIMENTAL_TYPE_TRAITS`, `DUNE_HAVE_CXX_APPLY`, `DUNE_HAVE_CXX_EXPERIMENTAL_APPLY`, `HAVE_IS_INDEXABLE_SUPPORT` in `config.h` for one more release. - Add backport of `FindPkgConfig.cmake` from cmake 3.19.4 since there was a bug in an older find module leading to problems finding tbb in debian:10. - Update the FindTBB cmake module to search for the `TBBConfig.cmake` or the `tbb.pc` file containing the configuration. Add the `AddTBBFlags.cmake` file containing the macro `add_dune_tbb_flags` that must be called to use TBB. - Set minimal required MPI version to >= 3.0. - Previous versions of dune-common imported `std::shared_ptr` and `std::make_shared` into the `Dune` namespace. dune-common-2.8 stops doing that. - The file `function.hh` is deprecated. It contained the two base classes `Function` and `VirtualFunction`. In downstream codes, these should be replaced by C++ function objects, `std::function` etc. - Python bindings have been moved from the `dune-python` module which is now obsolete. To activate Python bindings the CMake flag `DUNE_ENABLE_PYTHONBINDINGS` needs to be turned on (default is off). Furthermore, flags for either shared library or position independent code needs to be used. - Support for distributing DUNE modules as python packages has been added. Package meta data is parsed in `packagemetadata.py` from the dune.module file. A script `/bin/dunepackaging.py` was added to generate package files (`setup.py`, `pyproject.toml`) that can also be used to upload packages to the Python Package Index. For a brief description of what is required to add this support to existing dune modules see https://gitlab.dune-project.org/core/dune-common/-/merge_requests/900 Note that this can also be used to generate a package for dune modules that don't provide Python bindings. - Eigenvectors of symmetric 2x2 `FieldMatrix`es are now computed correctly even when they have zero eigenvalues. - Eigenvectors and values are now also supported for matrices and vectors with field_type being float. - The `ParameterTreeParser::readINITree` can now directly construct and return a parameter tree by using the new overload without parameter tree argument. - MPIHelper::instance can now be called without parameters if it was already initialized. - MPITraits now support complex. - There is now a matrix wrapper transpose(M) that represents the transpose of a matrix. ## build-system - The name mangling for Fortran libraries like BLAS and LAPACK is now done without a Fortran compiler. So a Fortran compiler is no longer a built requirement. - `dune_list_filter` is deprecated and will be removed after Dune 2.8. Use `list(FILTER ...)` introduced by CMake 3.6 instead. - `ToUniquePtr` is deprecated and will be removed after Dune 2.8. Use `std::unique_ptr` or `std::shared_ptr` instead. - Remove the CMake options `DUNE_BUILD_BOTH_LIBS` and `DUNE_USE_ONLY_STATIC_LIBS`. Use the default CMake way instead by setting `BUILD_SHARED_LIBS` accordingly. Building both static and shared libraries is no longer supported. - Remove the CMake function deprecated `inkscape_generate_png_from_svg`. - Remove the old and deprecated use of UseLATEX.cmake. `dune_add_latex_document' is a redirection to `add_latex_document` which internally uses `latexmk`. - Many of the CMake find modules habe been rewritten to use CMake's imported targets. These targets are also used in the DUNE CMake package configuration files, where they might appear in e.g. the dune-module_LIBRARIES. If you do not use the DUNE CMake build system the linker might complain about e.g. METIS::METIS not being found. In that case your either need to use the CMake modules shipped with DUNE or create these targets manually. ## Deprecations and removals - Remove deprecated header `dune/common/std/memory.hh`; use `` instead. - Deprecate header `dune/common/std/utility.hh`; use `` instead. - Deprecate header `dune/common/std/variant.hh`; use `` instead. - Remove incomplete CPack support that was never used to make an official build or tarball. - Both macros `DUNE_DEPRECATED` and `DUNE_DEPRECATED_MSG(text)` are deprecated and will be removed after Dune 2.8. Use C++14 attribute `[[deprecated]]` but be aware that it is no drop-in replacement, as it must be sometimes placed at different position in the code. - The macros `DUNE_UNUSED` is deprecated and will be removed after Dune 2.8. Use C++17's attribute `[[maybe_unused]]` instead, but be aware that it is no drop-in replacement, as it must be sometimes placed at different position in the code. The use of `DUNE_UNUSED_PARAMETER` is discouraged. - Dune::void_t has been deprecated and will be removed. Please use std::void_t - Dune::lcd and Dune::gcd are deprecated and will be removed. Please use std::lcd and std::gcd. - VariableSizeCommunicator::fixedsize has been renamed to FixedSize in line with the communicator changes of dune-grid. The old method will be removed in 2.9. # Release 2.7 - Added fallback implementation to C++20 feature: `std::identity`. - A helper class `TransformedRangeView` was added representing a transformed version of a given range using an unary transformation function. The transformation is done on the fly leaving the wrapped range unchanged. - `dune-common` now provides an implementation of `std::variant` for all compilers that support C++14. It is contained in the file `dune/common/std/variant.hh`, in the namespace `Dune::Std::`. If your compiler does support C++17 the implementation in `dune-common` is automatically disabled, and the official implementation from the standard library is used instead. - By popular demand, dense vectors and matrices like `FieldVector` and `FieldMatrix` now have additional operators. In particular, there are - Vector = - Vector - Matrix = - Matrix While these two work for any vector or matrix class that inherits from `DenseVector` or `DenseMatrix`, the following additional methods only work for `FieldVector`: - Vector = Scalar * Vector - Vector = Vector * Scalar - Vector = Vector / Scalar Correspondingly, the `FieldMatrix` class now has - Matrix = Matrix + Matrix - Matrix = Matrix - Matrix - Matrix = Scalar * Matrix - Matrix = Matrix * Scalar - Matrix = Matrix / Scalar - Matrix = Matrix * Matrix Note that the operators - Vector = Vector + Vector - Vector = Vector - Vector have been introduced earlier. - The matrix size functions `N()` and `M()` of `FieldMatrix` and `DiagonalMatrix` can now be used in a `constexpr` context. - There is now (finally!) a method `power` in the file `math.hh` that computes powers with an integer exponent, and is usable in compile-time expressions. The use of the old power methods in `power.hh` is henceforth discouraged. - `FieldMatrix` and `FieldVector` are now [trivially copyable types] if the underlying field type is trivially copyable. As a consequence the copy assignment operator of the `DenseVector` class can no longer be used; just avoid going through `DenseVector` and use the real vector type instead (e.g. `FieldVector`). [trivially copyable types]: https://en.cppreference.com/w/cpp/named_req/TriviallyCopyable ## Deprecations and removals - The `VectorSize` helper has been deprecated. The `size()` method of vectors should be called directly instead. - Drop support for Python 2. Only Python 3 works with Dune 2.7. - Support for older version than METIS 5.x and ParMETIS 4.x is deprecated and will be removed after Dune 2.7. - Deprecated header `dune/common/parallel/collectivecommunication.hh` which will be removed after Dune 2.7. Use dune/common/parallel/communication.hh instead! - Deprecated header `dune/common/parallel/mpicollectivecommunication.hh` which will be removed after Dune 2.7. Use dune/common/parallel/mpicommunication.hh instead! ## build-system - When run with an absolute build directory, `dunecontrol` now exposes the root build directory to CMake in the variable `DUNE_BUILD_DIRECTORY_ROOT_PATH`. See core/dune-common!542 - The `dune_symlink_to_sources_files` CMake function now has a `DESTINATION` argument. - Dune no longer applies architecture flags detected by the Vc library automatically. This applies to all targets that link to Vc explicitly (with `add_dune_vc_flags()`) or implicitly (with `dune_enable_all_packages()`). If you do want to make use of extended architecture features, set the architecture explicitly in the compiler options, e.g. by specifying ```sh CMAKE_FLAGS="-DCMAKE_CXX_FLAGS=-march=native" ``` in your opts-file. Vc also sets compiler options to select a particular C++ abi (`-fabi-version` and `-fabi-compat-version`), these continue to be applied automatically. See core/dune-common!677 - `FindParMETIS.cmake` assumes METIS was found first using `FindMETIS.cmake` and does not longer try to find METIS itself. - The `inkscape_generate_png_from_svg` CMake function is deprecated and will be removed after 2.7. - LaTeX documents can now be built using `latexmk` with the help of UseLatexmk.cmake's `add_latex_document`. `dune_add_latex_document` will use the new way of calling LaTeX when the first argument is `SOURCE`. As a side effect, in-source builds are supported, too. The old function call and UseLATEX.cmake are deprecated and will be removed after 2.7. See core/dune-common!594 - The build system has learned some new tricks when creating or looking for the Python virtualenv: When using an absolute build directory with `dunecontrol`, the virtualenv will now be placed directly inside the root of the build directory hierarchy in the directory `dune-python-env`. This should make it much easier to actually find the virtualenv and also avoids some corner cases where the build system would create multiple virtualenvs that did not know about each other. This behavior can be disabled by setting `DUNE_PYTHON_EXTERNAL_VIRTUALENV_FOR_ABSOLUTE_BUILDDIR=0`. If you need even more precise control about the location of the virtualenv, you can now also directly set the CMake variable `DUNE_PYTHON_VIRTUALENV_PATH` to the directory in which to create the virtualenv. # Release 2.6 **This release is dedicated to Elias Pipping (1986-2017).** - New class `IntegralRange` and free standing function `range` added, providing a feature similar to Python's `range` function: ``` for (const auto &i : range(5,10)) ``` See core/dune-common!325 - `Dune::array` was deprecated, use `std::array` from instead. Instead of `Dune::make_array`, use `Dune::Std::make_array` from dune/common/std/make_array.hh and instead of `Dune::fill_array` use `Dune::filledArray` from dune/common/filledarray.hh.` See core/dune-common!359 - The `DUNE_VERSION...` macros are deprecated use the new macros `DUNE_VERSION_GT`, `DUNE_VERSION_GTE`, `DUNE_VERSION_LTE`, and `DUNE_VERSION_LT` instead. See core/dune-common!329 - Added some additional fallback implementation to C++17 features: (e.g. `optional`, `conjunction`, `disjunction`) - `makeVirtualFunction`: allows to easily convert any function object (e.g. lambda) to a `VirtualFunction` See core/dune-common!282 - Added infrastructure for explicit vectorization *(experimental)* We added experimental support for SIMD data types. We currently provide infrastructure to use [Vc](https://github.com/VcDevel/Vc) and some helper functions to transparently switch between scalar data types and SIMD data types. - `FieldMatrix` now has experimental support for SIMD types from [Vc](https://github.com/VcDevel/Vc) as field types. See core/dune-common!121 ## build-system - Variables passed via `dunecontrol`'s command `--configure-opts=..` are now added to the CMake flags. - Bash-style variables which are passed to `dunecontrol`'s command `configure-opts` are no longer transformed to their equivalent CMake command. Pass `-DCMAKE_C_COMPILER=gcc` instead of `CC=gcc`. - Added support for modules providing additional Python modules or bindings. dune-common-2.8.0/CMakeLists.txt000066400000000000000000000015311411343567400165120ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.13) project(dune-common LANGUAGES C CXX) # make sure our own modules are found list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules) # set the script dir for the macros. set(DUNE_COMMON_SCRIPT_DIR ${PROJECT_SOURCE_DIR}/cmake/scripts) #include the dune macros include(DuneMacros) # start a dune project with information from dune.module dune_project() # add subdirectories to execute CMakeLists.txt there add_subdirectory(bin) add_subdirectory(cmake) add_subdirectory(doc) add_subdirectory(dune) add_subdirectory(lib) add_subdirectory(share) # if Python bindings are enabled, include necessary sub directories. if(DUNE_ENABLE_PYTHONBINDINGS) add_subdirectory(python) dune_python_install_package(PATH "python") endif() # finalize the dune project, e.g. generating config.h etc. finalize_dune_project() dune-common-2.8.0/CONTRIBUTING.md000066400000000000000000000072651411343567400162150ustar00rootroot00000000000000Contributing to the Dune Core Modules ===================================== You've squashed an annoying bug or implemented a nifty new feature in DUNE? And you're willing to share your improvements with the community? This page explains how to get those changes to us and what to take care of. Take a look at the DUNE coding style ------------------------------------ Your work will enjoy much smoother sailing if you take a look at the [Coding Style](https://dune-project.org/dev/codingstyle/) and try to stick to it with your changes. We understand that everyone has their personal preferences and that there is no such thing as the *right* coding style (in the end, it's a matter of taste), but DUNE is a pretty large project, and a consistent way of doing things really helps a lot when trying to find your way around a body of code as big as DUNE. Make sure to install the Whitespace Hook before starting to work, because our repositories enforce certain rules about whitespace and will not accept commits that violate those rules. And a developer will be much more motivated to merge your patch if doing so does not involve fixing a bunch of tab-based indentations that you inadvertently added as part of your changes Use Git to your advantage ------------------------- We know, Git can be a bit daunting at first, but trust us, it's really worth investing half an hour to learn the basics! Even though you don't have any commit rights to the DUNE repositories, Git still allows you to create local commits on your machine, avoiding the usual ugly business of creating backup copies, copying around code in files, commenting and uncommenting variants etc. And when you're done and send the changes to us, we can simply import those commits into our repositories. That saves a lot of time and when your changes can be applied in five minutes using two or three commands, chances are a developer will much more easily find the time to do so. Git is really popular, so there are tons of tutorials all over the web. Here are some pointers: * http://try.github.io/ is a very quick, hands-down introduction to Git that allows you to try out Git directly in your browser. Requires a GitHub account to continue at some point, though. * http://git-scm.com/book is a very well-written and detailed resource for all things Git. Chapter 2 is a great introduction to Git that also explains a little bit how Git works, which really helps to reduce the number of *WTF just happened?* moments. ;-) * http://eagain.net/articles/git-for-computer-scientists/ is a short and sweet explanation of what Git does at a fundamental level - just the thing for scientists! ;-) * http://git-scm.com/doc/ext is a collection of both introductory and more in-depth Git resources. Whatever you do, make sure to set your Git identity so that the commits tell us who authored them! Getting the changes to us ------------------------- You should get your changes to us in the following way: * Get an account for [our GitLab instance](http://gitlab.dune-project.org). * Fork the core module that you want to contribute to, just as you would do on GitHub. * Push your changes to your fork on some branch. * Open a merge request using the branch you pushed your changes to as the source branch and the master of the core module repository as the target branch. GitLab will usually ask you about opening a merge request if you browse it right after pushing to some branch. * Follow the discussion on the merge request to see what improvements should be done to the branch before merging. If you have any questions or complaints about this workflow of contributing to Dune, please rant on the [dune-devel mailing list](mailto:dune-devel@lists.dune-project.org). dune-common-2.8.0/COPYING000077700000000000000000000000001411343567400164042LICENSE.mdustar00rootroot00000000000000dune-common-2.8.0/INSTALL000066400000000000000000000046631411343567400150140ustar00rootroot00000000000000Installation Instructions ========================= For a full explanation of the DUNE installation process please read the installation notes [0]. The following introduction is meant for the impatient. Getting started --------------- Suppose you have downloaded all DUNE modules of interest to your computer and extracted then in one common directory. See [1] for a list of available modules. To compile the modules Dune has to check several components of your system and whether prerequisites within the modules are met. For the ease of users we have designed a custom build system on top of CMake. Run ./dune-common/bin/dunecontrol all to commence those tests and build all modules you have downloaded. Don't worry about messages telling you that libraries are missing: they are only needed for grid-self-checks we need for developing. You can customize the build to your specific needs by using an options file (see below) ./dune-common/bin/dunecontrol --opts=/path_to/file.opts If you did not tell dunecontrol to install with an options file you need to run ./dune-common/bin/dunecontrol make install to install Dune (you may need root-permissions for the install part depending on the prefix set) A more comprehensive introduction to the build system can be found in [0]. Passing options to the build process ------------------------------------ Using the dunecontrol script the following atomic commands can be executed: - configure (runs the CMake configuration tests for each module) - exec (executes a command in each module source directory) - bexec (executes a command in each module build directory) - make (builds each module) - update (updates the Git or Subversion version) The composite command all simply runs configure and make for each module. As it is often not convenient to specify the desired options after the duncontroll call, one can pass the options via a file specified by the --opts= option. Specify the options via the variable CMAKE_FLAGS= An example of an options file is # use a special compiler (g++ version 5.0), # install to a custom directory, default is /usr/local/bin, # disable the external library SuperLU, # and use Ninja-build instead of make as the build-tool CMAKE_FLAGS="-DCMAKE_CXX_COMPILER=g++-5 -DCMAKE_INSTALL_PREFIX='/tmp/HuHu' -DCMAKE_DISABLE_FIND_PACKAGE_SuperLU=true -GNinja" Links ----- 0. https://www.dune-project.org/doc/installation 1. https://dune-project.org/releases/ dune-common-2.8.0/LICENSE.md000066400000000000000000000521001411343567400153540ustar00rootroot00000000000000Copyright holders: ================== 2015--2017 Marco Agnese 2015 Martin Alkämper 2003--2019 Peter Bastian 2004--2020 Markus Blatt 2013 Andreas Buhr 2020--2021 Samuel Burbulla 2011--2020 Ansgar Burchardt 2004--2005 Adrian Burri 2014 Benjamin Bykowski (may appear in the logs as "Convex Function") 2014 Marco Cecchetti 2018 Matthew Collins 2006--2021 Andreas Dedner 2019--2021 Nils-Arne Dreier 2003 Marc Droske 2003--2021 Christian Engwer 2004--2020 Jorrit Fahlke 2016 Thomas Fetzer 2008--2017 Bernd Flemisch 2013--2014 Christoph Gersbacher 2017--2020 Janick Gerstenberger 2015 Stefan Girke 2005--2021 Carsten Gräser 2015--2017 Felix Gruber 2010--2021 Christoph Grüninger 2006 Bernhard Haasdonk 2015--2018 Claus-Justus Heine 2015--2020 René Heß 2017--2019 Stephan Hilb 2017--2021 Lasse Hinrichsen 2012--2013 Olaf Ippisch 2020 Patrick Jaap 2020 Liam Keegan 2013--2021 Dominic Kempf 2009 Leonard Kern 2017--2018 Daniel Kienle 2013 Torbjörn Klatt 2003--2021 Robert Klöfkorn 2017--2021 Timo Koch 2005--2007 Sreejith Pulloor Kuttanikkad 2012--2016 Arne Morten Kvarving 2010--2014 Andreas Lauser 2016--2019 Tobias Leibner 2015 Lars Lubkoll 2012--2017 Tobias Malkmus 2007--2011 Sven Marnach 2010--2017 Rene Milk 2019--2020 Felix Müller 2011--2019 Steffen Müthing 2018 Lisa Julia Nebel 2003--2006 Thimo Neubauer 2011 Rebecca Neumann 2008--2018 Martin Nolte 2014 Andreas Nüßing 2004--2005 Mario Ohlberger 2019--2020 Santiago Ospina De Los Rios 2014 Steffen Persvold 2008--2017 Elias Pipping 2021 Joscha Podlesny 2011 Dan Popovic 2017--2021 Simon Praetorius 2009 Atgeirr Rasmussen 2017--2020 Lukas Renelt 2006--2014 Uli Sack 2003--2020 Oliver Sander 2006 Klaus Schneider 2004 Roland Schulz 2015 Nicolas Schwenck 2016 Linus Seelinger 2009--2014 BÃ¥rd Skaflestad 2019 Henrik Stolzmann 2012 Matthias Wohlmuth 2011--2016 Jonathan Youett This Licence does not cover the header files taken from the [pybind11 project][pybind11] which are included here (`dune/python/pybind11`) together with their own [licence file][pybind11Licence]. The DUNE library and headers are licensed under version 2 of the GNU General Public License (see below), with a special exception for linking and compiling against DUNE, the so-called "runtime exception." The license is intended to be similar to the GNU Lesser General Public License, which by itself isn't suitable for a template library. The exact wording of the exception reads as follows: As a special exception, you may use the DUNE source files as part of a software library or application without restriction. Specifically, if other files instantiate templates or use macros or inline functions from one or more of the DUNE source files, or you compile one or more of the DUNE source files and link them with other files to produce an executable, this does not by itself cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) 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 this service 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 make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. 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. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey 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 2 of the License, or (at your option) any later version. This program is distributed in the hope that 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision 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, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This 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. [pybind11]: https://github.com/pybind/pybind11 [pybind11Licence]: https://github.com/pybind/pybind11/blob/master/LICENSE dune-common-2.8.0/README.md000066400000000000000000000053231411343567400152340ustar00rootroot00000000000000DUNE-library ============ DUNE, the Distributed and Unified Numerics Environment is a modular toolbox for solving partial differential equations with grid-based methods. The main intention is to create slim interfaces allowing an efficient use of legacy and/or new libraries. Using C++ techniques DUNE allows one to use very different implementation of the same concept (i.e. grid, solver, ...) under a common interface with a very low overhead. DUNE was designed with flexibility in mind. It supports easy discretization using methods, like Finite Elements, Finite Volume and also Finite Differences. Through separation of data structures DUNE allows fast Linear Algebra like provided in the ISTL module, or usage of external libraries like blas. This package contains the basic DUNE common classes. Dependencies ------------ dune-common depends on the following software packages - pkg-config - Compiler (C, C++): GNU >=7 or Clang >= 5 Other compilers might work too, they need to support C++17 to the extend the ones above do. The following software is recommended but optional: - MPI (either OpenMPI, lam, or mpich suffice) For a full explanation of the DUNE installation process please read the [installation notes][installation]. The following introduction is meant for the impatient. License ------- The DUNE-library and headers are licensed under version 2 of the GNU General Public License, with the so-called "runtime exception", as follows: > As a special exception, you may use the DUNE source files as part > of a software library or application without restriction. > Specifically, if other files instantiate templates or use macros or > inline functions from one or more of the DUNE source files, or you > compile one or more of the DUNE source files and link them with > other files to produce an executable, this does not by itself cause > Athe resulting executable to be covered by the GNU General Public > License. This exception does not however invalidate any other > reasons why the executable file might be covered by the GNU General > Public License. This licence clones the one of the libstc++ library. For further implications of this library please see their [licence page][licence] See the file COPYING for full copying permissions. Installation ------------ Short installation instructions can be found in file INSTALL. For the full instructions please see [here][installation]. Links ----- 0. https://www.dune-project.org/doc/installation 1. https://dune-project.org/releases/ 2. https://dune-project.org/buildsystem/ 3. http://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.license [installation]: https://www.dune-project.org/doc/installation [licence]: http://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.licensedune-common-2.8.0/TODO000066400000000000000000000001121411343567400144340ustar00rootroot00000000000000Please see the Dune bugtracker at www.dune-project.org for things to do. dune-common-2.8.0/bin/000077500000000000000000000000001411343567400145225ustar00rootroot00000000000000dune-common-2.8.0/bin/CMakeLists.txt000066400000000000000000000002621411343567400172620ustar00rootroot00000000000000install(PROGRAMS dune-ctest duneproject dunecontrol dunepackaging.py dune-git-whitespace-hook rmgenerated.py setup-dunepy.py DESTINATION ${CMAKE_INSTALL_BINDIR}) dune-common-2.8.0/bin/dune-ctest000077500000000000000000000205721411343567400165310ustar00rootroot00000000000000#! /usr/bin/env python3 # # Wrapper around CTest for DUNE # # CTest returns with an error status not only when tests failed, but also # when tests were only skipped. This wrapper checks the log and returns # successfully if no tests failed; skipped tests do not result in an error. # This behaviour is needed in a continuous integration environment, when # building binary packages or in other cases where the testsuite should be # run automatically. # # Moreover, this script also converts the XML test report generated by CTest # into a JUnit report file that can be consumed by a lot of reporting # software. # # Author: Ansgar Burchardt # Author: Steffen Müthing (for the JUnit part) import errno import glob import os.path import shutil import subprocess import sys import xml.etree.ElementTree as et from pathlib import Path import os import re class CTestParser: def findCTestOutput(self): files = glob.glob("Testing/*/Test.xml") if len(files) != 1: fn = files.join(", ") raise Exception("Found multiple CTest output files: {}".format(files.join(", "))) return files[0] def printTest(self,test,output=None): status = test.get("Status") name = test.find("Name").text fullName = test.find("FullName").text if output is not None: output = test.find("Results").find("Measurement").find("Value").text print("======================================================================") print("Name: {}".format(name)) print("FullName: {}".format(fullName)) print("Status: {}".format(status.upper())) if output: print("Output:") for line in output.splitlines(): print(" ", line) print() def __init__(self,junitpath=None): self.inputpath = self.findCTestOutput() if junitpath is None: if "CI_PROJECT_DIR" in os.environ: buildroot = Path(os.environ["CI_PROJECT_DIR"]) # create a slug from the project name name = os.environ["CI_PROJECT_NAME"].lower() name = re.sub(r"[^-a-z0-9]","-",name); junitbasename = "{}-".format(name) else: buildroot = Path.cwd() junitbasename = "" junitdir = buildroot / "junit" junitdir.mkdir(parents=True,exist_ok=True) self.junitpath = junitdir / "{}cmake.xml".format(junitbasename) else: self.junitpath = Path(junitpath) junitdir = junitpath.resolve().parent junitdir.mkdir(parents=True,exist_ok=True) self.tests = 0 self.passed = 0 self.failures = 0 self.skipped = 0 self.errors = 0 self.skipped = 0 self.time = 0.0 def createJUnitSkeleton(self): self.testsuites = et.Element("testsuites") self.testsuite = et.SubElement(self.testsuites,"testsuite") self.properties = et.SubElement(self.testsuite,"properties") def fillJUnitStatistics(self): self.testsuite.set("name","cmake") self.testsuite.set("tests",str(self.tests)) self.testsuite.set("disabled","0") self.testsuite.set("errors",str(self.errors)) self.testsuite.set("failures",str(self.failures)) self.testsuite.set("skipped",str(self.skipped)) self.testsuite.set("time",str(self.time)) def processTest(self,test): testcase = et.SubElement(self.testsuite,"testcase") testcase.set("name",test.find("Name").text) testcase.set("assertions","1") testcase.set("classname","cmake") time = test.find("./Results/NamedMeasurement[@name='Execution Time']/Value") if time is not None: self.time += float(time.text) testcase.set("time",time.text) self.tests += 1 outcome = test.get("Status") if outcome == "passed": testcase.set("status","passed") self.passed += 1 elif outcome == "failed": self.failures += 1 testcase.set("status","failure") failure = et.SubElement(testcase,"failure") failure.set("message","program execution failed") failure.text = test.find("./Results/Measurement/Value").text self.printTest(test) elif outcome == "notrun": # This does not exit on older CMake versions, so work around that try: status = test.find("./Results/NamedMeasurement[@name='Completion Status']/Value").text if status == "SKIP_RETURN_CODE=77": self.skipped += 1 et.SubElement(testcase,"skipped") elif status == "Required Files Missing": self.errors += 1 error = et.SubElement(testcase,"error") error.set("message","compilation failed") error.set("type","compilation error") self.printTest(test,output="Compilation error") else: error = et.SubElement(testcase,"error") error.set("message","unknown error during test execution") error.set("type","unknown") error.text = test.find("./Results/Measurement/Value").text self.errors += 1 self.printTest(test) except AttributeError: output_tag = test.find("./Results/Measurement/Value") if output_tag is not None: msg = output_tag.text if "skipped" in msg: self.skipped += 1 et.SubElement(testcase,"skipped") elif "Unable to find required file" in msg: self.errors += 1 error = et.SubElement(testcase,"error") error.set("message","compilation failed") error.set("type","compilation error") self.printTest(test,output="Compilation error") else: error = et.SubElement(testcase,"error") error.set("message","unknown error during test execution") error.set("type","unknown") error.text = msg self.errors += 1 self.printTest(test) else: error = et.SubElement(testcase,"error") error.set("message","unknown error during test execution") error.set("type","unknown") error.text = "no message" self.errors += 1 self.printTest(test) output_tag = test.find("./Results/Measurement/Value") if output_tag is not None: out = et.SubElement(testcase,"system-out") out.text = output_tag.text def process(self): with open(self.inputpath, "r", encoding="utf-8") as fh: tree = et.parse(fh) root = tree.getroot() self.createJUnitSkeleton() for test in root.findall(".//Testing/Test"): self.processTest(test) self.fillJUnitStatistics() with self.junitpath.open("wb") as fh: fh.write(et.tostring(self.testsuites,encoding="utf-8")) print("JUnit report for CTest results written to {}".format(self.junitpath)) return self.errors + self.failures def runCTest(argv=[]): cmd = ["ctest", "--output-on-failure", "--dashboard", "ExperimentalTest", "--no-compress-output", ] cmd.extend(argv) subprocess.call(cmd) def checkDirectory(): if not os.path.exists("CMakeCache.txt"): raise Exception("ERROR: dune-ctest must be run in a cmake build directory") def removeCTestOutput(): try: shutil.rmtree("Testing") except OSError as e: if e.errno != errno.ENOENT: raise def main(): try: checkDirectory() removeCTestOutput() runCTest(argv=sys.argv[1:]) parser = CTestParser() errors = parser.process() status = 0 if errors == 0 else 1 sys.exit(status) except Exception as e: print("Internal error: {}".format(e)) sys.exit(127) if __name__ == "__main__": main() dune-common-2.8.0/bin/dune-git-whitespace-hook000077500000000000000000000125771411343567400212700ustar00rootroot00000000000000#!/bin/sh # dune-git-whitespace-hook # DO NOT TOUCH THE PRECEDING LINE # It is used by dunecontrol to enable automatic updates of the whitespace hook # DUNE pre-commit hook to enforce whitespace policy # This hook prevents adding lines with trailing whitespace and or tab characters # in line indentation for certain files (see the TRAILING_WHITESPACE_DEFAULT and # TAB_IN_INDENT_DEFAULT variables below for the default sets of files that will # be checked). # You can tell the hook which files should be inspected by setting the Git # configuration variables "hooks.whitespace.trailing" and "hooks.whitespace.tabinindent". # Those variables should contain valid Perl regular expressions. The names of modified # files will be matched against those regexes. # git-diff-index needs a valid commit to compare to if git rev-parse --verify HEAD >/dev/null 2>&1 then against=HEAD else # Initial commit: diff against an empty tree object against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 fi # By default, we disallow trailing whitespace for the following files, but the check for C/C++ and CMake sources # happens in the tab-in-indent check to avoid confusing users with duplicate error messages TRAILING_WHITESPACE_DEFAULT='^(dune\.module|README|README\.SVN|COPYING|INSTALL|TODO)$|^[^/]*(\.md|\.pc\.in)$|^doc/.*\.md$' # By default, we disallow tabs in indents and trailing whitespace in C/C++ and CMake source files TAB_IN_INDENT_DEFAULT='(^|/)CMakeLists\.txt$|(\.cpp|\.hpp|\.cc|\.hh|\.c|\.h|\.cmake|\.sh|\.py)$' # Get user preferences TRAILING_WHITESPACE_FILES=$(git config hooks.whitespace.trailing) # Set default regex for disallowing trailing whitespace if the user did not set anything. # We need to check the return value of git-config to distinguish the case # when the user set an empty value if [ $? -ne 0 ]; then TRAILING_WHITESPACE_FILES="$TRAILING_WHITESPACE_DEFAULT" fi TAB_IN_INDENT_FILES=$(git config hooks.whitespace.tabinindent) # Set default regex for disallowing tabs if the user did not set anything. # We need to check the return value of git-config to distinguish the case # when the user set an empty value if [ $? -ne 0 ]; then TAB_IN_INDENT_FILES="$TAB_IN_INDENT_DEFAULT" fi # Unfortunately, we have to mess directly with the repository config file, # as git won't honor a custom config file specified by GIT_CONFIG # backup repository-local user setting for core.whitespace USER_WHITESPACE=$(git config --local --get core.whitespace) if [ $? -ne 0 ]; then USER_HAS_CUSTOM_WHITESPACE=0 else USER_HAS_CUSTOM_WHITESPACE=1 fi # Figure out how to call xargs to make sure it won't invoke its argument with # an empty argument list. BSD xargs will not do that by default, while GNU xargs # needs -r to do the same. So we start by checking whether xargs does the right # thing without options. Now there could be other obscure versions of xargs out # there (on clusters etc.) that behave in yet another way, so we try with -r as # well. If that fails, we throw a big error message at the user. # In the following line, xargs should not call false, so the return value should be 0. echo "" | xargs false if [ $? -ne 0 ]; then # Let's try with -r echo "" | xargs -r false if [ $? -ne 0 ]; then # Houston, we have a problem if [ -z "$DUNE_WHITESPACE_IGNORE_XARGS" ]; then echo "You seem to be lacking a version of xargs that is compatible to either BSD or GNU!" 1>&2 echo "Please file a bug report at http://dune-project.org about this issue with your exact operating system type and version!" 1>&2 echo "You can still use this hook by setting the environment variable DUNE_WHITESPACE_IGNORE_XARGS to 1, but please be aware" 1>&2 echo "that the hook might create false positives." 1>&2 echo "==============================================================" 1>&2 echo "Aborting the commit..." 1>&2 exit 99 else SILENTXARGS=xargs fi else SILENTXARGS="xargs -r" fi else SILENTXARGS=xargs fi fail=0 done=0 do_cleanup() { if [ $done -ne 1 ]; then echo "Error while executing whitespace checking pre-commit hook!" 1>&2 echo "There might still be whitespace errors in your commit!" 1>&2 fi if [ $USER_HAS_CUSTOM_WHITESPACE -eq 1 ]; then git config --replace-all core.whitespace "$USER_WHITESPACE" else git config --unset core.whitespace fi # be nice and let the commit go through if something went wrong along the # way and we did not record a failure exit $fail } trap do_cleanup EXIT # set custom value git config --replace-all core.whitespace trailing-space if [ -z "$TRAILING_WHITESPACE_FILES" ]; then git diff-index --check --cached $against -- result=$? else export TRAILING_WHITESPACE_FILES git diff-index --cached --name-only $against \ | perl -ne 'print if /$ENV{TRAILING_WHITESPACE_FILES}/' \ | $SILENTXARGS git diff-index --check --cached $against -- result=$? fi if [ $result -ne 0 ]; then fail=1 fi git config --replace-all core.whitespace trailing-space,tab-in-indent if [ -z "$TAB_IN_INDENT_FILES" ]; then git diff-index --check --cached $against -- result=$? else export TAB_IN_INDENT_FILES git diff-index --cached --name-only $against \ | perl -ne 'print if /$ENV{TAB_IN_INDENT_FILES}/' \ | $SILENTXARGS git diff-index --check --cached $against -- result=$? fi if [ $result -ne 0 ]; then fail=1 fi done=1 # trap will call the cleanup code dune-common-2.8.0/bin/dunecontrol000077500000000000000000000770271411343567400170210ustar00rootroot00000000000000#!/usr/bin/env bash set -e ############################################### ### ### check for environment variables ### if test -z "$GREP"; then GREP=grep fi if test -z "$SED"; then SED=sed fi if test -z "$MAKE"; then MAKE=make fi system_default_cmake="no" if test -z "$CMAKE"; then CMAKE=cmake system_default_cmake="yes" fi space=" " tab=" " BLANK="$space$tab" nl=$'\n' ############################################### ### ### read lib ### # quote parameter for passing it through the shell # the result is meant to be used inside "...", i.e. the outer quotes are _not_ # included # # you should have the identity # eval "[ x\"\$param\" = x\"$(doublequote "$param")\" ]" doublequote() { local val="$1" local result= local token= local special= while [ -n "$val" ]; do token=${val%%[\"\$\`\\]*} val=${val#"$token"} special=${val:0:1} val=${val:1} result=$result$token${special:+\\$special} done # if the value ends in \n, protect it by appending two double-quotes so it # wont get stripped by the surrounding $(...) case $result in *"$nl") result=$result'""';; esac printf "%s" "$result" } canonicalname(){ if test $# -ne 1; then echo Usage: canonicalname path >&2 return 1 fi file="`eval echo $1`" # expand ~ if test ! -e "$file"; then echo $file: file not found >&2 return 1 fi # if this is a symlink, then follow the symlink if test -L "$file"; then fdir="`dirname \"$file\"`" flink="`readlink \"$file\"`" if test -e "$flink"; then # these are absolute links, or links in the CWD canonicalname "$flink" else canonicalname "$fdir/$flink" fi else # if this is a file, then remember the filename and # canonicalize the directory name if test -f "$file"; then fdir="`dirname \"$file\"`" fname="`basename \"$file\"`" fdir="`canonicalname \"$fdir\"`" echo "$fdir/$fname" fi # if this is a directory, then create an absolute # directory name and we are done if test -d "$file"; then (cd "$file"; pwd) fi fi } canonicalpath(){ if test $# -ne 1; then echo Usage: canonicalpath path >&2 return 1 fi dirname "`canonicalname "$1"`" } checkdebug () { while test $# -gt 0; do if test x$1 = x--debug; then echo yes return fi shift done echo no } DEBUG=`checkdebug $@` if test "x$DEBUG" = "xyes"; then set -x set -v fi onbuildfailure() { echo "Terminating $(basename "$0") due to previous errors!" >&2 exit 1 } # # for each module load the $CONTROL script part and run $command # # parameters: # $1 list of modules # $2-$* commands + parameters to execute # build_module() { local module=$1 shift while test $# -gt 0; do # get command command=$1 shift # only load other parameters load_opts NONE # get command options CMD_FLAGS= while test $# -gt 0 && test "$1" != ":"; do COMMAND=$(echo $command | tr '[:lower:]' '[:upper:]') # setup parameter list CMD_FLAGS="$CMD_FLAGS \"$(doublequote "$1")\"" shift done if test -z "$CMD_FLAGS"; then load_opts $command else # disable usage of opts file if test "x$DUNE_OPTS_FILE" != "x"; then echo "WARNING: commandline parameters will overwrite setting in opts file \"$DUNE_OPTS_FILE\"" fi fi # skip command delimiter if test "$1" = ":"; then shift; fi # actually run the commands (we already know that these are valid commands) local runcommand=run_$command # build the modules local path="$(eval "echo \$PATH_${module}")" eval echo "--- calling $command for \$NAME_${module} ---" trap onbuildfailure EXIT if ! ( set -e cd "$path" export module export ABS_BUILDDIR=$(abs_builddir $module $BUILDDIR) eval_control $runcommand "$path/$CONTROL" ); then eval echo "--- Failed to build \$NAME_${module} ---"; exit 1; fi trap onfailure EXIT eval echo "--- \$NAME_${module} done ---" done } # # load command options from an opts file # the name of the opts file is stored in the global variable $DUNE_OPTS_FILE # # parameters: # $1 command # load_opts() { local command=$1 local COMMAND=$(echo $command | tr '[:lower:]' '[:upper:]') CMD_FLAGS=$(eval echo \$${COMMAND}_FLAGS) local CMD_FLAGS_FROM_FILE="" if test "$command" = "NONE"; then BUILDDIR=$DUNE_BUILDDIR if test "x$DUNE_OPTS_FILE" != "x"; then if test -z "$BUILDDIR"; then # no builddir set yet, use build dir from opts file if set # Note: if --use-buiddir is used BUILDDIR will be set already OPTS_FILE_BUILDDIR="$(eval BUILDDIR=""; . $DUNE_OPTS_FILE; eval echo \$BUILDDIR)" if test -n "$OPTS_FILE_BUILDDIR"; then BUILDDIR="$OPTS_FILE_BUILDDIR" fi fi if test "$system_default_cmake" = "yes"; then # We use cmake for building, but CMAKE is not yet set. # Check the opts file for it OPTS_FILE_CMAKE="$(eval CMAKE=""; . $DUNE_OPTS_FILE; eval echo \$CMAKE)" if test -n "$OPTS_FILE_CMAKE"; then CMAKE="$OPTS_FILE_CMAKE" fi fi fi fi if test "x$DUNE_OPTS_FILE" != "x"; then if test "$command" = "configure"; then CMAKE_FLAGS="$(. $DUNE_OPTS_FILE; eval echo \$CMAKE_FLAGS)" CMAKE_MODULE_PATH="$(. $DUNE_OPTS_FILE; eval echo \$CMAKE_MODULE_PATH)" fi CMD_FLAGS_FROM_FILE="$(eval ${COMMAND}_FLAGS=""; . $DUNE_OPTS_FILE; eval echo \$${COMMAND}_FLAGS)" fi if test -n "$CMD_FLAGS_FROM_FILE"; then echo "----- using default flags \$${COMMAND}_FLAGS from $DUNE_OPTS_FILE -----" CMD_FLAGS=$CMD_FLAGS_FROM_FILE elif test -n "$CMD_FLAGS"; then echo "----- using default flags \$${COMMAND}_FLAGS from environment -----" fi # if no build directory is set, use default "build-cmake" if test -z "$BUILDDIR"; then export BUILDDIR=build-cmake fi } abs_builddir() { local m=$1 local builddir=$2 local name="$(eval echo \$NAME_$m)" local path="$(eval echo \$PATH_$m)" case $BUILDDIR in /*) echo $builddir/$name ;; *) echo $path/$builddir ;; esac } # Uses the current compiler to extract information about the # multiarch triplets and sets the export variable MULTIARCH_LIBDIR # according to it. # If no compiler is specified then cc or gcc is used. extract_multiarch(){ set +e #error in the multiarch detection should not be fatal. local my_cxx_compiler if test "x$MULTIARCH_LIBDIR" != "x"; then return fi load_opts "cmake" if test "x$my_cxx_compiler" == "x"; then load_opts "configure" fi my_cxx_compiler=`echo $CMD_FLAGS | $GREP CXX | $SED "s/.*CXX=[\"']\{0,1\}\([^$BLANK'\"]*\)[\"']\{0,1\}.*/\1/"` if test "x$my_cxx_compiler" == "x"; then $(which cc &>/dev/null) if test $? -eq "0"; then my_cxx_compiler=cc else my_cxx_compiler=gcc fi fi multiarch=$($my_cxx_compiler --print-multiarch 2>/dev/null) if test $? -gt 0; then for i in "target=" "Target:"; do multiarch=$($my_cxx_compiler -v 2>&1| $GREP "$i" | $SED "s/.*$i[$BLANK]*\([a-z0-9_-]*\)/\1/" | $SED "s/-[a-z]*-linux-gnu/-linux-gnu/") if test -n "$multiarch"; then break; fi done fi set -e # set to old value. export MULTIARCH_LIBDIR="lib/$multiarch" } export PREFIX_DIR="`canonicalpath "$0"`/.." # Read the modules find part . "$PREFIX_DIR/lib/dunemodules.lib" ############################################### ############################################### ### ### Commands ### # check all parameter check_commands() { while test $# -gt 0; do # get command command=$1 shift # skip command options while test $# -gt 0 && test "$1" != ":"; do shift done # skip command delimiter if test "$1" = ":"; then shift; fi # test the commands if ! is_command $command; then usage echo "ERROR: unknown command \"$command\"" >&2 exit 1 fi done } # check whether the parameter is valid command or not is_command() { eval ' case "$1" in '`echo $COMMANDS | $SED -e 's/ / | /g'`') return 0 ;; *) return 1 ;; esac' } # list of all dunecontrol commands COMMANDS="printdeps vcsetup update cmake configure make all exec bexec status svn git" # list of dunecontrol commands for which the version check is skipped by default COMMANDSTOSKIPVERSIONCHECK="update status svn git exec bexec" # help string for the commands printdeps_HELP="print recursive dependencies of a module" vcsetup_HELP="setup version control repository (Git etc.) or working copy (SVN)" update_HELP="update all modules from their repositories" cmake_HELP="run cmake for each module" configure_HELP="${cmake_HELP}" make_HELP="build each module" all_HELP="\trun 'vcsetup', 'configure' and 'make' command for each module" exec_HELP="execute an arbitrary command in each module source directory" bexec_HELP="execute an arbitrary command in each module build directory" status_HELP="show vc status for all modules" svn_HELP="\trun svn command for each svn managed module" git_HELP="\trun git command for each git managed module" # # setup command proxies # call will be forwarded to run_default_$command # for command in $COMMANDS; do eval "run_$command () { run_default_$command; }" done # # default implementations for commands... # these can be overwritten in the $CONTROL files # run_default_exec () { bash -c "eval $CMD_FLAGS"; } run_default_bexec () { if test -d "$ABS_BUILDDIR"; then bash -c "cd \"$ABS_BUILDDIR\" && eval $CMD_FLAGS"; else eval echo "Build directory \\\"$ABS_BUILDDIR\\\" not found, skipping bexec for \$NAME_${module}" fi } run_default_status () { local verbose=0 local update="" local is_git="" local is_svn="" name="$(eval echo \$NAME_$module)" if test -e .git; then is_git=1; fi if test -d .svn; then is_svn=1; fi if test ! "$is_svn" -a ! "$is_git" ; then echo "module $name not under known version control" return fi for i in $CMD_FLAGS; do if eval test "x$i" = "x-v"; then verbose=1; fi if eval test "x$i" = "x-vv"; then verbose=2; fi if eval test "x$i" = "x-u"; then update="-u"; fi done # is out output connected to a tty? if test -t 1; then blue="\e[1m\e[34m" green="\e[1m\e[32m" red="\e[1m\e[31m" reset="\e[0m\e[0m" fi if test $verbose -eq 1; then test "$is_svn" && svn status $update | $GREP -E "^M|^A|^D|^C|^U" test "$is_git" && git status -uno elif test $verbose -eq 2; then test "$is_svn" && svn status $update test "$is_git" && git status fi if test "$is_svn" ; then changed=$(svn status | $GREP -E "^M|^A|^D" | wc -l) collisions=$(svn status | $GREP -E "^C"| wc -l) pending=$(svn status $update | $GREP -E "^...... \* " | wc -l) fi if test "$is_git" ; then changed=$(git status --porcelain | $GREP -E "^ *M|^ *A|^ *D|^ *R|^ *C" | wc -l) collisions=$(git status --porcelain | $GREP -E "^ *U"| wc -l) pending=$(git status | $GREP -E "^\# Your branch is ahead |^\# Your branch is behind " | wc -l) fi color=$green text="no changes" if [ $changed -eq 0 ]; then true elif [ $changed -eq 1 ]; then color=$blue; text="1 change" else color=$blue; text="$changed changes" fi if [ $pending -eq 0 ]; then true elif [ $pending -eq 1 ]; then color=$blue; text="$text, 1 update pending" else color=$blue; text="$text, $pending updates pending" fi if [ $collisions -eq 0 ]; then true elif [ $collisions -eq 1 ]; then color=$red text="$text, 1 collision" else color=$red text="$text, $count collisions" fi echo -e "$color[$text]$reset $name" } run_default_vcsetup() { # load user options if [ -n "$CMD_FLAGS" ]; then eval "$CMD_FLAGS" fi # Check for both a file and a directory to cope with Git submodules if [ -e .git ] ; then # Read Whitespace-Hook setting from dune.module file local SETUPGITHOOK="$($GREP -i "^[$BLANK]*Whitespace-Hook:" dune.module | cut -d ':' -f2 | eval $PARSER_TRIM | tr '[:upper:]' '[:lower:]')" if [ "x$SETUPGITHOOK" = "xyes" ]; then # we have to install the Git whitespace hook # There are several options as to what the current worktree might be backed by right now: # - a plain old repository -> copy to .git/hooks # - a submodule repository -> .git refers to the submodule repository inside the root $GIT_DIR # - a git repo worktree -> .git refers to the worktree data inside the original $GIT_DIR and we need to find # the "canonical" $GIT_DIR root # - a submodule in a worktree -> That just gets checked out again into the worktree backing store, so no worktree # dereferencing here # We try this first by trying git's built-in infrastructure, but if the user's git is too old, we fall back to # manual parsing GITHOOKPATH="$(git rev-parse --git-common-dir)" if [ $? -ne 0 -o "${GITHOOKPATH}" = "--git-common-dir" ] ; then # no worktree support from here on out GITHOOKPATH="$(git rev-parse --git-dir)" if [ $? -ne 0 -o "${GITHOOKPATH}" = "--git-dir" ] ; then # do the parsing manually if [ -f .git ] ; then # submodule -> .git contains a pointer to the repository GITHOOKPATH="$($SED 's/gitdir: //' < .git)" else # standard case, .git is the repository GITHOOKPATH=.git fi fi fi GITHOOKPATH="${GITHOOKPATH}/hooks/pre-commit" if [ -n "$DISABLEWHITESPACEHOOK" ] ; then # the user doesn't want the Git whitespace hook - deinstall it if necessary and warn the user echo "WARNING: The current module wants to install the DUNE whitespace hook, but you have disabled the hook in your options!" echo "WARNING: You will have to make sure that your commits don't introduce any trailing whitespace or indentation with tabs!" echo "WARNING: Otherwise, your commits might be rejected when trying to push them to an official repository!" if [ -e "$GITHOOKPATH" ]; then # there is a pre-commit hook, check whether it is our whitespace hook local HOOKTAG="$(eval head -n 2 \"$GITHOOKPATH\" | tail -n 1)" if [ "x$HOOKTAG" = "x# dune-git-whitespace-hook" ]; then echo "--> Removing DUNE whitespace hook as requested by the user" rm "$GITHOOKPATH" fi fi else # standard handling of Git whitespace hook for f in dune-git-whitespace-hook git-whitespace-hook; do f="${PREFIX_DIR}/bin/${f}" if [ -e "${f}" ]; then git_whitespace_hook="${f}" break fi done if [ -z "${git_whitespace_hook:-}" ]; then echo "Did not find git-whitespace-hook." >&2 exit 1 fi if [ ! -e "$GITHOOKPATH" ]; then # there is no hook yet, we can safely install ours echo "--> Installing Git pre-commit hook to enforce whitespace policy" cp -p "${git_whitespace_hook}" "$GITHOOKPATH" else # there is already a hook, check whether it is our whitespace hook local HOOKTAG="$(eval head -n 2 \"$GITHOOKPATH\" | tail -n 1)" if [ "x$HOOKTAG" = "x# dune-git-whitespace-hook" ]; then if [ "${git_whitespace_hook}" -nt "$GITHOOKPATH" ]; then echo "--> Updating Git pre-commit hook with newer version" cp -p "${git_whitespace_hook}" "$GITHOOKPATH" fi else echo "WARNING: Existing pre-commit hook found!" echo "WARNING: Skipping installation of DUNE whitespace hook!" echo "WARNING: If you want to contribute patches to DUNE, you should make sure to call the whitespace hook" echo "WARNING: (dune-common/bin/git-whitespace-hook) from you custom pre-commit hook, otherwise your commits" echo "WARNING: might contain trailing whitespace and will not apply cleanly to the official repositories!" fi fi fi fi # Apply git configuration settings if [ -f .vcsetup/config ]; then echo -n "--> Setting Git configuration entries... " cat .vcsetup/config | while read; do # Filter out comments local COMMENT="$(echo $REPLY | $GREP '^#')" if [ ! "x$COMMENT" = "x$REPLY" ]; then # parse line into an array first to catch obvious syntax errors # like 'option value; rm -rf /' eval local GIT_ARGS=($REPLY) git config "${GIT_ARGS[@]}" fi done echo "done" fi # Apply user supplied configuration settings if [ -n "$GIT_CONFIG_FILE" ]; then if [ -f "$GIT_CONFIG_FILE" ]; then echo -n "--> Setting custom Git configuration entries from '$GIT_CONFIG_FILE'... " cat "$GIT_CONFIG_FILE" | while read; do # Filter out comments local COMMENT="$(echo $REPLY | $GREP '^#')" if [ ! "x$COMMENT" = "x$REPLY" ]; then # parse line into an array first to catch obvious syntax errors # like 'option value; rm -rf /' eval local GIT_ARGS=($REPLY) git config "${GIT_ARGS[@]}" fi done echo "done" else echo "WARNING: custom Git config file '$GIT_CONFIG_FILE' not found!" fi fi fi # Run custom setup scripts if [ -e .git -o -d .svn ]; then if [ -d .vcsetup/run.d ]; then for SCRIPT in .vcsetup/run.d/* ; do if [ -x "$SCRIPT" ]; then echo "--> Running $SCRIPT" "$SCRIPT" fi done fi fi } run_default_update () { if test -d .svn; then svn update elif test -e .git; then if test -d .git && test -d ".git/svn" && test -n "`git svn find-rev HEAD`"; then # If the current HEAD points to a SVN commit, update via git-svn git svn rebase else # Update all remotes (if any) git remote update # merge all changes fast-forward style if possible if ! git merge --ff-only FETCH_HEAD 2> /dev/null; then eval echo "\$NAME_${module} seems to be using git, and could not be" echo "updated automatically. Please update it manually." echo "(Usually, this is done via 'git svn rebase' for modules using" echo "subversion or 'git merge' for modules which use git natively." echo "Conflicts can be resolved using 'git mergetool'.)" fi fi else eval echo "WARNING: \$NAME_${module} is not under a known version control system." echo " We support svn and git." fi } run_default_cmake () { extract_multiarch # tell CMake about the build directory root when we are using an absolute build directory if [[ ${BUILDDIR} = /* ]] ; then CMAKE_PARAMS="$CMAKE_PARAMS -DDUNE_BUILD_DIRECTORY_ROOT_PATH='${BUILDDIR}'" fi # add arguments given as configure-opts to CMAKE_params CMAKE_PARAMS="$CMAKE_PARAMS $CMD_FLAGS" # get dependencies & suggestions sort_modules $module for m in $MODULES; do path="$(eval "echo \$PATH_$m")" # add other module's build dir to path if [ $module != $m ] ; then name=$(eval "echo \$NAME_$m") local m_ABS_BUILDDIR=$(abs_builddir $m $BUILDDIR) if test -d "$m_ABS_BUILDDIR"; then CMAKE_PARAMS="$CMAKE_PARAMS \"-D""$name""_DIR=$m_ABS_BUILDDIR\"" else TMP_PARAMS="\"-D""$name""_DIR=$path\"" for i in $MULTIARCH_LIBDIR lib lib64 lib32; do if test -d "$path/$i/cmake/$name"; then TMP_PARAMS="\"-D""$name""_DIR=$path/$i/cmake/$name\"" break; fi done CMAKE_PARAMS="$CMAKE_PARAMS $TMP_PARAMS" fi fi done # create build directory if requested test -d "$ABS_BUILDDIR" || mkdir -p "$ABS_BUILDDIR" SRCDIR="$PWD" cd "$ABS_BUILDDIR" # Prevent using an empty module path if test -n "$CMAKE_MODULE_PATH"; then _MODULE_PATH="-DCMAKE_MODULE_PATH=\"$CMAKE_MODULE_PATH\"" fi echo "$CMAKE $_MODULE_PATH $CMAKE_PARAMS $CMAKE_FLAGS \"$SRCDIR\"" eval $CMAKE "$_MODULE_PATH $CMAKE_PARAMS $CMAKE_FLAGS \"$SRCDIR\"" || exit 1 } run_default_configure () { # configure just forwards to cmake run_default_cmake } run_default_make () { test ! -d "$ABS_BUILDDIR" || cd "$ABS_BUILDDIR" PARAMS="$CMD_FLAGS" echo "build directory: $BUILDDIR" # prepend '--' to separate cmake and make parameters if ! $(echo "$PARAMS" | grep -q -- '--'); then PARAMS="-- $PARAMS" fi echo $CMAKE --build . "$PARAMS" eval $CMAKE --build . "$PARAMS" } run_default_all () { for cmd in vcsetup cmake make; do eval echo "--- calling $cmd for \$NAME_${module} ---" load_opts $cmd run_$cmd done } run_default_svn () { if test -d .svn; then PARAMS="$CMD_FLAGS" eval svn "$PARAMS" fi } run_default_git () { if test -e .git; then PARAMS="$CMD_FLAGS" eval git "$PARAMS" fi } ############################################### ### ### main ### onfailure() { echo "Execution of $(basename "$0") terminated due to errors!" >&2 exit 1 } usage () { ( echo "Usage: $(basename "$0") [OPTIONS] COMMANDS [COMMAND-OPTIONS]" echo "" echo " Execute COMMANDS for all Dune modules found. All entries in the" echo " DUNE_CONTROL_PATH variable are scanned recursively for Dune modules." echo " If DUNE_CONTROL_PATH is empty, the current directory is scanned." echo " Dependencies are controlled by the $CONTROL files." echo "" echo "OPTIONS:" echo " -h, --help show this help" echo " --debug enable debug output of this script" echo " --module=mod apply the actions on module mod" echo " and all modules it depends on" echo " --only=mod only apply the actions on module mod" echo " and not the modules it depends on" echo " --current only apply the actions on the current module," echo " i.e. the one whose source tree we are standing in," echo " and not the modules it depends on" echo " --current-dep apply the actions on the current module," echo " and all modules it depends on" echo " --resume resume a previous run (only consider the modules" echo " not built successfully on the previous run)" echo " --skipfirst skip the first module (use with --resume)" echo " --skipversioncheck do not perform version checks when looking for other Dune modules" echo " --opts=FILE load default options from FILE" echo " --builddir=NAME make out-of-source builds in a subdir NAME." echo " This directory is created inside each module." echo " If NAME is an absolute path, the build directory " echo " is set to NAME/module-name for each module." echo " --[COMMAND]-opts=opts set options for COMMAND" echo " (this is mainly useful for the 'all' COMMAND)" echo "COMMANDS:" echo " Colon-separated list of commands. Available commands are:" printf " \`help'\tguess what :-)\n" printf " \`print'\tprint the list of modules sorted after their dependencies\n" printf " \`info'\tsame as \`print\', but including whether it is a dependency or suggestion\n" for i in $COMMANDS; do printf " \`$i'\t$(eval echo \$${i}_HELP)\n" done printf " \`export'\trun eval \`dunecontrol export\` to save the list of\n" printf " \t\tdune.module files to the DUNE_CONTROL_PATH variable\n" echo ) >&2 } # create the module list create_module_list() { # try to get the resume file name from the options if test -z "$RESUME_FILE" && test -n "$DUNE_OPTS_FILE"; then export RESUME_FILE="$(eval . $DUNE_OPTS_FILE; eval echo \$RESUME_FILE)" fi if test "$RESUME_FLAG" = "yes" ; then if ! test -s "$RESUME_FILE" ; then echo "Error: No previous run to resume. Please make sure that the RESUME_FILE" echo " is the name of a writeable file (currently it is '$RESUME_FILE')" exit 1 fi export MODULES= RESUME="`cat "$RESUME_FILE"`" for a in $RESUME ; do export NAME_`fix_variable_name $a`="$a" fix_and_assign MODULE "$a" export SEARCH_MODULES="$SEARCH_MODULES $MODULE" export ONLY="$ONLY $MODULE" done fi find_modules_in_path if test "x$ONLY" != x; then export MODULES="$ONLY" elif test "x$SEARCH_MODULES" != "x"; then sort_modules $SEARCH_MODULES else sort_modules $MODULES fi if test "x$REVERSE_FLAG" = "xyes"; then export MODULES="$REVERSEMODULES" fi if test "x$SKIPFIRST" = "xyes" ; then export MODULES=`echo $MODULES " " | cut '--delimiter= ' --fields=2-` fi # warn about superseeded modules: if test -n "$superseded_modules"; then # sort moules list and make it unique. superseded_modules=$(echo $superseded_modules | tr ' ' '\n'| sort -u) echo >&2 echo "The following local modules do supersede the corresponding installed ones:" >&2 echo "$superseded_modules" >&2 echo >&2 fi } # print the module list print_module_list() { DELIM=$1 shift while test -n "$2"; do echo -n "$(eval echo \$NAME_$1)$DELIM" shift done echo -n "$(eval echo \$NAME_$1)" } trap onfailure EXIT # clear variables export SEARCH_MODULES="" export MODULES="" export ONLY="" export RESUME_FLAG=no export REVERSE_FLAG=no export SKIPFIRST=no # parse commandline parameters while test $# -gt 0; do # get option command=$1 option=$1 # get args set +e # stolen from configure... # when no option is set, this returns an error code arg=`expr "x$option" : 'x[^=]*=\(.*\)'` set -e # switch case "$option" in --opts=*) if test "x$arg" = "x"; then usage echo "ERROR: Parameter for --opts is missing" >&2 echo >&2 exit 1; fi DUNE_OPTS_FILE=`canonicalname $arg` if ! test -r "$DUNE_OPTS_FILE"; then usage echo "ERROR: could not read opts file \"$DUNE_OPTS_FILE\"" >&2 echo >&2 exit 1; fi ;; --*-opts=*) optcmd=`expr "x$option=" : 'x--\([^-]*\)-opts=.*'` if is_command $optcmd; then COMMAND=`echo $optcmd | tr '[:lower:]' '[:upper:]'` export ${COMMAND}_FLAGS="$arg" else usage echo "ERROR: unknown option \"$option\"" >&2 exit 1 fi ;; -h|--help) command=help break ;; -p|--print) command=print break ;; --module=*) if test "x$arg" = "x"; then usage echo "ERROR: Parameter for --module is missing" >&2 echo >&2 exit 1; fi for a in `echo $arg | tr ',' ' '`; do export NAME_`fix_variable_name $a`="$a" fix_and_assign MODULE "$a" export SEARCH_MODULES="$SEARCH_MODULES $MODULE" done ;; --only=*) if test "x$arg" = "x"; then usage echo "ERROR: Parameter for --only is missing" >&2 echo >&2 exit 1; fi for a in `echo $arg | tr ',' ' '`; do export NAME_`fix_variable_name $a`="$a" fix_and_assign MODULE "$a" export SEARCH_MODULES="$SEARCH_MODULES $MODULE" export ONLY="$ONLY $MODULE" done ;; --builddir=*) export DUNE_BUILDDIR=$arg ;; --no-builddir) export DUNE_BUILDDIR="" ;; --skipversioncheck) export SKIPVERSIONCHECK=yes ;; --current) while ! test -f $CONTROL; do cd .. if test "$OLDPWD" = "$PWD"; then echo "You are not inside the source tree of a DUNE module." >&2 exit -1 fi done; parse_control $PWD/$CONTROL fix_and_assign MODULE "$module" export SEARCH_MODULES="$SEARCH_MODULES $MODULE" export ONLY="$ONLY $MODULE" ;; --current-dep) while ! test -f $CONTROL; do cd .. if test "$OLDPWD" = "$PWD"; then echo "You are not inside the source tree of a DUNE module." >&2 exit -1 fi done; parse_control $PWD/$CONTROL fix_and_assign MODULE "$module" export SEARCH_MODULES="$SEARCH_MODULES $MODULE" ;; --resume) export RESUME_FLAG="yes" ;; --reverse) export REVERSE_FLAG="yes" ;; --skipfirst) export SKIPFIRST=yes ;; --debug) true ;; # ignore this option, it is handled right at the beginning --*) usage echo "ERROR: Unknown option \`$option'" >&2 echo >&2 exit 1 ;; *) break ;; esac shift done extract_multiarch # create PKG_CONFIG_PATH for installed dune modules for i in $MULTIARCH_LIBDIR lib64 lib32 lib; do if test -d "$PREFIX_DIR/$i/pkgconfig"; then export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$PREFIX_DIR/$i/pkgconfig" fi done # we assume there should be a command... if test "x$command" = "x"; then usage exit 1 fi case "$command" in print) create_module_list eval "print_module_list ' ' $MODULES" echo >&2 ;; info) create_module_list echo $SORTEDMODULES_INFO ;; export) create_module_list DUNE_CONTROL_PATH="" for mod in $MODULES; do path="$(eval echo \$PATH_$mod)" name=$(eval echo \$NAME_$mod) if test -f "$path/dune.module"; then export DUNE_CONTROL_PATH="$DUNE_CONTROL_PATH:$path/dune.module" else if test -f "$path/lib/dunecontrol/$name/dune.module"; then export DUNE_CONTROL_PATH="$DUNE_CONTROL_PATH:$path/lib/dunecontrol/$name/dune.module" else echo "ERROR: while creating list of dune.module files" >&2 echo " couldn't find dune.module file for $name in $path" >&2 echo >&2 exit 1 fi fi done echo export DUNE_CONTROL_PATH=$(echo $DUNE_CONTROL_PATH | $SED -e 's/^://') ;; printdeps) find_modules_in_path if test "x$SEARCH_MODULES" == "x"; then echo "ERROR: printdeps requires an explicit --module=... parameter" >&2 exit 1 fi mainmod=`echo $SEARCH_MODULES` name=`eval echo \\${NAME_$mainmod}` echo "dependencies for $name" ### DEPENDENCIES sort_modules $mainmod for mod in $SORTEDMODULES_DEPS; do eval echo "\" \$NAME_${mod} (required)\"" done for mod in $SORTEDMODULES_SUGS; do eval echo "\" \$NAME_${mod} (suggested)\"" done ;; unexport) echo export DUNE_CONTROL_PATH="" ;; help) usage ;; *) set -e # skip version check if command is in according list if grep -q "$1" <<<"$COMMANDSTOSKIPVERSIONCHECK" ; then export SKIPVERSIONCHECK=yes; fi check_commands "$@" create_module_list NAMES="" BUILDMODULES="" for mod in $MODULES; do if test "$(eval echo \$INST_$mod)" != "yes"; then NAMES="$NAMES$(eval echo \$NAME_$mod) " BUILDMODULES="$BUILDMODULES$mod " fi done echo "--- going to build $NAMES ---" if test -n "$RESUME_FILE"; then # write all modules to the resume file for mod in $MODULES ; do echo "$mod" done > "$RESUME_FILE" fi for mod in $BUILDMODULES; do build_module "$mod" "$@" if test -n "$RESUME_FILE"; then # remove the current module from the resume file modules_togo=`cat "$RESUME_FILE"` for mod_togo in $modules_togo ; do if test "$mod_togo" != "$mod" ; then echo "$mod_togo" fi done > "$RESUME_FILE" fi done echo "--- done ---" ;; esac trap - EXIT dune-common-2.8.0/bin/dunepackaging.py000077500000000000000000000200571411343567400177030ustar00rootroot00000000000000#!/usr/bin/env python3 import sys, os, io, getopt, re, shutil import importlib, subprocess import email.utils import pkg_resources from datetime import date # make sure that 'metadata' is taken from the current `dune-common` folder # and not some installed version which might be different from the one I'm # packaging (by mistake). The path to `packagemetadata.py` needs to be # added to the python path (to work here) and to the environment so that a # later call to `python setup.py` also works. here = os.path.dirname(os.path.abspath(__file__)) mods = os.path.join(here, "..", "python", "dune") sys.path.append(mods) pythonpath = mods + ":" + os.environ.get('PYTHONPATH','.') os.environ['PYTHONPATH'] = pythonpath from packagemetadata import metaData def main(argv): repositories = ["gitlab", "testpypi", "pypi"] def usage(): return 'usage: dunepackaging.py [--upload <'+"|".join(repositories)+'> | -c | --clean | --version | --onlysdist | --bdist_conda]' try: opts, args = getopt.getopt(argv, "hc", ["upload=", "clean", "version=", "onlysdist", "bdist_conda"]) except getopt.GetoptError: print(usage()) sys.exit(2) upload = False repository = "gitlab" clean = False version = None onlysdist = False bdistconda = False for opt, arg in opts: if opt == '-h': print(usage()) sys.exit(2) elif opt in ("--upload"): upload = True if arg != '': repository = arg if repository not in repositories: print("Specified repository must be one of: " + " ".join(repositories)) sys.exit(2) elif opt in ("-c", "--clean"): clean = True elif opt in ("--version"): version = arg elif opt in ("--onlysdist"): onlysdist = True elif opt in ("--bdist_conda"): onlysdist = True bdistconda = True # Remove generated files def removeFiles(): import glob files = ['MANIFEST', 'dist', '_skbuild', '__pycache__'] print("Remove generated files: " + ", ".join(files)) remove = ['rm', '-rf'] + files subprocess.call(remove) # checkout setup.py and pyproject.toml checkout = ['git', 'checkout', 'setup.py', 'pyproject.toml'] subprocess.call(checkout) if clean: removeFiles() sys.exit(0) data, cmake_flags = metaData(version, dependencyCheck=False) if version is None: version = data.version # Generate setup.py print("Generate setup.py") f = open("setup.py", "w") if data.name == 'dune-common': f.write("import os, sys\n") f.write("here = os.path.dirname(os.path.abspath(__file__))\n") f.write("mods = os.path.join(here, \"python\", \"dune\")\n") f.write("sys.path.append(mods)\n\n") f.write("try:\n") f.write(" from dune.packagemetadata import metaData\n") f.write("except ImportError:\n") f.write(" from packagemetadata import metaData\n") f.write("from skbuild import setup\n") f.write("setup(**metaData('"+version+"')[1])\n") f.close() # Generate pyproject.toml print("Generate pyproject.toml") f = open("pyproject.toml", "w") requires = ["pip", "setuptools", "wheel", "scikit-build", "cmake", "ninja", "requests"] requires += [r for r in data.asPythonRequirementString(data.depends + data.python_requires) if r not in requires] f.write("[build-system]\n") f.write("requires = "+requires.__str__()+"\n") f.write("build-backend = 'setuptools.build_meta'\n") f.close() # Create source distribution and upload to repository python = sys.executable if upload or onlysdist: print("Remove dist") remove = ['rm', '-rf', 'dist'] subprocess.call(remove) # check if we have scikit-build import pkg_resources installed = {pkg.key for pkg in pkg_resources.working_set} if not 'scikit-build' in installed: print("Please install the pip package 'scikit-build' to build the source distribution.") sys.exit(2) # append hash of current git commit to README shutil.copy('README.md', 'tmp_README.md') githash = ['git', 'rev-parse', 'HEAD'] hash = subprocess.check_output(githash, encoding='UTF-8') with open("README.md", "a") as f: f.write("\n\ngit-" + hash) print("Create source distribution") # make sure setup.py/pyproject.toml are tracked by git so that # they get added to the package by scikit gitadd = ['git', 'add', 'setup.py', 'pyproject.toml'] subprocess.call(gitadd) # run sdist build = [python, 'setup.py', 'sdist'] subprocess.call(build, stdout=subprocess.DEVNULL) # undo the above git add gitreset = ['git', 'reset', 'setup.py', 'pyproject.toml'] subprocess.call(gitreset) # restore README.md shutil.move('tmp_README.md', 'README.md') if not onlysdist: # check if we have twine import pkg_resources installed = {pkg.key for pkg in pkg_resources.working_set} if not 'twine' in installed: print("Please install the pip package 'twine' to upload the source distribution.") sys.exit(2) twine = [python, '-m', 'twine', 'upload'] twine += ['--repository', repository] twine += ['dist/*'] subprocess.call(twine) removeFiles() # create conda package meta.yaml (experimental) if bdistconda: import hashlib remove = ['rm', '-rf', 'dist/'+data.name] subprocess.call(remove) mkdir = ['mkdir', 'dist/'+data.name ] subprocess.call(mkdir) print("Create bdist_conda (experimental)") distfile = 'dist/'+data.name+'-'+version+'.tar.gz' datahash = '' with open(distfile, "rb") as include: source = include.read() datahash = hashlib.sha256( source ).hexdigest() print("Generate ",'dist/'+data.name+'/meta.yaml') f = open('dist/'+data.name+'/meta.yaml', "w") f.write('{% set name = "' + data.name + '" %}\n') f.write('{% set version = "' + version + '" %}\n') f.write('{% set hash = "' + datahash + '" %}\n\n') f.write('package:\n') f.write(' name: "{{ name|lower }}"\n') f.write(' version: "{{ version }}"\n\n') f.write('source:\n') f.write(' path: ../{{ name }}-{{ version }}/\n') f.write(' sha256: {{ hash }}\n\n') f.write('build:\n') f.write(' number: 1\n') if 'TMPDIR' in os.environ: f.write(' script_env:\n') f.write(' - TMPDIR=' + os.environ['TMPDIR'] +'\n') f.write(' script: "{{ PYTHON }} -m pip install . --no-deps --ignore-installed -vv "\n\n') f.write('requirements:\n') requirements = ['pip', 'python', 'mkl', 'tbb', 'intel-openmp', 'libgcc-ng', 'libstdcxx-ng', 'gmp', 'scikit-build', 'mpi4py', 'matplotlib', 'numpy', 'scipy', 'ufl'] for dep in data.depends: requirements += [dep[0]] f.write(' host:\n') for dep in requirements: f.write(' - ' + dep + '\n') f.write('\n') f.write(' run:\n') for dep in requirements: f.write(' - ' + dep + '\n') f.write('\n') f.write('test:\n') f.write(' imports:\n') f.write(' - ' + data.name.replace('-','.') + '\n\n') f.write('about:\n') f.write(' home: '+data.url+'\n') f.write(' license: GPLv2 with linking exception.\n') f.write(' license_family: GPL\n') f.write(' summary: '+data.description+'\n') f.close() if __name__ == "__main__": main(sys.argv[1:]) dune-common-2.8.0/bin/duneproject000077500000000000000000000457731411343567400170120ustar00rootroot00000000000000#!/usr/bin/env bash # -*- indent-tabs-mode: nil; sh-basic-offset: 2; sh-indentation: 2 -*- # vi: set et sw=2: # The sh-indentation in the emacs mode-line is needed for emacs <26, see # https://debbugs.gnu.org/21751 # # TODO: # # * Check module names entered as dependencies. set -e canonicalname(){ if test $# -ne 1; then echo Usage: canonicalname path >&2 return 1 fi file="`eval echo $1`" # expand ~ if test ! -e "$file"; then echo $file: file not found >&2 return 1 fi # if this is a symlink, then follow the symlink if test -L "$file"; then fdir="`dirname \"$file\"`" flink="`readlink \"$file\"`" if test -e "$flink"; then # these are absolute links, or links in the CWD canonicalname "$flink" else canonicalname "$fdir/$flink" fi else # if this is a file, then remember the filename and # canonicalize the directory name if test -f "$file"; then fdir="`dirname \"$file\"`" fname="`basename \"$file\"`" fdir="`canonicalname \"$fdir\"`" echo "$fdir/$fname" fi # if this is a directory, then create an absolute # directory name and we are done if test -d "$file"; then (cd "$file"; pwd) fi fi } canonicalpath(){ if test $# -ne 1; then echo Usage: canonicalpath path >&2 return 1 fi dirname "$(canonicalname "$1")" } pkg_config_dependencies(){ if test $# -ne 1; then echo Usage: pkg_config_dependencies name >&2 return 1 fi name="$1" depends="`pkg-config --variable=DEPENDENCIES $name| sed -e 's/,/ /g'`" for pkg in $depends; do depends="$depends `pkg_config_dependencies $pkg`" done echo $depends } # modulesexist DEPS MODULES # # DEPS is a space seperated list of modules the new module should depend on # MODULES is a space seperated list of modules that are known to be present # # Each name in DEPS is checked to see wether it is present in MODULES. If # not, is is checked whether it can be found with pkg-config. If still no, an # error message is issued and modulesexist will return with an exit status # indicating failure. modulesexist(){ local status dep found status=0 for dep in $1; do found=false if [[ " $2 " == *" $dep "* ]]; then found=true fi # If module not found in list, try pkg-config if ! $found && pkg-config $dep &> /dev/null; then found=true fi if ! $found; then echo "ERROR:">&2 echo "Module with name $dep was not found" >&2 echo "Did you forget to specify its location" >&2 echo "in the DUNE_CONTROL_PATH variable?">&2 echo >&2 status=1 fi done return $status } make_unique(){ if [ "$#" = "1" ]; then # take first word for exclude_word in $1; do break; done make_unique $exclude_word "$1" 0 else local exclude_word="$1" local words="$2" local pos="$3" local length=0 local i=0 local new_words="" local cur=0 for word in $words; do if [ $i -le $pos ]; then i=$((i+1)) length=$((length+1)) new_words="$new_words $word" continue fi if [ "$word" != "$exclude_word" ]; then new_words="$new_words $word" if [ "$((length-1))" = "$pos" ]; then next_word="$word" fi length=$((length+1)) fi done if [ "$pos" -lt "$length" ]; then # process next word make_unique "$next_word" "$new_words" $((pos+1)) else export UNIQUE_WORDS="$new_words" fi fi } echo echo == Dune project/module generator == echo echo duneproject will assist you in the creation of a new Dune application. echo During this process a new directory with the name of your project will be echo created. This directory will hold all configuration and Makefiles and a echo simple example application. echo ################## FIND AVAILABLE MODULES ################## . "$(canonicalpath $0)/../lib/dunemodules.lib" export PREFIX_DIR="`canonicalpath "$0"`/.." extract_multiarch_pkg_config_path # search for modules, both installed and src modules find_modules_in_path # sort modules to remove duplicates sort_modules $FOUND_MODULES FOUND_MODULES=$MODULES # get the real module names MODULES="" for i in $FOUND_MODULES; do mod=$(eval echo \$NAME_$i) MODULES="$MODULES$mod " done if [ "$MODULES" = "" ]; then echo "ERROR:">&2 echo " No dune modules were found!">&2 echo " Did you forget to specify the places where ">&2 echo " you installed your modules in the ">&2 echo " DUNE_CONTROL_PATH environment variable">&2 echo " and adjusted the PKG_CONFIG_PATH environment">&2 echo " accordingly?" >&2 exit 1; fi ################## READ CMDLINE OPTIONS ########## PROJECT="$1" DEPENDENCIES="$2" VERSION="$3" MAINTAINER="$4" ################## READ OPTIONS ################## while [ "$DATACORRECT" != "y" -a "$DATACORRECT" != "Y" ]; do while [ -z $PROJECT ]; do read -p "1) Name of your new Project? (e.g.: dune-grid): " PROJECT if echo "$MODULES" | grep -q ^$PROJECT$; then read -p " A module named $PROJECT already exists. Continue anyway? [y/N] " CONT if test x$DELETE = xy -o x$DELETE = xY; then PROJECT="" fi elif echo "$PROJECT" | grep -q "\."; then echo "The Name contains a dot (.) which is not allowed." PROJECT="" fi done MODULE="$PROJECT" DEPOK=1 while [ "$DEPOK" != 0 ]; do echo "2) Which modules should this module depend on?" echo " The following modules have been found:" echo " $MODULES" # for i in $MODULES; do echo -n " $i"; done # echo "" while [ -z "$DEPENDENCIES" ]; do read -p " Enter space-separated list: " DEPENDENCIES done set +e modulesexist "$DEPENDENCIES" "$MODULES" DEPOK=$? set -e if [ "$DEPOK" != 0 ]; then DEPENDENCIES="" fi done while [ -z $VERSION ]; do read -p "3) Project/Module version? " VERSION done while [ -z "$MAINTAINER" ]; do read -p "4) Maintainer's email address? " MAINTAINER done echo echo "creating Project \"$PROJECT\", version $VERSION " echo "which depends on \"$DEPENDENCIES\"" echo "with maintainer \"$MAINTAINER\"" read -p "Are these informations correct? [y/N] " DATACORRECT # reset data if necessary if [ "$DATACORRECT" != "y" -a "$DATACORRECT" != "Y" ]; then PROJECT="" DEPENDENCIES="" VERSION="" MAINTAINER="" fi done echo echo "A sample code $MODULE.cc is generated in the \"$PROJECT\" directory." echo "Look at the README and dune.module files there." echo "Now you can run the dunecontrol script which will setup the new module." echo "Sometimes you may have to tweak CMakeLists.txt a bit." if test -d $PROJECT; then echo WARNING: echo "A directory with the name $PROJECT already exists." echo "Do you want to continue anyway?" read -p "Type Y to overwrite the old directory, N to abort. [y/N] " DELETE if test x$DELETE != xy -a x$DELETE != xY; then echo Abort... exit 1 fi rm -rf "$PROJECT" fi mkdir "$PROJECT" ################## dune.module ################## cat > "$PROJECT/dune.module" < "$PROJECT/README" <= 3.13 Getting started --------------- If these preliminaries are met, you should run dunecontrol all which will find all installed dune modules as well as all dune modules (not installed) which sources reside in a subdirectory of the current directory. Note that if dune is not installed properly you will either have to add the directory where the dunecontrol script resides (probably ./dune-common/bin) to your path or specify the relative path of the script. Most probably you'll have to provide additional information to dunecontrol (e. g. compilers, configure options) and/or make options. The most convenient way is to use options files in this case. The files define four variables: CMAKE_FLAGS flags passed to cmake (during configure) An example options file might look like this: #use this options to configure and make if no other options are given CMAKE_FLAGS=" \\ -DCMAKE_CXX_COMPILER=g++-5 \\ -DCMAKE_CXX_FLAGS='-Wall -pedantic' \\ -DCMAKE_INSTALL_PREFIX=/install/path" #Force g++-5 and set compiler flags If you save this information into example.opts you can pass the opts file to dunecontrol via the --opts option, e. g. dunecontrol --opts=example.opts all More info --------- See dunecontrol --help for further options. The full build system is described in the dune-common/doc/buildsystem (Git version) or under share/doc/dune-common/buildsystem if you installed DUNE! R_DELIM ################## CMakeLists.txt ################## echo "- $PROJECT/CMakeLists.txt" cat> "$PROJECT/CMakeLists.txt" << M_DELIM cmake_minimum_required(VERSION 3.13) project($PROJECT CXX) if(NOT (dune-common_DIR OR dune-common_ROOT OR "\${CMAKE_PREFIX_PATH}" MATCHES ".*dune-common.*")) string(REPLACE \${PROJECT_NAME} dune-common dune-common_DIR \${PROJECT_BINARY_DIR}) endif() #find dune-common and set the module path find_package(dune-common REQUIRED) list(APPEND CMAKE_MODULE_PATH "\${PROJECT_SOURCE_DIR}/cmake/modules" \${dune-common_MODULE_PATH}) #include the dune macros include(DuneMacros) # start a dune project with information from dune.module dune_project() dune_enable_all_packages() add_subdirectory(src) add_subdirectory(dune) add_subdirectory(doc) add_subdirectory(cmake/modules) # finalize the dune project, e.g. generating config.h etc. finalize_dune_project(GENERATE_CONFIG_H_CMAKE) M_DELIM ################## PROJECT.PC.IN ################## echo "- $PROJECT/$MODULE.pc.in" cat> "$PROJECT/$MODULE.pc.in" << CC_DELIM prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ CXX=@CXX@ CC=@CC@ DEPENDENCIES=@REQUIRES@ Name: @PACKAGE_NAME@ Version: @VERSION@ Description: $MODULE module URL: http://dune-project.org/ Requires: ${DEPENDENCIES} Libs: -L\${libdir} Cflags: -I\${includedir} CC_DELIM echo " Please remember to update your $PROJECT/$MODULE.pc.in," echo " Description and URL are missing right now." ################# config.h.cmake ##################### echo "- $PROJECT/config.h.cmake" cat> "$PROJECT/config.h.cmake" < "$PROJECT/src/CMakeLists.txt" << M_DELIM add_executable("${MODULE}" ${MODULE}.cc) target_link_dune_default_libraries("${MODULE}") M_DELIM ################## PROJECT.CC ################## echo "- $PROJECT/src/$MODULE.cc" cat> "$PROJECT/src/$MODULE.cc" << CC_DELIM // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include // An initializer of MPI #include // We use exceptions int main(int argc, char** argv) { try{ // Maybe initialize MPI Dune::MPIHelper& helper = Dune::MPIHelper::instance(argc, argv); std::cout << "Hello World! This is ${PROJECT}." << std::endl; if(Dune::MPIHelper::isFake) std::cout<< "This is a sequential program." << std::endl; else std::cout<<"I am rank "< $PROJECT/dune/CMakeLists.txt < $PROJECT/dune/$NAME/CMakeLists.txt < $PROJECT/dune/$NAME/$NAME.hh < "$PROJECT/doc/CMakeLists.txt" << CC_DELIM add_subdirectory("doxygen") CC_DELIM ############################################################### ############### The doc/doxygen subdirectory ################## ############################################################### mkdir "$PROJECT/doc/doxygen" #################### basic Doxylocal ########################## echo "- $PROJECT/doc/doxygen/Doxylocal" if [ "x`which doxygen`" == "x" ]; then echo "Doxygen is not installed! Your documentation will not work without it." fi # Where to search and which files to use cat> $PROJECT/doc/doxygen/Doxylocal << CC_DELIM # This file contains local changes to the doxygen configuration # please use '+=' to add files/directories to the lists # 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 += @top_srcdir@/dune/ # see e.g. dune-grid for the examples of mainpage and modules # INPUT += @srcdir@/mainpage \\ # @srcdir@/modules # The EXCLUDE tag can be used to specify files and/or directories that should # be 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 += @top_srcdir@/dune/$NAME/test # 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 += @top_srcdir@/src # 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 += @top_srcdir@/dune/$NAME/pics CC_DELIM ################# doc/doxygen/CMakeLists.txt ##################### echo "- $PROJECT/doc/doxygen/CMakeLists.txt" cat> "$PROJECT/doc/doxygen/CMakeLists.txt" << CC_DELIM # shortcut for creating the Doxyfile.in and Doxyfile add_doxygen_target() CC_DELIM ######################################################### ############### The cmake subdirectory ################## ######################################################### mkdir "$PROJECT/cmake" ######################################################### ############### The cmake/modules subdirectory ########## ######################################################### mkdir "$PROJECT/cmake/modules" macroname="" for i in $(echo $PROJECT| sed 's/-/ /g'); do firstchar=$(echo $i | sed 's/\(.\).*/\1/') macroname=$macroname$(echo $firstchar | tr '[a-z]' '[A-Z]')$(echo $i | sed 's/.\(.*\)/\1/') done macroname="$macroname""Macros.cmake" ################# cmake/modules/CMakeLists.txt ##################### echo "- $PROJECT/cmake/modules/CMakeLists.txt" cat> "$PROJECT/cmake/modules/CMakeLists.txt" < "$PROJECT/cmake/modules/$macroname" <0: for m in args.modules: base = os.path.join(generated_dir, m+'*') for filename in glob.iglob( base ): os.remove( filename ) moduleFiles.update( [os.path.splitext(os.path.basename(filename))[0]] ) else: parser.print_help() sys.exit(0) for line in fileinput.input( os.path.join(generated_dir, 'CMakeLists.txt'), inplace = True): if not any( [m in line for m in moduleFiles] ): print(line, end="") dune-common-2.8.0/bin/setup-dunepy.py000077500000000000000000000120551411343567400175440ustar00rootroot00000000000000#!/usr/bin/env python3 import getopt import os import shlex import subprocess import sys import shutil import logging logger = logging.getLogger(__name__) try: from dune.common.module import build_dune_py_module, get_dune_py_dir, make_dune_py_module, select_modules, resolve_dependencies, resolve_order from dune.common.locking import Lock, LOCK_EX except ImportError: import os here = os.path.dirname(os.path.abspath(__file__)) modsA = os.path.join(os.path.dirname(here), "python", "dune") modsB = os.path.join(modsA,"common") sys.path.append(modsB) sys.path.append(modsA) if os.path.exists(os.path.join(modsB, "module.py")): from module import build_dune_py_module, get_dune_py_dir, make_dune_py_module, select_modules, resolve_dependencies, resolve_order from locking import Lock, LOCK_EX else: raise def buffer_to_str(b): return b if sys.version_info.major == 2 else b.decode('utf-8') def toBuildDir(builddir, moddir, module): if os.path.isabs(builddir): return os.path.join(builddir ,module) else: return os.path.join(moddir, builddir) def main(argv): try: opts, args = getopt.getopt(argv,"ho",["opts=","builddir=","module="]) except getopt.GetoptError: print('usage: setup-dunepy.py [-o config.opts | --opts=config.opts | --builddir] [--module=mod] [install]') sys.exit(2) optsfile = None builddir = None masterModule = None for opt, arg in opts: if opt == '-h': print('usage: setup-dunepy.py [-o config.opts | --opts=config.opts] [install]') sys.exit(2) elif opt in ("-o", "--opts"): optsfile = arg elif opt in ("--builddir",): builddir = arg elif opt in ("--module",): masterModule = arg if len(args) > 0: execute = args[0] else: execute = "" # see if the standard Dune enviroment variable for the opts file is defined if optsfile is None: optsfile = os.environ.get('DUNE_OPTS_FILE', None) if optsfile is not None: definitions = {} command = ['bash', '-c', 'source ' + optsfile + ' && echo "$CMAKE_FLAGS"'] proc = subprocess.Popen(command, stdout = subprocess.PIPE) stdout, _ = proc.communicate() cmake_args = shlex.split(buffer_to_str(stdout)) if builddir is None: # get the build dir (check for BUILDDIR, DUNE_BUILDDIR in opts file # and then DUNE_BUILDDIR in environment variable command = ['bash', '-c', 'source ' + optsfile + ' && echo "$BUILDDIR"'] proc = subprocess.Popen(command, stdout = subprocess.PIPE) stdout, _ = proc.communicate() builddir = buffer_to_str(stdout).strip() if not builddir: command = ['bash', '-c', 'source ' + optsfile + ' && echo "$DUNE_BUILDDIR"'] proc = subprocess.Popen(command, stdout = subprocess.PIPE) stdout, _ = proc.communicate() builddir = buffer_to_str(stdout).strip() if not builddir: builddir = os.environ.get('DUNE_BUILDDIR', 'build-cmake') else: cmake_args = None if builddir is None: builddir = os.environ.get('DUNE_BUILDDIR', 'build-cmake') # Generate list of all modules duneModules = select_modules() # Generate list of dependencies for dune-py. If --module=mod is passed, # use mod and all its dependencies only. Otherwise use all found modules # as dependencies. if masterModule is None: deps = resolve_order(duneModules[0]) else: depsList = resolve_dependencies(duneModules[0], masterModule) deps = {k:v for k,v in duneModules[0].items() if k in depsList} deps = resolve_order(deps) deps += [masterModule] if execute == "install": for m in deps: moddir = duneModules[1][m] pythonModule = toBuildDir(builddir,moddir,m) print("calling install_python for %s (%s)" % (m,pythonModule)) try: command = ['cmake', '--build', '.', '--target', 'install_python'] proc = subprocess.Popen(command, cwd=pythonModule, stdout = subprocess.PIPE) stdout, stderr = proc.communicate() logger.debug(buffer_to_str(stdout)) except FileNotFoundError: print("Warning: build dir not found possibly module is installed then python bindings should be already available") dunepy = get_dune_py_dir() dunepyBase = os.path.realpath( os.path.join(dunepy,"..") ) if not os.path.exists(dunepyBase): os.makedirs(dunepyBase) with Lock(os.path.join(dunepyBase, 'lock-module.lock'), flags=LOCK_EX): if os.path.exists(dunepy): shutil.rmtree(dunepy) os.makedirs(dunepy) foundModule = make_dune_py_module(dunepy, deps) output = build_dune_py_module(dunepy, cmake_args, None, builddir, deps, writetagfile=True) print("CMake output") print(output) if __name__ == "__main__": main(sys.argv[1:]) dune-common-2.8.0/cmake/000077500000000000000000000000001411343567400150325ustar00rootroot00000000000000dune-common-2.8.0/cmake/CMakeLists.txt000066400000000000000000000000641411343567400175720ustar00rootroot00000000000000add_subdirectory(modules) add_subdirectory(scripts) dune-common-2.8.0/cmake/modules/000077500000000000000000000000001411343567400165025ustar00rootroot00000000000000dune-common-2.8.0/cmake/modules/AddBLASLapackFlags.cmake000066400000000000000000000024301411343567400227260ustar00rootroot00000000000000# Defines the functions to use BLAS/Lapack # # .. cmake_function:: add_dune_blas_lapack_flags # # .. cmake_param:: targets # :positional: # :single: # :required: # # A list of targets to use BLAS/Lapack with. # include_guard(GLOBAL) set_package_properties("BLAS" PROPERTIES DESCRIPTION "fast linear algebra routines") set_package_properties("LAPACK" PROPERTIES DESCRIPTION "fast linear algebra routines") # register HAVE_BLAS and HAVE_LAPACK for config.h set(HAVE_BLAS ${BLAS_FOUND}) set(HAVE_LAPACK ${LAPACK_FOUND}) # register Lapack library as dune package if(HAVE_LAPACK) dune_register_package_flags(LIBRARIES "${LAPACK_LIBRARIES}") cmake_push_check_state() set(CMAKE_REQUIRED_LIBRARIES ${LAPACK_LIBRARIES}) check_function_exists("dsyev_" LAPACK_NEEDS_UNDERLINE) cmake_pop_check_state() elseif(HAVE_BLAS) dune_register_package_flags(LIBRARIES "${BLAS_LIBRARIES}") endif() # add function to link against the BLAS/Lapack library function(add_dune_blas_lapack_flags _targets) foreach(_target ${_targets}) if(LAPACK_FOUND) target_link_libraries(${_target} PUBLIC ${LAPACK_LIBRARIES}) elseif(BLAS_FOUND) target_link_libraries(${_target} PUBLIC ${BLAS_LIBRARIES}) endif() endforeach(_target) endfunction(add_dune_blas_lapack_flags) dune-common-2.8.0/cmake/modules/AddGMPFlags.cmake000066400000000000000000000014411411343567400215150ustar00rootroot00000000000000# Defines the functions to use GMP # # .. cmake_function:: add_dune_gmp_flags # # .. cmake_param:: targets # :positional: # :single: # :required: # # A list of targets to use GMP with. # include_guard(GLOBAL) # set HAVE_GMP for the config.h file set(HAVE_GMP ${GMP_FOUND}) # register all GMP related flags if(GMP_FOUND) dune_register_package_flags( LIBRARIES GMP::gmpxx COMPILE_DEFINITIONS "ENABLE_GMP=1" ) endif() # add function to link against the GMP library function(add_dune_gmp_flags _targets) if(GMP_FOUND) foreach(_target ${_targets}) target_link_libraries(${_target} PUBLIC GMP::gmpxx) target_compile_definitions(${_target} PUBLIC ENABLE_GMP=1) endforeach(_target ${_targets}) endif(GMP_FOUND) endfunction(add_dune_gmp_flags) dune-common-2.8.0/cmake/modules/AddMETISFlags.cmake000066400000000000000000000013071411343567400217540ustar00rootroot00000000000000# Defines the functions to use METIS # # .. cmake_function:: add_dune_metis_flags # # .. cmake_param:: targets # :positional: # :single: # :required: # # A list of targets to use METIS with. # include_guard(GLOBAL) # register HAVE_METIS for config.h set(HAVE_METIS ${METIS_FOUND}) # register METIS library as dune package if(METIS_FOUND) dune_register_package_flags(LIBRARIES METIS::METIS) endif() # Add function to link targets against METIS library function(add_dune_metis_flags _targets) if(METIS_FOUND) foreach(_target ${_targets}) target_link_libraries(${_target} PUBLIC METIS::METIS) endforeach(_target) endif() endfunction(add_dune_metis_flags _targets) dune-common-2.8.0/cmake/modules/AddMPIFlags.cmake000066400000000000000000000021661411343567400215240ustar00rootroot00000000000000# The DUNE way to compile MPI applications is to use the CXX # compiler with MPI flags usually used for C. CXX bindings # are deactivated to prevent ABI problems. # # .. cmake_function:: add_dune_mpi_flags # # .. cmake_param:: targets # :single: # :required: # :positional: # # The target list to add the MPI flags to. # include_guard(GLOBAL) # text for feature summary set_package_properties("MPI" PROPERTIES DESCRIPTION "Message Passing Interface library" PURPOSE "Parallel programming on multiple processors") if(MPI_C_FOUND) set(HAVE_MPI ${MPI_C_FOUND}) dune_register_package_flags(COMPILE_DEFINITIONS "ENABLE_MPI=1" LIBRARIES MPI::MPI_C) endif() # adds MPI flags to the targets function(add_dune_mpi_flags) cmake_parse_arguments(ADD_MPI "SOURCE_ONLY;OBJECT" "" "" ${ARGN}) # ignored set(targets ${ADD_MPI_UNPARSED_ARGUMENTS}) if(MPI_C_FOUND) foreach(target ${targets}) target_link_libraries(${target} PUBLIC MPI::MPI_C) target_compile_definitions(${target} PUBLIC "ENABLE_MPI=1") endforeach(target) endif() endfunction(add_dune_mpi_flags) dune-common-2.8.0/cmake/modules/AddPTScotchFlags.cmake000066400000000000000000000017201411343567400225610ustar00rootroot00000000000000# Defines the functions to use PTScotch # # .. cmake_function:: add_dune_ptscotch_flags # # .. cmake_param:: targets # :positional: # :single: # :required: # # A list of targets to use PTScotch with. # include_guard(GLOBAL) # set HAVE_PTSCOTCH for config.h set(HAVE_PTSCOTCH ${PTScotch_FOUND}) # register all PTScotch related flags if(PTScotch_SCOTCH_FOUND) dune_register_package_flags(LIBRARIES PTScotch::Scotch) endif() if(PTScotch_PTSCOTCH_FOUND) dune_register_package_flags(LIBRARIES PTScotch::PTScotch) endif() function(add_dune_ptscotch_flags _targets) if(PTScotch_SCOTCH_FOUND) foreach(_target ${_targets}) target_link_libraries(${_target} PUBLIC PTScotch::Scotch) endforeach(_target ${_targets}) endif() if(PTScotch_PTSCOTCH_FOUND) foreach(_target ${_targets}) target_link_libraries(${_target} PUBLIC PTScotch::PTScotch) endforeach(_target ${_targets}) endif() endfunction(add_dune_ptscotch_flags) dune-common-2.8.0/cmake/modules/AddParMETISFlags.cmake000066400000000000000000000013371411343567400224220ustar00rootroot00000000000000# Defines the functions to use ParMETIS # # .. cmake_function:: add_dune_parmetis_flags # # .. cmake_param:: targets # :positional: # :single: # :required: # # A list of targets to use ParMETIS with. # include_guard(GLOBAL) # set HAVE_PARMETIS for config.h set(HAVE_PARMETIS ${ParMETIS_FOUND}) # register all ParMETIS related flags if(ParMETIS_FOUND) dune_register_package_flags(LIBRARIES ParMETIS::ParMETIS) endif() # add function to link against the ParMETIS library function(add_dune_parmetis_flags _targets) if(ParMETIS_FOUND) foreach(_target ${_targets}) target_link_libraries(${_target} PUBLIC ParMETIS::ParMETIS) endforeach(_target) endif() endfunction(add_dune_parmetis_flags) dune-common-2.8.0/cmake/modules/AddQuadMathFlags.cmake000066400000000000000000000015451411343567400226030ustar00rootroot00000000000000# Defines the functions to use QuadMath # # .. cmake_function:: add_dune_quadmath_flags # # .. cmake_param:: targets # :positional: # :single: # :required: # # A list of targets to use QuadMath with. # include_guard(GLOBAL) # set HAVE_QUADMATH for config.h set(HAVE_QUADMATH ${QuadMath_FOUND}) # register the QuadMath imported target if(QuadMath_FOUND) dune_register_package_flags( LIBRARIES QuadMath::QuadMath COMPILE_DEFINITIONS "ENABLE_QUADMATH=1" ) endif() # add function to link against QuadMath::QuadMath function(add_dune_quadmath_flags _targets) if(QuadMath_FOUND) foreach(_target ${_targets}) target_link_libraries(${_target} PUBLIC QuadMath::QuadMath) target_compile_definitions(${_target} PUBLIC ENABLE_QUADMATH=1) endforeach(_target ${_targets}) endif() endfunction(add_dune_quadmath_flags) dune-common-2.8.0/cmake/modules/AddSuiteSparseFlags.cmake000066400000000000000000000017131411343567400233430ustar00rootroot00000000000000# Defines the functions to use SuiteSparse # # .. cmake_function:: add_dune_suitesparse_flags # # .. cmake_param:: targets # :positional: # :single: # :required: # # A list of targets to use SuiteSparse with. # include_guard(GLOBAL) # set HAVE_SUITESPARSE for config.h set(HAVE_SUITESPARSE ${SuiteSparse_FOUND}) set(HAVE_UMFPACK ${SuiteSparse_UMFPACK_FOUND}) # register all SuiteSparse related flags if(SuiteSparse_FOUND) dune_register_package_flags( COMPILE_DEFINITIONS "ENABLE_SUITESPARSE=1" LIBRARIES SuiteSparse::SuiteSparse) endif() # Provide function to set target properties for linking to SuiteSparse function(add_dune_suitesparse_flags _targets) if(SuiteSparse_FOUND) foreach(_target ${_targets}) target_link_libraries(${_target} PUBLIC SuiteSparse::SuiteSparse) target_compile_definitions(${_target} PUBLIC ENABLE_SUITESPARSE=1) endforeach(_target) endif() endfunction(add_dune_suitesparse_flags) dune-common-2.8.0/cmake/modules/AddTBBFlags.cmake000066400000000000000000000014111411343567400214760ustar00rootroot00000000000000# Defines the functions to use TBB # # .. cmake_function:: add_dune_tbb_flags # # .. cmake_param:: targets # :positional: # :single: # :required: # # A list of targets to use TBB with. # include_guard(GLOBAL) # set variable for config.h set(HAVE_TBB ${TBB_FOUND}) # perform DUNE-specific setup tasks if (TBB_FOUND) dune_register_package_flags( COMPILE_DEFINITIONS ENABLE_TBB=1 LIBRARIES TBB::tbb ) endif() # function for adding TBB flags to a list of targets function(add_dune_tbb_flags _targets) if(TBB_FOUND) foreach(_target ${_targets}) target_link_libraries(${_target} PUBLIC TBB::tbb) target_compile_definitions(${_target} PUBLIC ENABLE_TBB=1) endforeach(_target) endif() endfunction(add_dune_tbb_flags) dune-common-2.8.0/cmake/modules/AddThreadsFlags.cmake000066400000000000000000000004711411343567400224660ustar00rootroot00000000000000include_guard(GLOBAL) # text for feature summary set_package_properties("Threads" PROPERTIES DESCRIPTION "Multi-threading library") # set HAVE_THREADS for config.h set(HAVE_THREADS ${Threads_FOUND}) # register the Threads imported target globally if(Threads_FOUND) link_libraries(Threads::Threads) endif() dune-common-2.8.0/cmake/modules/AddVcFlags.cmake000066400000000000000000000023101411343567400214360ustar00rootroot00000000000000# Defines the functions to use Vc # # Vc is a library for high-level Vectorization support in C++ # see https://github.com/VcDevel/Vc # # .. cmake_function:: add_dune_vc_flags # # .. cmake_param:: targets # :positional: # :single: # :required: # # A list of targets to use VC with. # include_guard(GLOBAL) # text for feature summary set_package_properties("Vc" PROPERTIES DESCRIPTION "C++ Vectorization library" URL "https://github.com/VcDevel/Vc" PURPOSE "For use of SIMD instructions") function(add_dune_vc_flags _targets) if(Vc_FOUND) foreach(_target ${_targets}) target_link_libraries(${_target} PUBLIC ${Vc_LIBRARIES}) target_compile_options(${_target} PUBLIC ${Vc_COMPILE_FLAGS}) target_compile_definitions(${_target} PUBLIC ENABLE_VC=1) target_include_directories(${_target} SYSTEM PUBLIC ${Vc_INCLUDE_DIR}) endforeach(_target ${_targets}) endif(Vc_FOUND) endfunction(add_dune_vc_flags) if(Vc_FOUND) dune_register_package_flags(COMPILE_OPTIONS "${Vc_COMPILE_FLAGS};-DENABLE_VC=1" LIBRARIES "${Vc_LIBRARIES}" INCLUDE_DIRS "${Vc_INCLUDE_DIR}") endif(Vc_FOUND) set(HAVE_VC ${Vc_FOUND}) dune-common-2.8.0/cmake/modules/CMakeBuiltinFunctionsDocumentation.cmake000066400000000000000000000037261411343567400264460ustar00rootroot00000000000000# This modules contains only documentation for CMake builtins. # This is necessary to have an complete API documentation. # # .. cmake_function:: add_subdirectory # # .. cmake_param:: dir # :single: # :positional: # :required: # # The :code:`CMakeLists.txt` file from this subdirectory # will be executed next. # # .. cmake_param:: EXCLUDE_FROM_ALL # :option: # # Whether targets added in this subdirectory should be built # during :code:`make all`. # # This is a cmake builtin command. # For detailed information, check the cmake documentation: # # :: # # cmake --help-command add_subdirectory # # .. cmake_function:: install # # Define installation rules to customize the behaviour of :code:`make install`. # # This is a cmake builtin command. # For detailed information, check the cmake documentation: # # :: # # cmake --help-command install # # .. cmake_function:: add_executable # # Adds an executable to the project. # # This is a cmake builtin command. # For detailed information, check the cmake documentation: # # :: # # cmake --help-command add_executable # # .. cmake_variable:: CMAKE__COMPILER # # Set the compiler for the language LANG. # LANG is in our case out of C, CXX. # # This is a cmake builtin variable. # For detailed information, check the cmake documentation: # # :: # # cmake --help-variable CMAKE_\_COMPILER # # .. cmake_variable:: CMAKE__FLAGS # # Set the compile flags for the language LANG. # LANG is in our case out of C, CXX. # # This is a cmake builtin variable. # For detailed information, check the cmake documentation: # # :: # # cmake --help-variable CMAKE_\_FLAGS # # .. cmake_function:: find_package # # Look for an external package. # # This is a cmake builtin command. # For detailed information, check the cmake documentation: # # :: # # cmake --help-command find_package # dune-common-2.8.0/cmake/modules/CMakeLists.txt000066400000000000000000000024721411343567400212470ustar00rootroot00000000000000add_subdirectory(FindPkgConfig) add_subdirectory(FindPython3) install(FILES AddBLASLapackFlags.cmake AddGMPFlags.cmake AddMETISFlags.cmake AddMPIFlags.cmake AddParMETISFlags.cmake AddPTScotchFlags.cmake AddQuadMathFlags.cmake AddTBBFlags.cmake AddThreadsFlags.cmake AddSuiteSparseFlags.cmake AddVcFlags.cmake CheckCXXFeatures.cmake CMakeBuiltinFunctionsDocumentation.cmake DuneAddPybind11Module.cmake DuneCMakeCompat.cmake DuneCommonMacros.cmake DuneCxaDemangle.cmake DuneDoc.cmake DuneDoxygen.cmake DuneEnableAllPackages.cmake DuneExecuteProcess.cmake DuneInstance.cmake DuneMacros.cmake DuneMPI.cmake DunePathHelper.cmake DunePkgConfig.cmake DunePythonCommonMacros.cmake DunePythonFindPackage.cmake DunePythonInstallPackage.cmake DunePythonMacros.cmake DunePythonTestCommand.cmake DunePythonVirtualenv.cmake DuneSphinxDoc.cmake DuneSphinxCMakeDoc.cmake DuneStreams.cmake DuneSymlinkOrCopy.cmake DuneTestMacros.cmake FindGMP.cmake FindInkscape.cmake FindLatexMk.cmake FindMETIS.cmake FindParMETIS.cmake FindPTScotch.cmake FindQuadMath.cmake FindSphinx.cmake FindSuiteSparse.cmake FindTBB.cmake Headercheck.cmake latexmkrc.cmake OverloadCompilerFlags.cmake UseInkscape.cmake UseLatexMk.cmake DESTINATION ${DUNE_INSTALL_MODULEDIR}) dune-common-2.8.0/cmake/modules/CheckCXXFeatures.cmake000066400000000000000000000200451411343567400226040ustar00rootroot00000000000000# .. cmake_module:: # # Module that checks for supported C++20, C++17 and non-standard features. # # The behaviour of this module can be modified by the following variable: # # :ref:`DISABLE_CXX_VERSION_CHECK` # Disable checking for std=c++20 (c++23, ...) # # This module internally sets the following variables, which are then # exported into the config.h of the current dune module. # # :code:`HAS_ATTRIBUTE_UNUSED` # True if attribute unused is supported # # :code:`HAS_ATTRIBUTE_DEPRECATED` # True if attribute deprecated is supported # # :code:`HAS_ATTRIBUTE_DEPRECATED_MSG` # True if attribute deprecated("msg") is supported # # .. cmake_variable:: DISABLE_CXX_VERSION_CHECK # # You may set this variable to TRUE to disable checking for # std=c++11 (c++14, c++1y). For more details, check :ref:`CheckCXXFeatures`. # include(CMakePushCheckState) include(CheckCXXCompilerFlag) include(CheckIncludeFileCXX) include(CheckCXXSourceCompiles) include(CheckCXXSymbolExists) # C++ standard versions that this test knows about set(CXX_VERSIONS 20 17) # Compile tests for the different standard revisions; these test both the compiler # and the associated library to avoid problems like using a C++20 user-installed # compiler together with a non C++20-compliant stdlib from the system compiler. # we need to escape semicolons in the tests to be able to stick them into a list string(REPLACE ";" "\;" cxx_20_test " #include // `if constexpr` is a C++20 compiler feature template void f() { if constexpr (T::anything) {} } int main() { // std::is_bounded_array_v is a C++20 library feature return std::is_bounded_array_v; } ") string(REPLACE ";" "\;" cxx_17_test " #include // nested namespaces are a C++17 compiler feature namespace A::B { using T = int; } int main() { // std::void_t is a C++17 library feature return not std::is_same >{}; } ") # build a list out of the pre-escaped tests set(CXX_VERSIONS_TEST "${cxx_20_test}" "${cxx_17_test}") # these are appended to "-std=c++" and tried in this order # note the escaped semicolons; that's necessary to create a nested list set(CXX_VERSIONS_FLAGS "20\;2a" "17\;1z") # by default, we enable C++17 for now, but not C++20 # The user can override this choice by explicitly setting this variable set(CXX_MAX_STANDARD 17 CACHE STRING "highest version of the C++ standard to enable. This version is also used if the version check is disabled") function(dune_require_cxx_standard) include(CMakeParseArguments) cmake_parse_arguments("" "" "MODULE;VERSION" "" ${ARGN}) if(_UNPARSED_ARGUMENTS) message(WARNING "Unknown arguments in call to dune_require_cxx_standard(${ARGN})") endif() if(${_VERSION} GREATER ${CXX_MAX_SUPPORTED_STANDARD}) if(NOT _MODULE) set(_MODULE "This module") endif() if(${_VERSION} GREATER ${CXX_MAX_STANDARD}) message(FATAL_ERROR "\ ${_MODULE} requires compiler support for C++${_VERSION}, but the build system is currently \ set up to not allow newer language standards than C++${CXX_MAX_STANDARD}. Try setting the \ CMake variable CXX_MAX_STANDARD to at least ${_VERSION}." ) else() if(${CXX_MAX_SUPPORTED_STANDARD} EQUAL 17) set(CXX_STD_NAME 17) else() set(CXX_STD_NAME ${CXX_MAX_SUPPORTED_STANDARD}) endif() message(FATAL_ERROR "${_MODULE} requires support for C++${_VERSION}, but your compiler failed our compatibility test." ) endif() endif() endfunction() # try to enable all of the C++ standards that we know about, in descending order if(NOT DISABLE_CXX_VERSION_CHECK) foreach(version ${CXX_VERSIONS}) # skip versions that are newer than allowed if(NOT(version GREATER CXX_MAX_STANDARD)) list(FIND CXX_VERSIONS ${version} version_index) list(GET CXX_VERSIONS_FLAGS ${version_index} version_flags) # First try whether the compiler accepts one of the command line flags for this standard foreach(flag ${version_flags}) set(cxx_std_flag_works "cxx_std_flag_${flag}") check_cxx_compiler_flag("-std=c++${flag}" ${cxx_std_flag_works}) if(${cxx_std_flag_works}) set(cxx_std_flag "-std=c++${flag}") break() endif() endforeach() # and if it did, run the compile test if(cxx_std_flag) list(GET CXX_VERSIONS_TEST ${version_index} version_test) set(test_compiler_output "compiler_supports_cxx${version}") cmake_push_check_state() set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${cxx_std_flag}") check_cxx_source_compiles("${version_test}" ${test_compiler_output}) cmake_pop_check_state() if(${test_compiler_output}) set(CXX_MAX_SUPPORTED_STANDARD ${version}) set(CMAKE_CXX_FLAGS "${cxx_std_flag} ${CMAKE_CXX_FLAGS}") break() else() # Wipe the variable, as this version of the standard doesn't seem to work unset(cxx_std_flag) endif() endif() endif() endforeach() if(NOT DEFINED CXX_MAX_SUPPORTED_STANDARD) # Let's just assume every compiler at least claims C++03 compliance by now message(WARNING "\ Unable to determine C++ standard support for your compiler, falling back to C++17. \ If you know that your compiler supports a newer version of the standard, please set the CMake \ variable DISABLE_CXX_VERSION_CHECK to true and the CMake variable CXX_MAX_SUPPORTED_STANDARD \ to the highest version of the standard supported by your compiler (e.g. 20). If your compiler \ needs custom flags to switch to that standard version, you have to manually add them to \ CMAKE_CXX_FLAGS." ) set(CXX_MAX_SUPPORTED_STANDARD 17) endif() else() # We did not check version but need to set maximum supported # version for some checks. Therefore we set it to CXX_MAX_STANDARD. set(CXX_MAX_SUPPORTED_STANDARD ${CXX_MAX_STANDARD}) endif() # make sure we have at least C++17 dune_require_cxx_standard(MODULE "DUNE" VERSION 17) # perform tests # __attribute__((unused)) check_cxx_source_compiles(" int main(void) { int __attribute__((unused)) foo; return 0; }; " HAS_ATTRIBUTE_UNUSED ) # __attribute__((deprecated)) check_cxx_source_compiles(" #define DEP __attribute__((deprecated)) class bar { bar() DEP; }; class peng { } DEP; template class t_bar { t_bar() DEP; }; template class t_peng { t_peng() {}; } DEP; void foo() DEP; void foo() {} int main(void) { return 0; }; " HAS_ATTRIBUTE_DEPRECATED ) # __attribute__((deprecated("msg"))) check_cxx_source_compiles(" #define DEP __attribute__((deprecated(\"message\"))) class bar { bar() DEP; }; class peng { } DEP; template class t_bar { t_bar() DEP; }; template class t_peng { t_peng() {}; } DEP; void foo() DEP; void foo() {} int main(void) { return 0; }; " HAS_ATTRIBUTE_DEPRECATED_MSG ) # ****************************************************************************** # # Checks for standard library features # # While there are __cpp_lib_* feature test macros for all of these, those are # unfortunately unreliable, as libc++ does not have feature test macros yet. # # In order to keep the tests short, they use check_cxx_symbol_exists(). That # function can only test for macros and linkable symbols, however, so we wrap # tested types into a call to std::move(). That should be safe, as std::move() # does not require a complete type. # # ****************************************************************************** check_cxx_symbol_exists( "std::experimental::make_array" "experimental/array" DUNE_HAVE_CXX_EXPERIMENTAL_MAKE_ARRAY ) check_cxx_symbol_exists( "std::move>" "utility;experimental/type_traits" DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED ) check_cxx_symbol_exists( "std::identity" "functional" DUNE_HAVE_CXX_STD_IDENTITY ) dune-common-2.8.0/cmake/modules/DuneAddPybind11Module.cmake000066400000000000000000000062741411343567400234770ustar00rootroot00000000000000# This cmake module provides infrastructure for building modules using Pybind11 # # .. cmake_function:: dune_add_pybind11_module # # .. cmake_param:: NAME # :required: # :single: # # name of the Python module # # .. cmake_param:: SOURCES # :multi: # # source files to build shared library # # If this parameter is omitted, .cc will be used if it exists. # # .. cmake_param:: EXCLUDE_FROM_ALL # :option: # # exclude this module from the all target # # .. cmake_param:: COMPILE_DEFINITIONS # :multi: # :argname: def # # A set of compile definitions to add to the target. # Only definitions beyond the application of :ref:`add_dune_all_flags` # have to be stated. # # .. cmake_param:: CMAKE_GUARD # :multi: # :argname: condition # # A number of conditions that CMake should evaluate before adding this # module. Use this feature instead of guarding the call to # :code:`dune_add_pybind11_module` with an :code:`if` clause. # # The passed condition can be a complex expression like # `( A OR B ) AND ( C OR D )`. Mind the spaces around the parentheses. # # Example: Write CMAKE_GUARD dune-foo_FOUND if you want your module to only # build when the dune-foo module is present. # include_guard(GLOBAL) function(dune_add_pybind11_module) include(CMakeParseArguments) cmake_parse_arguments(PYBIND11_MODULE "EXCLUDE_FROM_ALL" "NAME" "SOURCES;COMPILE_DEFINITIONS;CMAKE_GUARD" ${ARGN}) if(PYBIND11_MODULE_UNPARSED_ARGUMENTS) message(WARNING "dune_add_pybind11_module: extra arguments provided (typos in named arguments?)") endif() if(NOT PYBIND11_MODULE_NAME) message(FATAL_ERROR "dune_add_pybind11_module: module name not specified") endif() if(NOT PYBIND11_MODULE_SOURCES) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${PYBIND11_MODULE_NAME}.cc) set(PYBIND11_MODULE_SOURCES ${PYBIND11_MODULE_NAME}.cc) else() message(FATAL_ERROR "dune_add_pybind11_module: no source files specified") endif() endif() foreach(condition ${PYBIND11_MODULE_CMAKE_GUARD}) separate_arguments(condition) if(NOT (${condition})) message(STATUS "not building ${PYBIND11_MODULE_NAME}, because condition ${condition} failed.") return() endif() endforeach() add_library(${PYBIND11_MODULE_NAME} SHARED ${PYBIND11_MODULE_SOURCES}) set_target_properties(${PYBIND11_MODULE_NAME} PROPERTIES PREFIX "") # force '.so' as library suffix on macOS due to a problem in Python # https://stackoverflow.com/questions/2488016/how-to-make-python-load-dylib-on-osx # and add -undefined dynamic_lookup flag to linker # https://pybind11.readthedocs.io/en/stable/compiling.html#building-manually if (APPLE) set_target_properties(${PYBIND11_MODULE_NAME} PROPERTIES SUFFIX ".so") target_link_options(${PYBIND11_MODULE_NAME} PRIVATE -undefined dynamic_lookup) endif() target_compile_definitions(${PYBIND11_MODULE_NAME} PRIVATE ${PYBIND11_MODULE_COMPILE_DEFINITIONS}) dune_target_enable_all_packages(${PYBIND11_MODULE_NAME}) if(PYBIND11_MODULE_EXCLUDE_FROM_ALL) set_property(TARGET ${PYBIND11_MODULE_NAME} PROPERTY EXCLUDE_FROM_ALL 1) endif() endfunction() dune-common-2.8.0/cmake/modules/DuneCMakeCompat.cmake000066400000000000000000000063561411343567400224560ustar00rootroot00000000000000# Module with backward compatibility implementation of newer cmake functionality # # .. cmake_module:: # # This module contains backward compatibility implementations of cmake # functionality that is not available in all cmake versions we support. # # * :ref:`dune_list_filter(...) ` for ``list(FILTER # ...)`` from cmake 3.7 # # # .. cmake_function:: dune_list_filter # # .. cmake_brief:: # # Compatibility implementation of ``list(FILTER)`` # # .. cmake_param:: list # :positional: # :single: # :required: # # Name of list variable used as both input and output. # # .. cmake_param:: # :positional: # :option: # :required: # # Whether to include or to exclude the items matching the regular # expression. # # .. cmake_param:: REGEX # :single: # :required: # :argname: regular_expression # # The regular expression to match the items against. # # Match each item in the list against the regular expression. In # ``INCLUDE`` mode the result contains all items that matched, in # ``EXCLUDE`` mode it contains all items that did not match. Store the # result back in the variable ``list`` in the scope of the caller. # # This is exactly the same as the ``list(FILTER ...)`` command available in # cmake 3.7 and onward. include_guard(GLOBAL) # list(FILTER...) was introduced in cmake 3.6, this is a compatibility # implementation for earlier cmakes function(dune_list_filter list mode REGEX regular_expression) message(DEPRECATION "dune_list_filter is deprecated and will be removed after Dune 2.8. Use list(FILTER ...) from CMake 3.6") # validate arguments if(NOT (("${mode}" STREQUAL "INCLUDE") OR ("${mode}" STREQUAL "EXCLUDE"))) message(FATAL_ERROR "unsupported mode '${mode}', must be either INCLUDE or EXCLUDE") endif() if(NOT ("${REGEX}" STREQUAL "REGEX")) message(FATAL_ERROR "dune_list_filter can only filter by regular expression") endif() if("${ARGC}" GREATER 4) message(FATAL_ERROR "extra arguments given: <${ARGN}>") endif() # cmake can't destinguish between empty lists and lists with one empty # element. This is a problem when consecutively appending elements to a # list: if the first elements we append are empty, we loose them. The # "non-empty" token makes sure we start with a non-empty list and avoid this # problem. set(matched "non-empty") set(unmatched "non-empty") foreach(item IN LISTS "${list}") # list(APPEND) does not quote the appended item (as of cmake 3.7.2), so do # it manually string(REPLACE [[;]] [[\;]] quoted_item "${item}") if("${item}" MATCHES "${regular_expression}") list(APPEND matched "${quoted_item}") else() list(APPEND unmatched "${quoted_item}") endif() endforeach(item) if("${mode}" STREQUAL "INCLUDE") set(result "${matched}") else() set(result "${unmatched}") endif() # remove the non-empty token from above. If the proper result would be a # list of one empty element, we have no way of preserving that, it will turn # into an empty list. string(REGEX REPLACE "^non-empty;?" "" result "${result}") # export set("${list}" "${result}" PARENT_SCOPE) endfunction(dune_list_filter) dune-common-2.8.0/cmake/modules/DuneCommonMacros.cmake000066400000000000000000000024361411343567400227220ustar00rootroot00000000000000# enforce C++-14 dune_require_cxx_standard(MODULE "dune-common" VERSION 14) include(DuneStreams) dune_set_minimal_debug_level() # search for lapack find_package(LAPACK) include(AddBLASLapackFlags) find_package(GMP) include(AddGMPFlags) find_package(QuadMath) include(AddQuadMathFlags) # find program for image manipulation find_package(Inkscape) include(UseInkscape) # find the threading library find_package(Threads) include(AddThreadsFlags) # find the MPI library find_package(MPI 3.0 COMPONENTS C) include(AddMPIFlags) # find library for Threading Building Blocks find_package(TBB) include(AddTBBFlags) # find libraries for graph partitioning find_package(PTScotch) include(AddPTScotchFlags) find_package(METIS) include(AddMETISFlags) find_package(ParMETIS 4.0) include(AddParMETISFlags) # try to find the Vc library set(MINIMUM_VC_VERSION) if((CMAKE_CXX_COMPILER_ID STREQUAL Clang) AND (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7)) message("Raising minimum acceptable Vc version to 1.4.1 due to use of Clang 7 (or later), see https://gitlab.dune-project.org/core/dune-common/issues/132") set(MINIMUM_VC_VERSION 1.4.1) endif() find_package(Vc ${MINIMUM_VC_VERSION} NO_MODULE) include(AddVcFlags) # Run the python extension of the Dune cmake build system include(DunePythonCommonMacros) dune-common-2.8.0/cmake/modules/DuneCxaDemangle.cmake000066400000000000000000000002771411343567400224760ustar00rootroot00000000000000message(DEPRECATION "The cmake file 'DuneCxaDemangle.cmake' is deprecated. " "Include the 'dune/common/classname.hh' header if you want to ensure that " "HAVE_CXA_DEMANGLE is defined") dune-common-2.8.0/cmake/modules/DuneDoc.cmake000066400000000000000000000051761411343567400210360ustar00rootroot00000000000000# # Module that provides a custom target make doc at the top level # directory and utility macros for creating install directives # that make sure that the files to be installed are previously # generated even if make doc was not called. # # All documentation (Latex, Doxygen) will be generated during # make doc. # It provides the following macros: # # .. cmake_function:: dune_add_latex_document # # .. cmake_brief:: # # wrapper around add_latex_document for compatibility reasons # # .. cmake_function:: create_doc_install # # .. cmake_brief:: # # creates a target for creating and installing a file # to a given directory. # # .. cmake_param:: filename # :single: # :required: # :positional: # # The name of the file to be installed. # # .. cmake_param:: targetdir # :single: # :required: # :positional: # # The directory into which the beforementioned file will be installed. # # .. cmake_param:: dependency # :single: # :required: # :positional: # # A target that gets called to create the file that will be installed. # # .. note:: # # This macro is needed, as we cannot add dependencies to the install # target. See https://gitlab.kitware.com/cmake/cmake/issues/8438 # and https://gitlab.dune-project.org/core/dune-common/issues/36 # include_guard(GLOBAL) include(UseLatexMk) if (LATEXMK_FOUND AND PDFLATEX_COMPILER) set(LATEX_USABLE TRUE) endif() add_custom_target(doc) # add the Sphinx-generated build system documentation include(DuneSphinxCMakeDoc) # Support building documentation with doxygen. include(DuneDoxygen) macro(create_doc_install filename targetdir dependency) if(LATEX_USABLE) dune_module_path(MODULE dune-common RESULT scriptdir SCRIPT_DIR) get_filename_component(targetfile ${filename} NAME) set(install_command ${CMAKE_COMMAND} -D FILES=${filename} -D DIR=${CMAKE_INSTALL_PREFIX}/${targetdir} -P ${scriptdir}/InstallFile.cmake) # create a custom target for the installation add_custom_target(install_${targetfile} ${install_command} COMMENT "Installing ${filename} to ${targetdir}" DEPENDS ${dependency}) # When installing, call cmake install with the above install target and add the file to install_manifest.txt install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build \"${CMAKE_BINARY_DIR}\" --target install_${targetfile} ) LIST(APPEND CMAKE_INSTALL_MANIFEST_FILES ${CMAKE_INSTALL_PREFIX}/${targetdir}/${targetfile})") endif() endmacro(create_doc_install) macro(dune_add_latex_document) add_latex_document(${ARGN}) endmacro(dune_add_latex_document) dune-common-2.8.0/cmake/modules/DuneDoxygen.cmake000066400000000000000000000126321411343567400217410ustar00rootroot00000000000000# Module for building documentation using doxygen. # # .. cmake_function:: add_doxygen_target # # .. cmake_param:: TARGET # :single: # # The suffix to add to the target name, default to the module name. # # .. cmake_param:: DEPENDS # :multi: # # A list of further dependencies of the doxygen documentation. # Might include :code:`mainpage.txt`. # # .. cmake_param:: OUTPUT # :single: # # Name of the output target, necessary if you don't generate html. # # This macro creates a target for building (:code:`doxygen_${ProjectName}`) and installing # (:code:`doxygen_install_${ProjectName}`) the generated doxygen documentation. # The documentation is built during the top-level :code:`make doc` call. We have added a dependency # that makes sure it is built before running :code:`make install`. # include_guard(GLOBAL) find_package(Doxygen) set_package_properties("Doxygen" PROPERTIES DESCRIPTION "Class documentation generator" URL "www.doxygen.org" PURPOSE "To generate the class documentation from C++ sources") include(CMakeParseArguments) # Set DOT_TRUE for the Doxyfile generation. if (NOT DOXYGEN_DOT_FOUND) set(DOT_TRUE '\#') endif() add_custom_target(doxygen_install) # # prepare_doxyfile() # This functions adds the necessary routines for the generation of the # Doxyfile[.in] files needed to doxygen. macro(prepare_doxyfile) message(STATUS "using ${DOXYSTYLE_FILE} to create doxystyle file") message(STATUS "using C macro definitions from ${DOXYGENMACROS_FILE} for Doxygen") # check whether module has a Doxylocal file find_file(_DOXYLOCAL Doxylocal PATHS ${CMAKE_CURRENT_SOURCE_DIR} NO_DEFAULT_PATH) if(_DOXYLOCAL) set(make_doxyfile_command ${CMAKE_COMMAND} -D DOT_TRUE=${DOT_TRUE} -D DUNE_MOD_NAME=${ProjectName} -D DUNE_MOD_VERSION=${ProjectVersion} -D DOXYSTYLE=${DOXYSTYLE_FILE} -D DOXYGENMACROS=${DOXYGENMACROS_FILE} -D DOXYLOCAL=${CMAKE_CURRENT_SOURCE_DIR}/Doxylocal -D abs_top_srcdir=${CMAKE_SOURCE_DIR} -D srcdir=${CMAKE_CURRENT_SOURCE_DIR} -D top_srcdir=${CMAKE_SOURCE_DIR} -P ${scriptdir}/CreateDoxyFile.cmake) add_custom_command(OUTPUT Doxyfile.in Doxyfile COMMAND ${make_doxyfile_command} COMMENT "Creating Doxyfile.in" DEPENDS ${DOXYSTYLE_FILE} ${DOXYGENMACROS_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/Doxylocal) else() set(make_doxyfile_command ${CMAKE_COMMAND} -D DOT_TRUE=${DOT_TRUE} -D DUNE_MOD_NAME=${ProjectName} -D DUNE_MOD_VERSION=${DUNE_MOD_VERSION} -D DOXYSTYLE=${DOXYSTYLE_FILE} -D DOXYGENMACROS=${DOXYGENMACROS_FILE} -D abs_top_srcdir=${CMAKE_SOURCE_DIR} -D top_srcdir=${CMAKE_SOURCE_DIR} -P ${scriptdir}/CreateDoxyFile.cmake) add_custom_command(OUTPUT Doxyfile.in Doxyfile COMMAND ${make_doxyfile_command} COMMENT "Creating Doxyfile.in" DEPENDS ${DOXYSTYLE_FILE} ${DOXYGENMACROS_FILE}) endif() add_custom_target(doxyfile DEPENDS Doxyfile.in Doxyfile) endmacro(prepare_doxyfile) macro(add_doxygen_target) set(options ) set(oneValueArgs TARGET OUTPUT) set(multiValueArgs DEPENDS) cmake_parse_arguments(DOXYGEN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) # default target name is the module name if(NOT DOXYGEN_TARGET) set(DOXYGEN_TARGET ${ProjectName}) endif() # default output is html if(NOT DOXYGEN_OUTPUT) set(DOXYGEN_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/html") endif() dune_module_path(MODULE dune-common RESULT scriptdir SCRIPT_DIR) if(PROJECT_NAME STREQUAL "dune-common") set(DOXYSTYLE_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Doxystyle) set(DOXYGENMACROS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/doxygen-macros) endif() message(STATUS "Using scripts from ${scriptdir} for creating doxygen stuff.") if(DOXYGEN_FOUND) prepare_doxyfile() # custom command that executes doxygen add_custom_command(OUTPUT ${DOXYGEN_OUTPUT} COMMAND ${CMAKE_COMMAND} -D DOXYGEN_EXECUTABLE=${DOXYGEN_EXECUTABLE} -P ${scriptdir}/RunDoxygen.cmake COMMENT "Building doxygen documentation. This may take a while" DEPENDS Doxyfile.in ${DOXYGEN_DEPENDS}) # Create a target for building the doxygen documentation of a module, # that is run during make doc add_custom_target(doxygen_${DOXYGEN_TARGET} DEPENDS ${DOXYGEN_OUTPUT}) add_dependencies(doc doxygen_${DOXYGEN_TARGET}) # Use a cmake call to install the doxygen documentation and create a # target for it include(GNUInstallDirs) # When installing call cmake install with the above install target install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target doxygen_${ProjectName} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) file(GLOB doxygenfiles GLOB ${CMAKE_CURRENT_BINARY_DIR}/html/*.html ${CMAKE_CURRENT_BINARY_DIR}/html/*.js ${CMAKE_CURRENT_BINARY_DIR}/html/*.png ${CMAKE_CURRENT_BINARY_DIR}/html/*.css ${CMAKE_CURRENT_BINARY_DIR}/html/*.gif ${CMAKE_CURRENT_BINARY_DIR}/*.tag ) set(doxygenfiles \"\${doxygenfiles}\") foreach(_file \${doxygenfiles}) get_filename_component(_basename \${_file} NAME) LIST(APPEND CMAKE_INSTALL_MANIFEST_FILES ${CMAKE_INSTALL_FULL_DOCDIR}/doxygen/\${_basename}) endforeach() file(INSTALL \${doxygenfiles} DESTINATION ${CMAKE_INSTALL_FULL_DOCDIR}/doxygen) message(STATUS \"Installed doxygen into ${CMAKE_INSTALL_FULL_DOCDIR}/doxygen\")") endif() endmacro(add_doxygen_target) dune-common-2.8.0/cmake/modules/DuneEnableAllPackages.cmake000066400000000000000000000371131411343567400236030ustar00rootroot00000000000000# Implementation of a simplified CMake build system. # # .. cmake_function:: dune_enable_all_packages # # .. cmake_brief:: # # Previously, the DUNE build system relied on the user to choose and add the compile and link flags # necessary to build an executable. While this offers full control to the user, it # is an error-prone procedure. # # Alternatively, users may use this function to simply add the compile flags for all # found external modules to all executables in a DUNE module. Likewise, all found libraries are # linked to all targets. # # .. cmake_param:: INCLUDE_DIRS # :multi: # # A list of include directories, that should be added to all targets. # In a standard Dune module, it is not necessary to specify anything. # # .. cmake_param:: COMPILE_DEFINITIONS # :multi: # # A list of compile definitions, that should be added to all targets. # In a standard Dune module, it is not necessary to specify anything. # # .. cmake_param:: COMPILE_OPTIONS # :multi: # # A list of non-definition compile options, that should be added to all targets. # In a standard Dune module, it is not necessary to specify anything. # # .. cmake_param:: MODULE_LIBRARIES # :multi: # # If your module contains libraries as well as programs and if the programs should automatically # link to those libraries, you *MUST* list these libraries in :code:`MODULE_LIBRARIES`. Those libraries will be # automatically created by :ref:`dune_enable_all_packages` (which internally calls :ref:`dune_add_library`) and placed # in the lib/ directory. The order of the libraries matters: if one library depends on another one, it must # be listed after its dependency. This special handling of the libraries is due to the way CMake # handle linking (in particular CMP022 and CMP038). You can later add source files to the library # anywhere in the source tree by calling :ref:`dune_library_add_sources`. # # .. cmake_param:: VERBOSE # :option: # # If this option is set, the set of compile flags, linked libraries and include directories # that is in use for all targets in the module is printed upon configuration. # # .. cmake_param:: APPEND # :option: # # If this option is set, the definitions, flags and directories specified in this function are # appended to the global collection of flags instead of being prepended. Only use it, if you know # what you are doing. # # Adds all flags and all libraries to all executables that are subsequently added in the directory # from where this function is called and from all its subdirectories (recursively). # If used, this function *MUST* be called in the top level CMakeLists.txt BEFORE adding any subdirectories! # You can optionally add additional include dirs and compile definitions that will also be applied to # all targets in the module. # # .. note:: # If you want to use :code:`dune_enable_all_packages` with an older version of CMake and your DUNE module # creates its own library, you have to manually create the library in the top-level CMakeLists.txt # file using :ref:`dune_add_library` (with all sources listed within that call), use # :ref:`dune_target_enable_all_packages` to add all packages to the library and finally list that library # under :code:`LIBRARIES` in the call to :ref:`dune_register_package_flags`. See dune-pdelab for an example of # how to do this correctly. # # While :ref:`dune_enable_all_packages` defines the user interface for this feature, developers might # also be interested in the following related functions: # # * :ref:`dune_target_enable_all_packages` # * :ref:`dune_register_package_flags` # * :ref:`dune_library_add_sources` # # .. cmake_function:: dune_target_enable_all_packages # # .. cmake_param:: TARGETS # :multi: # # A list of targets to add all flags etc. too. # # Adds all currently registered package flags (see :ref:`dune_register_package_flags`) to the given targets. # This function is mainly intended to help write DUNE modules that want to use :ref:`dune_enable_all_packages` and # define their own libraries, but need to be compatible with CMake < 3.1 # # .. cmake_function:: dune_register_package_flags # # .. cmake_param:: INCLUDE_DIRS # :multi: # # The list of include directories needed by the external package. # # .. cmake_param:: COMPILE_DEFINITIONS # :multi: # # The list of compile definitions needed by the external package. # # .. cmake_param:: COMPILE_OPTIONS # :multi: # # The list of compile options needed by the external package. # # .. cmake_param:: LIBRARIES # :multi: # # The list of libraries that the external package should link to. # The order of the input is preserved in the output. # # .. cmake_param:: APPEND # :option: # # If this option is set, the definitions, flags and directories specified in this function are # appended to the global collection of flags instead of being prepended. Only use it, if you know # what you are doing. # # To correctly implement the automatic handling of external libraries, the compile flags, include paths and link # flags of all found packages must be registered with this function. This function is only necessary for people that # want to write their own :code:`FindFooBar` CMake modules to link against additional libraries which are not supported by # the DUNE core modules. Call this function at the end of every find module. If you are using an external FindFoo # module which you cannot alter, call it after the call to :code:`find_package(foo)`. # # .. cmake_function:: dune_library_add_sources # # .. cmake_param:: module_library # :single: # :positional: # # The name of the module library target. # # .. cmake_param: SOURCES # :multi: # :required: # # The source files to add to the DUNE module library :code:`module_library`. # That library must have been created by an earlier call to :ref:`dune_enable_all_packages` # in the current DUNE module. # # Register sources for module exported library. # include_guard(GLOBAL) function(dune_register_package_flags) include(CMakeParseArguments) set(OPTIONS APPEND) set(SINGLEARGS) set(MULTIARGS COMPILE_DEFINITIONS COMPILE_OPTIONS INCLUDE_DIRS LIBRARIES) cmake_parse_arguments(REGISTRY "${OPTIONS}" "${SINGLEARGS}" "${MULTIARGS}" ${ARGN}) if(REGISTRY_UNPARSED_ARGUMENTS) message(WARNING "Unrecognized arguments for dune_register_package_flags!") endif() if(REGISTRY_APPEND) set_property(GLOBAL APPEND PROPERTY ALL_PKG_INCS "${REGISTRY_INCLUDE_DIRS}") set_property(GLOBAL APPEND PROPERTY ALL_PKG_LIBS "${REGISTRY_LIBRARIES}") set_property(GLOBAL APPEND PROPERTY ALL_PKG_DEFS "${REGISTRY_COMPILE_DEFINITIONS}") set_property(GLOBAL APPEND PROPERTY ALL_PKG_OPTS "${REGISTRY_COMPILE_OPTIONS}") else(REGISTRY_APPEND) get_property(all_incs GLOBAL PROPERTY ALL_PKG_INCS) get_property(all_libs GLOBAL PROPERTY ALL_PKG_LIBS) get_property(all_defs GLOBAL PROPERTY ALL_PKG_DEFS) get_property(all_opts GLOBAL PROPERTY ALL_PKG_OPTS) set_property(GLOBAL PROPERTY ALL_PKG_INCS "${REGISTRY_INCLUDE_DIRS}" "${all_incs}") set_property(GLOBAL PROPERTY ALL_PKG_LIBS "${REGISTRY_LIBRARIES}" "${all_libs}") set_property(GLOBAL PROPERTY ALL_PKG_DEFS "${REGISTRY_COMPILE_DEFINITIONS}" "${all_defs}") set_property(GLOBAL PROPERTY ALL_PKG_OPTS "${REGISTRY_COMPILE_OPTIONS}" "${all_opts}") endif(REGISTRY_APPEND) endfunction(dune_register_package_flags) function(dune_enable_all_packages) include(CMakeParseArguments) set(OPTIONS APPEND VERBOSE) set(SINGLEARGS) set(MULTIARGS COMPILE_DEFINITIONS COMPILE_OPTIONS INCLUDE_DIRS MODULE_LIBRARIES) cmake_parse_arguments(DUNE_ENABLE_ALL_PACKAGES "${OPTIONS}" "${SINGLEARGS}" "${MULTIARGS}" ${ARGN}) if(DUNE_ENABLE_ALL_PACKAGES_UNPARSED_ARGUMENTS) message(WARNING "Unrecognized arguments for dune_enable_all_packages!") endif() # handle additional include dirs specified in dune_enable_all_packages if(DUNE_ENABLE_ALL_PACKAGES_INCLUDE_DIRS) if(DUNE_ENABLE_ALL_PACKAGES_APPEND) set_property(GLOBAL APPEND PROPERTY ALL_PKG_INCS "${DUNE_ENABLE_ALL_PACKAGES_INCLUDE_DIRS}") else(DUNE_ENABLE_ALL_PACKAGES_APPEND) get_property(all_incs GLOBAL PROPERTY ALL_PKG_INCS) set_property(GLOBAL PROPERTY ALL_PKG_INCS "${DUNE_ENABLE_ALL_PACKAGES_INCLUDE_DIRS}" "${all_incs}") endif(DUNE_ENABLE_ALL_PACKAGES_APPEND) endif(DUNE_ENABLE_ALL_PACKAGES_INCLUDE_DIRS) # add include dirs to all targets in module get_property(all_incs GLOBAL PROPERTY ALL_PKG_INCS) include_directories(${all_incs}) # verbose output of include dirs if(DUNE_ENABLE_ALL_PACKAGES_VERBOSE) message("Include directories for this project: ${all_incs}") endif(DUNE_ENABLE_ALL_PACKAGES_VERBOSE) # handle additional compile definitions specified in dune_enable_all_packages if(DUNE_ENABLE_ALL_PACKAGES_COMPILE_DEFINITIONS) if(DUNE_ENABLE_ALL_PACKAGES_APPEND) set_property(GLOBAL APPEND PROPERTY ALL_PKG_DEFS "${DUNE_ENABLE_ALL_PACKAGES_COMPILE_DEFINITIONS}") else(DUNE_ENABLE_ALL_PACKAGES_APPEND) get_property(all_defs GLOBAL PROPERTY ALL_PKG_DEFS) set_property(GLOBAL PROPERTY ALL_PKG_DEFS "${DUNE_ENABLE_ALL_PACKAGES_COMPILE_DEFINITIONS}" "${all_defs}") endif(DUNE_ENABLE_ALL_PACKAGES_APPEND) endif(DUNE_ENABLE_ALL_PACKAGES_COMPILE_DEFINITIONS) # add compile definitions to all targets in module get_property(all_defs GLOBAL PROPERTY ALL_PKG_DEFS) # We have to do this in a loop because add_definitions() is kind of broken: even though it is supposed # to be *the* function for adding compile definitions, it does not prepend "-D" (as opposed to # target_compile_definitions(), which does). Well, whatever... foreach(_definition ${all_defs}) if(_definition) add_definitions("-D${_definition}") endif() endforeach() # verbose output of compile definitions if(DUNE_ENABLE_ALL_PACKAGES_VERBOSE) message("Compile definitions for this project: ${all_defs}") endif(DUNE_ENABLE_ALL_PACKAGES_VERBOSE) # handle additional compile options specified in dune_enable_all_packages if(DUNE_ENABLE_ALL_PACKAGES_COMPILE_OPTIONS) if(DUNE_ENABLE_ALL_PACKAGES_APPEND) set_property(GLOBAL APPEND PROPERTY ALL_PKG_OPTS "${DUNE_ENABLE_ALL_PACKAGES_COMPILE_OPTIONS}") else(DUNE_ENABLE_ALL_PACKAGES_APPEND) get_property(all_opts GLOBAL PROPERTY ALL_PKG_OPTS) set_property(GLOBAL PROPERTY ALL_PKG_OPTS "${DUNE_ENABLE_ALL_PACKAGES_COMPILE_OPTIONS}" "${all_opts}") endif(DUNE_ENABLE_ALL_PACKAGES_APPEND) endif(DUNE_ENABLE_ALL_PACKAGES_COMPILE_OPTIONS) # add compile options to all targets in module get_property(all_opts GLOBAL PROPERTY ALL_PKG_OPTS) add_compile_options(${all_opts}) # verbose output of compile definitions if(DUNE_ENABLE_ALL_PACKAGES_VERBOSE) message("Compile options for this project: ${all_opts}") endif(DUNE_ENABLE_ALL_PACKAGES_VERBOSE) # handle libraries # this is a little tricky because the libraries defined within the current module require special # handling to avoid tripping over CMake policies CMP022 and CMP038 # first add all libraries of upstream Dune modules and of external dependencies get_property(all_libs GLOBAL PROPERTY ALL_PKG_LIBS) link_libraries(${DUNE_LIBS} ${all_libs}) # now we have to do a little dance: Newer versions of CMake complain if a target links to itself, # so we have to create all targets for libraries inside the module before adding them to the set # of default libraries to link to. That works because calling link_libraries does not affect targets # which already exist. # Moroever, CMake generates a warning when creating a library without any source files, and the linker # does the same if we add an empty dummy file. We work around that problem by autogenerating a library-specific # stub source file with two functions ${lib_name}_version() and ${lib_name}_version_string() and add that # as an initial source file. # After creating the library with dune_add_library(), we add it to all future targets with a call to # link_libraries(). The user can then add the real source files by calling dune_library_add_sources() # throughout the module. if(DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES) # make sure the /lib directory exists - we need it to create the stub source file in there file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/lib") # figure out the location of the stub source template dune_module_path(MODULE dune-common RESULT script_dir SCRIPT_DIR) foreach(module_lib ${DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES}) # create the stub source file in the output directory (using a c++ compatible name)... string(REGEX REPLACE "[^a-zA-Z0-9]" "_" module_lib_mangled ${module_lib}) configure_file("${script_dir}/module_library.cc.in" "${PROJECT_BINARY_DIR}/lib/lib${module_lib}_stub.cc") # ...and create the library... dune_add_library(${module_lib} SOURCES "${PROJECT_BINARY_DIR}/lib/lib${module_lib}_stub.cc") # ...and add it to all future targets in the module link_libraries(${module_lib}) endforeach(module_lib ${DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES}) # export the DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES variable to the parent scope # this is required to make dune_library_add_sources() work (see further down) set( DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES ${DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES} PARENT_SCOPE ) endif(DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES) if(DUNE_ENABLE_ALL_PACKAGES_VERBOSE) get_property(all_libs GLOBAL PROPERTY ALL_PKG_LIBS) message("Libraries for this project: ${all_libs}") endif(DUNE_ENABLE_ALL_PACKAGES_VERBOSE) endfunction(dune_enable_all_packages) function(dune_target_enable_all_packages) foreach(_target ${ARGN}) get_property(all_incs GLOBAL PROPERTY ALL_PKG_INCS) target_include_directories(${_target} PUBLIC ${all_incs}) get_property(all_defs GLOBAL PROPERTY ALL_PKG_DEFS) target_compile_definitions(${_target} PUBLIC ${all_defs}) get_property(all_opts GLOBAL PROPERTY ALL_PKG_OPTS) target_compile_options(${_target} PUBLIC ${all_opts}) get_property(all_libs GLOBAL PROPERTY ALL_PKG_LIBS) target_link_libraries(${_target} PUBLIC ${DUNE_LIBS} ${all_libs}) endforeach() endfunction(dune_target_enable_all_packages) function(dune_library_add_sources lib) if (NOT (DEFINED DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES)) message(FATAL_ERROR "You must call dune_enable_all_packages with the MODULE_LIBRARIES option before calling dune_library_add_sources") endif() # This looks weird, but seems to be the most practical way to check for list membership, # as list(FIND ...) does not work reliably in a macro... if (NOT (";${DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES};" MATCHES ";${lib};")) message(FATAL_ERROR "Attempt to add sources to library ${lib}, which has not been defined in dune_enable_all_packages. List of libraries defined in dune_enable_all_packages: ${DUNE_ENABLE_ALL_PACKAGES_MODULE_LIBRARIES}") endif() include(CMakeParseArguments) cmake_parse_arguments(DUNE_LIBRARY_ADD_SOURCES "" "" "SOURCES" ${ARGN}) if(DUNE_LIBRARY_ADD_SOURCES_UNPARSED_ARGUMENTS) message(WARNING "Unrecognized arguments for dune_library_add_sources!") endif() foreach(source ${DUNE_LIBRARY_ADD_SOURCES_SOURCES}) if(IS_ABSOLUTE ${source}) target_sources(${lib} PRIVATE ${source}) else() target_sources(${lib} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${source}) endif() endforeach() endfunction() dune-common-2.8.0/cmake/modules/DuneExecuteProcess.cmake000066400000000000000000000037431411343567400232700ustar00rootroot00000000000000# An error checking wrapper around the cmake command execute_process # # .. cmake_command:: dune_execute_process # # .. cmake_param:: ERROR_MESSAGE # :single: # # Error message to show if command exited with non-zero exit code. # This also implies abortion of the current cmake run with a fatal error. # Note, that if this is omitted, no return code checking is done. # # A thin wrapper around the cmake command :code:`execute_process`, that # exits on non-zero exit codes. All arguments are forwarded to the actual # cmake command. # include_guard(GLOBAL) function(dune_execute_process) include(CMakeParseArguments) cmake_parse_arguments(EXECUTE "" "ERROR_MESSAGE;RESULT_VARIABLE;OUTPUT_VARIABLE;ERROR_VARIABLE" "" ${ARGN}) # Decide whether stdout and stderr have to be split if(EXECUTE_OUTPUT_VARIABLE AND EXECUTE_ERROR_VARIABLE) set(SPLIT_ERROR TRUE) set(ERRLOGVAR errlog) else() set(SPLIT_ERROR FALSE) set(ERRLOGVAR log) endif() # Call the original cmake function execute_process(${EXECUTE_UNPARSED_ARGUMENTS} RESULT_VARIABLE retcode OUTPUT_VARIABLE log ERROR_VARIABLE ${ERRLOGVAR} ) # Issue an error if requested! if(EXECUTE_ERROR_MESSAGE) if(NOT "${retcode}" STREQUAL "0") cmake_parse_arguments(ERR "" "" "COMMAND" ${EXECUTE_UNPARSED_ARGUMENTS}) if(SPLIT_ERROR) set(log "stdout:\n${log}\n\nstderr:\b${errlog}") endif() message(FATAL_ERROR "${EXECUTE_ERROR_MESSAGE}\nRun command:${ERR_COMMAND}\nReturn code: ${retcode}\nDetailed log:\n${log}") endif() endif() # Propagate logs back to the calling scope if(EXECUTE_RESULT_VARIABLE) set(${EXECUTE_RESULT_VARIABLE} ${retcode} PARENT_SCOPE) endif() if(EXECUTE_OUTPUT_VARIABLE) set(${EXECUTE_OUTPUT_VARIABLE} ${log} PARENT_SCOPE) endif() if(EXECUTE_ERROR_VARIABLE) set(${EXECUTE_ERROR_VARIABLE} ${${ERROR_VARIABLE}} PARENT_SCOPE) endif() endfunction() dune-common-2.8.0/cmake/modules/DuneInstance.cmake000066400000000000000000001046771411343567400221030ustar00rootroot00000000000000# Module to generate instantiations, typically for some template # # .. cmake_module:: # # This module can be used to generate explicit template instantiations. # Suppose you have a template test function that you want to call for a # number of template arguments. You want to explicitly instantiate the # function for each set of template arguments, and put the instanciation # into its own translation unit. (This can be beneficial in that it limits # the amount of code that the optimizer sees at once, and thus it can # reduce both memory and cpu requirements during compilation.) # # .. rubric:: Examples # # Let's say you are writing a test ``mytest.cc`` and need to call a # template function for several types:: # # #include # # int main() { # MyTestSuite suite; # # suite.test(); # suite.test(); # suite.test(); # suite.test(); # # return suite.good() ? EXIT_SUCCESS : EXIT_FAILURE; # } # # Let's further say that you want to explicitly instantiate each used # ``MyTestSuite::test()`` instance in it's own translation unit. Then you # need a series of files ``mytest_instance_bool.cc``, # ``mytest_instance_char.cc``, etc, all with essentially the same content:: # # #include # # template void MyTestSuite::test<@TYPE@>(); # # where ``@TYPE@`` is replaced by ``bool``, ``char``, etc as appropriate. # # This is however not enough: all translation units need to know which # instances of ``MyTestSuite::test()`` are instantiated explicitly so they # do not instantiate them implicitly themselves (that would violate the # one-definition rule). C++ only allows to declare individual instances as # extern, not all of them collectively, so we need to put a list of all # these instances into a header ``mytest.hh``:: # # #include # # extern template void MyTestSuite::test(); # extern template void MyTestSuite::test(); # extern template void MyTestSuite::test(); # extern template void MyTestSuite::test(); # # We also need to include that header from each translation unit in the # test, we can simply replace ``#include `` with ``#include # ``. # # This is of course tedious and prone tp break if the list of tested types # changes. To make this less fragile this module provides a series of # commands: :ref:`dune_instance_begin() `, # :ref:`dune_instance_add() `, and # :ref:`dune_instance_end() `, which can be used to # automatically generate the explicit instantiations for each type and the # contents for the header and the body of main. # # This may look like this in ``CMakeLists.txt``:: # # dune_instance_begin(FILES mytest.cc mytest.hh) # # foreach(TYPE IN ITEMS bool char int double) # dune_instance_add(ID "${TYPE}" FILES mytest_instance.cc) # endforeach(TYPE IN ITEMS bool char int double) # # dune_instance_end() # # list(FILTER DUNE_INSTANCE_GENERATED INCLUDE REGEX [[\.cc$]]) # dune_add_test(NAME mytest # SOURCES ${DUNE_INSTANCE_GENERATED}) # # The call to :ref:`dune_instance_begin() ` reads # ``mytest.cc.in`` and ``mytest.hh.in`` and splits them into embedded # templates and other content. It will replace occurrances of ``@VAR@`` # now in the other content and save the result for later. # # The call to :ref:`dune_instance_add() ` occurs in a # loop. Each call will instanciate the embedded templates extracted # earlier to replace occurance of ``@TYPE@`` by the value of the variable # ``TYPE`` set in the for loop. Then files containing explicit # instantiatons will be generated as ``mytest_instance_bool.cc``, # ``mytest_instance_bool.cc``, etc, from a template file # ``mytest_instance.cc.in``. The name of the generated files are the base # file name from the template definition with the ``ID`` inserted before # the extension. The name of the template file is the same base file name # with ``.in`` appended. # # :ref:`dune_instance_end() ` is used to write # ``mytest.cc`` and ``mytest.hh`` with the collected content from the # embedded templates. The list of generated files will be available in the # variable ``DUNE_INSTANCE_GENERATED``. # # The template files then look like this: # # ``mytest.cc.in``:: # # // @GENERATED_SOURCE@ # # #include # # #include # # int main() { # MyTestSuite suite; # # #cmake @template@ # suite.test<@TYPE@>(); # #cmake @endtemplate@ # # return suite.good() ? EXIT_SUCCESS : EXIT_FAILURE; # } # # ``mytest.hh.in``:: # # // @GENERATED_SOURCE@ # # #include # # #cmake @template@ # extern template void MyTestSuite::test<@TYPE@>(); # #cmake @endtemplate@ # # ``mytest_instance.cc.in``:: # # // @GENERATED_SOURCE@ # # #include # # #include # # template void MyTestSuite::test<@TYPE@>(); # # The ``@GENERATED_SOURCE@`` substitution is good practice, it tells a # human reader that this file was generated and what the template file was, # and it hints editors to go into read-only mode. # # .. rubric:: Embedded Templates # # The template files given in :ref:`dune_instance_begin() # ` can contain embedded templates. These will be # instantiated by :ref:`dune_instance_add() `, and all # instantiations will be concatenated together and replace the original # embedded template. # # The begin of an embedded template is marked by a line containing # ``@template@`` or ``@template NAME@``. Leaving off the name is # equivalent to an empty name. ``dune_instance_add(TEMPLATE NAME)`` will # only instanciate embedded templates whose name matches and ignore all # others. # # The end of an embedded template is marked by a line containing # ``@endtemplate@`` or ``@endtemplate NAME@``. If a name is given, it must # match the name of the embedded template it closes. If no name is given # (or the name is empty), that check is omitted. # # There may be arbitrary characters on the same line before or after the # begin and end markers. These are ignored, so you can use them for # comments or to trick your editor into proper indentation. The one # exception is that the line surrounding the marker may not contain any # ``@`` characters to avoid ambiguities. # # .. rubric:: How Files And Strings Are Generated # # The generation is done using the cmake command ``configure_file(...)`` # for template files and ``string(CONFIGURE ...)`` for template strings. # These simply substitute the current variable values, so make sure to set # up the variables to substitute before calling :ref:`dune_instance_add() # ` or :ref:`dune_instance_begin() # `. # # Refrain from using substitutions that begin with an underscore # (i.e. ``@_my_local_var@``). The generation functions in this module use # such names for their local variables and may hide the variable you are # trying to substitude. # # When instantiating files we set up a few convenience variables before # calling ``configure_file()`` that can be used in substitutions: # ``@TEMPLATE@`` contains the name of the template file. ``@INSTANCE@`` # contains the name of the file being generated, not including an implied # ``${CMAKE_CURRENT_BINARY_DIR}``. Use ``@BINDIR_INSTANCE@`` if you do # want the implied ``${CMAKE_CURRENT_BINARY_DIR}``. ``@GENERATED_SOURCE@`` # contains a one-line message that this file was generated, including the # name of the template file. # # .. rubric:: Main Interface # # These are the ones you normally use. # # * :ref:`dune_instance_begin() ` # * :ref:`dune_instance_add() ` # * :ref:`dune_instance_end() ` # * :ref:`DUNE_INSTANCE_GENERATED ` # # .. rubric:: Utilities # # You would not use these directly under normal circumstances. # # * :ref:`dune_instance_parse_file_spec() ` # * :ref:`dune_instance_from_id() ` # * :ref:`dune_instance_generate_file() ` # # # .. cmake_function:: dune_instance_begin # # .. cmake_brief:: # # Prepare for a list of instances. # # .. cmake_param:: FILES # :multi: # :argname: file_spec # # List of template files with embedded templates. # # Read the given template files, and extract embedded templates. Run the # generator on the remaining file content with the variables currently in # effect. # # .. note:: # # A matching :ref:`dune_instance_end() ` is required. # Since information is communicated through variables in the callers # scope, :ref:`dune_instance_begin() # `/:ref:`dune_instance_end() ` # blocks may not be nested inside the same scope. Since a function is a # new scope, it may safely contain a :ref:`dune_instance_begin() # `/:ref:`dune_instance_end() ` # block, even if it is itself called from one. # # # .. cmake_function:: dune_instance_add # # .. cmake_brief:: # # Instantiate a template with the currently set variable values. # # .. cmake_param:: FILES # :multi: # :argname: file_spec # # List of template file specifications. These are usually the names of # template files with the ``.in`` extension removed. See the ID # parameter for details. # # .. cmake_param:: ID # :single: # # Used to build the names of generated files. Each file specification # together with this id is given to :ref:`dune_instance_from_id() # ` to determine the name of a template file and # the name of an instance file. To get unique instance file names this # ID should usually be a list of variable values joined together by # ``_``. # # Specifically, each file specification may be of the form # ``template_file_name:base_instance_file_name``, or it may be a single # token not containing ``:``. In the latter case, if that token # contains a trailing ``.in``, that is removed and the result is the base # instance file name. The base instance file name has the ``.in`` # appended again to form the template file name. # # The template file name is used as-is to generate files from. # # The ID is mangled by replacing any runs of non-alphanumeric characters # with an underscore ``_``, and stripping any resulting underscore from # the beginning and the end. The result is inserted before any # extension into the base instance file name to form the instance file # name. # # .. cmake_param:: TEMPLATE # :single: # # Instantiate embedded templates by this name. Defaults to an empty # name, matching embedded templates without name. # # Instantiate any embedded templates that match the given template name, # substituting the current variables values. Then, generate files # according the the file specifications in the template, doing # substitutions as well. # # # .. cmake_function:: dune_instance_end # # .. cmake_brief:: # # Close a block started by :ref:`dune_instance_begin() # `, and write the files generated from the # templates given there. # # Write the files generated from the template files given in # :ref:`dune_instance_begin() `, including any content # generated from embedded templates in :ref:`dune_instance_add() # `. # # # .. cmake_function:: dune_instance_parse_file_spec # # .. cmake_brief:: # # Parse a file specification into a template file name and an instance # file name. # # .. cmake_param:: spec # :positional: # :single: # :required: # # The file specification. # # .. cmake_param:: template_var # :positional: # :single: # # Name of the variable to store the template file name in. Can be empty # to discard the template file name. # # .. cmake_param:: instance_var # :positional: # :single: # # Name of the variable to store the instance file name in. Can be empty # to discard then instance file name. # # The file specification can be the name of a template file if it has # ``.in`` at the end, or the name of an instance file if it doesn't. The # name of the other file is obtained by appending or removing ``.in``, as # applicable. Both file names can also be given explicitly in the form # ``template_file_name:instance_file_name``. # # .. note:: # # This is the function use to parse the file specifications in # :ref:`dune_instance_begin() `. It is also used # as a helper in :ref:`dune_instance_from_id() ` # to determine template file name and base instance file name. # # # .. cmake_function:: dune_instance_from_id # # .. cmake_brief:: # # Determine a template file name and an instance file name from a file # specification and a unique id. # # .. cmake_param:: file_spec # :positional: # :single: # :required: # # The file specification. # # .. cmake_param:: id # :positional: # :single: # :required: # # The id specification. This should uniquely identify an instance. # # .. cmake_param:: template_var # :positional: # :single: # # Name of the variable to store the template file name in. Can be empty # to discard the template file name. # # .. cmake_param:: instance_var # :positional: # :single: # # Name of the variable to store the instance file name in. Can be empty # to discard the instance file name. # # The file specification is handed to :ref:`dune_instance_parse_file_spec() # ` to determine a template file name and a # *base* instance file name. # # The ID is mangled by replacing any runs of non-alphanumeric characters # with an underscore ``_``, and stripping any resulting underscore from the # beginning and the end. The result is inserted before any extension into # the base instance file name to form the instance file name. # # .. note:: # # This is the function use to parse the file specifications given in # :ref:`dune_instance_add(FILES ...) `. # # # .. cmake_function:: dune_instance_apply_bindir # # .. cmake_brief:: # # Modify a filename to be relative to ``CMAKE_CURRENT_BINARY_DIR``. # # .. cmake_param:: fname_var # :positional: # :single: # :required: # # The name of the variable containing the file name. # # This is used to mimic the behaviour of ``configure_file()``. If the file # name given is not absolute, it is modified by prepending # ``${CMAKE_CURRENT_BINARY_DIR}``. # # # .. cmake_function:: dune_instance_generate_file # # .. cmake_brief:: # # Convenience replacement for ``configure_file()``: enable standard # substitutions, register files as generated, and flag the same file # being generated twice. # # .. cmake_param:: TEMPLATE # :positional: # :single: # :required: # # The name of the template file. # # .. cmake_param:: INSTANCE # :positional: # :single: # :required: # # The name of the generated file. This is assumed relative to # ``${CMAKE_CURRENT_BINARY_DIR}``. # # Make sure the variables ``TEMPLATE``, ``INSTANCE``, and # ``BINDIR_INSTANCE`` are set to the parameter values and available for # substitution. Also set the variable ``GENERATED_SOURCE`` to a one-line # message that tells a human reader that this file is generated, and the # name of the template file it was generated from. The message also # includes hints for common editors telling them to switch to read-only # mode. # # Then generate the file as if by ``configure_file()``. # # If the instance file has been registered as a generated source file # before, this function generates a fatal error. This ensures that any # accidential attempt to generate the same file twice is caught. As a # special exception, if the generated content is the same as before, the # error is silently skipped. # # # .. cmake_variable:: DUNE_INSTANCE_GENERATED # # After :ref:`dune_instance_end() `, this holds the list # of files that were generated. The list entries include an implied # ``${CMAKE_CURRENT_BINARY_DIR}``, as appropriate. # # Do not rely on the value of this variable and do not modify it inside a # :ref:`dune_instance_begin() # `/:ref:`dune_instance_end() ` # block. include_guard(GLOBAL) # macro to print additional information to the cmake output file. # Note: in cmake 3.15 this is available through the message(VERBOSE "...") function. macro(message_verbose TEXT) if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.15") message(VERBOSE "${TEXT}") else() file(APPEND ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log "${TEXT}\n") endif() endmacro(message_verbose) ###################################################################### # # Coping with cmake list shortcomings # # We use these commands internally to quote text before adding it to lists as # an element, and to unquote elements again after extracting them. The quoted # text is # - free of ';' characters. This avoids problems when using list(APPEND), # which does not quote ';' characters inside the appended element. It would # also avoid problems with list(INSERT), which mangles any cmake quoting in # the list it inserts to, but we don't actually use that command. # - free of '\' characters. This avoids problems with a list element that # ends in a '\' merging with the next element, because the '\' quotes the # ';' that is used to seperate the elements # - non-empty. This avoids the problem that cmake can't destinguish between # an empty list and a list with one empty element. function(dune_instance_quote_element VAR) set(content "${${VAR}}") string(REPLACE [[$]] [[$s]] content "${content}") string(REPLACE [[;]] [[$:]] content "${content}") string(REPLACE [[\]] [[$/]] content "${content}") if(content STREQUAL "") set(content [[$@]]) endif() set("${VAR}" "${content}" PARENT_SCOPE) endfunction(dune_instance_quote_element) function(dune_instance_unquote_element VAR) set(content "${${VAR}}") string(REPLACE [[$@]] [[]] content "${content}") string(REPLACE [[$/]] [[\]] content "${content}") string(REPLACE [[$:]] [[;]] content "${content}") string(REPLACE [[$s]] [[$]] content "${content}") set("${VAR}" "${content}" PARENT_SCOPE) endfunction(dune_instance_unquote_element) ###################################################################### # # instance name and template name manipulation # function(dune_instance_parse_file_spec spec template_var instance_var) string(REPLACE ":" ";" spec_items "${spec}") list(LENGTH spec_items len) # check arguments if(len GREATER 2) message(FATAL_ERROR "too many items in file specification: ${spec}") endif(len GREATER 2) if(len EQUAL 0) message(FATAL_ERROR "empty file specification") endif(len EQUAL 0) # use as-is if(len EQUAL 2) list(GET spec_items 0 instance) list(GET spec_items 1 template) endif(len EQUAL 2) # deduce if(len EQUAL 1) string(REGEX REPLACE ".in\\$" "" instance "${spec}") set(template "${instance}.in") endif(len EQUAL 1) #export if(NOT ("${template_var}" STREQUAL "")) set("${template_var}" "${template}" PARENT_SCOPE) endif(NOT ("${template_var}" STREQUAL "")) if(NOT ("${instance_var}" STREQUAL "")) set("${instance_var}" "${instance}" PARENT_SCOPE) endif(NOT ("${instance_var}" STREQUAL "")) endfunction(dune_instance_parse_file_spec) # build output file name: parse the file_spec into a template name and a base # instance name. Mangle the ID by replacing anything special with "_" and # intersperse the result between basename and extension of the base instance # name. Use the result as the instance name. function(dune_instance_from_id file_spec id template_var instance_var) dune_instance_parse_file_spec("${file_spec}" template base) # split into prefix and suffix if(base MATCHES "\\.") string(REGEX REPLACE "\\.[^.]*\$" "" prefix "${base}") string(REGEX REPLACE "^.*(\\.[^.]*)\$" "\\1" suffix "${base}") else(base MATCHES "\\.") set(prefix "${base}") set(suffix) endif(base MATCHES "\\.") # mangle the id string(REGEX REPLACE "[^a-zA-Z0-9]+" "_" mangled_id "${id}") string(REGEX REPLACE "^_+" "" mangled_id "${mangled_id}") string(REGEX REPLACE "_+\$" "" mangled_id "${mangled_id}") if(mangled_id STREQUAL "") message(FATAL_ERROR "\"${id}\" is empty after mangling") endif(mangled_id STREQUAL "") #export if(NOT ("${template_var}" STREQUAL "")) set("${template_var}" "${template}" PARENT_SCOPE) endif(NOT ("${template_var}" STREQUAL "")) if(NOT ("${instance_var}" STREQUAL "")) set("${instance_var}" "${prefix}_${mangled_id}${suffix}" PARENT_SCOPE) endif(NOT ("${instance_var}" STREQUAL "")) endfunction(dune_instance_from_id) # mimic the behaviour of configure_file(), placing relative paths in the # current binary dir function(dune_instance_apply_bindir fname_var) if(NOT (IS_ABSOLUTE ${fname_var})) set(${fname_var} "${CMAKE_CURRENT_BINARY_DIR}/${${fname_var}}" PARENT_SCOPE) endif() endfunction(dune_instance_apply_bindir) ###################################################################### # # File generation # function(dune_instance_set_generated) # prepare instance substitution variables set(GENERATED_SOURCE "generated from ${TEMPLATE} by cmake -*- buffer-read-only:t -*- vim: set readonly:" PARENT_SCOPE) set(BINDIR_INSTANCE "${INSTANCE}") dune_instance_apply_bindir(BINDIR_INSTANCE) set(BINDIR_INSTANCE "${BINDIR_INSTANCE}" PARENT_SCOPE) endfunction(dune_instance_set_generated) # Read a template file and split it into three lists # - content_parts contains the parts before, between, and after templates # - template_parts contains the content of each template # - template_names contains the names of each template # The elements in the lists are quoted using dune_instance_quote_element() to # protect against problems with empty elements and against cmakes list() # command butchering it's own quoting. function(dune_instance_parse_embedded name content_parts template_parts template_names) message_verbose("Parsing ${name} for embedded templates") file(READ "${name}" content) # ensure that the file content ends in a newline, which makes searching for # template marker easier string(APPEND content "\n") set(content_list "") set(template_list "") set(template_name_list "") set(acc "") set(lineno 0) set(in_template FALSE) while(NOT (content STREQUAL "")) string(FIND "${content}" "\n" nextline) math(EXPR nextline "${nextline} + 1") string(SUBSTRING "${content}" 0 "${nextline}" line) string(SUBSTRING "${content}" "${nextline}" -1 content) math(EXPR lineno "${lineno} + 1") if(line MATCHES "(.*)(@((end)?template)([ \t]+([-+._/0-9a-zA-Z]*))?@)(.*)") set(prefix "${CMAKE_MATCH_1}") set(sep "${CMAKE_MATCH_2}") set(sep_keyword "${CMAKE_MATCH_3}") set(sep_name "${CMAKE_MATCH_6}") set(sep_suffix "${CMAKE_MATCH_7}") if(in_template) if(NOT (sep_keyword STREQUAL "endtemplate")) message(FATAL_ERROR "\ ${name}:${lineno}: '${sep}' nested inside... ${name}:${template_lineno}: ...'${template_sep}' here") endif() if(NOT ((sep_name STREQUAL "") OR (sep_name STREQUAL template_name))) message(FATAL_ERROR "\ ${name}:${template_lineno}: '${template_sep}' closed by nonmatching... ${name}:${lineno}: ...'${sep}' here") endif() dune_instance_quote_element(acc) list(APPEND template_list "${acc}") dune_instance_quote_element(template_name) list(APPEND template_name_list "${template_name}") set(in_template FALSE) else() if(NOT (sep_keyword STREQUAL "template")) message(FATAL_ERROR "${name}:${lineno}: Lone '${sep}'") endif() dune_instance_quote_element(acc) list(APPEND content_list "${acc}") set(template_sep "${sep}") set(template_name "${sep_name}") set(template_lineno "${lineno}") set(in_template TRUE) endif() set(acc "") else() # line did not match seperator string(APPEND acc "${line}") endif() endwhile() if(in_template) message(FATAL_ERROR "${name}:${template_lineno}: Unclosed '${template_sep}'") endif() dune_instance_quote_element(acc) list(APPEND content_list "${acc}") set("${content_parts}" "${content_list}" PARENT_SCOPE) set("${template_parts}" "${template_list}" PARENT_SCOPE) set("${template_names}" "${template_name_list}" PARENT_SCOPE) endfunction(dune_instance_parse_embedded) # Take the name of a list variable containing content parts other then # embedded templates and instanciate each part. Put the result back into the # same variable. List elements are quoted. function(dune_instance_generate_parts _parts_list) set(_acc "") foreach(_part IN LISTS "${_parts_list}") dune_instance_unquote_element(_part) string(CONFIGURE "${_part}" _part) dune_instance_quote_element(_part) list(APPEND _acc "${_part}") endforeach(_part) set("${_parts_list}" "${_acc}" PARENT_SCOPE) endfunction(dune_instance_generate_parts) function(dune_instance_generate_file TEMPLATE INSTANCE) if(("${INSTANCE}" STREQUAL "") OR ("${TEMPLATE}" STREQUAL "")) message(FATAL_ERROR "need both INSTANCE and TEMPLATE") endif(("${INSTANCE}" STREQUAL "") OR ("${TEMPLATE}" STREQUAL "")) # prepare instance substitution variables dune_instance_set_generated() # do the generation message_verbose("Generating ${TEMPLATE} -> ${INSTANCE}") file(READ "${TEMPLATE}" _content) string(CONFIGURE "${_content}" _content) # make sure we did not generate this file before get_property(_seen SOURCE "${BINDIR_INSTANCE}" PROPERTY DUNE_INSTANCE_GENERATED) if(_seen) file(READ "${BINDIR_INSTANCE}" _oldcontent) if(NOT (_content STREQUAL _oldcontent)) message(FATAL_ERROR "Attempt to generate ${INSTANCE} (from ${TEMPLATE}), " "which has already been generated with different content") endif() # otherwise, the content matches, so nothing to do else(_seen) # _seen was false, but the file may still be around from a previous cmake # run, only write if changed to avoid recompilations dune_write_changed_file("${BINDIR_INSTANCE}" "${_content}") set_property(SOURCE "${BINDIR_INSTANCE}" PROPERTY DUNE_INSTANCE_GENERATED TRUE) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${TEMPLATE}") endif(_seen) endfunction(dune_instance_generate_file) # only write if the content changes, avoiding recompilations function(dune_write_changed_file name content) if(EXISTS "${name}") file(READ "${name}" oldcontent) if(content STREQUAL oldcontent) return() endif() endif() file(WRITE "${name}" "${content}") endfunction(dune_write_changed_file) ###################################################################### # # High-level interface commands # function(dune_instance_begin) cmake_parse_arguments(_arg "" # options "" # one_value_keywords "FILES" # multi_value_keywords ${ARGV} ) if(DEFINED _arg_UNPARSED_ARGUMENTS) message(FATAL_ERROR "unrecognized arguments: ${_arg_UNPARSED_ARGUMENTS}") endif(DEFINED _arg_UNPARSED_ARGUMENTS) set(_all_content_parts "") set(_all_template_parts "") set(_all_template_names "") foreach(_spec IN LISTS _arg_FILES) dune_instance_parse_file_spec("${_spec}" TEMPLATE INSTANCE) dune_instance_set_generated() # reconfigure if the input template file changes set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${TEMPLATE}") dune_instance_parse_embedded("${TEMPLATE}" _file_content_parts _file_template_parts _file_template_names) dune_instance_generate_parts(_file_content_parts) dune_instance_quote_element(_file_content_parts) list(APPEND _all_content_parts "${_file_content_parts}") dune_instance_quote_element(_file_template_parts) list(APPEND _all_template_parts "${_file_template_parts}") dune_instance_quote_element(_file_template_names) list(APPEND _all_template_names "${_file_template_names}") endforeach(_spec) set(_DUNE_INSTANCE_GLOBAL_FILES "${_arg_FILES}" PARENT_SCOPE) set(_DUNE_INSTANCE_CONTENT_PARTS "${_all_content_parts}" PARENT_SCOPE) set(_DUNE_INSTANCE_TEMPLATE_PARTS "${_all_template_parts}" PARENT_SCOPE) set(_DUNE_INSTANCE_TEMPLATE_NAMES "${_all_template_names}" PARENT_SCOPE) set(DUNE_INSTANCE_GENERATED "" PARENT_SCOPE) endfunction(dune_instance_begin) function(dune_instance_add) cmake_parse_arguments(_arg "" # options "ID;TEMPLATE" # one_value_keywords "FILES" # multi_value_keywords ${ARGV} ) if(DEFINED _arg_UNPARSED_ARGUMENTS) message(FATAL_ERROR "unrecognized arguments: ${_arg_UNPARSED_ARGUMENTS}") endif(DEFINED _arg_UNPARSED_ARGUMENTS) # ensure _arg_TEMPLATE is set, even if it is the empty value set(_arg_TEMPLATE "${_arg_TEMPLATE}") set(_template_used FALSE) ###################################################################### # Instantiate global (list) templates set(_all_content_parts "") list(LENGTH _DUNE_INSTANCE_GLOBAL_FILES _file_count) foreach(_file_index RANGE "${_file_count}") # filter out the end of the range, this also works with empty ranges if(_file_index EQUAL _file_count) break() endif() list(GET _DUNE_INSTANCE_GLOBAL_FILES "${_file_index}" _spec) dune_instance_parse_file_spec("${_spec}" TEMPLATE INSTANCE) dune_instance_set_generated() list(GET _DUNE_INSTANCE_CONTENT_PARTS "${_file_index}" _content_parts) dune_instance_unquote_element(_content_parts) list(GET _DUNE_INSTANCE_TEMPLATE_PARTS "${_file_index}" _template_parts) dune_instance_unquote_element(_template_parts) list(GET _DUNE_INSTANCE_TEMPLATE_NAMES "${_file_index}" _template_names) dune_instance_unquote_element(_template_names) set(_content_parts_result "") list(LENGTH _template_parts _parts_count) foreach(_part_index RANGE "${_parts_count}") list(GET _content_parts "${_part_index}" _content_part) # The list of template parts should be one shorter than the list of # content parts if(_part_index LESS _parts_count) list(GET _template_names "${_part_index}" _template_name) dune_instance_unquote_element(_template_name) if(_template_name STREQUAL _arg_TEMPLATE) set(_template_used TRUE) list(GET _template_parts "${_part_index}" _template_part) dune_instance_unquote_element(_template_part) string(CONFIGURE "${_template_part}" _result) dune_instance_unquote_element(_content_part) string(APPEND _content_part "${_result}") dune_instance_quote_element(_content_part) endif() endif() list(APPEND _content_parts_result "${_content_part}") endforeach(_part_index) dune_instance_quote_element(_content_parts_result) list(APPEND _all_content_parts "${_content_parts_result}") endforeach(_file_index) set(_DUNE_INSTANCE_CONTENT_PARTS "${_all_content_parts}" PARENT_SCOPE) ###################################################################### # instantiate per instance templates foreach(_spec IN LISTS _arg_FILES) set(_template_used TRUE) dune_instance_from_id("${_spec}" "${_arg_ID}" _template_file _instance_file) set(_bindir_instance_file "${_instance_file}") dune_instance_apply_bindir(_bindir_instance_file) dune_instance_generate_file("${_template_file}" "${_instance_file}") list(FIND DUNE_INSTANCE_GENERATED "${_bindir_instance_file}" _found_pos) if(_found_pos EQUAL -1) list(APPEND DUNE_INSTANCE_GENERATED "${_bindir_instance_file}") endif() endforeach(_spec) # if we did not instantiate anything, that is probably an error if(NOT _template_used) message(FATAL_ERROR "No embedded template matched template '${_arg_TEMPLATE}', and no instance template files were given") endif() set(DUNE_INSTANCE_GENERATED "${DUNE_INSTANCE_GENERATED}" PARENT_SCOPE) endfunction(dune_instance_add) function(dune_instance_end) if(ARGC GREATER 0) message(FATAL_ERROR "dune_instance_end() does not take any arguments") endif() ###################################################################### # Write global instances list(LENGTH _DUNE_INSTANCE_GLOBAL_FILES _file_count) foreach(_file_index RANGE "${_file_count}") # filter out the end of the range, this also works with empty ranges if(_file_index EQUAL _file_count) break() endif() list(GET _DUNE_INSTANCE_GLOBAL_FILES "${_file_index}" _spec) dune_instance_parse_file_spec("${_spec}" TEMPLATE INSTANCE) set(BINDIR_INSTANCE "${INSTANCE}") dune_instance_apply_bindir(BINDIR_INSTANCE) # make sure we did not generate this file before get_property(_seen SOURCE "${BINDIR_INSTANCE}" PROPERTY DUNE_INSTANCE_GENERATED) if("${_seen}") message(FATAL_ERROR "Attempt to generate ${INSTANCE} (from ${TEMPLATE}), " "which has already been generated") endif("${_seen}") list(GET _DUNE_INSTANCE_CONTENT_PARTS "${_file_index}" _content_parts) dune_instance_unquote_element(_content_parts) set(_content "") foreach(_part IN LISTS _content_parts) dune_instance_unquote_element(_part) string(APPEND _content "${_part}") endforeach(_part) # remove the final newline that we appended when reading the template file string(REGEX REPLACE "\n\$" "" _content "${_content}") message_verbose("Writing ${INSTANCE}") # only write if the content changes, avoiding recompilations dune_write_changed_file("${BINDIR_INSTANCE}" "${_content}") set_property(SOURCE "${BINDIR_INSTANCE}" PROPERTY DUNE_INSTANCE_GENERATED TRUE) list(APPEND DUNE_INSTANCE_GENERATED "${BINDIR_INSTANCE}") endforeach(_file_index) set(DUNE_INSTANCE_GENERATED "${DUNE_INSTANCE_GENERATED}" PARENT_SCOPE) endfunction(dune_instance_end) dune-common-2.8.0/cmake/modules/DuneMPI.cmake000066400000000000000000000001771411343567400207520ustar00rootroot00000000000000message(DEPRECATION "The cmake file 'DuneMPI.cmake' is deprecated. Include 'AddMPIFlags.cmake' instead.") include(AddMPIFlags) dune-common-2.8.0/cmake/modules/DuneMacros.cmake000066400000000000000000001355571411343567400215640ustar00rootroot00000000000000# Core DUNE module for CMake. # # Documentation of the public API defined in this module: # # .. cmake_function:: dune_project # # Initialize a Dune module. This function needs to be run from every # top-level CMakeLists.txt file. It sets up the module, defines basic # variables and manages depedencies. Don't forget to call # :ref:`finalize_dune_project` afterwards. # # .. cmake_function:: finalize_dune_project # # Finalize a Dune module. This function needs to be run at the end of # every top-level CMakeLists.txt file. Among other things it creates # the cmake package configuration files. Modules can add additional # entries to these files by setting the variable @${ProjectName}_INIT. # # .. cmake_function:: target_link_libraries # # .. cmake_brief:: # # Overwrite of CMake's :code:`target_link_libraries`. If no interface key # word (like PUBLIC, INTERFACE, PRIVATE etc.) is given, PUBLIC is added. # This is to fix problems with CMP0023. # # .. cmake_param:: basename # # .. cmake_function:: dune_add_library # # .. cmake_brief:: # # Add a library to a Dune module! # # .. cmake_param:: basename # :single: # :required: # :positional: # # The basename for the library. On Unix this created :code:`lib.so` # and :code:`lib.a` # # .. cmake_param:: NO_EXPORT # :option: # # If omitted the library is exported for usage in other modules. # # .. cmake_param:: ADD_LIBS # :multi: # # A list of libraries that should be incorporated into this library. # # .. cmake_param:: APPEND # :option: # # Whether the library should be appended to the # exported libraries. If there a DUNE module must # make several libraries available, then first one # must not use this option but the others have to # use it. Otherwise only the last library will be # exported as the others will be overwritten. # # .. cmake_param:: OBJECT # :option: # # .. note:: # This feature will very likely vanish in Dune 3.0 # # .. cmake_param:: SOURCES # :multi: # :required: # # The source files from which to build the library. # # .. cmake_param:: COMPILE_FLAGS # :single: # # Any additional compile flags for building the library. # # .. cmake_function:: dune_target_link_libraries # # .. cmake_param:: BASENAME # # .. cmake_param:: LIBRARIES # # Link libraries to the static and shared version of # library BASENAME # # # .. cmake_function:: add_dune_all_flags # # .. cmake_param:: targets # :single: # :required: # :positional: # # The targets to add the flags of all external libraries to. # # This function is superseded by :ref:`dune_target_enable_all_packages`. # # Documentation of internal macros in this module: # # dune_module_to_uppercase(upper_name module_name) # # Converts a module name given by module_name into an uppercase string # upper_name where all dashes (-) are replaced by underscores (_) # Example: dune-common -> DUNE_COMMON # # dune_module_information(MODULE_DIR [QUIET]) # # Parse ${MODULE_DIR}/dune.module and provide that information. # If the second argument is QUIET no status message is printed. # # dune_create_dependency_tree() # # Creates the dependency tree of the module. # # dune_module_to_macro(_macro_name, _dune_module) # # Converts a module name given by _dune_module into a string _macro_name # where all dashes (-) are removed and letters after a dash are capitalized # Example: dune-grid-howto -> DuneGridHowto # # _macro_name: variable where the name will be stored. # _dune_module: the name of the dune module. # # dune_regenerate_config_cmake() # # Creates a new config_collected.h.cmake file in ${CMAKE_CURRENT_BINARY_DIR} that # consists of entries from ${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake # and includes non-private entries from the config.h.cmake files # of all dependent modules. # Finally config.h is created from config_collected.h.cmake. # include_guard(GLOBAL) enable_language(C) # Enable C to skip CXX bindings for some tests. # By default use -pthread flag. This option is set at the beginning to enforce it for # find_package(Threads) everywhere set(THREADS_PREFER_PTHREAD_FLAG TRUE CACHE BOOL "Prefer -pthread compiler and linker flag") include(FeatureSummary) include(DuneEnableAllPackages) include(DuneTestMacros) include(OverloadCompilerFlags) include(DuneSymlinkOrCopy) include(DunePathHelper) include(DuneExecuteProcess) macro(target_link_libraries) # do nothing if not at least the two arguments target and scope are passed if(${ARGC} GREATER_EQUAL 2) target_link_libraries_helper(${ARGN}) endif() endmacro(target_link_libraries) # helper for overwritten target_link_libraries to handle arguments more easily macro(target_link_libraries_helper TARGET SCOPE) if(${SCOPE} MATCHES "^(PRIVATE|INTERFACE|PUBLIC|LINK_PRIVATE|LINK_PUBLIC|LINK_INTERFACE_LIBRARIES)$") _target_link_libraries(${TARGET} ${SCOPE} ${ARGN}) else() message(DEPRECATION "Calling target_link_libraries without the argument is deprecated.") _target_link_libraries(${TARGET} PUBLIC ${SCOPE} ${ARGN}) endif() endmacro(target_link_libraries_helper) # Converts a module name given by _module into an uppercase string # _upper where all dashes (-) are replaced by underscores (_) # Example: dune-common -> DUNE_COMMON macro(dune_module_to_uppercase _upper _module) string(TOUPPER "${_module}" ${_upper}) string(REPLACE "-" "_" ${_upper} "${${_upper}}") endmacro(dune_module_to_uppercase _upper _module) macro(find_dune_package module) include(CMakeParseArguments) cmake_parse_arguments(DUNE_FIND "REQUIRED" "VERSION" "" ${ARGN}) if(DUNE_FIND_REQUIRED) set(required REQUIRED) set_package_properties(${module} PROPERTIES TYPE REQUIRED) set(_warning_level "FATAL_ERROR") else() unset(required) set(_warning_level "WARNING") set_package_properties(${module} PROPERTIES TYPE OPTIONAL) endif() if(DUNE_FIND_VERSION MATCHES "(>=|=|<=).*") string(REGEX REPLACE "(>=|=|<=)(.*)" "\\1" DUNE_FIND_VERSION_OP ${DUNE_FIND_VERSION}) string(REGEX REPLACE "(>=|=|<=)(.*)" "\\2" DUNE_FIND_VERSION_NUMBER ${DUNE_FIND_VERSION}) string(STRIP ${DUNE_FIND_VERSION_NUMBER} DUNE_FIND_VERSION_NUMBER) extract_major_minor_version("${DUNE_FIND_VERSION_NUMBER}" DUNE_FIND_VERSION) set(DUNE_FIND_VERSION_STRING "${DUNE_FIND_VERSION_MAJOR}.${DUNE_FIND_VERSION_MINOR}.${DUNE_FIND_VERSION_REVISION}") else() set(DUNE_FIND_VERSION_STRING "0.0.0") endif() if(NOT ${module}_FOUND) if(NOT (${module}_DIR OR ${module}_ROOT OR "${CMAKE_PREFIX_PATH}" MATCHES ".*${module}.*")) string(REPLACE ${ProjectName} ${module} ${module}_DIR ${PROJECT_BINARY_DIR}) endif() find_package(${module} NO_CMAKE_PACKAGE_REGISTRY) endif() if(NOT ${module}_FOUND AND NOT CMAKE_DISABLE_FIND_PACKAGE_${module}) message(STATUS "No full CMake package configuration support available." " Falling back to pkg-config.") # use pkg-config find_package(PkgConfig) if(NOT PKG_CONFIG_FOUND AND required) message(FATAL_ERROR "Could not find module ${module}. We tried to use" "pkg-config but could not find it. ") endif() pkg_check_modules (${module} ${required} ${module}${DUNE_FIND_VERSION}) set(${module}_FAKE_CMAKE_PKGCONFIG TRUE) endif() if(${module}_FAKE_CMAKE_PKGCONFIG) # compute the path to the libraries if(${module}_LIBRARIES) unset(_module_lib) foreach(lib ${${module}_LIBRARIES}) foreach(libdir ${${module}_LIBRARY_DIRS}) if(EXISTS ${libdir}/lib${lib}.a) set(_module_lib ${libdir}/lib${lib}.a) set(_module_lib_static "STATIC") endif() if(EXISTS ${libdir}/lib${lib}.so) set(_module_lib ${libdir}/lib${lib}.so) set(_module_lib_static "") endif() if(_module_lib) #import library add_library(${lib} ${_module_lib_static} IMPORTED) set_property(TARGET ${lib} APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG) set_target_properties(${lib} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_NOCONFIG "CXX" IMPORTED_LOCATION_NOCONFIG "${_module_lib}") break() endif() endforeach() endforeach() endif() if(NOT ${module}_MODULE_PATH) if(${module}_INCLUDE_DIRS) list(GET ${module}_INCLUDE_DIRS 0 _dir) if(EXISTS ${_dir}/../share/dune/cmake/modules) set(${module}_MODULE_PATH ${_dir}/../share/dune/cmake/modules) endif() endif() endif() unset(${module}_FAKE_CMAKE_PKGCONFIG) endif() if(${module}_FOUND) # parse other module's dune.module file to generate variables for config.h unset(${module}_dune_module) foreach(_dune_module_file ${${module}_PREFIX}/dune.module ${${module}_PREFIX}/lib/dunecontrol/${module}/dune.module ${${module}_PREFIX}/lib64/dunecontrol/${module}/dune.module) if(EXISTS ${_dune_module_file}) get_filename_component(_dune_module_file_path ${_dune_module_file} PATH) dune_module_information(${_dune_module_file_path})# QUIET) set(${module}_dune_module 1) set(DUNE_FIND_MOD_VERSION_STRING "${DUNE_VERSION_MAJOR}.${DUNE_VERSION_MINOR}.${DUNE_VERSION_REVISION}") # check whether dependency mathes version requirement unset(module_version_wrong) if(DUNE_FIND_VERSION_OP MATCHES ">=") if(NOT (DUNE_FIND_MOD_VERSION_STRING VERSION_EQUAL DUNE_FIND_VERSION_STRING OR DUNE_FIND_MOD_VERSION_STRING VERSION_GREATER DUNE_FIND_VERSION_STRING)) set(module_version_wrong 1) endif() elseif(DUNE_FIND_VERSION_OP MATCHES "<=") if(NOT (DUNE_FIND_MOD_VERSION_STRING VERSION_EQUAL DUNE_FIND_VERSION_STRING OR DUNE_FIND_MOD_VERSION_STRING VERSION_LESS DUNE_FIND_VERSION_STRING)) set(module_version_wrong 1) endif() elseif(DUNE_FIND_VERSION_OP MATCHES "=" AND NOT (DUNE_FIND_MOD_VERSION_STRING VERSION_EQUAL DUNE_FIND_VERSION_STRING)) set(module_version_wrong 1) endif() endif() endforeach() if(NOT ${module}_dune_module) message(${_warning_level} "Could not find dune.module file for module ${module} " "in ${${module}_PREFIX}, ${${module}_PREFIX}/lib/dunecontrol/${module}/, " "${${module}_PREFIX}/lib64/dunecontrol/${module}/dune.module") set(${module}_FOUND OFF) endif() if(module_version_wrong) message(${_warning_level} "Could not find requested version of module ${module}. " "Requested version was ${DUNE_FIND_VERSION}, found version is ${DUNE_FIND_MOD_VERSION_STRING}") set(${module}_FOUND OFF) endif() else(${module}_FOUND) if(required) message(FATAL_ERROR "Could not find required module ${module}.") endif() endif() set(DUNE_${module}_FOUND ${${module}_FOUND}) endmacro(find_dune_package module) macro(extract_line HEADER OUTPUT FILE_NAME) set(REGEX "^${HEADER}[ ]*[^\\n]+") file(STRINGS "${FILE_NAME}" OUTPUT1 REGEX "${REGEX}") if(OUTPUT1) set(REGEX "^[ ]*${HEADER}[ ]*(.+)[ ]*$") string(REGEX REPLACE ${REGEX} "\\1" ${OUTPUT} "${OUTPUT1}") else(OUTPUT1) set(OUTPUT OUTPUT-NOTFOUND) endif() endmacro(extract_line) # # split list of modules, potentially with version information # into list of modules and list of versions # macro(split_module_version STRING MODULES VERSIONS) set(REGEX "[a-zA-Z0-9-]+[ ]*(\\([ ]*([^ ]+)?[ ]*[^ ]+[ ]*\\))?") string(REGEX MATCHALL "${REGEX}" matches "${STRING}") set(${MODULES} "") set(${VERSIONS} "") foreach(i ${matches}) string(REGEX REPLACE "^([a-zA-Z0-9-]+).*$" "\\1" mod ${i}) string(REGEX MATCH "\\([ ]*(([^ ]+)?[ ]*[^ ]+)[ ]*\\)" have_version ${i}) if(have_version) string(REGEX REPLACE "^\\([ ]*([^ ]*[ ]*[^ ]+)[ ]*\\)$" "\\1" version ${have_version}) else() set(version " ") # Mark as no version requested. # Having a space is mandatory as we will append it to a list # and an empty string will not be treated as entry we append to it. endif() list(APPEND ${MODULES} ${mod}) list(APPEND ${VERSIONS} ${version}) endforeach() endmacro(split_module_version) # # Convert a string with spaces in a list which is a string with semicolon # function(convert_deps_to_list var) string(REGEX REPLACE "([a-zA-Z0-9\\)]) ([a-zA-Z0-9])" "\\1;\\2" ${var} ${${var}}) set(${var} ${${var}} PARENT_SCOPE) endfunction(convert_deps_to_list var) # # extracts major, minor, and revision from version string # function(extract_major_minor_version version_string varname) string(REGEX REPLACE "([0-9]+).*" "\\1" ${varname}_MAJOR "${version_string}") string(REGEX REPLACE "[0-9]+\\.([0-9]+).*" "\\1" ${varname}_MINOR "${version_string}") string(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" ${varname}_REVISION "${version_string}") set(${varname}_MAJOR "${${varname}_MAJOR}" PARENT_SCOPE) # make variable accessible in parent scope # remove false matches in version string and export to parent scop string(REGEX MATCH "[^0-9]" NON_NUMBER_CHARACTER "${${varname}_MINOR}") if(NON_NUMBER_CHARACTER) set(${varname}_MINOR "0" PARENT_SCOPE) else() set(${varname}_MINOR ${${varname}_MINOR} PARENT_SCOPE) endif() string(REGEX MATCH "[^0-9]" NON_NUMBER_CHARACTER "${${varname}_REVISION}") if(NON_NUMBER_CHARACTER) set(${varname}_REVISION "0" PARENT_SCOPE) else() set(${varname}_REVISION ${${varname}_REVISION} PARENT_SCOPE) endif() endfunction(extract_major_minor_version version_string varname) # add dune-common version from dune.module to config.h # optional second argument is verbosity macro(dune_module_information MODULE_DIR) # find version strings extract_line("Version:" MODULE_LINE "${MODULE_DIR}/dune.module") if(NOT MODULE_LINE MATCHES ".+") message(FATAL_ERROR "${MODULE_DIR}/dune.module is missing a version.") endif() string(REGEX REPLACE ".*Version:[ ]*([^ \n]+).*" "\\1" DUNE_MOD_VERSION "${MODULE_LINE}") extract_major_minor_version("${DUNE_MOD_VERSION}" DUNE_VERSION) # find strings for module name, maintainer # 1. Check for line starting with Module extract_line("Module:" DUNE_MOD_NAME "${MODULE_DIR}/dune.module") if(NOT DUNE_MOD_NAME) message(FATAL_ERROR "${MODULE_DIR}/dune.module is missing a module name.") endif() # 2. Check for line starting with Maintainer extract_line("Maintainer:" DUNE_MAINTAINER "${MODULE_DIR}/dune.module") if(NOT DUNE_MAINTAINER) message(FATAL_ERROR "${MODULE_DIR}/dune.module is missing a maintainer.") endif() # 3. Check for line starting with Depends extract_line("Depends:" ${DUNE_MOD_NAME}_DEPENDS "${MODULE_DIR}/dune.module") if(${DUNE_MOD_NAME}_DEPENDS) split_module_version(${${DUNE_MOD_NAME}_DEPENDS} ${DUNE_MOD_NAME}_DEPENDS_MODULE ${DUNE_MOD_NAME}_DEPENDS_VERSION) foreach(_mod ${${DUNE_MOD_NAME}_DEPENDS}) set(${_mod}_REQUIRED REQUIRED) endforeach() convert_deps_to_list(${DUNE_MOD_NAME}_DEPENDS) if(NOT ("${ARGV1}" STREQUAL QUIET)) message(STATUS "Dependencies for ${DUNE_MOD_NAME}: ${${DUNE_MOD_NAME}_DEPENDS}") endif() endif() # 4. Check for line starting with Suggests extract_line("Suggests:" ${DUNE_MOD_NAME}_SUGGESTS "${MODULE_DIR}/dune.module") if(${DUNE_MOD_NAME}_SUGGESTS) split_module_version(${${DUNE_MOD_NAME}_SUGGESTS} ${DUNE_MOD_NAME}_SUGGESTS_MODULE ${DUNE_MOD_NAME}_SUGGESTS_VERSION) convert_deps_to_list(${DUNE_MOD_NAME}_SUGGESTS) if(NOT ("${ARGV1}" STREQUAL QUIET)) message(STATUS "Suggestions for ${DUNE_MOD_NAME}: ${${DUNE_MOD_NAME}_SUGGESTS}") endif() endif() dune_module_to_uppercase(DUNE_MOD_NAME_UPPERCASE ${DUNE_MOD_NAME}) # 5. Check for optional meta data extract_line("Author:" ${DUNE_MOD_NAME_UPPERCASE}_AUTHOR "${MODULE_DIR}/dune.module") extract_line("Description:" ${DUNE_MOD_NAME_UPPERCASE}_DESCRIPTION "${MODULE_DIR}/dune.module") extract_line("URL:" ${DUNE_MOD_NAME_UPPERCASE}_URL "${MODULE_DIR}/dune.module") extract_line("Python-Requires:" ${DUNE_MOD_NAME_UPPERCASE}_PYTHON_REQUIRES "${MODULE_DIR}/dune.module") # set module version set(${DUNE_MOD_NAME_UPPERCASE}_VERSION "${DUNE_MOD_VERSION}") set(${DUNE_MOD_NAME_UPPERCASE}_VERSION_MAJOR "${DUNE_VERSION_MAJOR}") set(${DUNE_MOD_NAME_UPPERCASE}_VERSION_MINOR "${DUNE_VERSION_MINOR}") set(${DUNE_MOD_NAME_UPPERCASE}_VERSION_REVISION "${DUNE_VERSION_REVISION}") endmacro(dune_module_information) macro(dune_process_dependency_leafs modules versions is_required next_level_deps next_level_sugs) # modules, and versions are not real variables, make them one set(mmodules ${modules}) set(mversions ${versions}) list(LENGTH mmodules mlength) list(LENGTH mversions vlength) if(NOT mlength EQUAL vlength) message(STATUS "mmodules=${mmodules} modules=${modules}") message(STATUS "mversions=${mversions} versions=${mversions}") message(FATAL_ERROR "List of modules and versions do not have the same length!") endif() if(mlength GREATER 0) math(EXPR length "${mlength}-1") foreach(i RANGE 0 ${length}) list(GET mmodules ${i} _mod) list(GET mversions ${i} _ver) find_dune_package(${_mod} ${is_required} VERSION "${_ver}") set(${_mod}_SEARCHED ON) if(NOT "${is_required}" STREQUAL "") set(${_mod}_REQUIRED ON) set(${next_level_deps} ${${_mod}_DEPENDS} ${${next_level_deps}}) else(NOT "${is_required}" STREQUAL "") set(${next_level_sugs} ${${_mod}_DEPENDS} ${${next_level_sugs}}) endif() set(${next_level_sugs} ${${_mod}_SUGGESTS} ${${next_level_sugs}}) endforeach() endif() if(${next_level_sugs}) list(REMOVE_DUPLICATES ${next_level_sugs}) endif() if(${next_level_deps}) list(REMOVE_DUPLICATES ${next_level_deps}) endif() endmacro(dune_process_dependency_leafs) function(remove_processed_modules modules versions is_required) list(LENGTH ${modules} mlength) if(mlength GREATER 0) math(EXPR length "${mlength}-1") foreach(i RANGE ${length} 0 -1) list(GET ${modules} ${i} _mod) if(${_mod}_SEARCHED) list(REMOVE_AT ${modules} ${i}) list(REMOVE_AT ${versions} ${i}) if(is_required AND NOT ${_mod}_REQUIRED AND NOT ${_mod}_FOUND) message(FATAL_ERROR "Required module ${_mod} not found!") endif() endif() endforeach() endif() set(${modules} ${${modules}} PARENT_SCOPE) set(${versions} ${${versions}} PARENT_SCOPE) endfunction(remove_processed_modules modules versions is_required) macro(dune_create_dependency_leafs depends depends_versions suggests suggests_versions) set(deps "") set(sugs "") #Process dependencies if(NOT "${depends}" STREQUAL "") dune_process_dependency_leafs("${depends}" "${depends_versions}" REQUIRED deps sugs) endif() # Process suggestions if(NOT "${suggests}" STREQUAL "") dune_process_dependency_leafs("${suggests}" "${suggests_versions}" "" deps sugs) endif() split_module_version("${deps}" next_mod_depends next_depends_versions) split_module_version("${sugs}" next_mod_suggests next_suggests_versions) set(ALL_DEPENDENCIES ${ALL_DEPENDENCIES} ${next_mod_depends} ${next_mod_suggests}) # Move to next level if(next_mod_suggests OR next_mod_depends) dune_create_dependency_leafs("${next_mod_depends}" "${next_depends_versions}" "${next_mod_suggests}" "${next_suggests_versions}") endif() endmacro(dune_create_dependency_leafs) macro(dune_create_dependency_tree) if(dune-common_MODULE_PATH) list(REMOVE_ITEM CMAKE_MODULE_PATH "${dune-common_MODULE_PATH}") endif() list(FIND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules start) set(ALL_DEPENDENCIES "") if(${ProjectName}_DEPENDS_MODULE OR ${ProjectName}_SUGGESTS_MODULE) set(ALL_DEPENDENCIES ${${ProjectName}_DEPENDS_MODULE} ${${ProjectName}_SUGGESTS_MODULE}) dune_create_dependency_leafs("${${ProjectName}_DEPENDS_MODULE}" "${${ProjectName}_DEPENDS_VERSION}" "${${ProjectName}_SUGGESTS_MODULE}" "${${ProjectName}_SUGGESTS_VERSION}") endif() set(_my_path "") if(ALL_DEPENDENCIES) # Reverse the order of the modules and remove duplicates # At end of this clause we have have a list modules # where for each entry all dependencies are before the # module in the list. set(NEW_ALL_DEPS "") list(LENGTH ALL_DEPENDENCIES length) if(length GREATER 0) math(EXPR length "${length}-1") list(GET ALL_DEPENDENCIES ${length} _mod) set(${_mod}_cmake_path_processed 1) set(_my_path ${${_mod}_MODULE_PATH}) list(APPEND NEW_ALL_DEPS ${_mod}) if(length GREATER 0) math(EXPR length "${length}-1") foreach(i RANGE ${length} 0 -1) list(GET ALL_DEPENDENCIES ${i} _mod) if(NOT ${_mod}_cmake_path_processed) set(${_mod}_cmake_path_processed 1) if(${_mod}_MODULE_PATH) list(INSERT _my_path 0 ${${_mod}_MODULE_PATH}) endif() list(APPEND NEW_ALL_DEPS ${_mod}) endif() endforeach() endif() list(LENGTH CMAKE_MODULE_PATH length) math(EXPR length "${length}-1") if(start EQUAL -1) list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules ${_my_path}) else() if(start EQUAL ${length}) list(APPEND CMAKE_MODULE_PATH ${_my_path}) else() if(_my_path) list(INSERT CMAKE_MODULE_PATH ${start} ${_my_path}) endif() endif() endif() endif() set(ALL_DEPENDENCIES ${NEW_ALL_DEPS}) endif() endmacro(dune_create_dependency_tree) # Converts a module name given by _dune_module into a string _macro_name # where all dashes (-) are removed and letters after a dash are capitalized # Example: dune-grid-howto -> DuneGridHowto macro(dune_module_to_macro _macro_name _dune_module) set(${_macro_name} "") set(_rest "${_dune_module}") string(FIND "${_rest}" "-" _found) while(_found GREATER -1) string(REGEX REPLACE "([^-]*)-.*" "\\1" _first_part "${_rest}") string(REGEX REPLACE "[^-]*-(.*)" "\\1" _rest "${_rest}") string(SUBSTRING "${_first_part}" 0 1 _first_letter) string(SUBSTRING "${_first_part}" 1 -1 _rest_first_part) string(TOUPPER "${_first_letter}" _first_letter) set(${_macro_name} "${${_macro_name}}${_first_letter}${_rest_first_part}") string(FIND "${_rest}" "-" _found) endwhile() string(LENGTH "${_rest}" _length) string(SUBSTRING "${_rest}" 0 1 _first_letter) string(SUBSTRING "${_rest}" 1 -1 _rest) string(TOUPPER "${_first_letter}" _first_letter) set(${_macro_name} "${${_macro_name}}${_first_letter}${_rest}") endmacro(dune_module_to_macro _macro_name _dune_module) macro(dune_process_dependency_macros) foreach(_mod ${ALL_DEPENDENCIES} ${ProjectName}) if(NOT ${_mod}_PROCESSED) # module not processed yet set(${_mod}_PROCESSED ${_mod}) # Search for a cmake files containing tests and directives # specific to this module dune_module_to_macro(_cmake_mod_name "${_mod}") set(_macro "${_cmake_mod_name}Macros") set(_mod_cmake _mod_cmake-NOTFOUND) # Prevent false positives due to caching message(STATUS "Searching for macro file '${_macro}' for module '${_mod}'.") find_file(_mod_cmake NAMES "${_macro}.cmake" PATHS ${CMAKE_MODULE_PATH} NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) if(_mod_cmake) message(STATUS "Performing tests specific to ${_mod} from file ${_mod_cmake}.") include(${_mod_cmake}) else() message(STATUS "No module specific tests performed for module '${_mod}' because macro file '${_macro}.cmake' not found in ${CMAKE_MODULE_PATH}.") endif() dune_module_to_uppercase(_upper_case "${_mod}") if(${_mod}_INCLUDE_DIRS) message(STATUS "Setting ${_mod}_INCLUDE_DIRS=${${_mod}_INCLUDE_DIRS}") include_directories("${${_mod}_INCLUDE_DIRS}") endif() if(${_mod}_LIBRARIES) message(STATUS "Setting ${_mod}_LIBRARIES=${${_mod}_LIBRARIES}") foreach(_lib ${${_mod}_LIBRARIES}) list(INSERT DUNE_DEFAULT_LIBS 0 "${_lib}") list(INSERT DUNE_LIBS 0 "${_lib}") endforeach() endif() # register dune module dune_register_package_flags(INCLUDE_DIRS "${${_mod}_INCLUDE_DIRS}") endif() endforeach() endmacro(dune_process_dependency_macros) # macro that should be called near the begin of the top level CMakeLists.txt. # Namely it sets up the module, defines basic variables and manages # depedencies. # Don't forget to call finalize_dune_project afterwards. macro(dune_project) # check if CXX flag overloading has been enabled (see OverloadCompilerFlags.cmake) initialize_compiler_script() # extract information from dune.module dune_module_information(${PROJECT_SOURCE_DIR}) set(ProjectName "${DUNE_MOD_NAME}") set(ProjectVersion "${DUNE_MOD_VERSION}") set(ProjectVersionString "${DUNE_VERSION_MAJOR}.${DUNE_VERSION_MINOR}.${DUNE_VERSION_REVISION}") set(ProjectVersionMajor "${DUNE_VERSION_MAJOR}") set(ProjectVersionMinor "${DUNE_VERSION_MINOR}") set(ProjectVersionRevision "${DUNE_VERSION_REVISION}") set(ProjectMaintainerEmail "${DUNE_MAINTAINER}") set(ProjectDescription "${${DUNE_MOD_NAME_UPPERCASE}_DESCRIPTION}") set(ProjectAuthor "${${DUNE_MOD_NAME_UPPERCASE}_AUTHOR}") set(ProjectUrl "${${DUNE_MOD_NAME_UPPERCASE}_URL}") set(ProjectPythonRequires "${${DUNE_MOD_NAME_UPPERCASE}_PYTHON_REQUIRES}") # check whether this module has been explicitly disabled through the cmake flags. # If so, stop the build. This is necessary because dunecontrol does not parse # the given CMake flags for a disabled Dune modules. if(CMAKE_DISABLE_FIND_PACKAGE_${ProjectName}) message("Module ${ProjectName} has been explicitly disabled through the cmake flags. Skipping build.") return() endif() define_property(GLOBAL PROPERTY DUNE_MODULE_LIBRARIES BRIEF_DOCS "List of libraries of the module. DO NOT EDIT!" FULL_DOCS "List of libraries of the module. Used to generate CMake's package configuration files. DO NOT EDIT!") dune_create_dependency_tree() # assert the project names matches if(NOT (ProjectName STREQUAL PROJECT_NAME)) message(FATAL_ERROR "Module name from dune.module does not match the name given in CMakeLists.txt.") endif() # As default request position independent code if shared libraries are built # This should allow DUNE modules to use CMake's object libraries. # This can be overwritten for targets by setting the target property # POSITION_INDEPENDENT_CODE to false/OFF include(CMakeDependentOption) cmake_dependent_option(CMAKE_POSITION_INDEPENDENT_CODE "Build position independent code" ON "NOT BUILD_SHARED_LIBS" ON) # check for C++ features, set compiler flags for C++14 or C++11 mode include(CheckCXXFeatures) # set include path and link path for the current project. include_directories("${PROJECT_BINARY_DIR}") include_directories("${PROJECT_SOURCE_DIR}") include_directories("${CMAKE_CURRENT_BINARY_DIR}") include_directories("${CMAKE_CURRENT_SOURCE_DIR}") add_definitions(-DHAVE_CONFIG_H) # Create custom target for building the documentation # and provide macros for installing the docs and force # building them before. include(DuneDoc) # activate pkg-config include(DunePkgConfig) # Process the macros provided by the dependencies and ourself dune_process_dependency_macros() include(GNUInstallDirs) # Set variable where the cmake modules will be installed. # Thus the user can override it and for example install # directly into the CMake installation. We use a cache variable # that is overridden by a local variable of the same name if # the user does not explicitely set a value for it. Thus the value # will automatically change if the user changes CMAKE_INSTALL_DATAROOTDIR # or CMAKE_INSTALL_PREFIX if(NOT DUNE_INSTALL_MODULEDIR) set(DUNE_INSTALL_MODULEDIR "" CACHE PATH "Installation directory for CMake modules. Default is \${CMAKE_INSTALL_DATAROOTDIR}/dune/cmake/modules when not set explicitely") set(DUNE_INSTALL_MODULEDIR ${CMAKE_INSTALL_DATAROOTDIR}/dune/cmake/modules) endif() if(NOT DUNE_INSTALL_NONOBJECTLIBDIR) set(DUNE_INSTALL_NONOBJECTLIBDIR "" CACHE PATH "Installation directory for libraries that are not architecture dependent. Default is lib when not set explicitely") set(DUNE_INSTALL_NONOBJECTLIBDIR lib) endif() # set up make headercheck include(Headercheck) setup_headercheck() endmacro(dune_project) # create a new config.h file and overwrite the existing one macro(dune_regenerate_config_cmake) set(CONFIG_H_CMAKE_FILE "${PROJECT_BINARY_DIR}/config_collected.h.cmake") if(EXISTS ${PROJECT_SOURCE_DIR}/config.h.cmake) file(READ ${PROJECT_SOURCE_DIR}/config.h.cmake _file) string(REGEX MATCH "/[\\*/][ ]*begin[ ]+${ProjectName}.*\\/[/\\*][ ]*end[ ]*${ProjectName}[^\\*]*\\*/" _myfile "${_file}") endif() # overwrite file with new content file(WRITE ${CONFIG_H_CMAKE_FILE} "/* config.h. Generated from config_collected.h.cmake by CMake. It was generated from config_collected.h.cmake which in turn is generated automatically from the config.h.cmake files of modules this module depends on. */" ) # define that we found this module set(${ProjectName}_FOUND 1) foreach(_dep ${ProjectName} ${ALL_DEPENDENCIES}) dune_module_to_uppercase(upper ${_dep}) set(HAVE_${upper} ${${_dep}_FOUND}) file(APPEND ${CONFIG_H_CMAKE_FILE} "\n\n/* Define to 1 if you have module ${_dep} available */ #cmakedefine01 HAVE_${upper}\n") endforeach() # add previous module specific section foreach(_dep ${ALL_DEPENDENCIES}) foreach(_mod_conf_file ${${_dep}_PREFIX}/config.h.cmake ${${_dep}_PREFIX}/share/${_dep}/config.h.cmake) if(EXISTS ${_mod_conf_file}) file(READ "${_mod_conf_file}" _file) string(REGEX REPLACE ".*/\\*[ ]*begin[ ]+${_dep}[^\\*]*\\*/(.*)/[/\\*][ ]*end[ ]*${_dep}[^\\*]*\\*/" "\\1" _tfile "${_file}") # strip the private section string(REGEX REPLACE "(.*)/[\\*][ ]*begin private.*/[\\*][ ]*end[ ]*private[^\\*]\\*/(.*)" "\\1\\2" _ttfile "${_tfile}") # extract the bottom section string(REGEX MATCH "/[\\*][ ]*begin bottom.*/[\\*][ ]*end[ ]*bottom[^\\*]\\*/" _tbottom "${_ttfile}") string(REGEX REPLACE ".*/\\*[ ]*begin[ ]+bottom[^\\*]*\\*/(.*)/[/\\*][ ]*end[ ]*bottom[^\\*]*\\*/" "\\1" ${_dep}_CONFIG_H_BOTTOM "${_tbottom}" ) string(REGEX REPLACE "(.*)/[\\*][ ]*begin bottom.*/[\\*][ ]*end[ ]*bottom[^\\*]\\*/(.*)" "\\1\\2" _file "${_ttfile}") # append bottom section if(${_dep}_CONFIG_H_BOTTOM) set(CONFIG_H_BOTTOM "${CONFIG_H_BOTTOM} ${${_dep}_CONFIG_H_BOTTOM}") endif() file(APPEND ${CONFIG_H_CMAKE_FILE} "${_file}") endif() endforeach() endforeach() # parse again dune.module file of current module to set PACKAGE_* variables dune_module_information(${PROJECT_SOURCE_DIR} QUIET) file(APPEND ${CONFIG_H_CMAKE_FILE} "\n${_myfile}") # append CONFIG_H_BOTTOM section at the end if found if(CONFIG_H_BOTTOM) file(APPEND ${CONFIG_H_CMAKE_FILE} "${CONFIG_H_BOTTOM}") endif() endmacro(dune_regenerate_config_cmake) # macro that should be called at the end of the top level CMakeLists.txt. # Namely it creates config.h and the cmake-config files, # some install directives and exports the module. macro(finalize_dune_project) if(DUNE_SYMLINK_TO_SOURCE_TREE) dune_symlink_to_source_tree() endif() #configure all headerchecks finalize_headercheck() #create cmake-config files for installation tree include(CMakePackageConfigHelpers) include(GNUInstallDirs) set(DOXYSTYLE_DIR ${CMAKE_INSTALL_DATAROOTDIR}/dune-common/doc/doxygen/) set(SCRIPT_DIR ${CMAKE_INSTALL_DATAROOTDIR}/dune/cmake/scripts) # Set the location where the doc sources are installed. # Needed by custom package configuration # file section of dune-grid. set(DUNE_MODULE_SRC_DOCDIR "\${${ProjectName}_PREFIX}/${CMAKE_INSTALL_DOCDIR}") if(NOT EXISTS ${PROJECT_SOURCE_DIR}/cmake/pkg/${ProjectName}-config.cmake.in) # Generate a standard cmake package configuration file file(WRITE ${PROJECT_BINARY_DIR}/CMakeFiles/${ProjectName}-config.cmake.in "if(NOT ${ProjectName}_FOUND) # Whether this module is installed or not set(${ProjectName}_INSTALLED @MODULE_INSTALLED@) # Settings specific to the module @${ProjectName}_INIT@ # Package initialization @PACKAGE_INIT@ #report other information set_and_check(${ProjectName}_PREFIX \"\${PACKAGE_PREFIX_DIR}\") set_and_check(${ProjectName}_INCLUDE_DIRS \"@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@\") set(${ProjectName}_CXX_FLAGS \"${CMAKE_CXX_FLAGS}\") set(${ProjectName}_CXX_FLAGS_DEBUG \"${CMAKE_CXX_FLAGS_DEBUG}\") set(${ProjectName}_CXX_FLAGS_MINSIZEREL \"${CMAKE_CXX_FLAGS_MINSIZEREL}\") set(${ProjectName}_CXX_FLAGS_RELEASE \"${CMAKE_CXX_FLAGS_RELEASE}\") set(${ProjectName}_CXX_FLAGS_RELWITHDEBINFO \"${CMAKE_CXX_FLAGS_RELWITHDEBINFO}\") set(${ProjectName}_DEPENDS \"@${ProjectName}_DEPENDS@\") set(${ProjectName}_SUGGESTS \"@${ProjectName}_SUGGESTS@\") set(${ProjectName}_MODULE_PATH \"@PACKAGE_DUNE_INSTALL_MODULEDIR@\") set(${ProjectName}_LIBRARIES \"@DUNE_MODULE_LIBRARIES@\") # Lines that are set by the CMake build system via the variable DUNE_CUSTOM_PKG_CONFIG_SECTION ${DUNE_CUSTOM_PKG_CONFIG_SECTION} #import the target if(${ProjectName}_LIBRARIES) get_filename_component(_dir \"\${CMAKE_CURRENT_LIST_FILE}\" PATH) include(\"\${_dir}/${ProjectName}-targets.cmake\") endif() endif()") set(CONFIG_SOURCE_FILE ${PROJECT_BINARY_DIR}/CMakeFiles/${ProjectName}-config.cmake.in) else() set(CONFIG_SOURCE_FILE ${PROJECT_SOURCE_DIR}/cmake/pkg/${ProjectName}-config.cmake.in) endif() get_property(DUNE_MODULE_LIBRARIES GLOBAL PROPERTY DUNE_MODULE_LIBRARIES) # compute under which libdir the package configuration files are to be installed. # If the module installs an object library we use CMAKE_INSTALL_LIBDIR # to capture the multiarch triplet of Debian/Ubuntu. # Otherwise we fall back to DUNE_INSTALL_NONOBJECTLIB which is lib # if not set otherwise. get_property(DUNE_MODULE_LIBRARIES GLOBAL PROPERTY DUNE_MODULE_LIBRARIES) if(DUNE_MODULE_LIBRARIES) set(DUNE_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR}) else() set(DUNE_INSTALL_LIBDIR ${DUNE_INSTALL_NONOBJECTLIBDIR}) endif() # Set the location of the doc file source. Needed by custom package configuration # file section of dune-grid. set(DUNE_MODULE_SRC_DOCDIR "${PROJECT_SOURCE_DIR}/doc") set(MODULE_INSTALLED ON) configure_package_config_file(${CONFIG_SOURCE_FILE} ${PROJECT_BINARY_DIR}/cmake/pkg/${ProjectName}-config.cmake INSTALL_DESTINATION ${DUNE_INSTALL_LIBDIR}/cmake/${ProjectName} PATH_VARS CMAKE_INSTALL_DATAROOTDIR DUNE_INSTALL_MODULEDIR CMAKE_INSTALL_INCLUDEDIR DOXYSTYLE_DIR SCRIPT_DIR) #create cmake-config files for build tree set(PACKAGE_CMAKE_INSTALL_INCLUDEDIR ${PROJECT_SOURCE_DIR}) set(PACKAGE_CMAKE_INSTALL_DATAROOTDIR ${PROJECT_BINARY_DIR}) set(PACKAGE_DOXYSTYLE_DIR ${PROJECT_SOURCE_DIR}/doc/doxygen) set(PACKAGE_SCRIPT_DIR ${PROJECT_SOURCE_DIR}/cmake/scripts) set(PACKAGE_DUNE_INSTALL_MODULEDIR ${PROJECT_SOURCE_DIR}/cmake/modules) set(PACKAGE_PREFIX_DIR ${PROJECT_BINARY_DIR}) set(PACKAGE_INIT "# Set prefix to source dir set(PACKAGE_PREFIX_DIR ${PROJECT_SOURCE_DIR}) macro(set_and_check _var _file) set(\${_var} \"\${_file}\") if(NOT EXISTS \"\${_file}\") message(FATAL_ERROR \"File or directory \${_file} referenced by variable \${_var} does not exist !\") endif() endmacro()") set(MODULE_INSTALLED OFF) configure_file( ${CONFIG_SOURCE_FILE} ${PROJECT_BINARY_DIR}/${ProjectName}-config.cmake @ONLY) if(NOT EXISTS ${PROJECT_SOURCE_DIR}/${ProjectName}-config-version.cmake.in) file(WRITE ${PROJECT_BINARY_DIR}/CMakeFiles/${ProjectName}-config-version.cmake.in "set(PACKAGE_VERSION \"${ProjectVersionString}\") if(\"\${PACKAGE_FIND_VERSION_MAJOR}\" EQUAL \"${ProjectVersionMajor}\" AND \"\${PACKAGE_FIND_VERSION_MINOR}\" EQUAL \"${ProjectVersionMinor}\") set (PACKAGE_VERSION_COMPATIBLE 1) # compatible with newer if (\"\${PACKAGE_FIND_VERSION}\" VERSION_EQUAL \"${ProjectVersionString}\") set(PACKAGE_VERSION_EXACT 1) #exact match for this version endif() endif() ") set(CONFIG_VERSION_FILE ${PROJECT_BINARY_DIR}/CMakeFiles/${ProjectName}-config-version.cmake.in) else() set(CONFIG_VERSION_FILE ${PROJECT_SOURCE_DIR}/${ProjectName}-config-version.cmake.in) endif() configure_file( ${CONFIG_VERSION_FILE} ${PROJECT_BINARY_DIR}/${ProjectName}-config-version.cmake @ONLY) # install dune.module file install(FILES dune.module DESTINATION ${DUNE_INSTALL_NONOBJECTLIBDIR}/dunecontrol/${ProjectName}) # install cmake-config files install(FILES ${PROJECT_BINARY_DIR}/cmake/pkg/${ProjectName}-config.cmake ${PROJECT_BINARY_DIR}/${ProjectName}-config-version.cmake DESTINATION ${DUNE_INSTALL_LIBDIR}/cmake/${ProjectName}) # install config.h if(EXISTS ${PROJECT_SOURCE_DIR}/config.h.cmake) install(FILES config.h.cmake DESTINATION share/${ProjectName}) endif() # install pkg-config files create_and_install_pkconfig(${DUNE_INSTALL_LIBDIR}) if("${ARGC}" EQUAL "1") message(STATUS "Adding custom target for config.h generation") dune_regenerate_config_cmake() # add a target to generate config.h.cmake if(NOT TARGET OUTPUT) add_custom_target(OUTPUT config_collected.h.cmake COMMAND dune_regenerate_config_cmake()) endif() # actually write the config.h file to disk # using generated file configure_file(${CMAKE_CURRENT_BINARY_DIR}/config_collected.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) else() message(STATUS "Not adding custom target for config.h generation") # actually write the config.h file to disk configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h) endif() if(PROJECT_NAME STREQUAL CMAKE_PROJECT_NAME) feature_summary(WHAT ALL) endif() # check if CXX flag overloading has been enabled # and write compiler script (see OverloadCompilerFlags.cmake) finalize_compiler_script() endmacro(finalize_dune_project) macro(target_link_dune_default_libraries _target) foreach(_lib ${DUNE_DEFAULT_LIBS}) target_link_libraries(${_target} PUBLIC ${_lib}) endforeach() endmacro(target_link_dune_default_libraries) function(dune_expand_object_libraries _SOURCES_var _ADD_LIBS_var _COMPILE_FLAGS_var) set(_new_SOURCES "") set(_new_ADD_LIBS "${${_ADD_LIBS_var}}") set(_new_COMPILE_FLAGS "${${_COMPILE_FLAGS_var}}") set(_regex "_DUNE_TARGET_OBJECTS:([a-zA-Z0-9_-]+)_") foreach(_source ${${_SOURCES_var}}) string(REGEX MATCH ${_regex} _matched "${_source}") if(_matched) string(REGEX REPLACE "${_regex}" "\\1" _basename "${_source}") foreach(var _SOURCES _ADD_LIBS _COMPILE_FLAGS) get_property(_prop GLOBAL PROPERTY DUNE_LIB_${_basename}${var}) list(APPEND _new${var} "${_prop}") endforeach() else() list(APPEND _new_SOURCES "${_source}") endif() endforeach() foreach(var _SOURCES _ADD_LIBS _COMPILE_FLAGS) set(${${var}_var} "${_new${var}}" PARENT_SCOPE) endforeach() endfunction(dune_expand_object_libraries) # Creates shared and static libraries with the same basename. # More docu can be found at the top of this file. macro(dune_add_library basename) include(CMakeParseArguments) cmake_parse_arguments(DUNE_LIB "APPEND;NO_EXPORT;OBJECT" "COMPILE_FLAGS" "ADD_LIBS;SOURCES" ${ARGN}) list(APPEND DUNE_LIB_SOURCES ${DUNE_LIB_UNPARSED_ARGUMENTS}) if(DUNE_LIB_OBJECT) if(DUNE_LIB_${basename}_SOURCES) message(FATAL_ERROR "There is already a library with the name ${basename}, " "but only one is allowed!") else() foreach(source ${DUNE_LIB_SOURCES}) list(APPEND full_path_sources ${CMAKE_CURRENT_SOURCE_DIR}/${source}) endforeach() # register sources, libs and flags for building the library later define_property(GLOBAL PROPERTY DUNE_LIB_${basename}_SOURCES BRIEF_DOCS "Convenience property with sources for library ${basename}. DO NOT EDIT!" FULL_DOCS "Convenience property with sources for library ${basename}. DO NOT EDIT!") set_property(GLOBAL PROPERTY DUNE_LIB_${basename}_SOURCES "${full_path_sources}") define_property(GLOBAL PROPERTY DUNE_LIB_${basename}_ADD_LIBS BRIEF_DOCS "Convenience property with libraries for library ${basename}. DO NOT EDIT!" FULL_DOCS "Convenience property with libraries for library ${basename}. DO NOT EDIT!") set_property(GLOBAL PROPERTY DUNE_LIB_${basename}_ADD_LIBS "${DUNE_LIB_ADD_LIBS}") define_property(GLOBAL PROPERTY DUNE_LIB_${basename}_COMPILE_FLAGS BRIEF_DOCS "Convenience property with compile flags for library ${basename}. DO NOT EDIT!" FULL_DOCS "Convenience property with compile flags for library ${basename}. DO NOT EDIT!") set_property(GLOBAL PROPERTY DUNE_LIB_${basename}_COMPILE_FLAGS "${DUNE_LIB_COMPILE_FLAGS}") endif() else(DUNE_LIB_OBJECT) dune_expand_object_libraries(DUNE_LIB_SOURCES DUNE_LIB_ADD_LIBS DUNE_LIB_COMPILE_FLAGS) #create lib add_library(${basename} ${DUNE_LIB_SOURCES}) get_property(_prop GLOBAL PROPERTY DUNE_MODULE_LIBRARIES) set_property(GLOBAL PROPERTY DUNE_MODULE_LIBRARIES ${_prop} ${basename}) # link with specified libraries. if(DUNE_LIB_ADD_LIBS) target_link_libraries(${basename} PUBLIC "${DUNE_LIB_ADD_LIBS}") endif() if(DUNE_LIB_COMPILE_FLAGS) set_property(${basename} APPEND_STRING COMPILE_FLAGS "${DUNE_LIB_COMPILE_FLAGS}") endif() # Build library in ${PROJECT_BINARY_DIR}/lib set_target_properties(${basename} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib" ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") if(NOT DUNE_LIB_NO_EXPORT) # The following allows for adding multiple libs in the same # directory or below with passing the APPEND keyword. # If there are additional calls to dune_add_library in other # modules then you have to use APPEND or otherwise only the # last lib will get exported as a target. if(NOT _MODULE_EXPORT_USED) set(_MODULE_EXPORT_USED ON) set(_append "") else() set(_append APPEND) endif() # Allow to explicitly pass APPEND if(DUNE_LIB_APPEND) set(_append APPEND) endif() # install targets to use the libraries in other modules. install(TARGETS ${basename} EXPORT ${ProjectName}-targets DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(EXPORT ${ProjectName}-targets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${ProjectName}) # export libraries for use in build tree export(TARGETS ${basename} ${_append} FILE ${PROJECT_BINARY_DIR}/${ProjectName}-targets.cmake) endif() endif() endmacro(dune_add_library basename sources) macro(replace_properties_for_one) get_property(properties ${option_command} ${_target} PROPERTY ${REPLACE_PROPERTY}) if(NOT properties) # property not set. set it directly foreach(i RANGE 0 ${hlength}) math(EXPR idx "(2 * ${i}) + 1") list(GET REPLACE_UNPARSED_ARGUMENTS ${idx} repl) list(APPEND replacement ${repl}) endforeach() list(REMOVE_DUPLICATES replacement) set_property(${option_command} ${_target} ${REPLACE_APPEND} ${REPLACE_APPEND_STRING} PROPERTY ${REPLACE_PROPERTY} ${replacement}) else() foreach(prop ${properties}) set(matched FALSE) foreach(i RANGE 0 ${hlength}) math(EXPR regexi "2 * ${i}") math(EXPR repli "${regexi} +1") list(GET REPLACE_UNPARSED_ARGUMENTS ${regexi} regex) list(GET REPLACE_UNPARSED_ARGUMENTS ${repli} replacement) string(REGEX MATCH ${regex} match ${prop}) if(match) list(APPEND new_props ${replacement}) set(matched TRUE) endif() endforeach() if(NOT matched) list(APPEND new_props ${prop}) endif() endforeach() list(REMOVE_DUPLICATES new_props) set_property(${option_command} ${_target} PROPERTY ${REPLACE_PROPERTY} ${new_props}) endif() get_property(properties ${option_command} ${_target} PROPERTY ${REPLACE_PROPERTY}) endmacro(replace_properties_for_one) function(dune_target_link_libraries basename libraries) target_link_libraries(${basename} PUBLIC ${libraries}) endfunction(dune_target_link_libraries basename libraries) function(replace_properties) include(CMakeParseArguments) set(_first_opts "GLOBAL;DIRECTORY;TARGET;SOURCE;CACHE") cmake_parse_arguments(REPLACE "GLOBAL" "DIRECTORY;PROPERTY" "TARGET;SOURCE;TEST;CACHE" ${ARGN}) set(MY_DIRECTORY TRUE) foreach(i ${_first_opts}) if(REPLACE_${i}) set(MY_DIRECTORY FALSE) endif() endforeach() if(NOT MY_DIRECTORY) list(FIND REPLACE_UNPARSED_ARGUMENTS DIRECTORY _found) if(_found GREATER -1) list(REMOVE_AT REPLACE_UNPARSED_ARGUMENTS ${_found}) set(MY_DIRECTORY TRUE) set(REPLACE_DIRECTORY "") endif() endif() # setup options if(REPLACE_GLOBAL) set(option_command GLOBAL) elseif(MY_DIRECTORY) set(option_command DIRECTORY) elseif(REPLACE_DIRECTORY) set(option_command DIRECTORY) set(option_arg ${REPLACE_DIRECTORY}) elseif(REPLACE_TARGET) set(option_command TARGET) set(option_arg ${REPLACE_TARGET}) elseif(REPLACE_SOURCE) set(option_command SOURCE) set(option_arg ${REPLACE_SOURCE}) elseif(REPLACE_TEST) set(option_command TEST) set(option_arg${REPLACE_TEST}) elseif(REPLACE_CACHE) set(option_command CACHE) set(option_arg ${REPLACE_CACHE}) endif() if(NOT (REPLACE_CACHE OR REPLACE_TEST OR REPLACE_SOURCE OR REPLACE_TARGET OR REPLACE_DIRECTORY OR REPLACE_GLOBAL OR MY_DIRECTORY)) message(ERROR "One of GLOBAL, DIRECTORY, TARGET, SOURCE, TEST, or CACHE" " has to be present") endif() list(LENGTH REPLACE_UNPARSED_ARGUMENTS length) # if(NOT (REPLACE_GLOBAL AND REPLACE_TARGET AND # REPLACE_SOURCE AND REPLACE math(EXPR mlength "${length} % 2 ") math(EXPR hlength "${length} / 2 - 1") if(NOT ${mlength} EQUAL 0) message(ERROR "You need to specify pairs consisting of a regular expression and a replacement string.") endif() if(NOT length GREATER 0) message(ERROR "You need to specify at least on pair consisting of a regular expression and a replacement string. ${REPLACE_UNPARSED_ARGUMENTS}") endif() foreach(_target ${option_arg}) replace_properties_for_one() endforeach() list(LENGTH option_arg _length) if(_length EQUAL 0) replace_properties_for_one() endif() endfunction(replace_properties) macro(add_dune_all_flags targets) get_property(incs GLOBAL PROPERTY ALL_PKG_INCS) get_property(defs GLOBAL PROPERTY ALL_PKG_DEFS) get_property(libs GLOBAL PROPERTY ALL_PKG_LIBS) get_property(opts GLOBAL PROPERTY ALL_PKG_OPTS) foreach(target ${targets}) set_property(TARGET ${target} APPEND PROPERTY INCLUDE_DIRECTORIES ${incs}) set_property(TARGET ${target} APPEND PROPERTY COMPILE_DEFINITIONS ${defs}) target_link_libraries(${target} PUBLIC ${DUNE_LIBS} ${libs}) target_compile_options(${target} PUBLIC ${opts}) endforeach() endmacro(add_dune_all_flags targets) dune-common-2.8.0/cmake/modules/DunePathHelper.cmake000066400000000000000000000055061411343567400223620ustar00rootroot00000000000000# Some helper functions for people developing the CMake build system # to get quick and easy access to path variables of Dune modules. # # .. cmake_function:: dune_module_path # # .. cmake_param:: MODULE # :single: # :required: # # The name of the module. # # .. cmake_param:: RESULT # :single: # :required: # # The name of the variable to export the result. # # .. cmake_param:: CMAKE_MODULES # :option: # # Set to return the path to cmake modules # # .. cmake_param:: BUILD_DIR # :option: # # Set to return the path to the build directory # # .. cmake_param:: SOURCE_DIR # :option: # # Set to return the include path of the module # # .. cmake_param:: SCRIPT_DIR # :option: # # Set to return the CMake script dir # # # Returns the specified path of the given module. This differs # whether it is called from the actual module, or from a module # requiring or suggesting this module. One and only one type of path # may be requested. # include_guard(GLOBAL) function(dune_module_path) # Parse Arguments set(OPTION CMAKE_MODULES BUILD_DIR SOURCE_DIR SCRIPT_DIR) set(SINGLE MODULE RESULT) set(MULTI) include(CMakeParseArguments) cmake_parse_arguments(PATH "${OPTION}" "${SINGLE}" "${MULTI}" ${ARGN}) if(PATH_UNPARSED_ARGUMENTS) message(WARNING "Unparsed arguments in dune_module_path: This often indicates typos!") endif() # Check whether one and only one path type was set. set(OPTION_FOUND 0) foreach(opt ${OPTION}) if(${PATH_${opt}}) if(OPTION_FOUND) message(FATAL_ERROR "Cannot request two different paths from dune_module_path") else() set(OPTION_FOUND 1) endif() endif() endforeach() if(NOT OPTION_FOUND) message(FATAL_ERROR "Cannot determine type of requested path!") endif() # Set the requested paths for the cmake module path if(PATH_CMAKE_MODULES) set(IF_CURRENT_MOD ${PROJECT_SOURCE_DIR}/cmake/modules) set(IF_NOT_CURRENT_MOD ${${PATH_MODULE}_MODULE_PATH}) endif() # Set the requested paths for the cmake script path if(PATH_SCRIPT_DIR) set(IF_CURRENT_MOD ${PROJECT_SOURCE_DIR}/cmake/scripts) set(IF_NOT_CURRENT_MOD ${${PATH_MODULE}_SCRIPT_DIR}) endif() # Set the requested paths for the build directory if(PATH_BUILD_DIR) set(IF_CURRENT_MOD ${PROJECT_BINARY_DIR}) set(IF_NOT_CURRENT_MOD ${${PATH_MODULE}_DIR}) endif() # Set the requested paths for the include directory if(PATH_SOURCE_DIR) set(IF_CURRENT_MOD ${PROJECT_SOURCE_DIR}) set(IF_NOT_CURRENT_MOD ${${PATH_MODULE}_PREFIX}) endif() # Now set the path in the outer scope! if(PROJECT_NAME STREQUAL ${PATH_MODULE}) set(${PATH_RESULT} ${IF_CURRENT_MOD} PARENT_SCOPE) else() set(${PATH_RESULT} ${IF_NOT_CURRENT_MOD} PARENT_SCOPE) endif() endfunction() dune-common-2.8.0/cmake/modules/DunePkgConfig.cmake000066400000000000000000000042361411343567400221740ustar00rootroot00000000000000# searches for pkg-config, creates the # file .pc from .pc.in, # and adds installation directives. # include_guard(GLOBAL) find_package(PkgConfig) # text for feature summary set_package_properties("PkgConfig" PROPERTIES DESCRIPTION "Unified interface for querying installed libraries" PURPOSE "To find Dune module dependencies") function(create_and_install_pkconfig installlibdir) # set some variables that are used in the pkg-config file include(GNUInstallDirs) if(SKBUILD) # we are using scikit-build to build a python wheel. The install prefix # set by scikit is within a tmp directory (isolated build) and # therefore not suitable for the prefix in the pc file. At least when # installed into a virtual env the correct prefix path is two below the # location of the pc file, i.e., # location of pc files: dune-env/lib/pkgconfig # location of dune.module files: dune-env/lib/dunecontrol # and from the documentation # installed module: ${path}/lib/dunecontrol/${name}/dune.module # and there is a file ${path}/lib/pkgconfig/${name}.pc set( prefix "\${pcfiledir}/../..") else() set( prefix ${CMAKE_INSTALL_PREFIX}) endif() set(exec_prefix "\${prefix}") set(libdir "\${exec_prefix}/${installlibdir}") set(includedir "\${prefix}/${CMAKE_INSTALL_INCLUDEDIR}") set(PACKAGE_NAME ${ProjectName}) set(VERSION ${ProjectVersion}) set(CC ${CMAKE_C_COMPILER}) set(CXX "${CMAKE_CXX_COMPILER} ${CXX_STD11_FLAGS}") if(DUNE_DEPENDS) foreach(_DUNE_DEPEND ${DUNE_DEPENDS}) string(REGEX REPLACE "\\(" "" REQF1 ${_DUNE_DEPEND}) string(REGEX REPLACE "\\)" "" LR ${REQF1}) if(REQUIRES) set(REQUIRES "${REQUIRES} ${LR}") else() set(REQUIRES ${LR}) endif(REQUIRES) endforeach(_DUNE_DEPEND ${DUNE_DEPENDS}) endif(DUNE_DEPENDS) #create pkg-config file configure_file( ${PROJECT_SOURCE_DIR}/${ProjectName}.pc.in ${PROJECT_BINARY_DIR}/${ProjectName}.pc @ONLY ) # install pkgconfig file install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${ProjectName}.pc DESTINATION ${installlibdir}/pkgconfig) endfunction(create_and_install_pkconfig) dune-common-2.8.0/cmake/modules/DunePythonCommonMacros.cmake000066400000000000000000000162761411343567400241330ustar00rootroot00000000000000# The python extension of the Dune cmake build system # # .. cmake_module:: # # This module is the main entry point for the python extension of the Dune cmake # build system. It handles the detection of the python installation, defines installation # rules for python packages in Dune modules and provides virtual environments to # run python code from cmake. # # If you want to use Dune modules that provide Python functionality, you should be aware # of some facts: # # * CMake looks for your python interpreter during configure. If you want to have it # work with a virtual environment, you should activate your virtualenv before configure. # * Each module has an additional target :code:`make install_python`, that installs python packages # defined in the Dune module. You can customize the install location with # :ref:`DUNE_PYTHON_INSTALL_LOCATION`. This is also included in :code:`make install`. # * There is additional functionality, that automatically sets up a virtual environment # at configure time, you can read more at :ref:`DunePythonVirtualenv`. # # After the module :code:`DunePythonCommonMacros` is run (which happens automatically when # configuring dune-common) the following python-related variables will be set and available # for use in downstream modules: # # * All variables set by :code:`FindPythonInterp.cmake` and :code:`FindPythonLibs.cmake` # * :code:`DUNE_PYTHON_SYSTEM_IS_VIRTUALENV`: True if the given system interpreter resides in # virtual environment. # # For documentation on how to customize the build process, check the input variable # reference for any variables prefixed with :code:`DUNE_PYTHON`. To learn how to write build # system code for Dune modules shipping python, have a look at the command reference for # commands prefixed :code:`dune_python`. # # .. cmake_variable:: DUNE_PYTHON_INSTALL_LOCATION # # This variable can be used to control where Dune should install python # packages. Possible values are: # # * :code:`user`: installs into the users home directory through :code:`pip --user`. Note, that # this is incompatible with using virtual environments (as per pip docs). # * :code:`system`: into the standard paths of the interpreter which was found # by cmake. # * :code:`none`: Never install any python packages. # # The default value in use depends on the system interpreter to run in a virtual environment # or not: If it does, :code:`system` is the default, if it does not :code:`none` is the default. # This rather unintuitive default originates from the strong belief, that installing # python packages into the system locations at :code:`/usr/...` should be discouraged. # # .. cmake_variable:: DUNE_PYTHON_VIRTUALENV_SETUP # # Set this variable to allow the Dune build system to set up a virtualenv at # configure time. Such virtual environment is very useful, whenever python code # is to be run at configure time, i.e. to implement code generation in Python or # to use Python wrappers in testing. Some downstream modules will *require* you # to set this variable. When setting this variable, you allow the Dune buildsystem # to install packages through :code:`pip` into a virtualenv, that resides in a cmake # build directory. For all the information on this virtualenv, see :ref:`DunePythonVirtualenv`. # # .. cmake_function:: dune_python_require_virtualenv_setup # # Call this function from a downstream module, if that module relies on the # the presence of the configure time virtualenv described in :ref:`DunePythonVirtualenv`. # include_guard(GLOBAL) # unless the user has defined the variable, unversioned names (like python3) are found # first, to match what users most probably use later on to call the executable if(NOT DEFINED Python3_FIND_UNVERSIONED_NAMES) set(Python3_FIND_UNVERSIONED_NAMES "FIRST") endif() # include code from CMake 3.20 to back-port using unversioned Python first if(${CMAKE_VERSION} VERSION_LESS "3.20") list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_LIST_DIR}/FindPython3") endif() # Include all the other parts of the python extension to avoid that users need # to explicitly include parts of our build system. include(DunePythonFindPackage) include(DunePythonInstallPackage) include(DunePythonTestCommand) # Find the Python Interpreter and libraries find_package(Python3 COMPONENTS Interpreter Development) # Determine whether the given interpreter is running inside a virtualenv if(Python3_Interpreter_FOUND) include(DuneExecuteProcess) include(DunePathHelper) dune_module_path(MODULE dune-common RESULT scriptdir SCRIPT_DIR) dune_execute_process(COMMAND "${Python3_EXECUTABLE}" "${scriptdir}/envdetect.py" RESULT_VARIABLE DUNE_PYTHON_SYSTEM_IS_VIRTUALENV ) endif() # Determine where to install python packages if(NOT DUNE_PYTHON_INSTALL_LOCATION) if(DUNE_PYTHON_SYSTEM_IS_VIRTUALENV) set(DUNE_PYTHON_INSTALL_LOCATION "system") else() set(DUNE_PYTHON_INSTALL_LOCATION "none") endif() endif() if(NOT(("${DUNE_PYTHON_INSTALL_LOCATION}" STREQUAL "user") OR ("${DUNE_PYTHON_INSTALL_LOCATION}" STREQUAL "system") OR ("${DUNE_PYTHON_INSTALL_LOCATION}" STREQUAL "none"))) message(FATAL_ERROR "DUNE_PYTHON_INSTALL_LOCATION must be user|system|none.") endif() if(("${DUNE_PYTHON_INSTALL_LOCATION}" STREQUAL "user") AND DUNE_PYTHON_SYSTEM_IS_VIRTUALENV) message(FATAL_ERROR "Specifying 'user' as install location is incomaptible with using virtual environments (as per pip docs)") endif() # Check presence of python packages required by the buildsystem dune_python_find_package(PACKAGE pip) # Add python related meta targets add_custom_target(test_python) add_custom_target(install_python) # Set the path to a Dune wheelhouse that is to be used during installation # NB: Right now, the same logic is used to retrieve the location of the # wheelhouse (which means that you have to use the same CMAKE_INSTALL_PREFIX # when *using* installed modules, you used when *installing* them. # TODO: Replace this with a better mechanism (like writing the location into # dune-commons package config file) set(DUNE_PYTHON_WHEELHOUSE ${CMAKE_INSTALL_PREFIX}/share/dune/wheelhouse) # Have make install do the same as make install_python install(CODE "set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) set(DUNE_PYTHON_WHEELHOUSE ${DUNE_PYTHON_WHEELHOUSE}) include(DuneExecuteProcess) dune_execute_process(COMMAND \"${CMAKE_COMMAND}\" --build . --target install_python --config $) ") # Implement a check for the presence of the virtualenv function(dune_python_require_virtualenv_setup) if(NOT DUNE_PYTHON_VIRTUALENV_SETUP) message(FATAL_ERROR "\n ${PROJECT_NAME} relies on a configure-time virtual environment being set up by the Dune python build system. You have to set the CMake variable DUNE_PYTHON_VIRTUALENV_SETUP to allow that.\n ") endif() endfunction() # If requested, switch into DunePythonVirtualenv.cmake and setup the virtualenv. if(DUNE_PYTHON_VIRTUALENV_SETUP) include(DunePythonVirtualenv) endif() # marcos used for the Python bindings include(DunePythonMacros) dune-common-2.8.0/cmake/modules/DunePythonFindPackage.cmake000066400000000000000000000100271411343567400236560ustar00rootroot00000000000000# This module provides functions to check for the existence of python packages on the host system. # # .. cmake_function:: dune_python_find_package # # .. cmake_param:: PACKAGE # :required: # :single: # # The package name to look for. # # .. cmake_param: RESULT # :single: # # The variable to store the result of the check in # in the calling scope. Defaults to :code:`DUNE_PYTHON__FOUND` # Note that the package name is case sensitive and will # usually be lowercase. # # .. cmake_param:: REQUIRED # :option: # # If set, the function will error out if the package is not # found. # # .. cmake_param:: VERSION # :single: # # The minimum version of the package that is required. # # .. cmake_param:: EXACT # :option: # # Whether the given version requirement has to be matched exactly. # # .. cmake_param:: INTERPRETER # :single: # # The python interpreter, whose paths are searched for the package. # Defaults to :code:`${Python3_EXECUTABLE}`, might differ when dealing with # the configure-time virtualenv set up with :ref:`DUNE_PYTHON_VIRTUALENV_SETUP`. # # Find a given python package on the system. # include_guard(GLOBAL) function(dune_python_find_package) # Parse Arguments set(OPTION REQUIRED EXACT) set(SINGLE PACKAGE RESULT VERSION INTERPRETER) set(MULTI) include(CMakeParseArguments) cmake_parse_arguments(PYPACKAGE "${OPTION}" "${SINGLE}" "${MULTI}" ${ARGN}) if(PYCHECK_UNPARSED_ARGUMENTS) message(WARNING "Unparsed arguments in dune_python_find_package: This often indicates typos!") endif() # Do error checking on input and apply defaults if(NOT PYPACKAGE_RESULT) set(PYPACKAGE_RESULT DUNE_PYTHON_${PYPACKAGE_PACKAGE}_FOUND) endif() if(NOT PYPACKAGE_INTERPRETER) set(PYPACKAGE_INTERPRETER "${Python3_EXECUTABLE}") endif() if(PYPACKAGE_EXACT AND NOT PYPACKAGE_VERSION) message(FATAL_ERROR "dune_python_find_package: EXACT given, but no VERSION specified.") endif() # Do the actual check execute_process(COMMAND "${PYPACKAGE_INTERPRETER}" -c "import ${PYPACKAGE_PACKAGE}" RESULT_VARIABLE PYPACKAGE_RETURN ERROR_QUIET) # Perform additional checks if(PYPACKAGE_RETURN STREQUAL "0") include(DunePathHelper) dune_module_path(MODULE dune-common RESULT scriptdir SCRIPT_DIR) # Check the found version of the given python package # We cannot use find_package_handle_standard_args for that, as it is too # closely tied to using find_package(), which we cannot use for variable package # name... execute_process(COMMAND "${PYPACKAGE_INTERPRETER}" "${scriptdir}/pyversion.py" "${PYPACKAGE_PACKAGE}" RESULT_VARIABLE retcode OUTPUT_VARIABLE VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE ) set(${PYPACKAGE_RESULT} TRUE) if("${retcode}" STREQUAL "0") if(("${VERSION_STRING}" VERSION_LESS "${PYPACKAGE_VERSION}") OR (PYPACKAGE_EXACT AND NOT ("${VERSION_STRING}" VERSION_EQUAL "${PYPACKAGE_VERSION}"))) set(${PYPACKAGE_RESULT} FALSE) endif() else() set(VERSION_STRING "unknown version") if(PYPACKAGE_VERSION) set(${PYPACKAGE_RESULT} FALSE) endif() endif() else() set(${PYPACKAGE_RESULT} FALSE) if(PYPACKAGE_REQUIRED) message(FATAL_ERROR "The python package ${PYPACKAGE_PACKAGE} could not be found! (for interpreter ${PYPACKAGE_INTERPRETER})") endif() endif() # Set the result variable and print the result include(FindPackageHandleStandardArgs) find_package_handle_standard_args(${PYPACKAGE_PACKAGE}_${PYPACKAGE_INTERPRETER} "Failed to find the python package ${PYPACKAGE_PACKAGE} with interpreter ${PYPACKAGE_INTERPRETER}." ${PYPACKAGE_RESULT} ) set(${PYPACKAGE_RESULT} ${${PYPACKAGE_RESULT}} PARENT_SCOPE) endfunction() dune-common-2.8.0/cmake/modules/DunePythonInstallPackage.cmake000066400000000000000000000131131411343567400244030ustar00rootroot00000000000000# This cmake module provides infrastructure for cmake installation rules concerning python packages. # # .. cmake_function:: dune_python_install_package # # .. cmake_param:: PATH # :required: # :single: # # Relative path to the given python package source code. # # .. cmake_param:: ADDITIONAL_PIP_PARAMS # :multi: # :argname: param # # Parameters to add to any :code:`pip install` call (appended). # # This function installs the python package located at the given path. It # # * installs it to the location specified with :ref:`DUNE_PYTHON_INSTALL_LOCATION` during # :code:`make install_python` and during :code:`make install`. # * installs a wheel into the Dune wheelhouse during :code:`make install`. # This is necessary for mixing installed and non-installed Dune modules. # # The package at the given location is expected to be a pip-installable package. # # .. cmake_variable:: DUNE_PYTHON_INSTALL_EDITABLE # # Set this variable to have all installations of python packages use # :code:`pip --editable`. # # # .. cmake_variable:: DUNE_PYTHON_ADDITIONAL_PIP_PARAMS # # Use this variable to set additional flags for pip in this build. This can e.g. # be used to point pip to alternative package indices in restricted environments. # include_guard(GLOBAL) function(dune_python_install_package) # Parse Arguments set(OPTION) set(SINGLE PATH) set(MULTI ADDITIONAL_PIP_PARAMS) include(CMakeParseArguments) cmake_parse_arguments(PYINST "${OPTION}" "${SINGLE}" "${MULTI}" ${ARGN}) if(PYINST_UNPARSED_ARGUMENTS) message(WARNING "Unparsed arguments in dune_python_install_package: This often indicates typos!") endif() set(PYINST_FULLPATH ${CMAKE_CURRENT_SOURCE_DIR}/${PYINST_PATH}) if(EXISTS ${PYINST_FULLPATH}/setup.py.in) configure_file(${PYINST_PATH}/setup.py.in ${PYINST_PATH}/setup.py) set(PYINST_FULLPATH ${CMAKE_CURRENT_BINARY_DIR}/${PYINST_PATH}) set(PYINST_PUREPYTHON FALSE) elseif(EXISTS ${PYINST_FULLPATH}/setup.py) set(PYINST_PUREPYTHON TRUE) else() message(FATAL_ERROR "dune_python_install_package: Requested installations, but neither setup.py nor setup.py.in found!") endif() # Find out whether we should install in editable mode set(INSTALL_EDITABLE ${DUNE_PYTHON_INSTALL_EDITABLE}) # Construct the wheel house installation option string set(WHEEL_OPTION "") if(IS_DIRECTORY ${DUNE_PYTHON_WHEELHOUSE}) set(WHEEL_OPTION "--find-links=${DUNE_PYTHON_WHEELHOUSE}") # # The following line is a bummer! # We cannot have editable packages once we start using global installations! # This is related to the nightmare that is https://github.com/pypa/pip/issues/3 # set(INSTALL_EDITABLE FALSE) endif() # Construct the editable option string set(EDIT_OPTION "") if(INSTALL_EDITABLE) set(EDIT_OPTION "-e") endif() # Construct the installation location option string set(INSTALL_OPTION "") if("${DUNE_PYTHON_INSTALL_LOCATION}" STREQUAL "user") set(INSTALL_OPTION "--user") endif() set(INSTALL_CMDLINE -m pip install "${INSTALL_OPTION}" --upgrade "${WHEEL_OPTION}" "${EDIT_OPTION}" ${PYINST_ADDITIONAL_PIP_PARAMS} ${DUNE_PYTHON_ADDITIONAL_PIP_PARAMS} "${PYINST_FULLPATH}") # Leave this function if no installation rules are required if("${DUNE_PYTHON_INSTALL_LOCATION}" STREQUAL "none" AND NOT DUNE_PYTHON_VIRTUALENV_SETUP) return() endif() # Check for the presence of the pip package if(NOT DUNE_PYTHON_pip_FOUND) message(FATAL_ERROR "dune_python_install_package: Requested installations, but pip was not found!") endif() # # If requested, install into the configure-time Dune virtualenv # if(PYINST_PUREPYTHON AND DUNE_PYTHON_VIRTUALENV_SETUP) message("-- Installing python package at ${CMAKE_CURRENT_SOURCE_DIR}/${PYINST_PATH} into the virtualenv...") dune_execute_process(COMMAND "${DUNE_PYTHON_VIRTUALENV_EXECUTABLE}" "${INSTALL_CMDLINE}" ERROR_MESSAGE "dune_python_install_package: Error installing into virtualenv!") endif() # # Now define rules for `make install_python`. # # Leave this function if no installation rules are required if("${DUNE_PYTHON_INSTALL_LOCATION}" STREQUAL "none") return() endif() dune_module_path(MODULE dune-common RESULT scriptdir SCRIPT_DIR) # Determine a target name for installing this package string(REPLACE "/" "_" targetname "install_python_${CMAKE_CURRENT_SOURCE_DIR}_${PYINST_PATH}") # Add a custom target that globally installs this package if requested add_custom_target(${targetname} COMMAND ${Python3_EXECUTABLE} ${INSTALL_CMDLINE} COMMENT "Installing the python package at ${PYINST_FULLPATH}" ) add_dependencies(install_python ${targetname}) # Define rules for `make install` that install a wheel into a central wheelhouse # # NB: This is necessary, to allow mixing installed and non-installed modules # with python packages. The wheelhouse will allow to install any missing # python packages into a virtual environment. # # Construct the wheel installation commandline set(WHEEL_COMMAND ${Python3_EXECUTABLE} -m pip wheel -w ${DUNE_PYTHON_WHEELHOUSE} ${PYINST_ADDITIONAL_PIP_PARAMS} ${DUNE_PYTHON_ADDITIONAL_PIP_PARAMS} ${PYINST_FULLPATH}) # Add the installation rule install(CODE "message(\"Installing wheel for python package at ${PYINST_FULLPATH}...\") dune_execute_process(COMMAND ${WHEEL_COMMAND} )" ) endfunction() dune-common-2.8.0/cmake/modules/DunePythonMacros.cmake000066400000000000000000000022071411343567400227470ustar00rootroot00000000000000# this option enables the build of Python bindings for DUNE modules option(DUNE_ENABLE_PYTHONBINDINGS "Enable Python bindings for DUNE" OFF) if( DUNE_ENABLE_PYTHONBINDINGS ) if(NOT Python3_Interpreter_FOUND) message(FATAL_ERROR "Python bindings require a Python 3 interpreter") endif() if(NOT Python3_INCLUDE_DIRS) message(FATAL_ERROR "Found a Python interpreter but the Python bindings also requires the Python libraries (a package named like python-dev package or python3-devel)") endif() include_directories("${Python3_INCLUDE_DIRS}") function(add_python_targets base) include(DuneSymlinkOrCopy) if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) message(WARNING "Source and binary dir are the same, skipping symlink!") else() foreach(file ${ARGN}) dune_symlink_to_source_files(FILES ${file}.py) endforeach() endif() endfunction() include(DuneAddPybind11Module) # Add a custom command that triggers the configuration of dune-py add_custom_command(TARGET install_python POST_BUILD COMMAND ${Python3_EXECUTABLE} -m dune configure ) endif() dune-common-2.8.0/cmake/modules/DunePythonTestCommand.cmake000066400000000000000000000074351411343567400237510ustar00rootroot00000000000000# Wrap python testing commands into the CMake build system # # .. cmake_function:: dune_python_add_test # # .. cmake_param:: SCRIPT # :multi: # # The script to execute using the python interpreter. It will be executed during :code:`make test_python` # and during `ctest`. You are required to either pass SCRIPT or MODULE. # # .. note:: # # The script will be executed using :code:`${Python3_EXECUTABLE} SCRIPT`. If the INTERPRETER # option is given, that interpreter is used instead. # # .. cmake_param:: MODULE # :multi: # # The Python module to be executed. It will be executed during :code:`make test_python` # and during `ctest`. You are required to either pass SCRIPT or MODULE. # # .. note:: # # The script will be executed using :code:`${Python3_EXECUTABLE} -m MODULE`. If the INTERPRETER # option is given, that interpreter is used instead. # # .. cmake_param:: INTERPRETER # :single: # # The Python interpreter to use for this test. It defaults to the one found by CMake. # # .. cmake_param:: WORKING_DIRECTORY # :single: # :argname: dir # # The working directory of the command. Defaults to # the current build directory. # # .. cmake_param:: NAME # :single: # # A name to identify this test in ctest. Names must be unique throughout # the project. If omitted, defaults to mangling of the command. # # Integrates a python testing framework command into the Dune # build system. Added commands are run, when the target # :code:`test_python` is built and during :code:`ctest`. # include_guard(GLOBAL) function(dune_python_add_test) # Parse Arguments include(CMakeParseArguments) set(OPTION) set(SINGLE WORKING_DIRECTORY NAME INTERPRETER) set(MULTI SCRIPT COMMAND LABELS MODULE) cmake_parse_arguments(PYTEST "${OPTION}" "${SINGLE}" "${MULTI}" ${ARGN}) if(PYTEST_COMMAND) message(FATAL_ERROR "dune_python_add_test: COMMAND argument should not be used, use SCRIPT instead providing only the Python script and not the Python interpreter") endif() if(PYTEST_UNPARSED_ARGUMENTS) message(WARNING "Unparsed arguments in dune_python_add_test: This often indicates typos!") endif() # Apply defaults if(NOT PYTEST_INTERPRETER) set(PYTEST_INTERPRETER ${Python3_EXECUTABLE}) endif() if(NOT PYTEST_WORKING_DIRECTORY) set(PYTEST_WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) endif() if((NOT PYTEST_MODULE) AND (NOT PYTEST_SCRIPT)) message(FATAL_ERROR "dune_python_add_test: Either SCRIPT or MODULE need to be specified!") endif() if(PYTEST_MODULE AND PYTEST_SCRIPT) message(FATAL_ERROR "dune_python_add_test: You can only specify either SCRIPT or MODULE, not both!") endif() if(PYTEST_MODULE) set(PYTEST_SCRIPT -m ${PYTEST_MODULE}) endif() if(NOT PYTEST_NAME) set(commandstr "") foreach(comm ${PYTEST_SCRIPT}) set(commandstr "${commandstr}_${comm}") endforeach() set(commandstr "${commandstr}_${PYTEST_WORKING_DIRECTORY}") string(REPLACE "/" "_" PYTEST_NAME ${commandstr}) endif() # Actually run the command add_custom_target(target_${PYTEST_NAME} COMMAND ${PYTEST_INTERPRETER} ${PYTEST_SCRIPT} WORKING_DIRECTORY ${PYTEST_WORKING_DIRECTORY}) # Build this during make test_python add_dependencies(test_python target_${PYTEST_NAME}) # make sure each label exists and its name is acceptable dune_declare_test_label(LABELS ${PYTEST_LABELS}) # Also build this during ctest _add_test(NAME ${PYTEST_NAME} COMMAND ${PYTEST_INTERPRETER} ${PYTEST_SCRIPT} WORKING_DIRECTORY ${PYTEST_WORKING_DIRECTORY} ) # Set the labels on the test set_tests_properties(${PYTEST_NAME} PROPERTIES LABELS "${PYTEST_LABELS}") endfunction() dune-common-2.8.0/cmake/modules/DunePythonVirtualenv.cmake000066400000000000000000000264271411343567400236740ustar00rootroot00000000000000# Manage the creation of a configure-time virtual environment # # .. cmake_module:: # # This module manages the creation of virtual python environment during # configuration. Execution of this module must be explicitly enabled by # setting the variable :ref:`DUNE_PYTHON_VIRTUALENV_SETUP`. Note that some # downstream modules will require you to set this variable. The purpose # of this virtual environment is to be able to run python code from cmake # in situations such as python-based code generation, running postprocessing # in python during testing etc. # # Although designed for internal use, this virtualenv can also be manually # inspected. A symlink to the activation script is placed in the top level # build directory of all Dune modules in the stack. To directly execute a # command in the virtualenv, you can use the script :code:`run-in-dune-env `, # which is also placed into every build directory. # # All packages installed with :ref:`dune_python_install_package` are automatically # installed into the virtualenv. # # After execution of this module, the following are available for use in # downstream modules: # # * :code:`DUNE_PYTHON_VIRTUALENV_PATH` The path of the virtual environment # * :code:`DUNE_PYTHON_VIRTUALENV_EXECUTABLE` The python interpreter in the virtual environment # # By default, the created virtualenv resides in the first non-installed Dune module of # the module stack (if no installation is performed: dune-common). Be aware # that mixing installed and non-installed modules may result in a situation, # where multiple such environments are created, although only one should. # You can change this behavior by either specifying a fixed path for the virtualenv # using :ref:`DUNE_PYTHON_VIRTUALENV_PATH` or by enabling # :ref:`DUNE_PYTHON_EXTERNAL_VIRTUALENV_FOR_ABSOLUTE_BUILDDIR` if you are using an # absolute build directory with dunecontrol. Note that this flag is enabled by default # starting from Dune 2.7. # # .. cmake_variable:: DUNE_PYTHON_VIRTUALENV_PATH # # When the Dune build system has setup a virtualenv, this variable will contain its location. # You can also set this variable to a fixed path when CMake, and the virtualenv will be placed # at that location. # # .. cmake_variable:: DUNE_PYTHON_EXTERNAL_VIRTUALENV_FOR_ABSOLUTE_BUILDDIR # # Before Dune 2.7, the virtualenv was always placed inside the build directory of the first # non-installed Dune module that the current module depends on. When using installed core modules # or a multi-stage installation process, this can lead to situations where there are multiple # virtualenvs, making it impossible to find all Python modules installed by upstream modules. # In order to avoid this problem at least for builds using an absolute build directory (i.e., the # :code:`--builddir` option of dunecontrol refers to an absolute path), the build system will # place the virtualenv in a dedicated directory :code:`dune-python-env` inside that absolute # build directory, where it will be found by all Dune modules. If you want to disable this # behavior, set :code:`DUNE_PYTHON_EXTERNAL_VIRTUALENV_FOR_ABSOLUTE_BUILDDIR=0`. # # .. cmake_variable:: DUNE_PYTHON_ALLOW_GET_PIP # # The Dune build system will try to build a virtualenv with pip installed into it, # but this can fail in some situations, in particular on Debian and Ubuntu distributions. # In this case, you will se a warning message in the CMake output. If you are on Debian # or Ubuntu, try installing the :code:`python3-venv` (for Python 3) and / or # :code:`python-virtualenv` packages, delete your build directory and try configuring # again. # # If that still does not help, set this variable to allow the Dune build system to download # :code:`get-pip.py` from https://bootstrap.pypa.io/get-pip.py at configure time and execute # it to install pip into the freshly set up virtual environment. While this should normally # not be necessary anymore, see https://bugs.launchpad.net/debian/+source/python3.4/+bug/1290847 # for more information about the underlying distribution bug. # include_guard(GLOBAL) # If the user has not specified an absolute, we look through the dependency tree of this module # for a build directory that already contains a virtual environment. set(DUNE_PYTHON_VIRTUALENV_PATH "" CACHE PATH "Location of Python virtualenv created by the Dune build system" ) # pre-populate DUNE_PYTHON_EXTERNAL_VIRTUALENV_FOR_ABSOLUTE_BUILDDIR set(DUNE_PYTHON_EXTERNAL_VIRTUALENV_FOR_ABSOLUTE_BUILDDIR ON CACHE BOOL "Place Python virtualenv in top-level directory \"dune-python-env\" when using an absolute build directory" ) if(DUNE_PYTHON_VIRTUALENV_PATH STREQUAL "") foreach(mod ${ALL_DEPENDENCIES}) if(IS_DIRECTORY ${${mod}_DIR}/dune-env) set(DUNE_PYTHON_VIRTUALENV_PATH ${${mod}_DIR}/dune-env) break() endif() endforeach() # if we haven't found it yet, check in the current build directory - this might be a reconfigure if(DUNE_PYTHON_VIRTUALENV_PATH STREQUAL "") if(IS_DIRECTORY ${CMAKE_BINARY_DIR}/dune-env) set(DUNE_PYTHON_VIRTUALENV_PATH ${CMAKE_BINARY_DIR}/dune-env) endif() endif() endif() if(DUNE_PYTHON_VIRTUALENV_PATH STREQUAL "") # We didn't find anything, so figure out the correct location for building the virtualenv if(DUNE_PYTHON_EXTERNAL_VIRTUALENV_FOR_ABSOLUTE_BUILDDIR AND DUNE_BUILD_DIRECTORY_ROOT_PATH) # Use a dedicated directory not associated with any module set(DUNE_PYTHON_VIRTUALENV_PATH "${DUNE_BUILD_DIRECTORY_ROOT_PATH}/dune-python-env") else() # Create the virtualenv inside our build directory set(DUNE_PYTHON_VIRTUALENV_PATH ${CMAKE_BINARY_DIR}/dune-env) endif() endif() # If it does not yet exist, set it up! if(NOT IS_DIRECTORY "${DUNE_PYTHON_VIRTUALENV_PATH}") # Check for presence of the virtualenv/venv package dune_python_find_package(PACKAGE virtualenv) dune_python_find_package(PACKAGE venv) if(NOT(DUNE_PYTHON_virtualenv_FOUND OR DUNE_PYTHON_venv_FOUND)) message(FATAL_ERROR "One of the python packages virtualenv/venv is needed on the host system!") endif() # Set some options depending on which virtualenv package is used if(DUNE_PYTHON_venv_FOUND) set(VIRTUALENV_PACKAGE_NAME venv) set(NOPIP_OPTION --without-pip) set(INTERPRETER_OPTION "") endif() if(DUNE_PYTHON_virtualenv_FOUND) set(VIRTUALENV_PACKAGE_NAME virtualenv) set(NOPIP_OPTION --no-pip) set(INTERPRETER_OPTION -p "${Python3_EXECUTABLE}") endif() if(("${VIRTUALENV_PACKAGE_NAME}" STREQUAL "venv") AND DUNE_PYTHON_SYSTEM_IS_VIRTUALENV) message("-- WARNING: You are using a system interpreter which is a virtualenv and the venv package.") message(" You might want to consider installing the virtualenv package if you experience inconveniences.") endif() # Set up the env itself message("-- Building a virtualenv in ${DUNE_PYTHON_VIRTUALENV_PATH}") # First, try to build it with pip installed, but only if the user has not set DUNE_PYTHON_ALLOW_GET_PIP if(NOT DUNE_PYTHON_ALLOW_GET_PIP) dune_execute_process(COMMAND ${Python3_EXECUTABLE} -m ${VIRTUALENV_PACKAGE_NAME} ${INTERPRETER_OPTION} "${DUNE_PYTHON_VIRTUALENV_PATH}" RESULT_VARIABLE venv_install_result ) endif() if(NOT "${venv_install_result}" STREQUAL "0") if(NOT DUNE_PYTHON_ALLOW_GET_PIP) # we attempted the default installation before, so issue a warning message("-- WARNING: Failed to build a virtual env with pip installed, trying again without pip") message("-- If you are using Debian or Ubuntu, consider installing python3-venv and / or python-virtualenv") endif() # remove the remainder of a potential first attempt file(REMOVE_RECURSE "${DUNE_PYTHON_VIRTUALENV_PATH}") # try to build the env without pip dune_execute_process(COMMAND ${Python3_EXECUTABLE} -m ${VIRTUALENV_PACKAGE_NAME} ${INTERPRETER_OPTION} ${NOPIP_OPTION} "${DUNE_PYTHON_VIRTUALENV_PATH}" ERROR_MESSAGE "Fatal error when setting up a virtualenv." ) endif() else() message("-- Using existing virtualenv in ${DUNE_PYTHON_VIRTUALENV_PATH}") endif() # Also store the virtual env interpreter directly set(DUNE_PYTHON_VIRTUALENV_EXECUTABLE ${DUNE_PYTHON_VIRTUALENV_PATH}/bin/python) # Write a symlink for activation of the environment into all the # build directories of the Dune stack dune_execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${DUNE_PYTHON_VIRTUALENV_PATH}/bin/activate ${CMAKE_BINARY_DIR}/activate) # Also write a small wrapper script 'run-in-dune-env' into the build directory # This is necessary to execute installed python scripts (the bin path of a virtualenv # is *not* in the sys path, so a simple `python scriptname` does not work. if(UNIX) find_package(UnixCommands QUIET) dune_module_path(MODULE dune-common RESULT scriptdir SCRIPT_DIR) configure_file(${scriptdir}/run-in-dune-env.sh.in ${CMAKE_BINARY_DIR}/run-in-dune-env @ONLY) else() message(WARNING "Writing script 'run-in-dune-env' not implemented on your platform!") endif() # The virtualenv might not contain pip due to the distribution bug described in # https://bugs.launchpad.net/debian/+source/python3.4/+bug/1290847 # We need to install pip, so if pip is missing, we offer to download and run the get-pip # script. We ask users for permission to do so, or we allow them to set it up themselves. dune_python_find_package(PACKAGE pip RESULT pippresent INTERPRETER ${DUNE_PYTHON_VIRTUALENV_EXECUTABLE} ) if(NOT pippresent) if(DUNE_PYTHON_ALLOW_GET_PIP) # Fetch the get-pip.py script message("-- Installing pip using https://bootstrap.pypa.io/get-pip.py...") file(DOWNLOAD https://bootstrap.pypa.io/get-pip.py ${CMAKE_CURRENT_BINARY_DIR}/get-pip.py) # Verify that the script was successfully fetched file(READ ${CMAKE_CURRENT_BINARY_DIR}/get-pip.py verify LIMIT 1) if(NOT verify) message(FATAL_ERROR " Fetching get-pip.py failed. This often happens when CMake is built from source without SSL/TLS support. Consider using a different cmake version or fall back to manually installing pip into the virtualenv. ") endif() # Execute the script dune_execute_process(COMMAND ${DUNE_PYTHON_VIRTUALENV_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/get-pip.py ERROR_MESSAGE "Fatal error when installing pip into the virtualenv." ) else() message(FATAL_ERROR "dune-common set up a virtualenv, but needs pip to be installed into it. You can either install it yourself manually activating the virtualenv with the activate script in your build directory ${CMAKE_BINARY_DIR} or you set the CMake variable DUNE_PYTHON_ALLOW_GET_PIP to allow Dune to use get-pip.py from https://bootstrap.pypa.io/get-pip.py") endif() endif() dune-common-2.8.0/cmake/modules/DuneSphinxCMakeDoc.cmake000066400000000000000000000160471411343567400231300ustar00rootroot00000000000000# Module to generate CMake API documentation with Sphinx # # .. cmake_function:: dune_cmake_sphinx_doc # # .. cmake_brief:: # # Generate the documentation that you are just browsing!!! # # .. cmake_param:: BUILDTYPE # :multi: # # Set the type of build that is requested. By default, "html" is chosen. # The list of available build types: # # * `html` # # .. cmake_param:: SPHINX_CONF # :single: # :argname: conf # # A template for a conf file to be passed to :code:`sphinx-build`. # The real configuration file will be generated through CMakes # :code:`configure_file` mechanism. A reasonable default file is # provided by dune-common. Only use this if you want to create # custom documentation. # # .. cmake_param:: RST_SOURCES # :multi: # :argname: src # # A list of rst sources, that should be configured into the build tree # (using :code:`configure_file`). If omitted, this defaults to # :code:`index.rst` and :code:`contents.rst` with suitable content. # Only use this if you want to create custom documentation. # # .. cmake_param:: MODULE_ONLY # :option: # # Only document CMake functionality from the current Dune module. # # Generate a documentation for the CMake API. A set of cmake # modules defined by the parameters and all functions and macros # there in are automatically generated. The top level directory # of the documentation is the current build directory (aka the # directory that this function is called from) # # There are some assumptions on how the documentation in # the CMake modules is written: # # * At the beginning of each CMake module there is a comment block that is written in restructured text. # The first two characters of each line (the comment character # and a blank) are ignored. Any resulting content of lines most form valid rst. # * TODO document more # include_guard(GLOBAL) find_package(Sphinx) # text for feature summary set_package_properties("Sphinx" PROPERTIES DESCRIPTION "Documentation generator" URL "www.sphinx-doc.org" PURPOSE "To generate the documentation from CMake and Python sources") function(dune_cmake_sphinx_doc) # Only proceed if Sphinx was found on the system if(NOT SPHINX_FOUND) message("-- Skipping building CMake API documentation (Sphinx was not found!)") return() endif() # Only proceed if the python interpreter was found by cmake if(NOT Python3_Interpreter_FOUND) message("-- Skipping building CMake API documentation (Python interpreter was not found!)") return() endif() # Parse Arguments set(OPTION MODULE_ONLY) set(SINGLE SPHINX_CONF) set(MULTI BUILDTYPE RST_SOURCES) include(CMakeParseArguments) cmake_parse_arguments(SPHINX_CMAKE "${OPTION}" "${SINGLE}" "${MULTI}" ${ARGN}) if(SPHINX_CMAKE_UNPARSED_ARGUMENTS) message(WARNING "Unparsed arguments in dune_cmake_sphinx_doc: This often indicates typos!") endif() # Apply defaults if(NOT SPHINX_CMAKE_BUILDTYPE) set(SPHINX_CMAKE_BUILDTYPE html) endif() # Extract the script directory from dune-common dune_module_path(MODULE dune-common RESULT DUNE_SPHINX_EXT_PATH SCRIPT_DIR) # Find the configuration file template. if(NOT SPHINX_CMAKE_SPHINX_CONF) set(SPHINX_CMAKE_SPHINX_CONF ${DUNE_SPHINX_EXT_PATH}/conf.py.in) endif() # Apply defaults to the rst sources that are not module dependent. if(NOT SPHINX_CMAKE_RST_SOURCES) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/contents.rst "") set(SPHINX_CMAKE_RST_SOURCES ${DUNE_SPHINX_EXT_PATH}/index.rst.in ${CMAKE_CURRENT_BINARY_DIR}/contents.rst) endif() # Write the conf.py, which sets up Sphinx into the build directory configure_file(${SPHINX_CMAKE_SPHINX_CONF} ${CMAKE_CURRENT_BINARY_DIR}/conf.py) # Check whether we need to look through all dependencies set(DOC_CMAKE_MODULES) if(NOT SPHINX_CMAKE_MODULE_ONLY) set(DOC_CMAKE_MODULES ${ALL_DEPENDENCIES}) endif() # Now treat the module dependent rst sources. set(CMAKE_DOC_DEPENDENCIES "") set(${PROJECT_NAME}_PREFIX ${PROJECT_SOURCE_DIR}) foreach(dep ${DOC_CMAKE_MODULES} ${PROJECT_NAME}) # Look for a build system documentation exported by the module dep set(RSTFILE "") # check in the correct path for non-installed modules if(EXISTS ${${dep}_PREFIX}/doc/buildsystem/${dep}.rst) set(RSTFILE ${${dep}_PREFIX}/doc/buildsystem/${dep}.rst) endif() # now check for the correct path taking into account installed ones if(EXISTS ${${dep}_PREFIX}/share/doc/${dep}/${dep}.rst) set(RSTFILE ${${dep}_PREFIX}/share/doc/${dep}/${dep}.rst) endif() # Now process the file, if we have found one if(RSTFILE) # add it to index.rst then. set(CMAKE_DOC_DEPENDENCIES "${CMAKE_DOC_DEPENDENCIES} ${dep}\n") # ... and copy the rst file to the current build. configure_file(${RSTFILE} ${CMAKE_CURRENT_BINARY_DIR}/${dep}.rst) endif() endforeach() # Write the non-module dependent rst source files from templates foreach(rstin ${SPHINX_CMAKE_RST_SOURCES}) get_filename_component(rst ${rstin} NAME_WE) configure_file(${rstin} ${CMAKE_CURRENT_BINARY_DIR}/${rst}.rst) endforeach() # Generate the list of modules by looking through the module paths # of all dependencies for files matching *.cmake set(SPHINX_DOC_MODULE_LIST) set(${PROJECT_NAME}_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/modules) foreach(dep ${DOC_CMAKE_MODULES} ${PROJECT_NAME}) file(GLOB modules "${${dep}_MODULE_PATH}/*.cmake") set(SPHINX_DOC_MODULE_LIST ${SPHINX_DOC_MODULE_LIST} ${modules}) endforeach() # Initialize a variable that collects all dependencies of the documentation set(DOC_DEPENDENCIES) # Generate the rst files for all cmake modules foreach(module ${SPHINX_DOC_MODULE_LIST}) get_filename_component(modname ${module} NAME) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/modules/${modname} COMMAND ${Python3_EXECUTABLE} ${DUNE_SPHINX_EXT_PATH}/extract_cmake_data.py --module=${module} --builddir=${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${module} COMMENT "Extracting CMake API documentation from ${modname}" ) set(DOC_DEPENDENCIES ${DOC_DEPENDENCIES} ${CMAKE_CURRENT_BINARY_DIR}/modules/${modname}) endforeach() # Call Sphinx once for each requested build type foreach(type ${SPHINX_CMAKE_BUILDTYPE}) # Call the sphinx executable add_custom_target(sphinx_${type} COMMAND ${SPHINX_EXECUTABLE} -b ${type} -w ${PROJECT_BINARY_DIR}/SphinxError.log -c ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${type} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${DOC_DEPENDENCIES} ) add_dependencies(doc sphinx_${type}) endforeach() endfunction() dune-common-2.8.0/cmake/modules/DuneSphinxDoc.cmake000066400000000000000000000066711411343567400222310ustar00rootroot00000000000000include_guard(GLOBAL) find_package(Sphinx) find_package(Python3 COMPONENTS Interpreter Development) function(dune_sphinx_doc) # Only proceed if Sphinx was found on the system if(NOT SPHINX_FOUND) message("-- Skipping building Sphinx documentation (Sphinx was not found!)") return() endif() # Only proceed if the python interpreter was found by cmake if(NOT Python3_Interpreter_FOUND) message("-- Skipping building Sphinx documentation (Python interpreter was not found!)") return() endif() # Parse Arguments include(CMakeParseArguments) cmake_parse_arguments(SPHINX_DOC "" "CONF" "BUILDTYPE" ${ARGN}) if(SPHINX_DOC_UNPARSED_ARGUMENTS) message(WARNING "Unparsed arguments in dune_sphinx_doc") endif() # copy conf.py into build directory if(NOT SPHINX_DOC_CONF) set(SPHINX_DOC_CONF conf.py) endif() if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${SPHINX_DOC_CONF}.in) configure_file(${SPHINX_DOC_CONF}.in ${CMAKE_CURRENT_BINARY_DIR}/conf.py) elseif(EXISTS ${CMAKE_CURRENT_SOUREC_DIR}/${SPHINX_DOC_CONF}) configure_file(${SPHINX_DOC_CONF} ${CMAKE_CURRENT_BINARY_DIR}/conf.py COPYONLY) else() message(SEND_ERROR "Sphinx configuration '${SPHINX_DOC_CONF}' not found.") endif() # call Sphinx for each requested build type if(NOT SPHINX_DOC_BUILDTYPE) set(SPHINX_DOC_BUILDTYPE html) endif() foreach(type ${SPHINX_DOC_BUILDTYPE}) add_custom_target(sphinx_doc_${type} COMMAND ${SPHINX_EXECUTABLE} -b ${type} -w ${PROJECT_BINARY_DIR}/Sphinx-${type}.log -c ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${type} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/conf.py ) add_dependencies(sphinx_doc_${type} sphinx_files) add_dependencies(doc sphinx_doc_${type}) endforeach() endfunction() function(add_sphinx_target base file) find_program(JUPYTER jupyter) get_filename_component(extension ${file} EXT) set(SPHINXDIR ${PROJECT_BINARY_DIR}/doc/sphinx) set(OUT ${SPHINXDIR}/${file}) set(IN ${CMAKE_CURRENT_SOURCE_DIR}/${file}) string(REGEX REPLACE "\\.[^.]*$" "" filebase ${file}) set(TARGET ${base}.${file}) add_custom_target(${TARGET} DEPENDS ${OUT}) add_dependencies(sphinx_files ${TARGET}) add_custom_command( OUTPUT ${OUT} DEPENDS ${IN} COMMAND ${CMAKE_COMMAND} -E copy ${IN} ${OUT} VERBATIM ) if ("${extension}" STREQUAL ".ipynb") if (JUPYTER) set(TARGET ${base}.${filebase}.rst) set(OUTRST ${SPHINXDIR}/${filebase}.rst) add_custom_target(${TARGET} DEPENDS ${OUTRST}) add_dependencies(sphinx_files ${TARGET}) add_custom_command( OUTPUT ${OUTRST} DEPENDS ${OUT} COMMAND jupyter nbconvert --ExecutePreprocessor.timeout=-1 --execute --allow-errors --to="rst" ${OUT} --output ${filebase}.rst COMMAND sed -i "s/raw:: latex/math::/g" ${OUTRST} WORKING_DIRECTORY ${SPHINXDIR} VERBATIM ) endif() endif() endfunction() function(add_sphinx_files base) foreach(file ${ARGN}) add_sphinx_target(${base} ${file}) endforeach() endfunction() function(add_sphinx_targets base) add_custom_target(sphinx_files) add_sphinx_files(${base} ${ARGN}) dune_sphinx_doc() endfunction() dune-common-2.8.0/cmake/modules/DuneStreams.cmake000066400000000000000000000023551411343567400217430ustar00rootroot00000000000000# This Module configures the DUNE debug streams. # # .. cmake_variable:: MINIMAL_DEBUG_LEVEL # # This variable configures the Dune debug streams. # Standard debug streams with level below :code:`MINIMAL_DEBUG_LEVEL` will # collapse to doing nothing if output is requested. Possible values are # :code:`vverb`, :code:`verb`, :code:`info`, :code:`warn` and :code:`grave`. # Defaults to :code:`warn`. # include_guard(GLOBAL) macro(dune_set_minimal_debug_level) set(MINIMAL_DEBUG_LEVEL ON CACHE STRING "set the MINIMAL_DEBUG_LEVEL. Standard debug streams with level below MINIMAL_DEBUG_LEVEL will collapse to doing nothing if output is requested. (default=warn)") set_property(CACHE MINIMAL_DEBUG_LEVEL PROPERTY STRINGS "grave" "warn" "info" "verb" "vverb") if(MINIMAL_DEBUG_LEVEL STREQUAL "grave") set(DUNE_MINIMAL_DEBUG_LEVEL 5) elseif(MINIMAL_DEBUG_LEVEL STREQUAL "info") set(DUNE_MINIMAL_DEBUG_LEVEL 3) elseif(MINIMAL_DEBUG_LEVEL STREQUAL "verb") set(DUNE_MINIMAL_DEBUG_LEVEL 2) elseif(MINIMAL_DEBUG_LEVEL STREQUAL "vverb") set(DUNE_MINIMAL_DEBUG_LEVEL 1) # default to warn else() set(DUNE_MINIMAL_DEBUG_LEVEL 4) endif() message(STATUS "Set Minimal Debug Level to ${DUNE_MINIMAL_DEBUG_LEVEL}") endmacro(dune_set_minimal_debug_level) dune-common-2.8.0/cmake/modules/DuneSymlinkOrCopy.cmake000066400000000000000000000157011411343567400231060ustar00rootroot00000000000000# This module provides convenience macros to provide files from the source tree in the build tree. # # It provides the following macros: # # dune_add_copy_command(filename) # # This macro adds a file-copy command. # The file_name is the name of a file that exists # in the source tree. This file will be copied # to the build tree when executing this command. # Notice that this does not create a top-level # target. In order to do this you have to additionally # call add_custom_target(...) with dependency # on the file. # # dune_add_copy_target(target_name file_name) # # This macro adds a file-copy target under given target_name. # The file_name is the name of a file that exists # in the source tree. This file will be copied # to the build tree. # # dune_add_copy_dependency(target file_name) # # This macro adds a copy-dependency to a target # The file_name is the name of a file that exists # in the source tree. This file will be copied # to the build tree. # # # .. cmake_function:: dune_add_copy_command # # .. cmake_param:: filename # :positional: # :single: # :required: # # TODO DOC ME! # # .. cmake_function:: dune_add_copy_target # # .. cmake_param:: target_name # :positional: # :single: # :required: # # .. cmake_param:: filename # :positional: # :single: # :required: # # TODO DOC ME! # # .. cmake_function:: dune_add_copy_dependency # # .. cmake_param:: target # :positional: # :single: # :required: # # .. cmake_param:: filename # :positional: # :single: # :required: # # TODO DOC ME! # # .. cmake_function:: dune_symlink_to_source_tree # # .. cmake_param:: NAME # :single: # # The name of the symlink, defaults to :code:`src_dir`. # # This function will place a symlink into every subdirectory # of the build tree, that allows to jump to the corresponding # source directory. Call this from your top-level :code:`CMakeLists.txt` # to enable it for a given module. To enable it for all modules, # set the variable :ref:`DUNE_SYMLINK_TO_SOURCE_TREE` instead. # If used on Windows systems, a warning is issued. # # .. cmake_variable:: DUNE_SYMLINK_TO_SOURCE_TREE # # If this variable is set to TRUE, the functionality of # :ref:`dune_symlink_to_source_tree` is enabled in all modules. # This will place symlinks to the corresponding source directory # in every subdirectory of the build directory. # # .. cmake_variable:: DUNE_SYMLINK_RELATIVE_LINKS # # If this variable is set to TRUE, the buildsystem will create relative # links instead of absolute ones. # # .. cmake_function:: dune_symlink_to_source_files # # .. cmake_param:: FILES # :multi: # :required: # # The list of files to symlink # # .. cmake_param:: DESTINATION # :multi: # :required: # # Relative path of the target directory # # Create symlinks in the build tree that # point to particular files in the source directory. This is usually # used for grid and ini files and the like. On Windows systems, # a warning is issued and copying is used as a fallback to # symlinking. # include_guard(GLOBAL) macro(dune_add_copy_command file_name) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${file_name}" COMMAND ${CMAKE_COMMAND} ARGS -E copy "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}" "${file_name}" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}" ) endmacro(dune_add_copy_command file_name) macro(dune_add_copy_target target_name file_name) dune_add_copy_command(${file_name}) add_custom_target("${target_name}" ALL DEPENDS "${file_name}") endmacro(dune_add_copy_target target_name file_name) macro(dune_add_copy_dependency target file_name) message(STATUS "Adding copy-to-build-dir dependency for ${file_name} to target ${target}") dune_add_copy_target("${target}_copy_${file_name}" "${file_name}") add_dependencies(${target} "${target}_copy_${file_name}") endmacro(dune_add_copy_dependency) function(dune_symlink_to_source_tree) # if source and binary dir are equal then the symlink will create serious problems if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) return() endif() # parse arguments include(CMakeParseArguments) cmake_parse_arguments(ARG "" "NAME" "" ${ARGN}) if(NOT ARG_NAME) set(ARG_NAME "src_dir") endif() # check for Windows to issue a warning if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if(NOT DEFINED DUNE_WINDOWS_SYMLINK_WARNING) message(WARNING "Your module wanted to create symlinks, but you cannot do that on your platform.") set(DUNE_WINDOWS_SYMLINK_WARNING) endif() else() # get a list of all files in the current source directory and below. file(GLOB_RECURSE files RELATIVE ${PROJECT_SOURCE_DIR} "*CMakeLists.txt") # iterate over all files, extract the directory name and write a symlink in the corresponding build directory foreach(f ${files}) get_filename_component(dir ${f} DIRECTORY) set(_target "${PROJECT_SOURCE_DIR}/${dir}") if(DUNE_SYMLINK_RELATIVE_LINKS) file(RELATIVE_PATH _target "${PROJECT_BINARY_DIR}/${dir}" "${_target}") endif() execute_process(COMMAND ${CMAKE_COMMAND} "-E" "create_symlink" "${_target}" "${PROJECT_BINARY_DIR}/${dir}/${ARG_NAME}") endforeach() endif() endfunction(dune_symlink_to_source_tree) function(dune_symlink_to_source_files) # if source and binary dir are equal then the symlink will create serious problems if(PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR) return() endif() # parse arguments include(CMakeParseArguments) cmake_parse_arguments(ARG "" "DESTINATION" "FILES" ${ARGN}) if(ARG_UNPARSED_ARGUMENTS) message(WARNING "You are using dune_symlink_to_source_files without named arguments (or have typos in your named arguments)!") endif() # create symlinks for all given files foreach(f ${ARG_FILES}) # check whether there is an explicitly given destination if(ARG_DESTINATION) set(destination "${ARG_DESTINATION}/") else() set(destination "") endif() # check for Windows to issue a warning if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if(NOT DEFINED DUNE_WINDOWS_SYMLINK_WARNING) message(WARNING "Your module wanted to create symlinks, but you cannot do that on your platform.") set(DUNE_WINDOWS_SYMLINK_WARNING) endif() # create a copy execute_process(COMMAND ${CMAKE_COMMAND} "-E" "copy" "${CMAKE_CURRENT_SOURCE_DIR}/${f}" "${CMAKE_CURRENT_BINARY_DIR}/${destination}${f}") else() # create symlink set(_target "${CMAKE_CURRENT_SOURCE_DIR}/${f}") if(DUNE_SYMLINK_RELATIVE_LINKS) file(RELATIVE_PATH _target "${CMAKE_CURRENT_BINARY_DIR}/${destination}" "${_target}") endif() execute_process(COMMAND ${CMAKE_COMMAND} "-E" "create_symlink" "${_target}" "${CMAKE_CURRENT_BINARY_DIR}/${destination}${f}") endif() endforeach() endfunction(dune_symlink_to_source_files) dune-common-2.8.0/cmake/modules/DuneTestMacros.cmake000066400000000000000000000433511411343567400224120ustar00rootroot00000000000000# Module that provides tools for testing the Dune way. # # Note that "the Dune way" of doing this has changed after # the 2.4 release. See the build system documentation for details. # # .. cmake_function:: dune_declare_test_label # # .. cmake_brief:: # # Declare labels for :ref:`dune_add_test`. # # .. cmake_param:: LABELS # :multi: # # The names of labels to declare. Label names must be nonempty and # consist only of alphanumeric characters plus :code:`-` and :code:`_` # to make sure it is easy to construct regular expressions from them for # :code:`ctest -L ${label_regex}`. # # Labels need to be declared to ensure that the target # :code:`build_${label}_tests` exists. They will normally be declared # on-demand by :ref:`dune_add_test`. But sometimes it is useful to be able to # run :code:`make build_${label}_tests` whether or not any tests with that # label exists in a module. For these cases :ref:`dune_declare_test_label` can # be called explicitly. # # The label :code:`quick` is always predeclared. # # .. cmake_function:: dune_add_test # # .. cmake_brief:: # # Adds a test to the Dune testing suite! # # .. cmake_param:: NAME # :single: # # The name of the test that should be added. If an executable # is also added (by specifying SOURCES), the executable is also # named accordingly. If omitted, the name will be deduced from # the (single) sources parameter or from the given target. Note # that this requires you to take care, that you only use a target # or source file for but one such test. # # .. cmake_param:: SOURCES # :multi: # # The source files that this test depends on. These are the # sources that will be passed to :ref:`add_executable`. # # You *must* specify either :code:`SOURCES` or :code:`TARGET`. # # .. cmake_param:: TARGET # :single: # # An executable target which should be used for the test. Use # this option over the :code:`SOURCES` parameter if you want to # reuse already added targets. # # You *must* specify either :code:`SOURCES` or :code:`TARGET`. # # .. cmake_param:: COMPILE_DEFINITIONS # :multi: # :argname: def # # A set of compile definitions to add to the target. # Only definitions beyond the application of :ref:`add_dune_all_flags` # have to be stated. # This is only used, if :code:`dune_add_test` adds the executable itself. # # .. cmake_param:: COMPILE_FLAGS # :multi: # :argname: flag # # A set of non-definition compile flags to add to the target. # Only flags beyond the application of :ref:`add_dune_all_flags` # have to be stated. # This is only used, if :code:`dune_add_test` adds the executable itself. # # .. cmake_param:: LINK_LIBRARIES # :multi: # :argname: lib # # A list of libraries to link the target to. # Only libraries beyond the application of :ref:`add_dune_all_flags` # have to be stated. # This is only used, if :code:`dune_add_test` adds the executable itself. # # .. cmake_param:: EXPECT_COMPILE_FAIL # :option: # # If given, the test is expected to not compile successfully! # # .. cmake_param:: EXPECT_FAIL # :option: # # If given, this test is expected to compile, but fail to run. # # .. cmake_param:: CMD_ARGS # :multi: # :argname: arg # # Command line arguments that should be passed to this test. # # .. cmake_param:: MPI_RANKS # :multi: # :argname: ranks # # The numbers of cores that this test should be executed with. # Note that one test (in the ctest sense) is created for each number # given here. Any number exceeding the user-specified processor maximum # :ref:`DUNE_MAX_TEST_CORES` will be ignored. Tests with a # processor number :code:`n` higher than one will have the suffix # :code:`-mpi-n` appended to their name. You need to specify the # TIMEOUT option when specifying the MPI_RANKS option. # # .. cmake_param:: CMAKE_GUARD # :multi: # :argname: condition # # A number of conditions that CMake should evaluate before adding this # test. If one of the conditions fails, the test should be shown # as skipped in the test summary. Use this feature instead of guarding # the call to :code:`dune_add_test` with an :code:`if` clause. # # The passed condition can be a complex expression like # `( A OR B ) AND ( C OR D )`. Mind the spaces around the parentheses. # # Example: Write CMAKE_GUARD dune-foo_FOUND if you want your test to only # build and run when the dune-foo module is present. # # .. cmake_param:: COMMAND # :multi: # :argname: cmd # # You may specify the COMMAND option to give the exact command line to be # executed when running the test. This defaults to the name of the executable # added by dune_add_test for this test or the name of the executable of the given TARGET. # Note that if you specify both CMD_ARGS # and COMMAND, the given CMD_ARGS will be put behind your COMMAND. If you use # this in combination with the MPI_RANKS parameter, the call to mpi will still be # wrapped around the given commands. # # .. cmake_param:: COMPILE_ONLY # :option: # # Set if the given test should only be compiled during :code:`make build_tests`, # but not run during :code:`make test`. This is useful if you compile the same # executable twice, but with different compile flags, where you want to assure that # it compiles with both sets of flags, but you already know they will produce the # same result. # # .. cmake_param:: TIMEOUT # :single: # # If set, the test will time out after the given number of seconds. This supersedes # any timeout setting in ctest (see `cmake --help-property TIMEOUT`). If you # specify the MPI_RANKS option, you need to specify a TIMEOUT. # # .. cmake_param:: LABELS # :multi: # # A list of labels to add to the test. This has two effects: it sets # the LABELS property on the test so :code:`ctest -L ${label_regex}` can # be used to run all tests with certain labels. It also adds any # targets created as dependencies to a custom target, so you can build # all tests with a particular label by doing :code:`make # build_${label}_tests` without having to build all the other tests as # well. # # The :code:`build_${label}_tests` targets are created on-demand the # first time a test with that label is added. In some situations it can # depend on the values of cmake cache variables whether a test is added, # and then it can happen that the :code:`build_${target}_tests` target # exists only sometimes. If your workflow relies on the existance of # these targets, even if building them just returns successfully without # doing anything, you can ensure they exist by calling # :ref:`dune_declare_test_label` unconditionally. The label # :code:`quick` is always predeclared in this way. # # The label names must be non-empty, and must only contain alphanumeric # characters other than :code:`-` or :code:`_`. This restriction is in # place to make it easy to construct regular expressions from the label # names for :code:`ctest -L ${label_regex}`. # # This function defines the Dune way of adding a test to the testing suite. # You may either add the executable yourself through :ref:`add_executable` # and pass it to the :code:`TARGET` option, or you may rely on :ref:`dune_add_test` # to do so. # # .. cmake_variable:: DUNE_REENABLE_ADD_TEST # # You may set this variable to True either through your opts file or in your module # (before the call to :code:`include(DuneMacros)`) to suppress the error that is thrown if # :code:`add_test` is used. You should only do that if you have proper reason to do so. # # .. cmake_variable:: DUNE_MAX_TEST_CORES # # You may set this variable to give an upperbound to the number of processors, that # a single test may use. Defaults to 2, when MPI is found and to 1 otherwise. # # .. cmake_variable:: DUNE_BUILD_TESTS_ON_MAKE_ALL # # You may set this variable through your opts file or on a per module level (in the toplevel # :code:`CMakeLists.txt` before :code:`include(DuneMacros)`) to have the Dune build system # build all tests during `make all`. Note, that this may take quite some time for some modules. # If not in use, you have to build tests through the target :code:`build_tests`. # include_guard(GLOBAL) # enable the testing suite on the CMake side. enable_testing() include(CTest) # Introduce a target that triggers the building of all tests add_custom_target(build_tests) function(dune_declare_test_label) include(CMakeParseArguments) set(OPTIONS) set(SINGLEARGS) set(MULTIARGS LABELS) cmake_parse_arguments(arg "${OPTIONS}" "${SINGLEARGS}" "${MULTIARGS}" ${ARGN}) if( (DEFINED arg_UNPARSED_ARGUMENTS) AND NOT ( arg_UNPARSED_ARGUMENTS STREQUAL "" ) ) message(FATAL_ERROR "Unhandled extra arguments given to dune_declare_test_label(): " "<${arg_UNPARSED_ARGUMENTS}>") endif() foreach(label IN LISTS arg_LABELS) # Make sure the label is not empty, and does not contain any funny # characters, in particular regex characters if(NOT (label MATCHES "[-_0-9a-zA-Z]+")) message(FATAL_ERROR "Refusing to add label \"${label}\" since it is " "empty or contains funny characters (characters other than " "alphanumeric ones and \"-\" or \"_\"; the intent of this restriction " "is to make construction of the argument to \"ctest -L\" easier") endif() set(target "build_${label}_tests") if(NOT TARGET "${target}") add_custom_target("${target}") endif() endforeach() endfunction(dune_declare_test_label) # predefine "quick" test label so build_quick_tests can be built # unconditionally dune_declare_test_label(LABELS quick) # Set the default on the variable DUNE_MAX_TEST_CORES if(NOT DUNE_MAX_TEST_CORES) set(DUNE_MAX_TEST_CORES 2) endif() function(dune_add_test) include(CMakeParseArguments) set(OPTIONS EXPECT_COMPILE_FAIL EXPECT_FAIL SKIP_ON_77 COMPILE_ONLY) set(SINGLEARGS NAME TARGET TIMEOUT) set(MULTIARGS SOURCES COMPILE_DEFINITIONS COMPILE_FLAGS LINK_LIBRARIES CMD_ARGS MPI_RANKS COMMAND CMAKE_GUARD LABELS) cmake_parse_arguments(ADDTEST "${OPTIONS}" "${SINGLEARGS}" "${MULTIARGS}" ${ARGN}) # Check whether the parser produced any errors if(ADDTEST_UNPARSED_ARGUMENTS) message(WARNING "Unrecognized arguments ('${ADDTEST_UNPARSED_ARGUMENTS}') for dune_add_test!") endif() # Check input for validity and apply defaults if(NOT ADDTEST_SOURCES AND NOT ADDTEST_TARGET) message(FATAL_ERROR "You need to specify either the SOURCES or the TARGET option for dune_add_test!") endif() if(ADDTEST_SOURCES AND ADDTEST_TARGET) message(FATAL_ERROR "You cannot specify both SOURCES and TARGET for dune_add_test") endif() if(NOT ADDTEST_NAME) # try deducing the test name from the executable name if(ADDTEST_TARGET) set(ADDTEST_NAME ${ADDTEST_TARGET}) endif() # try deducing the test name form the source name if(ADDTEST_SOURCES) # deducing a name is only possible with a single source argument list(LENGTH ADDTEST_SOURCES len) if(NOT len STREQUAL "1") message(FATAL_ERROR "Cannot deduce test name from multiple sources!") endif() # strip file extension get_filename_component(ADDTEST_NAME ${ADDTEST_SOURCES} NAME_WE) endif() endif() if(NOT ADDTEST_COMMAND) if(ADDTEST_TARGET) set(ADDTEST_COMMAND ${ADDTEST_TARGET}) else() set(ADDTEST_COMMAND ${ADDTEST_NAME}) endif() endif() if(ADDTEST_MPI_RANKS AND (NOT ADDTEST_TIMEOUT)) message(FATAL_ERROR "dune_add_test: You need to specify the TIMEOUT parameter if using the MPI_RANKS parameter.") endif() if(NOT ADDTEST_MPI_RANKS) set(ADDTEST_MPI_RANKS 1) endif() if(NOT ADDTEST_TIMEOUT) set(ADDTEST_TIMEOUT 300) endif() foreach(num ${ADDTEST_MPI_RANKS}) if(NOT "${num}" MATCHES "[1-9][0-9]*") message(FATAL_ERROR "${num} was given to the MPI_RANKS arugment of dune_add_test, but it does not seem like a correct processor number") endif() endforeach() if(ADDTEST_SKIP_ON_77) message(WARNING "The SKIP_ON_77 option for dune_add_test is obsolete, it is now enabled by default.") endif() # Discard all parallel tests if MPI was not found if(NOT MPI_FOUND) set(DUNE_MAX_TEST_CORES 1) endif() # Find out whether this test should be a dummy set(SHOULD_SKIP_TEST FALSE) set(FAILED_CONDITION_PRINTING "") foreach(condition ${ADDTEST_CMAKE_GUARD}) separate_arguments(condition) if(NOT (${condition})) set(SHOULD_SKIP_TEST TRUE) set(FAILED_CONDITION_PRINTING "${FAILED_CONDITION_PRINTING}std::cout << \" ${condition}\" << std::endl;\n") endif() endforeach() # If we do nothing, switch the sources for a dummy source if(SHOULD_SKIP_TEST) dune_module_path(MODULE dune-common RESULT scriptdir SCRIPT_DIR) set(ADDTEST_TARGET) set(dummymain ${CMAKE_CURRENT_BINARY_DIR}/main77_${ADDTEST_NAME}.cc) configure_file(${scriptdir}/main77.cc.in ${dummymain}) set(ADDTEST_SOURCES ${dummymain}) endif() # Add the executable if it is not already present if(ADDTEST_SOURCES) add_executable(${ADDTEST_NAME} ${ADDTEST_SOURCES}) # add all flags to the target! add_dune_all_flags(${ADDTEST_NAME}) # This is just a placeholder target_compile_definitions(${ADDTEST_NAME} PUBLIC ${ADDTEST_COMPILE_DEFINITIONS}) target_compile_options(${ADDTEST_NAME} PUBLIC ${ADDTEST_COMPILE_FLAGS}) target_link_libraries(${ADDTEST_NAME} PUBLIC ${ADDTEST_LINK_LIBRARIES}) set(ADDTEST_TARGET ${ADDTEST_NAME}) endif() # Make sure to exclude the target from all, even when it is user-provided if(DUNE_BUILD_TESTS_ON_MAKE_ALL AND (NOT ADDTEST_EXPECT_COMPILE_FAIL)) set_property(TARGET ${ADDTEST_TARGET} PROPERTY EXCLUDE_FROM_ALL 0) else() set_property(TARGET ${ADDTEST_TARGET} PROPERTY EXCLUDE_FROM_ALL 1) endif() # make sure each label exists and its name is acceptable dune_declare_test_label(LABELS ${ADDTEST_LABELS}) # Have build_tests and build_${label}_tests depend on the given target in # order to trigger the build correctly if(NOT ADDTEST_EXPECT_COMPILE_FAIL) add_dependencies(build_tests ${ADDTEST_TARGET}) foreach(label IN LISTS ADDTEST_LABELS) add_dependencies(build_${label}_tests ${ADDTEST_TARGET}) endforeach() endif() # Process the EXPECT_COMPILE_FAIL option if(ADDTEST_EXPECT_COMPILE_FAIL) set(ADDTEST_COMMAND "${CMAKE_COMMAND}") set(ADDTEST_CMD_ARGS --build . --target ${ADDTEST_TARGET} --config "$") endif() # Add one test for each specified processor number foreach(procnum ${ADDTEST_MPI_RANKS}) if((NOT "${procnum}" GREATER "${DUNE_MAX_TEST_CORES}") AND (NOT ADDTEST_COMPILE_ONLY)) set(ACTUAL_NAME ${ADDTEST_NAME}) set(ACTUAL_CMD_ARGS ${ADDTEST_CMD_ARGS}) if(TARGET "${ADDTEST_COMMAND}") # if the target name is specified as command, expand to full path using the TARGET_FILE generator expression set(ACTUAL_TESTCOMMAND "$") else() set(ACTUAL_TESTCOMMAND "${ADDTEST_COMMAND}") endif() # modify test name and command for parallel tests if(NOT ${procnum} STREQUAL "1") set(ACTUAL_NAME "${ACTUAL_NAME}-mpi-${procnum}") set(ACTUAL_CMD_ARGS ${MPIEXEC_PREFLAGS} ${MPIEXEC_NUMPROC_FLAG} ${procnum} "${ACTUAL_TESTCOMMAND}" ${MPIEXEC_POSTFLAGS} ${ACTUAL_CMD_ARGS}) set(ACTUAL_TESTCOMMAND "${MPIEXEC}") endif() # if this is a skipped test because a guard was false, overwrite the command if(SHOULD_SKIP_TEST) set(ACTUAL_TESTCOMMAND "$") set(ACTUAL_CMD_ARGS) endif() # Now add the actual test _add_test(NAME ${ACTUAL_NAME} COMMAND "${ACTUAL_TESTCOMMAND}" ${ACTUAL_CMD_ARGS} ) # Make the test depend on the existence of the target to trigger "Not Run" response if(NOT ADDTEST_EXPECT_COMPILE_FAIL) set_tests_properties(${ACTUAL_NAME} PROPERTIES REQUIRED_FILES $) endif() # Define the number of processors (ctest will coordinate this with the -j option) set_tests_properties(${ACTUAL_NAME} PROPERTIES PROCESSORS ${procnum}) # Apply the timeout (which was defaulted to 5 minutes if not specified) set_tests_properties(${ACTUAL_NAME} PROPERTIES TIMEOUT ${ADDTEST_TIMEOUT}) # Process the EXPECT_FAIL option if(ADDTEST_EXPECT_COMPILE_FAIL OR ADDTEST_EXPECT_FAIL) set_tests_properties(${ACTUAL_NAME} PROPERTIES WILL_FAIL true) endif() # When using ninja, we must call the build command from ${PROJECT_BINARY_DIR} if(ADDTEST_EXPECT_COMPILE_FAIL) set_tests_properties(${ACTUAL_NAME} PROPERTIES WORKING_DIRECTORY "${PROJECT_BINARY_DIR}") endif() # Skip the test if the return code is 77! set_tests_properties(${ACTUAL_NAME} PROPERTIES SKIP_RETURN_CODE 77) # Set the labels on the test set_tests_properties(${ACTUAL_NAME} PROPERTIES LABELS "${ADDTEST_LABELS}") endif() endforeach() endfunction() macro(add_directory_test_target) message(FATAL_ERROR "The function add_directory_test_target has been removed alongside all testing magic in dune-common. Check dune_add_test for the new way!") endmacro() macro(add_test) if(NOT DUNE_REENABLE_ADD_TEST) message(SEND_ERROR "Please use dune_add_test instead of add_test! If you need add_test in a downstream project, set the variable DUNE_REENABLE_ADD_TEST to True in that project to suppress this error.") else() _add_test(${ARGN}) endif() endmacro() dune-common-2.8.0/cmake/modules/FindGMP.cmake000066400000000000000000000051351411343567400207340ustar00rootroot00000000000000#[=======================================================================[.rst: FindGMP ------- Find the GNU MULTI-Precision Bignum (GMP) library and the corresponding C++ bindings GMPxx. This module searches for both libraries and only considers the package found if both can be located. It then defines separate targets for the C and the C++ library. Imported Targets ^^^^^^^^^^^^^^^^ This module provides the following imported targets, if found: ``GMP::gmp`` Library target of the C library. ``GMP::gmpxx`` Library target of the C++ library, which also links to the C library. Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``GMP_FOUND`` True if the GMP library, the GMPxx headers and the GMPxx library were found. Cache Variables ^^^^^^^^^^^^^^^ You may set the following variables to modify the behaviour of this module: ``GMP_INCLUDE_DIR`` The directory containing ``gmp.h``. ``GMP_LIB`` The path to the gmp library. ``GMPXX_INCLUDE_DIR`` The directory containing ``gmpxx.h``. ``GMPXX_LIB`` The path to the gmpxx library. #]=======================================================================] # Add a feature summary for this package include(FeatureSummary) set_package_properties(GMP PROPERTIES DESCRIPTION "GNU multi-precision library" URL "https://gmplib.org" ) # Try finding the package with pkg-config find_package(PkgConfig QUIET) pkg_check_modules(PKG QUIET gmp gmpxx) # Try to locate the libraries and their headers, using pkg-config hints find_path(GMP_INCLUDE_DIR gmp.h HINTS ${PKG_gmp_INCLUDEDIR}) find_library(GMP_LIB gmp HINTS ${PKG_gmp_LIBDIR}) find_path(GMPXX_INCLUDE_DIR gmpxx.h HINTS ${PKG_gmpxx_INCLUDEDIR}) find_library(GMPXX_LIB gmpxx HINTS ${PKG_gmpxx_LIBDIR}) # Remove these variables from cache inspector mark_as_advanced(GMP_INCLUDE_DIR GMP_LIB GMPXX_INCLUDE_DIR GMPXX_LIB) # Report if package was found include(FindPackageHandleStandardArgs) find_package_handle_standard_args(GMP DEFAULT_MSG GMPXX_LIB GMPXX_INCLUDE_DIR GMP_INCLUDE_DIR GMP_LIB ) # Set targets if(GMP_FOUND) # C library if(NOT TARGET GMP::gmp) add_library(GMP::gmp UNKNOWN IMPORTED) set_target_properties(GMP::gmp PROPERTIES IMPORTED_LOCATION ${GMP_LIB} INTERFACE_INCLUDE_DIRECTORIES ${GMP_INCLUDE_DIR} ) endif() # C++ library, which requires a link to the C library if(NOT TARGET GMP::gmpxx) add_library(GMP::gmpxx UNKNOWN IMPORTED) set_target_properties(GMP::gmpxx PROPERTIES IMPORTED_LOCATION ${GMPXX_LIB} INTERFACE_INCLUDE_DIRECTORIES ${GMPXX_INCLUDE_DIR} INTERFACE_LINK_LIBRARIES GMP::gmp ) endif() endif() dune-common-2.8.0/cmake/modules/FindInkscape.cmake000066400000000000000000000016331411343567400220450ustar00rootroot00000000000000# .. cmake_module:: # # Module that checks for inkscape # # Sets the following variables # # :code:`INKSCAPE_FOUND` # Whether inkscape was found # # :code:`INKSCAPE` # Path to inkscape to generate .png's form .svg's # find_program(INKSCAPE inkscape DOC "Path to inkscape to generate png files from svg files") find_program(CONVERT convert DOC "Path to convert program") if(INKSCAPE) set(INKSCAPE_FOUND True) # check for inkscape >= 1.0 execute_process(COMMAND ${INKSCAPE} -z -e OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE INKSCAPE_RETURNED_ONE) # if error (i.e. 1) was returned we have new inkscape version (>=1.0) if(INKSCAPE_RETURNED_ONE) set(INKSCAPE_NEW_VERSION True) endif() endif(INKSCAPE) # text for feature summary set_package_properties("Inkscape" PROPERTIES DESCRIPTION "converts SVG images" URL "www.inkscape.org" PURPOSE "To generate the documentation with LaTeX") dune-common-2.8.0/cmake/modules/FindLatexMk.cmake000066400000000000000000000062231411343567400216550ustar00rootroot00000000000000# Find module for LatexMk # # This module honors the following input variables: # LATEXMK_ROOT # Directory to take the latexmk executable from # LATEXMK_DIR # Alternative variable instead of LATEXMK_ROOT # # The module checks for the presence of the LatexMk executable # and sets the following variables: # # LATEXMK_FOUND # Whether the latexmk executable was found on the system # LATEXMK_EXECUTABLE # The full path of the found latexmk executable # LATEXMK_VERSION_STRING # A well readable string of the latexmk version. # LATEXMK_VERSION_MAJOR # The major version of the latexmk executable # LATEXMK_VERSION_MINOR # The minor version of the latexmk executable # # Copyright (c) 2017, Dominic Kempf, Steffen Müthing # # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * 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. # # * Neither the name of the Universität Heidelberg nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # 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 HOLDER 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. # # Find the actual program find_program(LATEXMK_EXECUTABLE latexmk PATHS ${LATEXMK_ROOT} ${LATEXMK_DIR} ) # If found, figure out a version if(LATEXMK_EXECUTABLE) execute_process(COMMAND ${LATEXMK_EXECUTABLE} --version OUTPUT_VARIABLE LATEXMK_VERSION_LINE OUTPUT_STRIP_TRAILING_WHITESPACE ) string(REGEX MATCH "Version.*$" LATEXMK_VERSION_STRING "${LATEXMK_VERSION_LINE}") string(REGEX REPLACE "([0-9]+)\\." "\\1" LATEXMK_VERSION_MINOR "${LATEXMK_VERSION_STRING}") string(REGEX REPLACE "[0-9]+\\.([0-9a-z]+)" "\\1" LATEXMK_VERSION_MAJOR "${LATEXMK_VERSION_STRING}") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(LatexMk FOUND_VAR LATEXMK_FOUND REQUIRED_VARS LATEXMK_EXECUTABLE VERSION_VAR LATEXMK_VERSION_STRING) dune-common-2.8.0/cmake/modules/FindMETIS.cmake000066400000000000000000000140211411343567400211640ustar00rootroot00000000000000#[=======================================================================[.rst: FindMETIS --------- Find Serial Graph Partitioning library METIS (see http://glaros.dtc.umn.edu/gkhome/metis/metis/overview) Imported targets ^^^^^^^^^^^^^^^^ This module defines the following :prop_tgt:`IMPORTED` target: ``METIS::METIS`` The libraries, flags, and includes to use for METIS, if found. Result Variables ^^^^^^^^^^^^^^^^ This module defines the following variables: ``METIS_FOUND`` The METIS library with all its dependencies is found Cache Variables ^^^^^^^^^^^^^^^ The following variables may be set to influence this module's behavior: ``METIS_INCLUDE_DIR`` Include directory of METIS ``METIS_LIBRARY`` Full path to the METIS library ``METIS_API_VERSION`` This variable specifies the METIS API version provided by the scotch-metis library. This is required for Scotch >= 6.0.7 versions if it is not detected automatically. The variable may be set to 3 to indicate that scotch implements the METIS API v3 (default for older Scotch versions), or it can be set to 5 to indicate that v5 of the METIS API is provided. This variable corresponds to the preprocessor flag `SCOTCH_METIS_VERSION` that is used when compiling Scotch from source. #]=======================================================================] # Text for feature summary include(FeatureSummary) set_package_properties("METIS" PROPERTIES DESCRIPTION "Serial Graph Partitioning" ) # The METIS API version provided by the METIS or scotch-metis library set(METIS_API_VERSION 0 CACHE STRING "METIS API version provided by METIS or scotch-metis library") # Try to locate METIS header find_path(METIS_INCLUDE_DIR metis.h PATH_SUFFIXES metis) # Determine version of METIS installation find_file(METIS_HEADER_FILE metis.h PATHS ${METIS_INCLUDE_DIR} NO_DEFAULT_PATH) if(METIS_HEADER_FILE) file(READ "${METIS_HEADER_FILE}" metisheader) string(REGEX REPLACE ".*#define METIS_VER_MAJOR[ ]+([0-9]+).*" "\\1" METIS_MAJOR_VERSION "${metisheader}") string(REGEX REPLACE ".*#define METIS_VER_MINOR[ ]+([0-9]+).*" "\\1" METIS_MINOR_VERSION "${metisheader}") if(METIS_MAJOR_VERSION GREATER_EQUAL 0 AND METIS_MINOR_VERSION GREATER_EQUAL 0) set(METIS_VERSION "${METIS_MAJOR_VERSION}.${METIS_MINOR_VERSION}") # Specify an api version to be used in config.h files or compile flags if(NOT METIS_API_VERSION) if(METIS_MAJOR_VERSION GREATER_EQUAL 3 AND METIS_MAJOR_VERSION LESS 5) set(METIS_API_VERSION "3") else() set(METIS_API_VERSION "${METIS_MAJOR_VERSION}") endif() endif() else() unset(METIS_MAJOR_VERSION) unset(METIS_MINOR_VERSION) endif() # test whether header file is actually the scotch-metis header string(FIND "${metisheader}" "SCOTCH_METIS_PREFIX" IS_SCOTCH_METIS_HEADER) if(IS_SCOTCH_METIS_HEADER EQUAL "-1") set(IS_SCOTCH_METIS_HEADER FALSE) else() set(IS_SCOTCH_METIS_HEADER TRUE) endif() endif() unset(METIS_HEADER_FILE CACHE) # search for the METIS library or for the scotch-metis wrapper library if(IS_SCOTCH_METIS_HEADER) find_library(METIS_LIBRARY scotchmetis) else() find_library(METIS_LIBRARY metis) endif() # We need to check whether we need to link m, copy the lazy solution # from FindBLAS and FindLAPACK here. if(METIS_LIBRARY AND NOT WIN32) set(METIS_NEEDS_LIBM 1) endif() mark_as_advanced(METIS_INCLUDE_DIR METIS_LIBRARY METIS_NEEDS_LIBM METIS_API_VERSION) # If scotch is requested, find package PTScotch and check version compatibility: # Scotch provides METIS-3 interface only in version < 6.07, but provides an option to # select the API-version in later Scotch releases if(IS_SCOTCH_METIS_HEADER) find_package(PTScotch) set(HAVE_SCOTCH_METIS ${PTScotch_SCOTCH_FOUND}) if (PTScotch_SCOTCH_FOUND AND NOT METIS_API_VERSION) if(PTScotch_VERSION VERSION_LESS "6.0.7") set(METIS_API_VERSION "3") else() # try to figure out the METIS_API_VERSION by checking for symbols in the library include(CheckSymbolExists) include(CMakePushCheckState) find_package(Threads) cmake_push_check_state() set(CMAKE_REQUIRED_LIBRARIES ${METIS_LIBRARY} ${SCOTCH_LIBRARY} ${SCOTCHERR_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) if(METIS_NEEDS_LIBM) list(APPEND CMAKE_REQUIRED_LIBRARIES m) endif() set(CMAKE_REQUIRED_INCLUDES ${METIS_INCLUDE_DIR} ${SCOTCH_INCLUDE_DIR}) set(CMAKE_REQUIRED_DEFINITIONS "-DSCOTCH_METIS_VERSION=3") check_symbol_exists("METIS_PartGraphVKway" "stdio.h;stdint.h;scotch.h;metis.h" IS_SCOTCH_METIS_API_V3) if(IS_SCOTCH_METIS_API_V3) set(METIS_API_VERSION "3") else() set(CMAKE_REQUIRED_DEFINITIONS "-DSCOTCH_METIS_VERSION=5") check_symbol_exists("METIS_PartGraphKway" "stdio.h;stdint.h;scotch.h;metis.h" IS_SCOTCH_METIS_API_V5) if(IS_SCOTCH_METIS_API_V5) set(METIS_API_VERSION "5") endif() endif() cmake_pop_check_state() endif() endif() endif() # Behave like a CMake module is supposed to behave include(FindPackageHandleStandardArgs) find_package_handle_standard_args("METIS" REQUIRED_VARS METIS_LIBRARY METIS_INCLUDE_DIR METIS_API_VERSION VERSION_VAR METIS_VERSION ) # If both headers and library are found, create imported target if(METIS_FOUND AND NOT TARGET METIS::METIS) add_library(METIS::METIS UNKNOWN IMPORTED) set_target_properties(METIS::METIS PROPERTIES IMPORTED_LOCATION ${METIS_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES ${METIS_INCLUDE_DIR} INTERFACE_COMPILE_DEFINITIONS METIS_API_VERSION=${METIS_API_VERSION} ) # Link against libm if needed if(METIS_NEEDS_LIBM) set_property(TARGET METIS::METIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES m) endif() # Link against Scotch library if option is enabled if(IS_SCOTCH_METIS_HEADER AND PTScotch_FOUND) set_property(TARGET METIS::METIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES PTScotch::Scotch) set_property(TARGET METIS::METIS APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS SCOTCH_METIS_VERSION=${METIS_API_VERSION}) endif() endif() dune-common-2.8.0/cmake/modules/FindPTScotch.cmake000066400000000000000000000124631411343567400220020ustar00rootroot00000000000000#[=======================================================================[.rst: FindPTScotch ------------ Find library PTScotch, i.e. Software package and libraries for sequential and parallel graph partitioning, static mapping and clustering, sequential mesh and hypergraph partitioning, and sequential and parallel sparse matrix block ordering Components ^^^^^^^^^^ The PTScotch module allows to search for the following components ``SCOTCH`` Sequential version of Scotch ``PTSCOTCH`` Parallel version of Scotch. Requires MPI. Imported targets ^^^^^^^^^^^^^^^^ This module defines the following :prop_tgt:`IMPORTED` target: ``PTScotch::Scotch`` The sequential Scotch library to link against ``PTScotch::PTScotch`` The parallel PTScotch library to link against Result Variables ^^^^^^^^^^^^^^^^ This module defines the following variables: ``PTScotch_FOUND`` The Scotch and/or PTScotch library with all its dependencies is found ``PTScotch_SCOTCH_FOUND`` The sequential Scotch library is found ``PTScotch_PTSCOTCH_FOUND`` The parallel PTScotch library is found ``PTScotch_VERSION`` Version of Scotch that is found Cache Variables ^^^^^^^^^^^^^^^ The following variables may be set to influence this module's behavior: ``PTSCOTCH_SUFFIX`` Scotch might be compiled using different integer sizes (int32, int64, long). When this is set the headers and libaries are search under the suffix :code:`include/scotch-${PTSCOTCH_SUFFIX}`, and :code:`lib/scotch-${PTSCOTCH_SUFFIX}`, respectively. ``SCOTCH_INCLUDE_DIR`` Include directory where the scotch.h is found. ``PTSCOTCH_INCLUDE_DIR`` Include directory where the ptscotch.h is found. ``SCOTCH_LIBRARY`` and ``SCOTCHERR_LIBRARY`` Full path to the scotch library ``PTSCOTCH_LIBRARY`` and ``PTSCOTCHERR_LIBRARY`` Full path to the ptscotch library #]=======================================================================] # text for feature summary include(FeatureSummary) set_package_properties("PTScotch" PROPERTIES DESCRIPTION "Sequential and Parallel Graph Partitioning" ) # find dependency for PTScotch include(CMakeFindDependencyMacro) find_package(MPI QUIET) # search directory might have the PATH_SUFFIX scotch-SUFFIX if(PTSCOTCH_SUFFIX) set(PATH_SUFFIXES "scotch-${PTSCOTCH_SUFFIX}") else() set(PATH_SUFFIXES "scotch") endif() # Try to find the include files find_path(SCOTCH_INCLUDE_DIR scotch.h PATH_SUFFIXES ${PATH_SUFFIXES}) find_path(PTSCOTCH_INCLUDE_DIR ptscotch.h HINTS ${SCOTCH_INCLUDE_DIR} PATH_SUFFIXES ${PATH_SUFFIXES}) # Try to find the (pt)scotch libraries find_library(SCOTCH_LIBRARY scotch) find_library(SCOTCHERR_LIBRARY scotcherr) find_library(PTSCOTCH_LIBRARY ptscotch) find_library(PTSCOTCHERR_LIBRARY ptscotcherr) mark_as_advanced(SCOTCH_INCLUDE_DIR SCOTCH_LIBRARY SCOTCHERR_LIBRARY PTSCOTCH_INCLUDE_DIR PTSCOTCH_LIBRARY PTSCOTCHERR_LIBRARY) # check version of (PT)Scotch find_file(SCOTCH_HEADER "scotch.h" HINTS ${SCOTCH_INCLUDE_DIR} NO_DEFAULT_PATH) if(SCOTCH_HEADER) file(READ "${SCOTCH_HEADER}" scotchheader) string(REGEX REPLACE ".*#define SCOTCH_VERSION[ ]+([0-9]+).*" "\\1" SCOTCH_MAJOR_VERSION "${scotchheader}") string(REGEX REPLACE ".*#define SCOTCH_RELEASE[ ]+([0-9]+).*" "\\1" SCOTCH_MINOR_VERSION "${scotchheader}") string(REGEX REPLACE ".*#define SCOTCH_PATCHLEVEL[ ]+([0-9]+).*" "\\1" SCOTCH_PREFIX_VERSION "${scotchheader}") if(SCOTCH_MAJOR_VERSION GREATER_EQUAL 0) set(PTScotch_VERSION "${SCOTCH_MAJOR_VERSION}") endif() if (SCOTCH_MINOR_VERSION GREATER_EQUAL 0) set(PTScotch_VERSION "${PTScotch_VERSION}.${SCOTCH_MINOR_VERSION}") endif() if (SCOTCH_PREFIX_VERSION GREATER_EQUAL 0) set(PTScotch_VERSION "${PTScotch_VERSION}.${SCOTCH_PREFIX_VERSION}") endif() endif() unset(SCOTCH_HEADER CACHE) # set if (PT)Scotch components found if (SCOTCH_INCLUDE_DIR AND SCOTCH_LIBRARY AND SCOTCHERR_LIBRARY) set(PTScotch_SCOTCH_FOUND TRUE) endif () if (PTSCOTCH_INCLUDE_DIR AND PTSCOTCH_LIBRARY AND PTSCOTCHERR_LIBRARY AND MPI_FOUND) set(PTScotch_PTSCOTCH_FOUND TRUE) endif () # dependencies between components if (NOT PTScotch_SCOTCH_FOUND) set(PTScotch_PTSCOTCH_FOUND FALSE) endif () # behave like a CMake module is supposed to behave include(FindPackageHandleStandardArgs) find_package_handle_standard_args("PTScotch" REQUIRED_VARS SCOTCH_LIBRARY SCOTCHERR_LIBRARY SCOTCH_INCLUDE_DIR VERSION_VAR PTScotch_VERSION HANDLE_COMPONENTS ) if(PTScotch_FOUND) # Define an imported target for the sequential Scotch library if(PTScotch_SCOTCH_FOUND AND NOT TARGET PTScotch::Scotch) add_library(PTScotch::Scotch UNKNOWN IMPORTED) set_target_properties(PTScotch::Scotch PROPERTIES IMPORTED_LOCATION ${SCOTCH_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES ${SCOTCH_INCLUDE_DIR} INTERFACE_LINK_LIBRARIES ${SCOTCHERR_LIBRARY} ) endif() # Define an imported target for the parallel PTScotch library if(PTScotch_SCOTCH_FOUND AND PTScotch_PTSCOTCH_FOUND AND NOT TARGET PTScotch::PTScotch) add_library(PTScotch::PTScotch UNKNOWN IMPORTED) set_target_properties(PTScotch::PTScotch PROPERTIES IMPORTED_LOCATION ${PTSCOTCH_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES ${PTSCOTCH_INCLUDE_DIR} INTERFACE_LINK_LIBRARIES ${PTSCOTCHERR_LIBRARY} ) target_link_libraries(PTScotch::PTScotch INTERFACE PTScotch::Scotch MPI::MPI_C) endif() endif() dune-common-2.8.0/cmake/modules/FindParMETIS.cmake000066400000000000000000000073671411343567400216460ustar00rootroot00000000000000#[=======================================================================[.rst: FindParMETIS ------------ Find Parallel Graph Partitioning library ParMETIS (see http://glaros.dtc.umn.edu/gkhome/metis/parmetis/overview) Imported targets ^^^^^^^^^^^^^^^^ This module defines the following :prop_tgt:`IMPORTED` target: ``ParMETIS::ParMETIS`` The libraries, flags, and includes to use for ParMETIS, if found. Result Variables ^^^^^^^^^^^^^^^^ This module defines the following variables: ``ParMETIS_FOUND`` The ParMETIS library with all its dependencies is found Cache Variables ^^^^^^^^^^^^^^^ The following variables may be set to influence this module's behavior: ``PARMETIS_INCLUDE_DIR`` Include directory where the parmetis.h is found. ``PARMETIS_LIBRARY`` Full path to the ParMETIS library #]=======================================================================] # text for feature summary include(FeatureSummary) set_package_properties("ParMETIS" PROPERTIES DESCRIPTION "Parallel Graph Partitioning" ) find_path(PARMETIS_INCLUDE_DIR parmetis.h PATH_SUFFIXES parmetis) # determine version of ParMETIS installation find_file(PARMETIS_HEADER_FILE parmetis.h PATHS ${PARMETIS_INCLUDE_DIR} NO_DEFAULT_PATH) if(PARMETIS_HEADER_FILE) file(READ "${PARMETIS_HEADER_FILE}" parmetisheader) string(REGEX REPLACE ".*#define PARMETIS_MAJOR_VERSION[ ]+([0-9]+).*" "\\1" ParMETIS_MAJOR_VERSION "${parmetisheader}") string(REGEX REPLACE ".*#define PARMETIS_MINOR_VERSION[ ]+([0-9]+).*" "\\1" ParMETIS_MINOR_VERSION "${parmetisheader}") if(ParMETIS_MAJOR_VERSION GREATER_EQUAL 0 AND ParMETIS_MINOR_VERSION GREATER_EQUAL 0) set(ParMETIS_VERSION "${ParMETIS_MAJOR_VERSION}.${ParMETIS_MINOR_VERSION}") endif() # test whether header file is actually the ptscotch-parmetis header string(FIND "${parmetisheader}" "SCOTCH_METIS_PREFIX" IS_PTSCOTCH_PARMETIS_HEADER) if(IS_PTSCOTCH_PARMETIS_HEADER EQUAL "-1") set(IS_PTSCOTCH_PARMETIS_HEADER FALSE) else() set(IS_PTSCOTCH_PARMETIS_HEADER TRUE) endif() endif() unset(PARMETIS_HEADER_FILE CACHE) # search ParMETIS library if(IS_PTSCOTCH_PARMETIS_HEADER) find_library(PARMETIS_LIBRARY ptscotchparmetis) else() find_library(PARMETIS_LIBRARY parmetis) endif() mark_as_advanced(PARMETIS_INCLUDE_DIR PARMETIS_LIBRARY) # minimal requires METIS version 5.0 for ParMETIS >= 4.0 if(ParMETIS_VERSION VERSION_GREATER_EQUAL "4.0") set(METIS_MIN_VERSION "5.0") endif() # find package dependencies first find_package(METIS ${METIS_MIN_VERSION}) find_package(MPI COMPONENTS C) # set a list of required dependencies for ParMETIS set(PARMETIS_DEPENDENCIES METIS_FOUND MPI_FOUND) # If ptscotch-parmetis is requested, find package PTScotch if(IS_PTSCOTCH_PARMETIS_HEADER) find_package(PTScotch) set(HAVE_PTSCOTCH_PARMETIS ${PTScotch_PTSCOTCH_FOUND}) list(APPEND PARMETIS_DEPENDENCIES PTScotch_PTSCOTCH_FOUND) endif() # behave like a CMake module is supposed to behave include(FindPackageHandleStandardArgs) find_package_handle_standard_args("ParMETIS" REQUIRED_VARS PARMETIS_LIBRARY PARMETIS_INCLUDE_DIR ${PARMETIS_DEPENDENCIES} VERSION_VAR ParMETIS_VERSION ) # create imported target ParMETIS::ParMETIS if(PARMETIS_FOUND AND NOT TARGET ParMETIS::ParMETIS) add_library(ParMETIS::ParMETIS UNKNOWN IMPORTED) set_target_properties(ParMETIS::ParMETIS PROPERTIES IMPORTED_LOCATION ${PARMETIS_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES ${PARMETIS_INCLUDE_DIR} INTERFACE_LINK_LIBRARIES "METIS::METIS;MPI::MPI_C" INTERFACE_COMPILE_DEFINITIONS "MPICH_SKIP_MPICXX;OMPI_SKIP_MPICXX" ) # link against PTScotch if needed if(IS_PTSCOTCH_PARMETIS_HEADER AND PTScotch_PTSCOTCH_FOUND) set_property(TARGET ParMETIS::ParMETIS APPEND PROPERTY INTERFACE_LINK_LIBRARIES PTScotch::PTScotch) endif() endif() dune-common-2.8.0/cmake/modules/FindPkgConfig/000077500000000000000000000000001411343567400211525ustar00rootroot00000000000000dune-common-2.8.0/cmake/modules/FindPkgConfig/CMakeLists.txt000066400000000000000000000001321411343567400237060ustar00rootroot00000000000000install(FILES FindPkgConfig.cmake DESTINATION ${DUNE_INSTALL_MODULEDIR}/FindPkgConfig)dune-common-2.8.0/cmake/modules/FindPkgConfig/FindPkgConfig.cmake000066400000000000000000000775771411343567400246530ustar00rootroot00000000000000# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. # Note, this is a backport of the cmake/Modules/FindPkgConfig.cmake file from cmake version 3.19.4 #[========================================[.rst: FindPkgConfig ------------- A ``pkg-config`` module for CMake. Finds the ``pkg-config`` executable and adds the :command:`pkg_get_variable`, :command:`pkg_check_modules` and :command:`pkg_search_module` commands. The following variables will also be set: ``PKG_CONFIG_FOUND`` if pkg-config executable was found ``PKG_CONFIG_EXECUTABLE`` pathname of the pkg-config program ``PKG_CONFIG_VERSION_STRING`` version of pkg-config (since CMake 2.8.8) #]========================================] cmake_policy(PUSH) cmake_policy(SET CMP0054 NEW) # if() quoted variables not dereferenced cmake_policy(SET CMP0057 NEW) # if IN_LIST ### Common stuff #### set(PKG_CONFIG_VERSION 1) # find pkg-config, use PKG_CONFIG if set if((NOT PKG_CONFIG_EXECUTABLE) AND (NOT "$ENV{PKG_CONFIG}" STREQUAL "")) set(PKG_CONFIG_EXECUTABLE "$ENV{PKG_CONFIG}" CACHE FILEPATH "pkg-config executable") endif() set(PKG_CONFIG_NAMES "pkg-config") if(CMAKE_HOST_WIN32) list(PREPEND PKG_CONFIG_NAMES "pkg-config.bat") endif() find_program(PKG_CONFIG_EXECUTABLE NAMES ${PKG_CONFIG_NAMES} DOC "pkg-config executable") mark_as_advanced(PKG_CONFIG_EXECUTABLE) set(_PKG_CONFIG_FAILURE_MESSAGE "") if (PKG_CONFIG_EXECUTABLE) execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --version OUTPUT_VARIABLE PKG_CONFIG_VERSION_STRING OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_VARIABLE _PKG_CONFIG_VERSION_ERROR ERROR_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE _PKG_CONFIG_VERSION_RESULT ) if (NOT _PKG_CONFIG_VERSION_RESULT EQUAL 0) string(REPLACE "\n" "\n " _PKG_CONFIG_VERSION_ERROR " ${_PKG_CONFIG_VERSION_ERROR}") string(APPEND _PKG_CONFIG_FAILURE_MESSAGE "The command\n" " \"${PKG_CONFIG_EXECUTABLE}\" --version\n" " failed with output:\n${PKG_CONFIG_VERSION_STRING}\n" " stderr: \n${_PKG_CONFIG_VERSION_ERROR}\n" " result: \n${_PKG_CONFIG_VERSION_RESULT}" ) set(PKG_CONFIG_EXECUTABLE "") unset(PKG_CONFIG_VERSION_STRING) endif () unset(_PKG_CONFIG_VERSION_RESULT) endif () include(FindPackageHandleStandardArgs) find_package_handle_standard_args(PkgConfig REQUIRED_VARS PKG_CONFIG_EXECUTABLE FAIL_MESSAGE "${_PKG_CONFIG_FAILURE_MESSAGE}" VERSION_VAR PKG_CONFIG_VERSION_STRING) # This is needed because the module name is "PkgConfig" but the name of # this variable has always been PKG_CONFIG_FOUND so this isn't automatically # handled by FPHSA. set(PKG_CONFIG_FOUND "${PKGCONFIG_FOUND}") # Unsets the given variables macro(_pkgconfig_unset var) set(${var} "" CACHE INTERNAL "") endmacro() macro(_pkgconfig_set var value) set(${var} ${value} CACHE INTERNAL "") endmacro() # Invokes pkgconfig, cleans up the result and sets variables macro(_pkgconfig_invoke _pkglist _prefix _varname _regexp) set(_pkgconfig_invoke_result) execute_process( COMMAND ${PKG_CONFIG_EXECUTABLE} ${ARGN} ${_pkglist} OUTPUT_VARIABLE _pkgconfig_invoke_result RESULT_VARIABLE _pkgconfig_failed OUTPUT_STRIP_TRAILING_WHITESPACE) if (_pkgconfig_failed) set(_pkgconfig_${_varname} "") _pkgconfig_unset(${_prefix}_${_varname}) else() string(REGEX REPLACE "[\r\n]" " " _pkgconfig_invoke_result "${_pkgconfig_invoke_result}") if (NOT ${_regexp} STREQUAL "") string(REGEX REPLACE "${_regexp}" " " _pkgconfig_invoke_result "${_pkgconfig_invoke_result}") endif() separate_arguments(_pkgconfig_invoke_result) #message(STATUS " ${_varname} ... ${_pkgconfig_invoke_result}") set(_pkgconfig_${_varname} ${_pkgconfig_invoke_result}) _pkgconfig_set(${_prefix}_${_varname} "${_pkgconfig_invoke_result}") endif() endmacro() # Internal version of pkg_get_variable; expects PKG_CONFIG_PATH to already be set function (_pkg_get_variable result pkg variable) _pkgconfig_invoke("${pkg}" "prefix" "result" "" "--variable=${variable}") set("${result}" "${prefix_result}" PARENT_SCOPE) endfunction () # Invokes pkgconfig two times; once without '--static' and once with # '--static' macro(_pkgconfig_invoke_dyn _pkglist _prefix _varname cleanup_regexp) _pkgconfig_invoke("${_pkglist}" ${_prefix} ${_varname} "${cleanup_regexp}" ${ARGN}) _pkgconfig_invoke("${_pkglist}" ${_prefix} STATIC_${_varname} "${cleanup_regexp}" --static ${ARGN}) endmacro() # Splits given arguments into options and a package list macro(_pkgconfig_parse_options _result _is_req _is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global) set(${_is_req} 0) set(${_is_silent} 0) set(${_no_cmake_path} 0) set(${_no_cmake_environment_path} 0) set(${_imp_target} 0) set(${_imp_target_global} 0) if(DEFINED PKG_CONFIG_USE_CMAKE_PREFIX_PATH) if(NOT PKG_CONFIG_USE_CMAKE_PREFIX_PATH) set(${_no_cmake_path} 1) set(${_no_cmake_environment_path} 1) endif() elseif(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 3.1) set(${_no_cmake_path} 1) set(${_no_cmake_environment_path} 1) endif() foreach(_pkg ${ARGN}) if (_pkg STREQUAL "REQUIRED") set(${_is_req} 1) endif () if (_pkg STREQUAL "QUIET") set(${_is_silent} 1) endif () if (_pkg STREQUAL "NO_CMAKE_PATH") set(${_no_cmake_path} 1) endif() if (_pkg STREQUAL "NO_CMAKE_ENVIRONMENT_PATH") set(${_no_cmake_environment_path} 1) endif() if (_pkg STREQUAL "IMPORTED_TARGET") set(${_imp_target} 1) endif() if (_pkg STREQUAL "GLOBAL") set(${_imp_target_global} 1) endif() endforeach() if (${_imp_target_global} AND NOT ${_imp_target}) message(SEND_ERROR "the argument GLOBAL may only be used together with IMPORTED_TARGET") endif() set(${_result} ${ARGN}) list(REMOVE_ITEM ${_result} "REQUIRED") list(REMOVE_ITEM ${_result} "QUIET") list(REMOVE_ITEM ${_result} "NO_CMAKE_PATH") list(REMOVE_ITEM ${_result} "NO_CMAKE_ENVIRONMENT_PATH") list(REMOVE_ITEM ${_result} "IMPORTED_TARGET") list(REMOVE_ITEM ${_result} "GLOBAL") endmacro() # Add the content of a variable or an environment variable to a list of # paths # Usage: # - _pkgconfig_add_extra_path(_extra_paths VAR) # - _pkgconfig_add_extra_path(_extra_paths ENV VAR) function(_pkgconfig_add_extra_path _extra_paths_var _var) set(_is_env 0) if(ARGC GREATER 2 AND _var STREQUAL "ENV") set(_var ${ARGV2}) set(_is_env 1) endif() if(NOT _is_env) if(NOT "${${_var}}" STREQUAL "") list(APPEND ${_extra_paths_var} ${${_var}}) endif() else() if(NOT "$ENV{${_var}}" STREQUAL "") file(TO_CMAKE_PATH "$ENV{${_var}}" _path) list(APPEND ${_extra_paths_var} ${_path}) unset(_path) endif() endif() set(${_extra_paths_var} ${${_extra_paths_var}} PARENT_SCOPE) endfunction() # scan the LDFLAGS returned by pkg-config for library directories and # libraries, figure out the absolute paths of that libraries in the # given directories function(_pkg_find_libs _prefix _no_cmake_path _no_cmake_environment_path) unset(_libs) unset(_find_opts) # set the options that are used as long as the .pc file does not provide a library # path to look into if(_no_cmake_path) list(APPEND _find_opts "NO_CMAKE_PATH") endif() if(_no_cmake_environment_path) list(APPEND _find_opts "NO_CMAKE_ENVIRONMENT_PATH") endif() unset(_search_paths) unset(_next_is_framework) foreach (flag IN LISTS ${_prefix}_LDFLAGS) if (_next_is_framework) list(APPEND _libs "-framework ${flag}") unset(_next_is_framework) continue() endif () if (flag MATCHES "^-L(.*)") list(APPEND _search_paths ${CMAKE_MATCH_1}) continue() endif() if (flag MATCHES "^-l(.*)") set(_pkg_search "${CMAKE_MATCH_1}") else() if (flag STREQUAL "-framework") set(_next_is_framework TRUE) endif () continue() endif() if(_search_paths) # Firstly search in -L paths find_library(pkgcfg_lib_${_prefix}_${_pkg_search} NAMES ${_pkg_search} HINTS ${_search_paths} NO_DEFAULT_PATH) endif() find_library(pkgcfg_lib_${_prefix}_${_pkg_search} NAMES ${_pkg_search} ${_find_opts}) mark_as_advanced(pkgcfg_lib_${_prefix}_${_pkg_search}) if(pkgcfg_lib_${_prefix}_${_pkg_search}) list(APPEND _libs "${pkgcfg_lib_${_prefix}_${_pkg_search}}") else() list(APPEND _libs ${_pkg_search}) endif() endforeach() set(${_prefix}_LINK_LIBRARIES "${_libs}" PARENT_SCOPE) endfunction() # create an imported target from all the information returned by pkg-config function(_pkg_create_imp_target _prefix _imp_target_global) # only create the target if it is linkable, i.e. no executables if (NOT TARGET PkgConfig::${_prefix} AND ( ${_prefix}_INCLUDE_DIRS OR ${_prefix}_LINK_LIBRARIES OR ${_prefix}_LDFLAGS_OTHER OR ${_prefix}_CFLAGS_OTHER )) if(${_imp_target_global}) set(_global_opt "GLOBAL") else() unset(_global_opt) endif() add_library(PkgConfig::${_prefix} INTERFACE IMPORTED ${_global_opt}) if(${_prefix}_INCLUDE_DIRS) set_property(TARGET PkgConfig::${_prefix} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_prefix}_INCLUDE_DIRS}") endif() if(${_prefix}_LINK_LIBRARIES) set_property(TARGET PkgConfig::${_prefix} PROPERTY INTERFACE_LINK_LIBRARIES "${${_prefix}_LINK_LIBRARIES}") endif() if(${_prefix}_LDFLAGS_OTHER) set_property(TARGET PkgConfig::${_prefix} PROPERTY INTERFACE_LINK_OPTIONS "${${_prefix}_LDFLAGS_OTHER}") endif() if(${_prefix}_CFLAGS_OTHER) set_property(TARGET PkgConfig::${_prefix} PROPERTY INTERFACE_COMPILE_OPTIONS "${${_prefix}_CFLAGS_OTHER}") endif() endif() endfunction() # recalculate the dynamic output # this is a macro and not a function so the result of _pkg_find_libs is automatically propagated macro(_pkg_recalculate _prefix _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global) _pkg_find_libs(${_prefix} ${_no_cmake_path} ${_no_cmake_environment_path}) if(${_imp_target}) _pkg_create_imp_target(${_prefix} ${_imp_target_global}) endif() endmacro() ### macro(_pkg_set_path_internal) set(_extra_paths) if(NOT _no_cmake_path) _pkgconfig_add_extra_path(_extra_paths CMAKE_PREFIX_PATH) _pkgconfig_add_extra_path(_extra_paths CMAKE_FRAMEWORK_PATH) _pkgconfig_add_extra_path(_extra_paths CMAKE_APPBUNDLE_PATH) endif() if(NOT _no_cmake_environment_path) _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_PREFIX_PATH) _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_FRAMEWORK_PATH) _pkgconfig_add_extra_path(_extra_paths ENV CMAKE_APPBUNDLE_PATH) endif() if(NOT _extra_paths STREQUAL "") # Save the PKG_CONFIG_PATH environment variable, and add paths # from the CMAKE_PREFIX_PATH variables set(_pkgconfig_path_old "$ENV{PKG_CONFIG_PATH}") set(_pkgconfig_path "${_pkgconfig_path_old}") if(NOT _pkgconfig_path STREQUAL "") file(TO_CMAKE_PATH "${_pkgconfig_path}" _pkgconfig_path) endif() # Create a list of the possible pkgconfig subfolder (depending on # the system set(_lib_dirs) if(NOT DEFINED CMAKE_SYSTEM_NAME OR (CMAKE_SYSTEM_NAME MATCHES "^(Linux|kFreeBSD|GNU)$" AND NOT CMAKE_CROSSCOMPILING)) if(EXISTS "/etc/debian_version") # is this a debian system ? if(CMAKE_LIBRARY_ARCHITECTURE) list(APPEND _lib_dirs "lib/${CMAKE_LIBRARY_ARCHITECTURE}/pkgconfig") endif() else() # not debian, check the FIND_LIBRARY_USE_LIB32_PATHS and FIND_LIBRARY_USE_LIB64_PATHS properties get_property(uselib32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS) if(uselib32 AND CMAKE_SIZEOF_VOID_P EQUAL 4) list(APPEND _lib_dirs "lib32/pkgconfig") endif() get_property(uselib64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS) if(uselib64 AND CMAKE_SIZEOF_VOID_P EQUAL 8) list(APPEND _lib_dirs "lib64/pkgconfig") endif() get_property(uselibx32 GLOBAL PROPERTY FIND_LIBRARY_USE_LIBX32_PATHS) if(uselibx32 AND CMAKE_INTERNAL_PLATFORM_ABI STREQUAL "ELF X32") list(APPEND _lib_dirs "libx32/pkgconfig") endif() endif() endif() if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" AND NOT CMAKE_CROSSCOMPILING) list(APPEND _lib_dirs "libdata/pkgconfig") endif() list(APPEND _lib_dirs "lib/pkgconfig") list(APPEND _lib_dirs "share/pkgconfig") # Check if directories exist and eventually append them to the # pkgconfig path list foreach(_prefix_dir ${_extra_paths}) foreach(_lib_dir ${_lib_dirs}) if(EXISTS "${_prefix_dir}/${_lib_dir}") list(APPEND _pkgconfig_path "${_prefix_dir}/${_lib_dir}") list(REMOVE_DUPLICATES _pkgconfig_path) endif() endforeach() endforeach() # Prepare and set the environment variable if(NOT _pkgconfig_path STREQUAL "") # remove empty values from the list list(REMOVE_ITEM _pkgconfig_path "") file(TO_NATIVE_PATH "${_pkgconfig_path}" _pkgconfig_path) if(CMAKE_HOST_UNIX) string(REPLACE ";" ":" _pkgconfig_path "${_pkgconfig_path}") string(REPLACE "\\ " " " _pkgconfig_path "${_pkgconfig_path}") endif() set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path}") endif() # Unset variables unset(_lib_dirs) unset(_pkgconfig_path) endif() endmacro() macro(_pkg_restore_path_internal) if(NOT _extra_paths STREQUAL "") # Restore the environment variable set(ENV{PKG_CONFIG_PATH} "${_pkgconfig_path_old}") endif() unset(_extra_paths) unset(_pkgconfig_path_old) endmacro() # pkg-config returns frameworks in --libs-only-other # they need to be in ${_prefix}_LIBRARIES so "-framework a -framework b" does # not incorrectly be combined to "-framework a b" function(_pkgconfig_extract_frameworks _prefix) set(ldflags "${${_prefix}_LDFLAGS_OTHER}") list(FIND ldflags "-framework" FR_POS) list(LENGTH ldflags LD_LENGTH) # reduce length by 1 as we need "-framework" and the next entry math(EXPR LD_LENGTH "${LD_LENGTH} - 1") while (FR_POS GREATER -1 AND LD_LENGTH GREATER FR_POS) list(REMOVE_AT ldflags ${FR_POS}) list(GET ldflags ${FR_POS} HEAD) list(REMOVE_AT ldflags ${FR_POS}) math(EXPR LD_LENGTH "${LD_LENGTH} - 2") list(APPEND LIBS "-framework ${HEAD}") list(FIND ldflags "-framework" FR_POS) endwhile () set(${_prefix}_LIBRARIES ${${_prefix}_LIBRARIES} ${LIBS} PARENT_SCOPE) set(${_prefix}_LDFLAGS_OTHER "${ldflags}" PARENT_SCOPE) endfunction() # pkg-config returns -isystem include directories in --cflags-only-other, # depending on the version and if there is a space between -isystem and # the actual path function(_pkgconfig_extract_isystem _prefix) set(cflags "${${_prefix}_CFLAGS_OTHER}") set(outflags "") set(incdirs "${${_prefix}_INCLUDE_DIRS}") set(next_is_isystem FALSE) foreach (THING IN LISTS cflags) # This may filter "-isystem -isystem". That would not work anyway, # so let it happen. if (THING STREQUAL "-isystem") set(next_is_isystem TRUE) continue() endif () if (next_is_isystem) set(next_is_isystem FALSE) list(APPEND incdirs "${THING}") elseif (THING MATCHES "^-isystem") string(SUBSTRING "${THING}" 8 -1 THING) list(APPEND incdirs "${THING}") else () list(APPEND outflags "${THING}") endif () endforeach () set(${_prefix}_CFLAGS_OTHER "${outflags}" PARENT_SCOPE) set(${_prefix}_INCLUDE_DIRS "${incdirs}" PARENT_SCOPE) endfunction() ### macro(_pkg_check_modules_internal _is_required _is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global _prefix) _pkgconfig_unset(${_prefix}_FOUND) _pkgconfig_unset(${_prefix}_VERSION) _pkgconfig_unset(${_prefix}_PREFIX) _pkgconfig_unset(${_prefix}_INCLUDEDIR) _pkgconfig_unset(${_prefix}_LIBDIR) _pkgconfig_unset(${_prefix}_MODULE_NAME) _pkgconfig_unset(${_prefix}_LIBS) _pkgconfig_unset(${_prefix}_LIBS_L) _pkgconfig_unset(${_prefix}_LIBS_PATHS) _pkgconfig_unset(${_prefix}_LIBS_OTHER) _pkgconfig_unset(${_prefix}_CFLAGS) _pkgconfig_unset(${_prefix}_CFLAGS_I) _pkgconfig_unset(${_prefix}_CFLAGS_OTHER) _pkgconfig_unset(${_prefix}_STATIC_LIBDIR) _pkgconfig_unset(${_prefix}_STATIC_LIBS) _pkgconfig_unset(${_prefix}_STATIC_LIBS_L) _pkgconfig_unset(${_prefix}_STATIC_LIBS_PATHS) _pkgconfig_unset(${_prefix}_STATIC_LIBS_OTHER) _pkgconfig_unset(${_prefix}_STATIC_CFLAGS) _pkgconfig_unset(${_prefix}_STATIC_CFLAGS_I) _pkgconfig_unset(${_prefix}_STATIC_CFLAGS_OTHER) # create a better addressable variable of the modules and calculate its size set(_pkg_check_modules_list ${ARGN}) list(LENGTH _pkg_check_modules_list _pkg_check_modules_cnt) if(PKG_CONFIG_EXECUTABLE) # give out status message telling checked module if (NOT ${_is_silent}) if (_pkg_check_modules_cnt EQUAL 1) message(STATUS "Checking for module '${_pkg_check_modules_list}'") else() message(STATUS "Checking for modules '${_pkg_check_modules_list}'") endif() endif() set(_pkg_check_modules_packages) set(_pkg_check_modules_failed) _pkg_set_path_internal() # iterate through module list and check whether they exist and match the required version foreach (_pkg_check_modules_pkg ${_pkg_check_modules_list}) set(_pkg_check_modules_exist_query) # check whether version is given if (_pkg_check_modules_pkg MATCHES "(.*[^><])(=|[><]=?)(.*)") set(_pkg_check_modules_pkg_name "${CMAKE_MATCH_1}") set(_pkg_check_modules_pkg_op "${CMAKE_MATCH_2}") set(_pkg_check_modules_pkg_ver "${CMAKE_MATCH_3}") else() set(_pkg_check_modules_pkg_name "${_pkg_check_modules_pkg}") set(_pkg_check_modules_pkg_op) set(_pkg_check_modules_pkg_ver) endif() _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_VERSION) _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_PREFIX) _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_INCLUDEDIR) _pkgconfig_unset(${_prefix}_${_pkg_check_modules_pkg_name}_LIBDIR) list(APPEND _pkg_check_modules_packages "${_pkg_check_modules_pkg_name}") # create the final query which is of the format: # * > # * >= # * = # * <= # * < # * --exists list(APPEND _pkg_check_modules_exist_query --print-errors --short-errors) if (_pkg_check_modules_pkg_op) list(APPEND _pkg_check_modules_exist_query "${_pkg_check_modules_pkg_name} ${_pkg_check_modules_pkg_op} ${_pkg_check_modules_pkg_ver}") else() list(APPEND _pkg_check_modules_exist_query --exists) list(APPEND _pkg_check_modules_exist_query "${_pkg_check_modules_pkg_name}") endif() # execute the query execute_process( COMMAND ${PKG_CONFIG_EXECUTABLE} ${_pkg_check_modules_exist_query} RESULT_VARIABLE _pkgconfig_retval ERROR_VARIABLE _pkgconfig_error ERROR_STRIP_TRAILING_WHITESPACE) # evaluate result and tell failures if (_pkgconfig_retval) if(NOT ${_is_silent}) message(STATUS " ${_pkgconfig_error}") endif() set(_pkg_check_modules_failed 1) endif() endforeach() if(_pkg_check_modules_failed) # fail when requested if (${_is_required}) message(FATAL_ERROR "A required package was not found") endif () else() # when we are here, we checked whether requested modules # exist. Now, go through them and set variables _pkgconfig_set(${_prefix}_FOUND 1) list(LENGTH _pkg_check_modules_packages pkg_count) # iterate through all modules again and set individual variables foreach (_pkg_check_modules_pkg ${_pkg_check_modules_packages}) # handle case when there is only one package required if (pkg_count EQUAL 1) set(_pkg_check_prefix "${_prefix}") else() set(_pkg_check_prefix "${_prefix}_${_pkg_check_modules_pkg}") endif() _pkgconfig_invoke(${_pkg_check_modules_pkg} "${_pkg_check_prefix}" VERSION "" --modversion ) pkg_get_variable("${_pkg_check_prefix}_PREFIX" ${_pkg_check_modules_pkg} "prefix") pkg_get_variable("${_pkg_check_prefix}_INCLUDEDIR" ${_pkg_check_modules_pkg} "includedir") pkg_get_variable("${_pkg_check_prefix}_LIBDIR" ${_pkg_check_modules_pkg} "libdir") foreach (variable IN ITEMS PREFIX INCLUDEDIR LIBDIR) _pkgconfig_set("${_pkg_check_prefix}_${variable}" "${${_pkg_check_prefix}_${variable}}") endforeach () _pkgconfig_set("${_pkg_check_prefix}_MODULE_NAME" "${_pkg_check_modules_pkg}") if (NOT ${_is_silent}) message(STATUS " Found ${_pkg_check_modules_pkg}, version ${_pkgconfig_VERSION}") endif () endforeach() # set variables which are combined for multiple modules _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LIBRARIES "(^| )-l" --libs-only-l ) _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LIBRARY_DIRS "(^| )-L" --libs-only-L ) _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LDFLAGS "" --libs ) _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" LDFLAGS_OTHER "" --libs-only-other ) if (APPLE AND "-framework" IN_LIST ${_prefix}_LDFLAGS_OTHER) _pkgconfig_extract_frameworks("${_prefix}") endif() _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" INCLUDE_DIRS "(^| )(-I|-isystem ?)" --cflags-only-I ) _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" CFLAGS "" --cflags ) _pkgconfig_invoke_dyn("${_pkg_check_modules_packages}" "${_prefix}" CFLAGS_OTHER "" --cflags-only-other ) if (${_prefix}_CFLAGS_OTHER MATCHES "-isystem") _pkgconfig_extract_isystem("${_prefix}") endif () _pkg_recalculate("${_prefix}" ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global}) endif() _pkg_restore_path_internal() else() if (${_is_required}) message(SEND_ERROR "pkg-config tool not found") endif () endif() endmacro() #[========================================[.rst: .. command:: pkg_check_modules Checks for all the given modules, setting a variety of result variables in the calling scope. .. code-block:: cmake pkg_check_modules( [REQUIRED] [QUIET] [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH] [IMPORTED_TARGET [GLOBAL]] [...]) When the ``REQUIRED`` argument is given, the command will fail with an error if module(s) could not be found. When the ``QUIET`` argument is given, no status messages will be printed. By default, if :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` is 3.1 or later, or if :variable:`PKG_CONFIG_USE_CMAKE_PREFIX_PATH` is set to a boolean ``True`` value, then the :variable:`CMAKE_PREFIX_PATH`, :variable:`CMAKE_FRAMEWORK_PATH`, and :variable:`CMAKE_APPBUNDLE_PATH` cache and environment variables will be added to the ``pkg-config`` search path. The ``NO_CMAKE_PATH`` and ``NO_CMAKE_ENVIRONMENT_PATH`` arguments disable this behavior for the cache variables and environment variables respectively. The ``IMPORTED_TARGET`` argument will create an imported target named ``PkgConfig::`` that can be passed directly as an argument to :command:`target_link_libraries`. The ``GLOBAL`` argument will make the imported target available in global scope. Each ```` can be either a bare module name or it can be a module name with a version constraint (operators ``=``, ``<``, ``>``, ``<=`` and ``>=`` are supported). The following are examples for a module named ``foo`` with various constraints: - ``foo`` matches any version. - ``foo<2`` only matches versions before 2. - ``foo>=3.1`` matches any version from 3.1 or later. - ``foo=1.2.3`` requires that foo must be exactly version 1.2.3. The following variables may be set upon return. Two sets of values exist: One for the common case (`` = ``) and another for the information ``pkg-config`` provides when called with the ``--static`` option (`` = _STATIC``). ``_FOUND`` set to 1 if module(s) exist ``_LIBRARIES`` only the libraries (without the '-l') ``_LINK_LIBRARIES`` the libraries and their absolute paths ``_LIBRARY_DIRS`` the paths of the libraries (without the '-L') ``_LDFLAGS`` all required linker flags ``_LDFLAGS_OTHER`` all other linker flags ``_INCLUDE_DIRS`` the '-I' preprocessor flags (without the '-I') ``_CFLAGS`` all required cflags ``_CFLAGS_OTHER`` the other compiler flags All but ``_FOUND`` may be a :ref:`;-list ` if the associated variable returned from ``pkg-config`` has multiple values. There are some special variables whose prefix depends on the number of ```` given. When there is only one ````, ```` will simply be ````, but if two or more ```` items are given, ```` will be ``_``. ``_VERSION`` version of the module ``_PREFIX`` prefix directory of the module ``_INCLUDEDIR`` include directory of the module ``_LIBDIR`` lib directory of the module Examples: .. code-block:: cmake pkg_check_modules (GLIB2 glib-2.0) Looks for any version of glib2. If found, the output variable ``GLIB2_VERSION`` will hold the actual version found. .. code-block:: cmake pkg_check_modules (GLIB2 glib-2.0>=2.10) Looks for at least version 2.10 of glib2. If found, the output variable ``GLIB2_VERSION`` will hold the actual version found. .. code-block:: cmake pkg_check_modules (FOO glib-2.0>=2.10 gtk+-2.0) Looks for both glib2-2.0 (at least version 2.10) and any version of gtk2+-2.0. Only if both are found will ``FOO`` be considered found. The ``FOO_glib-2.0_VERSION`` and ``FOO_gtk+-2.0_VERSION`` variables will be set to their respective found module versions. .. code-block:: cmake pkg_check_modules (XRENDER REQUIRED xrender) Requires any version of ``xrender``. Example output variables set by a successful call:: XRENDER_LIBRARIES=Xrender;X11 XRENDER_STATIC_LIBRARIES=Xrender;X11;pthread;Xau;Xdmcp #]========================================] macro(pkg_check_modules _prefix _module0) _pkgconfig_parse_options(_pkg_modules _pkg_is_required _pkg_is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global "${_module0}" ${ARGN}) # check cached value if (NOT DEFINED __pkg_config_checked_${_prefix} OR __pkg_config_checked_${_prefix} LESS ${PKG_CONFIG_VERSION} OR NOT ${_prefix}_FOUND OR (NOT "${ARGN}" STREQUAL "" AND NOT "${__pkg_config_arguments_${_prefix}}" STREQUAL "${_module0};${ARGN}") OR ( "${ARGN}" STREQUAL "" AND NOT "${__pkg_config_arguments_${_prefix}}" STREQUAL "${_module0}")) _pkg_check_modules_internal("${_pkg_is_required}" "${_pkg_is_silent}" ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global} "${_prefix}" ${_pkg_modules}) _pkgconfig_set(__pkg_config_checked_${_prefix} ${PKG_CONFIG_VERSION}) if (${_prefix}_FOUND) _pkgconfig_set(__pkg_config_arguments_${_prefix} "${_module0};${ARGN}") endif() else() if (${_prefix}_FOUND) _pkg_recalculate("${_prefix}" ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global}) endif() endif() endmacro() #[========================================[.rst: .. command:: pkg_search_module The behavior of this command is the same as :command:`pkg_check_modules`, except that rather than checking for all the specified modules, it searches for just the first successful match. .. code-block:: cmake pkg_search_module( [REQUIRED] [QUIET] [NO_CMAKE_PATH] [NO_CMAKE_ENVIRONMENT_PATH] [IMPORTED_TARGET [GLOBAL]] [...]) If a module is found, the ``_MODULE_NAME`` variable will contain the name of the matching module. This variable can be used if you need to run :command:`pkg_get_variable`. Example: .. code-block:: cmake pkg_search_module (BAR libxml-2.0 libxml2 libxml>=2) #]========================================] macro(pkg_search_module _prefix _module0) _pkgconfig_parse_options(_pkg_modules_alt _pkg_is_required _pkg_is_silent _no_cmake_path _no_cmake_environment_path _imp_target _imp_target_global "${_module0}" ${ARGN}) # check cached value if (NOT DEFINED __pkg_config_checked_${_prefix} OR __pkg_config_checked_${_prefix} LESS ${PKG_CONFIG_VERSION} OR NOT ${_prefix}_FOUND) set(_pkg_modules_found 0) if (NOT ${_pkg_is_silent}) message(STATUS "Checking for one of the modules '${_pkg_modules_alt}'") endif () # iterate through all modules and stop at the first working one. foreach(_pkg_alt ${_pkg_modules_alt}) if(NOT _pkg_modules_found) _pkg_check_modules_internal(0 1 ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global} "${_prefix}" "${_pkg_alt}") endif() if (${_prefix}_FOUND) set(_pkg_modules_found 1) break() endif() endforeach() if (NOT ${_prefix}_FOUND) if(${_pkg_is_required}) message(SEND_ERROR "None of the required '${_pkg_modules_alt}' found") endif() endif() _pkgconfig_set(__pkg_config_checked_${_prefix} ${PKG_CONFIG_VERSION}) elseif (${_prefix}_FOUND) _pkg_recalculate("${_prefix}" ${_no_cmake_path} ${_no_cmake_environment_path} ${_imp_target} ${_imp_target_global}) endif() endmacro() #[========================================[.rst: .. command:: pkg_get_variable Retrieves the value of a pkg-config variable ``varName`` and stores it in the result variable ``resultVar`` in the calling scope. .. code-block:: cmake pkg_get_variable( ) If ``pkg-config`` returns multiple values for the specified variable, ``resultVar`` will contain a :ref:`;-list `. For example: .. code-block:: cmake pkg_get_variable(GI_GIRDIR gobject-introspection-1.0 girdir) #]========================================] function (pkg_get_variable result pkg variable) _pkg_set_path_internal() _pkgconfig_invoke("${pkg}" "prefix" "result" "" "--variable=${variable}") set("${result}" "${prefix_result}" PARENT_SCOPE) _pkg_restore_path_internal() endfunction () #[========================================[.rst: Variables Affecting Behavior ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. variable:: PKG_CONFIG_EXECUTABLE This can be set to the path of the pkg-config executable. If not provided, it will be set by the module as a result of calling :command:`find_program` internally. The ``PKG_CONFIG`` environment variable can be used as a hint. .. variable:: PKG_CONFIG_USE_CMAKE_PREFIX_PATH Specifies whether :command:`pkg_check_modules` and :command:`pkg_search_module` should add the paths in the :variable:`CMAKE_PREFIX_PATH`, :variable:`CMAKE_FRAMEWORK_PATH` and :variable:`CMAKE_APPBUNDLE_PATH` cache and environment variables to the ``pkg-config`` search path. If this variable is not set, this behavior is enabled by default if :variable:`CMAKE_MINIMUM_REQUIRED_VERSION` is 3.1 or later, disabled otherwise. #]========================================] ### Local Variables: ### mode: cmake ### End: cmake_policy(POP) dune-common-2.8.0/cmake/modules/FindPython3/000077500000000000000000000000001411343567400206475ustar00rootroot00000000000000dune-common-2.8.0/cmake/modules/FindPython3/CMakeLists.txt000066400000000000000000000001471411343567400234110ustar00rootroot00000000000000install(FILES FindPython3.cmake Support.cmake DESTINATION ${DUNE_INSTALL_MODULEDIR}/FindPython3) dune-common-2.8.0/cmake/modules/FindPython3/FindPython3.cmake000066400000000000000000000364011411343567400240220ustar00rootroot00000000000000# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #[=======================================================================[.rst: FindPython3 ----------- .. versionadded:: 3.12 Find Python 3 interpreter, compiler and development environment (include directories and libraries). When a version is requested, it can be specified as a simple value or as a range. For a detailed description of version range usage and capabilities, refer to the :command:`find_package` command. The following components are supported: * ``Interpreter``: search for Python 3 interpreter * ``Compiler``: search for Python 3 compiler. Only offered by IronPython. * ``Development``: search for development artifacts (include directories and libraries). This component includes two sub-components which can be specified independently: * ``Development.Module``: search for artifacts for Python 3 module developments. * ``Development.Embed``: search for artifacts for Python 3 embedding developments. * ``NumPy``: search for NumPy include directories. If no ``COMPONENTS`` are specified, ``Interpreter`` is assumed. If component ``Development`` is specified, it implies sub-components ``Development.Module`` and ``Development.Embed``. To ensure consistent versions between components ``Interpreter``, ``Compiler``, ``Development`` (or one of its sub-components) and ``NumPy``, specify all components at the same time:: find_package (Python3 COMPONENTS Interpreter Development) This module looks only for version 3 of Python. This module can be used concurrently with :module:`FindPython2` module to use both Python versions. The :module:`FindPython` module can be used if Python version does not matter for you. .. note:: If components ``Interpreter`` and ``Development`` (or one of its sub-components) are both specified, this module search only for interpreter with same platform architecture as the one defined by ``CMake`` configuration. This constraint does not apply if only ``Interpreter`` component is specified. Imported Targets ^^^^^^^^^^^^^^^^ This module defines the following :ref:`Imported Targets ` (when :prop_gbl:`CMAKE_ROLE` is ``PROJECT``): ``Python3::Interpreter`` Python 3 interpreter. Target defined if component ``Interpreter`` is found. ``Python3::Compiler`` Python 3 compiler. Target defined if component ``Compiler`` is found. ``Python3::Module`` Python 3 library for Python module. Target defined if component ``Development.Module`` is found. ``Python3::Python`` Python 3 library for Python embedding. Target defined if component ``Development.Embed`` is found. ``Python3::NumPy`` NumPy library for Python 3. Target defined if component ``NumPy`` is found. Result Variables ^^^^^^^^^^^^^^^^ This module will set the following variables in your project (see :ref:`Standard Variable Names `): ``Python3_FOUND`` System has the Python 3 requested components. ``Python3_Interpreter_FOUND`` System has the Python 3 interpreter. ``Python3_EXECUTABLE`` Path to the Python 3 interpreter. ``Python3_INTERPRETER_ID`` A short string unique to the interpreter. Possible values include: * Python * ActivePython * Anaconda * Canopy * IronPython * PyPy ``Python3_STDLIB`` Standard platform independent installation directory. Information returned by ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=True)`` or else ``sysconfig.get_path('stdlib')``. ``Python3_STDARCH`` Standard platform dependent installation directory. Information returned by ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=True)`` or else ``sysconfig.get_path('platstdlib')``. ``Python3_SITELIB`` Third-party platform independent installation directory. Information returned by ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)`` or else ``sysconfig.get_path('purelib')``. ``Python3_SITEARCH`` Third-party platform dependent installation directory. Information returned by ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)`` or else ``sysconfig.get_path('platlib')``. ``Python3_SOABI`` Extension suffix for modules. Information returned by ``distutils.sysconfig.get_config_var('SOABI')`` or computed from ``distutils.sysconfig.get_config_var('EXT_SUFFIX')`` or ``python3-config --extension-suffix``. If package ``distutils.sysconfig`` is not available, ``sysconfig.get_config_var('SOABI')`` or ``sysconfig.get_config_var('EXT_SUFFIX')`` are used. ``Python3_Compiler_FOUND`` System has the Python 3 compiler. ``Python3_COMPILER`` Path to the Python 3 compiler. Only offered by IronPython. ``Python3_COMPILER_ID`` A short string unique to the compiler. Possible values include: * IronPython ``Python3_DOTNET_LAUNCHER`` The ``.Net`` interpreter. Only used by ``IronPython`` implementation. ``Python3_Development_FOUND`` System has the Python 3 development artifacts. ``Python3_Development.Module_FOUND`` System has the Python 3 development artifacts for Python module. ``Python3_Development.Embed_FOUND`` System has the Python 3 development artifacts for Python embedding. ``Python3_INCLUDE_DIRS`` The Python 3 include directories. ``Python3_LINK_OPTIONS`` The Python 3 link options. Some configurations require specific link options for a correct build and execution. ``Python3_LIBRARIES`` The Python 3 libraries. ``Python3_LIBRARY_DIRS`` The Python 3 library directories. ``Python3_RUNTIME_LIBRARY_DIRS`` The Python 3 runtime library directories. ``Python3_VERSION`` Python 3 version. ``Python3_VERSION_MAJOR`` Python 3 major version. ``Python3_VERSION_MINOR`` Python 3 minor version. ``Python3_VERSION_PATCH`` Python 3 patch version. ``Python3_PyPy_VERSION`` Python 3 PyPy version. ``Python3_NumPy_FOUND`` System has the NumPy. ``Python3_NumPy_INCLUDE_DIRS`` The NumPy include directories. ``Python3_NumPy_VERSION`` The NumPy version. Hints ^^^^^ ``Python3_ROOT_DIR`` Define the root directory of a Python 3 installation. ``Python3_USE_STATIC_LIBS`` * If not defined, search for shared libraries and static libraries in that order. * If set to TRUE, search **only** for static libraries. * If set to FALSE, search **only** for shared libraries. ``Python3_FIND_ABI`` This variable defines which ABIs, as defined in `PEP 3149 `_, should be searched. .. note:: If ``Python3_FIND_ABI`` is not defined, any ABI will be searched. The ``Python3_FIND_ABI`` variable is a 3-tuple specifying, in that order, ``pydebug`` (``d``), ``pymalloc`` (``m``) and ``unicode`` (``u``) flags. Each element can be set to one of the following: * ``ON``: Corresponding flag is selected. * ``OFF``: Corresponding flag is not selected. * ``ANY``: The two possibilities (``ON`` and ``OFF``) will be searched. From this 3-tuple, various ABIs will be searched starting from the most specialized to the most general. Moreover, ``debug`` versions will be searched **after** ``non-debug`` ones. For example, if we have:: set (Python3_FIND_ABI "ON" "ANY" "ANY") The following flags combinations will be appended, in that order, to the artifact names: ``dmu``, ``dm``, ``du``, and ``d``. And to search any possible ABIs:: set (Python3_FIND_ABI "ANY" "ANY" "ANY") The following combinations, in that order, will be used: ``mu``, ``m``, ``u``, ````, ``dmu``, ``dm``, ``du`` and ``d``. .. note:: This hint is useful only on ``POSIX`` systems. So, on ``Windows`` systems, when ``Python3_FIND_ABI`` is defined, ``Python`` distributions from `python.org `_ will be found only if value for each flag is ``OFF`` or ``ANY``. ``Python3_FIND_STRATEGY`` This variable defines how lookup will be done. The ``Python3_FIND_STRATEGY`` variable can be set to one of the following: * ``VERSION``: Try to find the most recent version in all specified locations. This is the default if policy :policy:`CMP0094` is undefined or set to ``OLD``. * ``LOCATION``: Stops lookup as soon as a version satisfying version constraints is founded. This is the default if policy :policy:`CMP0094` is set to ``NEW``. ``Python3_FIND_REGISTRY`` On Windows the ``Python3_FIND_REGISTRY`` variable determine the order of preference between registry and environment variables. The ``Python3_FIND_REGISTRY`` variable can be set to one of the following: * ``FIRST``: Try to use registry before environment variables. This is the default. * ``LAST``: Try to use registry after environment variables. * ``NEVER``: Never try to use registry. ``Python3_FIND_FRAMEWORK`` On macOS the ``Python3_FIND_FRAMEWORK`` variable determine the order of preference between Apple-style and unix-style package components. This variable can take same values as :variable:`CMAKE_FIND_FRAMEWORK` variable. .. note:: Value ``ONLY`` is not supported so ``FIRST`` will be used instead. If ``Python3_FIND_FRAMEWORK`` is not defined, :variable:`CMAKE_FIND_FRAMEWORK` variable will be used, if any. ``Python3_FIND_VIRTUALENV`` This variable defines the handling of virtual environments managed by ``virtualenv`` or ``conda``. It is meaningful only when a virtual environment is active (i.e. the ``activate`` script has been evaluated). In this case, it takes precedence over ``Python3_FIND_REGISTRY`` and ``CMAKE_FIND_FRAMEWORK`` variables. The ``Python3_FIND_VIRTUALENV`` variable can be set to one of the following: * ``FIRST``: The virtual environment is used before any other standard paths to look-up for the interpreter. This is the default. * ``ONLY``: Only the virtual environment is used to look-up for the interpreter. * ``STANDARD``: The virtual environment is not used to look-up for the interpreter but environment variable ``PATH`` is always considered. In this case, variable ``Python3_FIND_REGISTRY`` (Windows) or ``CMAKE_FIND_FRAMEWORK`` (macOS) can be set with value ``LAST`` or ``NEVER`` to select preferably the interpreter from the virtual environment. .. note:: If the component ``Development`` is requested, it is **strongly** recommended to also include the component ``Interpreter`` to get expected result. ``Python3_FIND_IMPLEMENTATIONS`` This variable defines, in an ordered list, the different implementations which will be searched. The ``Python3_FIND_IMPLEMENTATIONS`` variable can hold the following values: * ``CPython``: this is the standard implementation. Various products, like ``Anaconda`` or ``ActivePython``, rely on this implementation. * ``IronPython``: This implementation use the ``CSharp`` language for ``.NET Framework`` on top of the `Dynamic Language Runtime` (``DLR``). See `IronPython `_. * ``PyPy``: This implementation use ``RPython`` language and ``RPython translation toolchain`` to produce the python interpreter. See `PyPy `_. The default value is: * Windows platform: ``CPython``, ``IronPython`` * Other platforms: ``CPython`` .. note:: This hint has the lowest priority of all hints, so even if, for example, you specify ``IronPython`` first and ``CPython`` in second, a python product based on ``CPython`` can be selected because, for example with ``Python3_FIND_STRATEGY=LOCATION``, each location will be search first for ``IronPython`` and second for ``CPython``. .. note:: When ``IronPython`` is specified, on platforms other than ``Windows``, the ``.Net`` interpreter (i.e. ``mono`` command) is expected to be available through the ``PATH`` variable. ``Python3_FIND_UNVERSIONED_NAMES`` .. versionadded:: 3.20 This variable defines how the generic names will be searched. Currently, it only applies to the generic names of the interpreter, namely, ``python3`` and ``python``. The ``Python3_FIND_UNVERSIONED_NAMES`` variable can be set to one of the following values: * ``FIRST``: The generic names are searched before the more specialized ones (such as ``python3.5`` for example). * ``LAST``: The generic names are searched after the more specialized ones. This is the default. * ``NEVER``: The generic name are not searched at all. Artifacts Specification ^^^^^^^^^^^^^^^^^^^^^^^ To solve special cases, it is possible to specify directly the artifacts by setting the following variables: ``Python3_EXECUTABLE`` The path to the interpreter. ``Python3_COMPILER`` The path to the compiler. ``Python3_DOTNET_LAUNCHER`` The ``.Net`` interpreter. Only used by ``IronPython`` implementation. ``Python3_LIBRARY`` The path to the library. It will be used to compute the variables ``Python3_LIBRARIES``, ``Python3_LIBRARY_DIRS`` and ``Python3_RUNTIME_LIBRARY_DIRS``. ``Python3_INCLUDE_DIR`` The path to the directory of the ``Python`` headers. It will be used to compute the variable ``Python3_INCLUDE_DIRS``. ``Python3_NumPy_INCLUDE_DIR`` The path to the directory of the ``NumPy`` headers. It will be used to compute the variable ``Python3_NumPy_INCLUDE_DIRS``. .. note:: All paths must be absolute. Any artifact specified with a relative path will be ignored. .. note:: When an artifact is specified, all ``HINTS`` will be ignored and no search will be performed for this artifact. If more than one artifact is specified, it is the user's responsibility to ensure the consistency of the various artifacts. By default, this module supports multiple calls in different directories of a project with different version/component requirements while providing correct and consistent results for each call. To support this behavior, ``CMake`` cache is not used in the traditional way which can be problematic for interactive specification. So, to enable also interactive specification, module behavior can be controlled with the following variable: ``Python3_ARTIFACTS_INTERACTIVE`` Selects the behavior of the module. This is a boolean variable: * If set to ``TRUE``: Create CMake cache entries for the above artifact specification variables so that users can edit them interactively. This disables support for multiple version/component requirements. * If set to ``FALSE`` or undefined: Enable multiple version/component requirements. Commands ^^^^^^^^ This module defines the command ``Python3_add_library`` (when :prop_gbl:`CMAKE_ROLE` is ``PROJECT``), which has the same semantics as :command:`add_library` and adds a dependency to target ``Python3::Python`` or, when library type is ``MODULE``, to target ``Python3::Module`` and takes care of Python module naming rules:: Python3_add_library ( [STATIC | SHARED | MODULE [WITH_SOABI]] [ ...]) If the library type is not specified, ``MODULE`` is assumed. For ``MODULE`` library type, if option ``WITH_SOABI`` is specified, the module suffix will include the ``Python3_SOABI`` value, if any. #]=======================================================================] set (_PYTHON_PREFIX Python3) set (_Python3_REQUIRED_VERSION_MAJOR 3) include (${CMAKE_CURRENT_LIST_DIR}/Support.cmake) if (COMMAND __Python3_add_library) macro (Python3_add_library) __Python3_add_library (Python3 ${ARGV}) endmacro() endif() unset (_PYTHON_PREFIX) dune-common-2.8.0/cmake/modules/FindPython3/Support.cmake000066400000000000000000004740141411343567400233370ustar00rootroot00000000000000# Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. # # This file is a "template" file used by various FindPython modules. # # # Initial configuration # cmake_policy(PUSH) # numbers and boolean constants cmake_policy (SET CMP0012 NEW) # IN_LIST operator cmake_policy (SET CMP0057 NEW) if (NOT DEFINED _PYTHON_PREFIX) message (FATAL_ERROR "FindPython: INTERNAL ERROR") endif() if (NOT DEFINED _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) message (FATAL_ERROR "FindPython: INTERNAL ERROR") endif() if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "3") set(_${_PYTHON_PREFIX}_VERSIONS 3.10 3.9 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0) elseif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "2") set(_${_PYTHON_PREFIX}_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0) else() message (FATAL_ERROR "FindPython: INTERNAL ERROR") endif() get_property(_${_PYTHON_PREFIX}_CMAKE_ROLE GLOBAL PROPERTY CMAKE_ROLE) include (FindPackageHandleStandardArgs) # # helper commands # macro (_PYTHON_DISPLAY_FAILURE _PYTHON_MSG) if (${_PYTHON_PREFIX}_FIND_REQUIRED) message (FATAL_ERROR "${_PYTHON_MSG}") else() if (NOT ${_PYTHON_PREFIX}_FIND_QUIETLY) message(STATUS "${_PYTHON_MSG}") endif () endif() set (${_PYTHON_PREFIX}_FOUND FALSE) string (TOUPPER "${_PYTHON_PREFIX}" _${_PYTHON_PREFIX}_UPPER_PREFIX) set (${_PYTHON_UPPER_PREFIX}_FOUND FALSE) endmacro() function (_PYTHON_MARK_AS_INTERNAL) foreach (var IN LISTS ARGV) if (DEFINED CACHE{${var}}) set_property (CACHE ${var} PROPERTY TYPE INTERNAL) endif() endforeach() endfunction() macro (_PYTHON_SELECT_LIBRARY_CONFIGURATIONS _PYTHON_BASENAME) if(NOT DEFINED ${_PYTHON_BASENAME}_LIBRARY_RELEASE) set(${_PYTHON_BASENAME}_LIBRARY_RELEASE "${_PYTHON_BASENAME}_LIBRARY_RELEASE-NOTFOUND") endif() if(NOT DEFINED ${_PYTHON_BASENAME}_LIBRARY_DEBUG) set(${_PYTHON_BASENAME}_LIBRARY_DEBUG "${_PYTHON_BASENAME}_LIBRARY_DEBUG-NOTFOUND") endif() get_property(_PYTHON_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if (${_PYTHON_BASENAME}_LIBRARY_DEBUG AND ${_PYTHON_BASENAME}_LIBRARY_RELEASE AND NOT ${_PYTHON_BASENAME}_LIBRARY_DEBUG STREQUAL ${_PYTHON_BASENAME}_LIBRARY_RELEASE AND (_PYTHON_isMultiConfig OR CMAKE_BUILD_TYPE)) # if the generator is multi-config or if CMAKE_BUILD_TYPE is set for # single-config generators, set optimized and debug libraries set (${_PYTHON_BASENAME}_LIBRARIES "") foreach (_PYTHON_libname IN LISTS ${_PYTHON_BASENAME}_LIBRARY_RELEASE) list( APPEND ${_PYTHON_BASENAME}_LIBRARIES optimized "${_PYTHON_libname}") endforeach() foreach (_PYTHON_libname IN LISTS ${_PYTHON_BASENAME}_LIBRARY_DEBUG) list( APPEND ${_PYTHON_BASENAME}_LIBRARIES debug "${_PYTHON_libname}") endforeach() elseif (${_PYTHON_BASENAME}_LIBRARY_RELEASE) set (${_PYTHON_BASENAME}_LIBRARIES "${${_PYTHON_BASENAME}_LIBRARY_RELEASE}") elseif (${_PYTHON_BASENAME}_LIBRARY_DEBUG) set (${_PYTHON_BASENAME}_LIBRARIES "${${_PYTHON_BASENAME}_LIBRARY_DEBUG}") else() set (${_PYTHON_BASENAME}_LIBRARIES "${_PYTHON_BASENAME}_LIBRARY-NOTFOUND") endif() endmacro() macro (_PYTHON_FIND_FRAMEWORKS) if (CMAKE_HOST_APPLE OR APPLE) file(TO_CMAKE_PATH "$ENV{CMAKE_FRAMEWORK_PATH}" _pff_CMAKE_FRAMEWORK_PATH) set (_pff_frameworks ${CMAKE_FRAMEWORK_PATH} ${_pff_CMAKE_FRAMEWORK_PATH} ~/Library/Frameworks /usr/local/Frameworks ${CMAKE_SYSTEM_FRAMEWORK_PATH}) if (_pff_frameworks) # Behavior change in CMake 3.14 list (REMOVE_DUPLICATES _pff_frameworks) endif () foreach (_pff_implementation IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS) unset (_${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS) if (_pff_implementation STREQUAL "CPython") foreach (_pff_framework IN LISTS _pff_frameworks) if (EXISTS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework) list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/Python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}.framework) endif() if (EXISTS ${_pff_framework}/Python.framework) list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/Python.framework) endif() endforeach() elseif (_pff_implementation STREQUAL "IronPython") foreach (_pff_framework IN LISTS _pff_frameworks) if (EXISTS ${_pff_framework}/IronPython.framework) list (APPEND _${_PYTHON_PREFIX}_${_pff_implementation}_FRAMEWORKS ${_pff_framework}/IronPython.framework) endif() endforeach() endif() endforeach() unset (_pff_implementation) unset (_pff_frameworks) unset (_pff_framework) endif() endmacro() function (_PYTHON_GET_FRAMEWORKS _PYTHON_PGF_FRAMEWORK_PATHS) cmake_parse_arguments (PARSE_ARGV 1 _PGF "" "" "IMPLEMENTATIONS;VERSION") if (NOT _PGF_IMPLEMENTATIONS) set (_PGF_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS}) endif() set (framework_paths) foreach (implementation IN LISTS _PGF_IMPLEMENTATIONS) if (implementation STREQUAL "CPython") foreach (version IN LISTS _PGF_VERSION) foreach (framework IN LISTS _${_PYTHON_PREFIX}_${implementation}_FRAMEWORKS) if (EXISTS "${framework}/Versions/${version}") list (APPEND framework_paths "${framework}/Versions/${version}") endif() endforeach() endforeach() elseif (implementation STREQUAL "IronPython") foreach (version IN LISTS _PGF_VERSION) foreach (framework IN LISTS _${_PYTHON_PREFIX}_${implementation}_FRAMEWORKS) # pick-up all available versions file (GLOB versions LIST_DIRECTORIES true RELATIVE "${framework}/Versions/" "${framework}/Versions/${version}*") list (SORT versions ORDER DESCENDING) list (TRANSFORM versions PREPEND "${framework}/Versions/") list (APPEND framework_paths ${versions}) endforeach() endforeach() endif() endforeach() set (${_PYTHON_PGF_FRAMEWORK_PATHS} ${framework_paths} PARENT_SCOPE) endfunction() function (_PYTHON_GET_REGISTRIES _PYTHON_PGR_REGISTRY_PATHS) cmake_parse_arguments (PARSE_ARGV 1 _PGR "" "" "IMPLEMENTATIONS;VERSION") if (NOT _PGR_IMPLEMENTATIONS) set (_PGR_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS}) endif() set (registries) foreach (implementation IN LISTS _PGR_IMPLEMENTATIONS) if (implementation STREQUAL "CPython") foreach (version IN LISTS _PGR_VERSION) string (REPLACE "." "" version_no_dots ${version}) list (APPEND registries [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]) if (version VERSION_GREATER_EQUAL "3.5") get_filename_component (arch "[HKEY_CURRENT_USER\\Software\\Python\\PythonCore\\${version};SysArchitecture]" NAME) if (arch MATCHES "(${_${_PYTHON_PREFIX}_ARCH}|${_${_PYTHON_PREFIX}_ARCH2})bit") list (APPEND registries [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}\\InstallPath]) endif() else() list (APPEND registries [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${version}\\InstallPath]) endif() list (APPEND registries [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${version}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${version}\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${version_no_dots}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]) endforeach() elseif (implementation STREQUAL "IronPython") foreach (version IN LISTS _PGR_VERSION) list (APPEND registries [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${version}\\InstallPath]) endforeach() endif() endforeach() set (${_PYTHON_PGR_REGISTRY_PATHS} "${registries}" PARENT_SCOPE) endfunction() function (_PYTHON_GET_ABIFLAGS _PGABIFLAGS) set (abiflags) list (GET _${_PYTHON_PREFIX}_FIND_ABI 0 pydebug) list (GET _${_PYTHON_PREFIX}_FIND_ABI 1 pymalloc) list (GET _${_PYTHON_PREFIX}_FIND_ABI 2 unicode) if (pymalloc STREQUAL "ANY" AND unicode STREQUAL "ANY") set (abiflags "mu" "m" "u" "") elseif (pymalloc STREQUAL "ANY" AND unicode STREQUAL "ON") set (abiflags "mu" "u") elseif (pymalloc STREQUAL "ANY" AND unicode STREQUAL "OFF") set (abiflags "m" "") elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ANY") set (abiflags "mu" "m") elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ON") set (abiflags "mu") elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "OFF") set (abiflags "m") elseif (pymalloc STREQUAL "ON" AND unicode STREQUAL "ANY") set (abiflags "u" "") elseif (pymalloc STREQUAL "OFF" AND unicode STREQUAL "ON") set (abiflags "u") endif() if (pydebug STREQUAL "ON") if (abiflags) list (TRANSFORM abiflags PREPEND "d") else() set (abiflags "d") endif() elseif (pydebug STREQUAL "ANY") if (abiflags) set (flags "${abiflags}") list (TRANSFORM flags PREPEND "d") list (APPEND abiflags "${flags}") else() set (abiflags "" "d") endif() endif() set (${_PGABIFLAGS} "${abiflags}" PARENT_SCOPE) endfunction() function (_PYTHON_GET_PATH_SUFFIXES _PYTHON_PGPS_PATH_SUFFIXES) cmake_parse_arguments (PARSE_ARGV 1 _PGPS "INTERPRETER;COMPILER;LIBRARY;INCLUDE" "" "IMPLEMENTATIONS;VERSION") if (NOT _PGPS_IMPLEMENTATIONS) set (_PGPS_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS}) endif() if (DEFINED _${_PYTHON_PREFIX}_ABIFLAGS) set (abi "${_${_PYTHON_PREFIX}_ABIFLAGS}") else() set (abi "mu" "m" "u" "") endif() set (path_suffixes) foreach (implementation IN LISTS _PGPS_IMPLEMENTATIONS) if (implementation STREQUAL "CPython") if (_PGPS_INTERPRETER) list (APPEND path_suffixes bin Scripts) else() foreach (version IN LISTS _PGPS_VERSION) if (_PGPS_LIBRARY) if (CMAKE_LIBRARY_ARCHITECTURE) list (APPEND path_suffixes lib/${CMAKE_LIBRARY_ARCHITECTURE}) endif() list (APPEND path_suffixes lib libs) if (CMAKE_LIBRARY_ARCHITECTURE) set (suffixes "${abi}") if (suffixes) list (TRANSFORM suffixes PREPEND "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}") list (TRANSFORM suffixes APPEND "-${CMAKE_LIBRARY_ARCHITECTURE}") else() set (suffixes "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}-${CMAKE_LIBRARY_ARCHITECTURE}") endif() list (APPEND path_suffixes ${suffixes}) endif() set (suffixes "${abi}") if (suffixes) list (TRANSFORM suffixes PREPEND "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}") else() set (suffixes "lib/python${_PGPS_VERSION}/config-${_PGPS_VERSION}") endif() list (APPEND path_suffixes ${suffixes}) elseif (_PGPS_INCLUDE) set (suffixes "${abi}") if (suffixes) list (TRANSFORM suffixes PREPEND "include/python${_PGPS_VERSION}") else() set (suffixes "include/python${_PGPS_VERSION}") endif() list (APPEND path_suffixes ${suffixes} include) endif() endforeach() endif() elseif (implementation STREQUAL "IronPython") if (_PGPS_INTERPRETER OR _PGPS_COMPILER) foreach (version IN LISTS _PGPS_VERSION) list (APPEND path_suffixes "share/ironpython${version}") endforeach() list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}) endif() elseif (implementation STREQUAL "PyPy") if (_PGPS_INTERPRETER) list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_EXECUTABLE_PATH_SUFFIXES}) elseif (_PGPS_LIBRARY) list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_LIBRARY_PATH_SUFFIXES}) elseif (_PGPS_INCLUDE) list (APPEND path_suffixes ${_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES}) endif() endif() endforeach() if (path_suffixes) # Behavior change in CMake 3.14 list (REMOVE_DUPLICATES path_suffixes) endif () set (${_PYTHON_PGPS_PATH_SUFFIXES} ${path_suffixes} PARENT_SCOPE) endfunction() function (_PYTHON_GET_NAMES _PYTHON_PGN_NAMES) cmake_parse_arguments (PARSE_ARGV 1 _PGN "POSIX;INTERPRETER;COMPILER;CONFIG;LIBRARY;WIN32;DEBUG" "" "IMPLEMENTATIONS;VERSION") if (NOT _PGN_IMPLEMENTATIONS) set (_PGN_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS}) endif() set (names) foreach (implementation IN LISTS _PGN_IMPLEMENTATIONS) if (implementation STREQUAL "CPython") if (_PGN_INTERPRETER AND _${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES STREQUAL "FIRST") list (APPEND names python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python) endif() foreach (version IN LISTS _PGN_VERSION) if (_PGN_WIN32) string (REPLACE "." "" version_no_dots ${version}) set (name python${version_no_dots}) if (_PGN_DEBUG) string (APPEND name "_d") endif() list (APPEND names "${name}") endif() if (_PGN_POSIX) if (DEFINED _${_PYTHON_PREFIX}_ABIFLAGS) set (abi "${_${_PYTHON_PREFIX}_ABIFLAGS}") else() if (_PGN_INTERPRETER OR _PGN_CONFIG) set (abi "") else() set (abi "mu" "m" "u" "") endif() endif() if (abi) if (_PGN_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE) set (abinames "${abi}") list (TRANSFORM abinames PREPEND "${CMAKE_LIBRARY_ARCHITECTURE}-python${version}") list (TRANSFORM abinames APPEND "-config") list (APPEND names ${abinames}) endif() set (abinames "${abi}") list (TRANSFORM abinames PREPEND "python${version}") if (_PGN_CONFIG) list (TRANSFORM abinames APPEND "-config") endif() list (APPEND names ${abinames}) else() unset (abinames) if (_PGN_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE) set (abinames "${CMAKE_LIBRARY_ARCHITECTURE}-python${version}") endif() list (APPEND abinames "python${version}") if (_PGN_CONFIG) list (TRANSFORM abinames APPEND "-config") endif() list (APPEND names ${abinames}) endif() endif() endforeach() if (_PGN_INTERPRETER AND _${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES STREQUAL "LAST") list (APPEND names python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python) endif() elseif (implementation STREQUAL "IronPython") if (_PGN_INTERPRETER) if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux") # Do not use wrapper script on Linux because it is buggy: -c interpreter option cannot be used foreach (version IN LISTS _PGN_VERSION) list (APPEND names "ipy${version}") endforeach() endif() list (APPEND names ${_${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES}) elseif (_PGN_COMPILER) list (APPEND names ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES}) endif() elseif (implementation STREQUAL "PyPy") if (_PGN_INTERPRETER) list (APPEND names ${_${_PYTHON_PREFIX}_PYPY_NAMES}) elseif (_PGN_LIBRARY) if (_PGN_WIN32) foreach (version IN LISTS _PGN_VERSION) string (REPLACE "." "" version_no_dots ${version}) set (name "python${version_no_dots}") if (_PGN_DEBUG) string (APPEND name "_d") endif() list (APPEND names "${name}") endforeach() endif() list (APPEND names ${_${_PYTHON_PREFIX}_PYPY_LIB_NAMES}) endif() endif() endforeach() set (${_PYTHON_PGN_NAMES} ${names} PARENT_SCOPE) endfunction() function (_PYTHON_GET_CONFIG_VAR _PYTHON_PGCV_VALUE NAME) unset (${_PYTHON_PGCV_VALUE} PARENT_SCOPE) if (NOT NAME MATCHES "^(PREFIX|ABIFLAGS|CONFIGDIR|INCLUDES|LIBS|SOABI)$") return() endif() if (_${_PYTHON_PREFIX}_CONFIG) if (NAME STREQUAL "SOABI") set (config_flag "--extension-suffix") else() set (config_flag "--${NAME}") endif() string (TOLOWER "${config_flag}" config_flag) execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" ${config_flag} RESULT_VARIABLE _result OUTPUT_VARIABLE _values ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_result) unset (_values) else() if (NAME STREQUAL "INCLUDES") # do some clean-up string (REGEX MATCHALL "(-I|-iwithsysroot)[ ]*[^ ]+" _values "${_values}") string (REGEX REPLACE "(-I|-iwithsysroot)[ ]*" "" _values "${_values}") if (_values) # Behavior change in CMake 3.14 list (REMOVE_DUPLICATES _values) endif () elseif (NAME STREQUAL "SOABI") # clean-up: remove prefix character and suffix if (_values MATCHES "^(\\.${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.so|\\.pyd)$") set(_values "") else() string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}") endif() endif() endif() endif() if (_${_PYTHON_PREFIX}_EXECUTABLE AND NOT CMAKE_CROSSCOMPILING) if (NAME STREQUAL "PREFIX") execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.PREFIX,sysconfig.EXEC_PREFIX,sysconfig.BASE_EXEC_PREFIX]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_config_var('base') or '', sysconfig.get_config_var('installed_base') or '']))" RESULT_VARIABLE _result OUTPUT_VARIABLE _values ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_result) unset (_values) else() if (_values) # Behavior change in CMake 3.14 list (REMOVE_DUPLICATES _values) endif () endif() elseif (NAME STREQUAL "INCLUDES") if (WIN32) set (_scheme "nt") else() set (_scheme "posix_prefix") endif() execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_python_inc(plat_specific=True),sysconfig.get_python_inc(plat_specific=False)]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_path('platinclude'),sysconfig.get_path('platinclude','${_scheme}'),sysconfig.get_path('include'),sysconfig.get_path('include','${_scheme}')]))" RESULT_VARIABLE _result OUTPUT_VARIABLE _values ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_result) unset (_values) else() if (_values) # Behavior change in CMake 3.14 list (REMOVE_DUPLICATES _values) endif () endif() elseif (NAME STREQUAL "SOABI") execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '',sysconfig.get_config_var('SO') or '']))\nexcept Exception:\n import sysconfig;sys.stdout.write(';'.join([sysconfig.get_config_var('SOABI') or '',sysconfig.get_config_var('EXT_SUFFIX') or '',sysconfig.get_config_var('SO') or '']))" RESULT_VARIABLE _result OUTPUT_VARIABLE _soabi ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_result) unset (_values) else() foreach (_item IN LISTS _soabi) if (_item) set (_values "${_item}") break() endif() endforeach() if (_values) # clean-up: remove prefix character and suffix if (_values MATCHES "^(\\.${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.so|\\.pyd)$") set(_values "") else() string (REGEX REPLACE "^[.-](.+)(${CMAKE_SHARED_LIBRARY_SUFFIX}|\\.(so|pyd))$" "\\1" _values "${_values}") endif() endif() endif() else() set (config_flag "${NAME}") if (NAME STREQUAL "CONFIGDIR") set (config_flag "LIBPL") endif() execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(sysconfig.get_config_var('${config_flag}'))\nexcept Exception:\n import sysconfig\n sys.stdout.write(sysconfig.get_config_var('${config_flag}'))" RESULT_VARIABLE _result OUTPUT_VARIABLE _values ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_result) unset (_values) endif() endif() endif() if (NAME STREQUAL "ABIFLAGS" OR NAME STREQUAL "SOABI") set (${_PYTHON_PGCV_VALUE} "${_values}" PARENT_SCOPE) return() endif() if (NOT _values OR _values STREQUAL "None") return() endif() if (NAME STREQUAL "LIBS") # do some clean-up string (REGEX MATCHALL "-(l|framework)[ ]*[^ ]+" _values "${_values}") # remove elements relative to python library itself list (FILTER _values EXCLUDE REGEX "-lpython") if (_values) # Behavior change in CMake 3.14 list (REMOVE_DUPLICATES _values) endif () endif() if (WIN32 AND NAME MATCHES "^(PREFIX|CONFIGDIR|INCLUDES)$") file (TO_CMAKE_PATH "${_values}" _values) endif() set (${_PYTHON_PGCV_VALUE} "${_values}" PARENT_SCOPE) endfunction() function (_PYTHON_GET_VERSION) cmake_parse_arguments (PARSE_ARGV 0 _PGV "LIBRARY;INCLUDE" "PREFIX" "") unset (${_PGV_PREFIX}VERSION PARENT_SCOPE) unset (${_PGV_PREFIX}VERSION_MAJOR PARENT_SCOPE) unset (${_PGV_PREFIX}VERSION_MINOR PARENT_SCOPE) unset (${_PGV_PREFIX}VERSION_PATCH PARENT_SCOPE) unset (${_PGV_PREFIX}ABI PARENT_SCOPE) if (_PGV_LIBRARY) # retrieve version and abi from library name if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE) get_filename_component (library_name "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" NAME) # extract version from library name if (library_name MATCHES "python([23])([0-9]+)") set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE) set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE) set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE) set (${_PGV_PREFIX}ABI "" PARENT_SCOPE) elseif (library_name MATCHES "python([23])\\.([0-9]+)([dmu]*)") set (${_PGV_PREFIX}VERSION_MAJOR "${CMAKE_MATCH_1}" PARENT_SCOPE) set (${_PGV_PREFIX}VERSION_MINOR "${CMAKE_MATCH_2}" PARENT_SCOPE) set (${_PGV_PREFIX}VERSION "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}" PARENT_SCOPE) set (${_PGV_PREFIX}ABI "${CMAKE_MATCH_3}" PARENT_SCOPE) elseif (library_name MATCHES "pypy(3)?-c") set (version "${CMAKE_MATCH_1}") if (version EQUAL "3") set (${_PGV_PREFIX}VERSION_MAJOR "3" PARENT_SCOPE) set (${_PGV_PREFIX}VERSION "3" PARENT_SCOPE) else() set (${_PGV_PREFIX}VERSION_MAJOR "2" PARENT_SCOPE) set (${_PGV_PREFIX}VERSION "2" PARENT_SCOPE) endif() set (${_PGV_PREFIX}ABI "" PARENT_SCOPE) endif() endif() else() if (_${_PYTHON_PREFIX}_INCLUDE_DIR) # retrieve version from header file file (STRINGS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/patchlevel.h" version REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"") string (REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"]+)\".*" "\\1" version "${version}") string (REGEX MATCHALL "[0-9]+" versions "${version}") list (GET versions 0 version_major) list (GET versions 1 version_minor) list (GET versions 2 version_patch) set (${_PGV_PREFIX}VERSION "${version_major}.${version_minor}.${version_patch}" PARENT_SCOPE) set (${_PGV_PREFIX}VERSION_MAJOR ${version_major} PARENT_SCOPE) set (${_PGV_PREFIX}VERSION_MINOR ${version_minor} PARENT_SCOPE) set (${_PGV_PREFIX}VERSION_PATCH ${version_patch} PARENT_SCOPE) # compute ABI flags if (version_major VERSION_GREATER "2") file (STRINGS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/pyconfig.h" config REGEX "(Py_DEBUG|WITH_PYMALLOC|Py_UNICODE_SIZE|MS_WIN32)") set (abi) if (config MATCHES "#[ ]*define[ ]+MS_WIN32") # ABI not used on Windows set (abi "") else() if (NOT config) # pyconfig.h can be a wrapper to a platform specific pyconfig.h # In this case, try to identify ABI from include directory if (_${_PYTHON_PREFIX}_INCLUDE_DIR MATCHES "python${version_major}\\.${version_minor}+([dmu]*)") set (abi "${CMAKE_MATCH_1}") else() set (abi "") endif() else() if (config MATCHES "#[ ]*define[ ]+Py_DEBUG[ ]+1") string (APPEND abi "d") endif() if (config MATCHES "#[ ]*define[ ]+WITH_PYMALLOC[ ]+1") string (APPEND abi "m") endif() if (config MATCHES "#[ ]*define[ ]+Py_UNICODE_SIZE[ ]+4") string (APPEND abi "u") endif() endif() set (${_PGV_PREFIX}ABI "${abi}" PARENT_SCOPE) endif() else() # ABI not supported set (${_PGV_PREFIX}ABI "" PARENT_SCOPE) endif() endif() endif() endfunction() function (_PYTHON_GET_LAUNCHER _PYTHON_PGL_NAME) cmake_parse_arguments (PARSE_ARGV 1 _PGL "INTERPRETER;COMPILER" "" "") unset ({_PYTHON_PGL_NAME} PARENT_SCOPE) if ((_PGL_INTERPRETER AND NOT _${_PYTHON_PREFIX}_EXECUTABLE) OR (_PGL_COMPILER AND NOT _${_PYTHON_PREFIX}_COMPILER)) return() endif() if ("IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS AND NOT SYSTEM_NAME MATCHES "Windows|Linux") if (_PGL_INTERPRETER) get_filename_component (name "${_${_PYTHON_PREFIX}_EXECUTABLE}" NAME) get_filename_component (ext "${_${_PYTHON_PREFIX}_EXECUTABLE}" LAST_EXT) if (name IN_LIST _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES AND ext STREQUAL ".exe") set (${_PYTHON_PGL_NAME} "${${_PYTHON_PREFIX}_DOTNET_LAUNCHER}" PARENT_SCOPE) endif() else() get_filename_component (name "${_${_PYTHON_PREFIX}_COMPILER}" NAME) get_filename_component (ext "${_${_PYTHON_PREFIX}_COMPILER}" LAST_EXT) if (name IN_LIST _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES AND ext STREQUAL ".exe") set (${_PYTHON_PGL_NAME} "${${_PYTHON_PREFIX}_DOTNET_LAUNCHER}" PARENT_SCOPE) endif() endif() endif() endfunction() function (_PYTHON_VALIDATE_INTERPRETER) if (NOT _${_PYTHON_PREFIX}_EXECUTABLE) return() endif() cmake_parse_arguments (PARSE_ARGV 0 _PVI "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "") if (_PVI_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_EXECUTABLE}") # interpreter does not exist anymore set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot find the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") return() endif() _python_get_launcher (launcher INTERPRETER) # validate ABI compatibility if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI) execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; sys.stdout.write(sys.abiflags)" RESULT_VARIABLE result OUTPUT_VARIABLE abi ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (result) # assume ABI is not supported set (abi "") endif() if (NOT abi IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS) # incompatible ABI set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong ABI for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") return() endif() endif() if (_PVI_IN_RANGE OR _PVI_VERSION) # retrieve full version execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))" RESULT_VARIABLE result OUTPUT_VARIABLE version ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (result) # interpreter is not usable set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") return() endif() if (_PVI_VERSION) # check against specified version ## compute number of components for version string (REGEX REPLACE "[^.]" "" dots "${_PVI_VERSION}") ## add one dot because there is one dot less than there are components string (LENGTH "${dots}." count) if (count GREATER 3) set (count 3) endif() set (version_regex "^[0-9]+") if (count EQUAL 3) string (APPEND version_regex "\\.[0-9]+\\.[0-9]+") elseif (count EQUAL 2) string (APPEND version_regex "\\.[0-9]+") endif() # extract needed range string (REGEX MATCH "${version_regex}" version "${version}") if (_PVI_EXACT AND NOT version VERSION_EQUAL _PVI_VERSION) # interpreter has wrong version set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") return() else() # check that version is OK string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}") string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${_PVI_VERSION}") if (NOT major_version VERSION_EQUAL expected_major_version OR NOT version VERSION_GREATER_EQUAL _PVI_VERSION) set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") return() endif() endif() endif() if (_PVI_IN_RANGE) # check if version is in the requested range find_package_check_version ("${version}" in_range HANDLE_VERSION_RANGE) if (NOT in_range) # interpreter has invalid version set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") return() endif() endif() else() get_filename_component (python_name "${_${_PYTHON_PREFIX}_EXECUTABLE}" NAME) if (NOT python_name STREQUAL "python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}${CMAKE_EXECUTABLE_SUFFIX}") # executable found do not have version in name # ensure major version is OK execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; sys.stdout.write(str(sys.version_info[0]))" RESULT_VARIABLE result OUTPUT_VARIABLE version ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (result OR NOT version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) # interpreter not usable or has wrong major version if (result) set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) else() set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong major version for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) endif() set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") return() endif() endif() endif() if (CMAKE_SIZEOF_VOID_P AND ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) AND NOT CMAKE_CROSSCOMPILING) # In this case, interpreter must have same architecture as environment execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys, struct; sys.stdout.write(str(struct.calcsize(\"P\")))" RESULT_VARIABLE result OUTPUT_VARIABLE size ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (result OR NOT size EQUAL CMAKE_SIZEOF_VOID_P) # interpreter not usable or has wrong architecture if (result) set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) else() set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Wrong architecture for the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"" PARENT_SCOPE) endif() set_property (CACHE _${_PYTHON_PREFIX}_EXECUTABLE PROPERTY VALUE "${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND") return() endif() endif() endfunction() function (_PYTHON_VALIDATE_COMPILER) if (NOT _${_PYTHON_PREFIX}_COMPILER) return() endif() cmake_parse_arguments (PARSE_ARGV 0 _PVC "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "") if (_PVC_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_COMPILER}") # Compiler does not exist anymore set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot find the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") return() endif() _python_get_launcher (launcher COMPILER) # retrieve python environment version from compiler set (working_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir") file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\n") execute_process (COMMAND ${launcher} "${_${_PYTHON_PREFIX}_COMPILER}" ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS} /target:exe /embed "${working_dir}/version.py" WORKING_DIRECTORY "${working_dir}" OUTPUT_QUIET ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) get_filename_component (ir_dir "${_${_PYTHON_PREFIX}_COMPILER}" DIRECTORY) execute_process (COMMAND "${CMAKE_COMMAND}" -E env "MONO_PATH=${ir_dir}" ${${_PYTHON_PREFIX}_DOTNET_LAUNCHER} "${working_dir}/version.exe" WORKING_DIRECTORY "${working_dir}" RESULT_VARIABLE result OUTPUT_VARIABLE version ERROR_QUIET) file (REMOVE_RECURSE "${working_dir}") if (result) # compiler is not usable set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot use the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") return() endif() if (_PVC_VERSION OR _PVC_IN_RANGE) if (_PVC_VERSION) # check against specified version ## compute number of components for version string (REGEX REPLACE "[^.]" "" dots "${_PVC_VERSION}") ## add one dot because there is one dot less than there are components string (LENGTH "${dots}." count) if (count GREATER 3) set (count 3) endif() set (version_regex "^[0-9]+") if (count EQUAL 3) string (APPEND version_regex "\\.[0-9]+\\.[0-9]+") elseif (count EQUAL 2) string (APPEND version_regex "\\.[0-9]+") endif() # extract needed range string (REGEX MATCH "${version_regex}" version "${version}") if (_PVC_EXACT AND NOT version VERSION_EQUAL _PVC_VERSION) # interpreter has wrong version set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") return() else() # check that version is OK string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}") string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" expected_major_version "${_PVC_VERSION}") if (NOT major_version VERSION_EQUAL expected_major_version OR NOT version VERSION_GREATER_EQUAL _PVC_VERSION) set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") return() endif() endif() endif() if (_PVC_IN_RANGE) # check if version is in the requested range find_package_check_version ("${version}" in_range HANDLE_VERSION_RANGE) if (NOT in_range) # interpreter has invalid version set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") return() endif() endif() else() string(REGEX REPLACE "^([0-9]+)\\.?.*$" "\\1" major_version "${version}") if (NOT major_version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) # Compiler has wrong major version set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Wrong major version for the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_COMPILER PROPERTY VALUE "${_PYTHON_PREFIX}_COMPILER-NOTFOUND") return() endif() endif() endfunction() function (_PYTHON_VALIDATE_LIBRARY) if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG) return() endif() cmake_parse_arguments (PARSE_ARGV 0 _PVL "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "") if (_PVL_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}") # library does not exist anymore set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") if (WIN32) set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND") endif() set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") return() endif() # retrieve version and abi from library name _python_get_version (LIBRARY PREFIX lib_) if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT lib_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS) # incompatible ABI set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") else() if (_PVL_VERSION OR _PVL_IN_RANGE) if (_PVL_VERSION) # library have only major.minor information string (REGEX MATCH "[0-9](\\.[0-9]+)?" version "${_PVL_VERSION}") if ((_PVL_EXACT AND NOT lib_VERSION VERSION_EQUAL version) OR (lib_VERSION VERSION_LESS version)) # library has wrong version set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") endif() endif() if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND _PVL_IN_RANGE) # check if library version is in the requested range find_package_check_version ("${lib_VERSION}" in_range HANDLE_VERSION_RANGE) if (NOT in_range) # library has wrong version set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") endif() endif() else() if (NOT lib_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) # library has wrong major version set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong major version for the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") endif() endif() endif() if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) if (WIN32) set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_DEBUG PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_DEBUG-NOTFOUND") endif() unset (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE CACHE) unset (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG CACHE) set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") endif() endfunction() function (_PYTHON_VALIDATE_INCLUDE_DIR) if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR) return() endif() cmake_parse_arguments (PARSE_ARGV 0 _PVID "IN_RANGE;EXACT;CHECK_EXISTS" "VERSION" "") if (_PVID_CHECK_EXISTS AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}") # include file does not exist anymore set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") return() endif() # retrieve version from header file _python_get_version (INCLUDE PREFIX inc_) if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT inc_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS) # incompatible ABI set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong ABI for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") else() if (_PVID_VERSION OR _PVID_IN_RANGE) if (_PVID_VERSION) if ((_PVID_EXACT AND NOT inc_VERSION VERSION_EQUAL expected_version) OR (inc_VERSION VERSION_LESS expected_version)) # include dir has wrong version set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") endif() endif() if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND PVID_IN_RANGE) # check if include dir is in the request range find_package_check_version ("${inc_VERSION}" in_range HANDLE_VERSION_RANGE) if (NOT in_range) # include dir has wrong version set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") endif() endif() else() if (NOT inc_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) # include dir has wrong major version set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Wrong major version for the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"" PARENT_SCOPE) set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") endif() endif() endif() endfunction() function (_PYTHON_FIND_RUNTIME_LIBRARY _PYTHON_LIB) string (REPLACE "_RUNTIME" "" _PYTHON_LIB "${_PYTHON_LIB}") # look at runtime part on systems supporting it if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR (CMAKE_SYSTEM_NAME MATCHES "MSYS|CYGWIN" AND ${_PYTHON_LIB} MATCHES "${CMAKE_IMPORT_LIBRARY_SUFFIX}$")) set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX}) # MSYS has a special syntax for runtime libraries if (CMAKE_SYSTEM_NAME MATCHES "MSYS") list (APPEND CMAKE_FIND_LIBRARY_PREFIXES "msys-") endif() find_library (${ARGV}) endif() endfunction() function (_PYTHON_SET_LIBRARY_DIRS _PYTHON_SLD_RESULT) unset (_PYTHON_DIRS) set (_PYTHON_LIBS ${ARGN}) foreach (_PYTHON_LIB IN LISTS _PYTHON_LIBS) if (${_PYTHON_LIB}) get_filename_component (_PYTHON_DIR "${${_PYTHON_LIB}}" DIRECTORY) list (APPEND _PYTHON_DIRS "${_PYTHON_DIR}") endif() endforeach() if (_PYTHON_DIRS) # Behavior change in CMake 3.14 list (REMOVE_DUPLICATES _PYTHON_DIRS) endif () set (${_PYTHON_SLD_RESULT} ${_PYTHON_DIRS} PARENT_SCOPE) endfunction() function (_PYTHON_SET_DEVELOPMENT_MODULE_FOUND module) if ("Development.${module}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) string(TOUPPER "${module}" id) set (module_found TRUE) if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) set (module_found FALSE) endif() if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS AND NOT _${_PYTHON_PREFIX}_INCLUDE_DIR) set (module_found FALSE) endif() set (${_PYTHON_PREFIX}_Development.${module}_FOUND ${module_found} PARENT_SCOPE) endif() endfunction() if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) # range must include internal major version if (${_PYTHON_PREFIX}_FIND_VERSION_MIN_MAJOR VERSION_GREATER _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR OR ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND ${_PYTHON_PREFIX}_FIND_VERSION_MAX VERSION_LESS _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) OR (${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND ${_PYTHON_PREFIX}_FIND_VERSION_MAX VERSION_LESS_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR))) _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong version range specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_RANGE}\", but expected version range must include major version \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"") cmake_policy(POP) return() endif() else() if (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR AND NOT ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) # If major version is specified, it must be the same as internal major version _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong major version specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}\", but expected major version is \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"") cmake_policy(POP) return() endif() endif() # handle components if (NOT ${_PYTHON_PREFIX}_FIND_COMPONENTS) set (${_PYTHON_PREFIX}_FIND_COMPONENTS Interpreter) set (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter TRUE) endif() if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS "Interpreter" "Development.Module") endif() if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) list (APPEND ${_PYTHON_PREFIX}_FIND_COMPONENTS "Development.Module" "Development.Embed") endif() if (${_PYTHON_PREFIX}_FIND_COMPONENTS) # Behavior change in CMake 3.14 list (REMOVE_DUPLICATES ${_PYTHON_PREFIX}_FIND_COMPONENTS) endif () foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development Development.Module Development.Embed NumPy) set (${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_FOUND FALSE) endforeach() if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development) set (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module TRUE) set (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed TRUE) endif() unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS) unset (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS) if ("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) if (CMAKE_SYSTEM_NAME MATCHES "^(Windows.*|CYGWIN|MSYS)$") list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS "LIBRARY") endif() list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS "INCLUDE_DIR") endif() if ("Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) list (APPEND _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS "LIBRARY" "INCLUDE_DIR") endif() set (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS} ${_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS}) if (_${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) # Behavior change in CMake 3.14 list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) endif () # Set versions to search ## default: search any version set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSIONS}) unset (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT) if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) unset (_${_PYTHON_PREFIX}_FIND_VERSIONS) foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS) if ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND _${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION_MIN) AND ((${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND _${_PYTHON_PREFIX}_VERSION VERSION_LESS_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION_MAX) OR (${_PYTHON_PREFIX}_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND _${_PYTHON_PREFIX}_VERSION VERSION_LESS ${_PYTHON_PREFIX}_FIND_VERSION_MAX))) list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION}) endif() endforeach() else() if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT GREATER 1) if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) set (_${_PYTHON_PREFIX}_FIND_VERSION_EXACT "EXACT") set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}) else() unset (_${_PYTHON_PREFIX}_FIND_VERSIONS) # add all compatible versions foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS) if (_${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL "${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}") list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION}) endif() endforeach() endif() endif() endif() # Set ABIs to search ## default: search any ABI if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR VERSION_LESS "3") # ABI not supported unset (_${_PYTHON_PREFIX}_FIND_ABI) set (_${_PYTHON_PREFIX}_ABIFLAGS "") else() unset (_${_PYTHON_PREFIX}_FIND_ABI) unset (_${_PYTHON_PREFIX}_ABIFLAGS) if (DEFINED ${_PYTHON_PREFIX}_FIND_ABI) # normalization string (TOUPPER "${${_PYTHON_PREFIX}_FIND_ABI}" _${_PYTHON_PREFIX}_FIND_ABI) list (TRANSFORM _${_PYTHON_PREFIX}_FIND_ABI REPLACE "^(TRUE|Y(ES)?|1)$" "ON") list (TRANSFORM _${_PYTHON_PREFIX}_FIND_ABI REPLACE "^(FALSE|N(O)?|0)$" "OFF") if (NOT _${_PYTHON_PREFIX}_FIND_ABI MATCHES "^(ON|OFF|ANY);(ON|OFF|ANY);(ON|OFF|ANY)$") message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_ABI}: invalid value for '${_PYTHON_PREFIX}_FIND_ABI'. Ignore it") unset (_${_PYTHON_PREFIX}_FIND_ABI) endif() _python_get_abiflags (_${_PYTHON_PREFIX}_ABIFLAGS) endif() endif() unset (${_PYTHON_PREFIX}_SOABI) # Define lookup strategy if(POLICY CMP0094) cmake_policy (GET CMP0094 _${_PYTHON_PREFIX}_LOOKUP_POLICY) else() set (_${_PYTHON_PREFIX}_LOOKUP_POLICY "OLD") endif() if (_${_PYTHON_PREFIX}_LOOKUP_POLICY STREQUAL "NEW") set (_${_PYTHON_PREFIX}_FIND_STRATEGY "LOCATION") else() set (_${_PYTHON_PREFIX}_FIND_STRATEGY "VERSION") endif() if (DEFINED ${_PYTHON_PREFIX}_FIND_STRATEGY) if (NOT ${_PYTHON_PREFIX}_FIND_STRATEGY MATCHES "^(VERSION|LOCATION)$") message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_STRATEGY}: invalid value for '${_PYTHON_PREFIX}_FIND_STRATEGY'. 'VERSION' or 'LOCATION' expected.") set (_${_PYTHON_PREFIX}_FIND_STRATEGY "VERSION") else() set (_${_PYTHON_PREFIX}_FIND_STRATEGY "${${_PYTHON_PREFIX}_FIND_STRATEGY}") endif() endif() # Python and Anaconda distributions: define which architectures can be used if (CMAKE_SIZEOF_VOID_P) # In this case, search only for 64bit or 32bit math (EXPR _${_PYTHON_PREFIX}_ARCH "${CMAKE_SIZEOF_VOID_P} * 8") set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH}) else() # architecture unknown, search for both 64bit and 32bit set (_${_PYTHON_PREFIX}_ARCH 64) set (_${_PYTHON_PREFIX}_ARCH2 32) endif() # IronPython support unset (_${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES) unset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES) unset (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS) if (CMAKE_SIZEOF_VOID_P) if (_${_PYTHON_PREFIX}_ARCH EQUAL "32") set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS "/platform:x86") else() set (_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS "/platform:x64") endif() endif() if (NOT CMAKE_SYSTEM_NAME STREQUAL "Linux") # Do not use wrapper script on Linux because it is buggy: -c interpreter option cannot be used list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES "ipy${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}" "ipy64" "ipy32" "ipy") list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES "ipyc") endif() list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_INTERPRETER_NAMES "ipy.exe") list (APPEND _${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_NAMES "ipyc.exe") set (_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES net45 net40 bin) # PyPy support if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL "3") set (_${_PYTHON_PREFIX}_PYPY_NAMES pypy3) set (_${_PYTHON_PREFIX}_PYPY_LIB_NAMES pypy3-c) if (WIN32) # special name for runtime part list (APPEND _${_PYTHON_PREFIX}_PYPY_LIB_NAMES libpypy3-c) endif() set (_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES lib/pypy3) else() set (_${_PYTHON_PREFIX}_PYPY_NAMES pypy) set (_${_PYTHON_PREFIX}_PYPY_LIB_NAMES pypy-c) if (WIN32) # special name for runtime part list (APPEND _${_PYTHON_PREFIX}_PYPY_LIB_NAMES libpypy-c) endif() set (_${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES lib/pypy) endif() set (_${_PYTHON_PREFIX}_PYPY_EXECUTABLE_PATH_SUFFIXES bin) set (_${_PYTHON_PREFIX}_PYPY_LIBRARY_PATH_SUFFIXES lib libs bin) list (APPEND _${_PYTHON_PREFIX}_PYPY_INCLUDE_PATH_SUFFIXES include) # Python Implementations handling unset (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS) if (DEFINED ${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS) foreach (_${_PYTHON_PREFIX}_IMPLEMENTATION IN LISTS ${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS) if (NOT _${_PYTHON_PREFIX}_IMPLEMENTATION MATCHES "^(CPython|IronPython|PyPy)$") message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${_${_PYTHON_PREFIX}_IMPLEMENTATION}: invalid value for '${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS'. 'CPython', 'IronPython' or 'PyPy' expected. Value will be ignored.") else() list (APPEND _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS ${_${_PYTHON_PREFIX}_IMPLEMENTATION}) endif() endforeach() else() if (WIN32) set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS CPython IronPython) else() set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS CPython) endif() endif() # compute list of names for header file unset (_${_PYTHON_PREFIX}_INCLUDE_NAMES) foreach (_${_PYTHON_PREFIX}_IMPLEMENTATION IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS) if (_${_PYTHON_PREFIX}_IMPLEMENTATION STREQUAL "CPython") list (APPEND _${_PYTHON_PREFIX}_INCLUDE_NAMES "Python.h") elseif (_${_PYTHON_PREFIX}_IMPLEMENTATION STREQUAL "PyPy") list (APPEND _${_PYTHON_PREFIX}_INCLUDE_NAMES "PyPy.h") endif() endforeach() # Apple frameworks handling _python_find_frameworks () set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST") if (DEFINED ${_PYTHON_PREFIX}_FIND_FRAMEWORK) if (NOT ${_PYTHON_PREFIX}_FIND_FRAMEWORK MATCHES "^(FIRST|LAST|NEVER)$") message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_FRAMEWORK}: invalid value for '${_PYTHON_PREFIX}_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.") else() set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${${_PYTHON_PREFIX}_FIND_FRAMEWORK}) endif() elseif (DEFINED CMAKE_FIND_FRAMEWORK) if (CMAKE_FIND_FRAMEWORK STREQUAL "ONLY") message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: CMAKE_FIND_FRAMEWORK: 'ONLY' value is not supported. 'FIRST' will be used instead.") elseif (NOT CMAKE_FIND_FRAMEWORK MATCHES "^(FIRST|LAST|NEVER)$") message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${CMAKE_FIND_FRAMEWORK}: invalid value for 'CMAKE_FIND_FRAMEWORK'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.") else() set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK}) endif() endif() # Save CMAKE_FIND_APPBUNDLE if (DEFINED CMAKE_FIND_APPBUNDLE) set (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE}) else() unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) endif() # To avoid app bundle lookup set (CMAKE_FIND_APPBUNDLE "NEVER") # Save CMAKE_FIND_FRAMEWORK if (DEFINED CMAKE_FIND_FRAMEWORK) set (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK}) else() unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK) endif() # To avoid framework lookup set (CMAKE_FIND_FRAMEWORK "NEVER") # Windows Registry handling if (DEFINED ${_PYTHON_PREFIX}_FIND_REGISTRY) if (NOT ${_PYTHON_PREFIX}_FIND_REGISTRY MATCHES "^(FIRST|LAST|NEVER)$") message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_REGISTRY}: invalid value for '${_PYTHON_PREFIX}_FIND_REGISTRY'. 'FIRST', 'LAST' or 'NEVER' expected. 'FIRST' will be used instead.") set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST") else() set (_${_PYTHON_PREFIX}_FIND_REGISTRY ${${_PYTHON_PREFIX}_FIND_REGISTRY}) endif() else() set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST") endif() # virtual environments recognition if (DEFINED ENV{VIRTUAL_ENV} OR DEFINED ENV{CONDA_PREFIX}) if (DEFINED ${_PYTHON_PREFIX}_FIND_VIRTUALENV) if (NOT ${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY|STANDARD)$") message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_VIRTUALENV}: invalid value for '${_PYTHON_PREFIX}_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'STANDARD' expected. 'FIRST' will be used instead.") set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV "FIRST") else() set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV ${${_PYTHON_PREFIX}_FIND_VIRTUALENV}) endif() else() set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV FIRST) endif() else() set (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STANDARD) endif() # Python naming handling if (DEFINED ${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES) if (NOT ${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES MATCHES "^(FIRST|LAST|NEVER)$") message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES}: invalid value for '${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES'. 'FIRST', 'LAST' or 'NEVER' expected. 'LAST' will be used instead.") set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES LAST) else() set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES ${${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES}) endif() else() set (_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES LAST) endif() # Compute search signature # This signature will be used to check validity of cached variables on new search set (_${_PYTHON_PREFIX}_SIGNATURE "${${_PYTHON_PREFIX}_ROOT_DIR}:${_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS}:${_${_PYTHON_PREFIX}_FIND_STRATEGY}:${${_PYTHON_PREFIX}_FIND_VIRTUALENV}${_${_PYTHON_PREFIX}_FIND_UNVERSIONED_NAMES}") if (NOT WIN32) string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${${_PYTHON_PREFIX}_USE_STATIC_LIBS}:") endif() if (CMAKE_HOST_APPLE) string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${_${_PYTHON_PREFIX}_FIND_FRAMEWORK}") endif() if (CMAKE_HOST_WIN32) string (APPEND _${_PYTHON_PREFIX}_SIGNATURE ":${_${_PYTHON_PREFIX}_FIND_REGISTRY}") endif() function (_PYTHON_CHECK_DEVELOPMENT_SIGNATURE module) if ("Development.${module}" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) string (TOUPPER "${module}" id) set (signature "${_${_PYTHON_PREFIX}_SIGNATURE}:") if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) list (APPEND signature "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:") endif() if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) list (APPEND signature "${_${_PYTHON_PREFIX}_INCLUDE_DIR}:") endif() string (MD5 signature "${signature}") if (signature STREQUAL _${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE) if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) _python_validate_library (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) _python_validate_library (IN_RANGE CHECK_EXISTS) elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION) _python_validate_library (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) else() _python_validate_library (CHECK_EXISTS) endif() endif() if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) _python_validate_include_dir (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) _python_validate_include_dir (IN_RANGE CHECK_EXISTS) elseif (${_PYTHON_PREFIX}_FIND_VERSION) _python_validate_include_dir (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) else() _python_validate_include_dir (CHECK_EXISTS) endif() endif() else() if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) unset (_${_PYTHON_PREFIX}_LIBRARY_RELEASE CACHE) unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE) endif() if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE) endif() endif() if (("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) OR ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS AND NOT _${_PYTHON_PREFIX}_INCLUDE_DIR)) unset (_${_PYTHON_PREFIX}_CONFIG CACHE) unset (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE CACHE) endif() endif() endfunction() function (_PYTHON_COMPUTE_DEVELOPMENT_SIGNATURE module) string (TOUPPER "${module}" id) if (${_PYTHON_PREFIX}_Development.${module}_FOUND) set (signature "${_${_PYTHON_PREFIX}_SIGNATURE}:") if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) list (APPEND signature "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}:") endif() if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_${id}_ARTIFACTS) list (APPEND signature "${_${_PYTHON_PREFIX}_INCLUDE_DIR}:") endif() string (MD5 signature "${signature}") set (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE "${signature}" CACHE INTERNAL "") else() unset (_${_PYTHON_PREFIX}_DEVELOPMENT_${id}_SIGNATURE CACHE) endif() endfunction() unset (_${_PYTHON_PREFIX}_REQUIRED_VARS) unset (_${_PYTHON_PREFIX}_CACHED_VARS) unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE) unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE) unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE) unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE) # preamble ## For IronPython on platforms other than Windows, search for the .Net interpreter if ("IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS AND NOT WIN32) find_program (${_PYTHON_PREFIX}_DOTNET_LAUNCHER NAMES "mono") endif() # first step, search for the interpreter if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_EXECUTABLE _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES) if (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter) list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_EXECUTABLE) endif() if (DEFINED ${_PYTHON_PREFIX}_EXECUTABLE AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_EXECUTABLE}") if (NOT ${_PYTHON_PREFIX}_EXECUTABLE STREQUAL _${_PYTHON_PREFIX}_EXECUTABLE) # invalidate cache properties unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE) endif() set (_${_PYTHON_PREFIX}_EXECUTABLE "${${_PYTHON_PREFIX}_EXECUTABLE}" CACHE INTERNAL "") elseif (DEFINED _${_PYTHON_PREFIX}_EXECUTABLE) # compute interpreter signature and check validity of definition string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}") if (__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE) # check version validity if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) _python_validate_interpreter (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) _python_validate_interpreter (IN_RANGE CHECK_EXISTS) elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION) _python_validate_interpreter (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) else() _python_validate_interpreter (CHECK_EXISTS) endif() else() unset (_${_PYTHON_PREFIX}_EXECUTABLE CACHE) endif() if (NOT _${_PYTHON_PREFIX}_EXECUTABLE) unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE) unset (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES CACHE) endif() endif() if (NOT _${_PYTHON_PREFIX}_EXECUTABLE) set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION") # build all executable names _python_get_names (_${_PYTHON_PREFIX}_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} POSIX INTERPRETER) _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} INTERPRETER) # Framework Paths _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}) # Registry Paths _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}) set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE) elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION) list (APPEND VERSION ${${_PYTHON_PREFIX}_FIND_VERSION}) endif() while (TRUE) # Virtual environments handling if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_interpreter (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY") break() endif() endif() # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() endif() # Windows registry if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() endif() # try using HINTS find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() # try using standard paths find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() endif() # Windows registry if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) _python_validate_interpreter (${${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() endif() break() endwhile() else() # look-up for various versions and locations set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS EXACT) if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE) endif() foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) _python_get_names (_${_PYTHON_PREFIX}_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX INTERPRETER) _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} INTERPRETER) _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION}) _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION}) # Virtual environments handling if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY") continue() endif() endif() # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() # Windows registry if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() # try using HINTS find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() # try using standard paths. # NAMES_PER_DIR is not defined on purpose to have a chance to find # expected version. # For example, typical systems have 'python' for version 2.* and 'python3' # for version 3.*. So looking for names per dir will find, potentially, # systematically 'python' (i.e. version 2) even if version 3 is searched. find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) endif() # Windows registry if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES} NAMES_PER_DIR PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) endif() _python_validate_interpreter (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_EXECUTABLE) break() endif() endforeach() if (NOT _${_PYTHON_PREFIX}_EXECUTABLE AND NOT _${_PYTHON_PREFIX}_FIND_VIRTUALENV STREQUAL "ONLY") # No specific version found. Retry with generic names and standard paths. # NAMES_PER_DIR is not defined on purpose to have a chance to find # expected version. # For example, typical systems have 'python' for version 2.* and 'python3' # for version 3.*. So looking for names per dir will find, potentially, # systematically 'python' (i.e. version 2) even if version 3 is searched. _python_get_names (_${_PYTHON_PREFIX}_NAMES POSIX INTERPRETER) find_program (_${_PYTHON_PREFIX}_EXECUTABLE NAMES ${_${_PYTHON_PREFIX}_NAMES}) _python_validate_interpreter () endif() endif() endif() set (${_PYTHON_PREFIX}_EXECUTABLE "${_${_PYTHON_PREFIX}_EXECUTABLE}") _python_get_launcher (_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER INTERPRETER) # retrieve exact version of executable found if (_${_PYTHON_PREFIX}_EXECUTABLE) execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))" RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE ${_PYTHON_PREFIX}_VERSION ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (NOT _${_PYTHON_PREFIX}_RESULT) set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE TRUE) else() # Interpreter is not usable set (_${_PYTHON_PREFIX}_EXECUTABLE_USABLE FALSE) unset (${_PYTHON_PREFIX}_VERSION) set (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE "Cannot run the interpreter \"${_${_PYTHON_PREFIX}_EXECUTABLE}\"") endif() endif() if (_${_PYTHON_PREFIX}_EXECUTABLE AND _${_PYTHON_PREFIX}_EXECUTABLE_USABLE) if (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES) set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 0 ${_PYTHON_PREFIX}_INTERPRETER_ID) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 1 ${_PYTHON_PREFIX}_VERSION_MAJOR) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 2 ${_PYTHON_PREFIX}_VERSION_MINOR) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 3 ${_PYTHON_PREFIX}_VERSION_PATCH) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 4 _${_PYTHON_PREFIX}_ARCH) set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH}) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 5 _${_PYTHON_PREFIX}_ABIFLAGS) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 6 ${_PYTHON_PREFIX}_SOABI) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 7 ${_PYTHON_PREFIX}_STDLIB) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 8 ${_PYTHON_PREFIX}_STDARCH) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 9 ${_PYTHON_PREFIX}_SITELIB) list (GET _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES 10 ${_PYTHON_PREFIX}_SITEARCH) else() string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${${_PYTHON_PREFIX}_VERSION}") list (GET _${_PYTHON_PREFIX}_VERSIONS 0 ${_PYTHON_PREFIX}_VERSION_MAJOR) list (GET _${_PYTHON_PREFIX}_VERSIONS 1 ${_PYTHON_PREFIX}_VERSION_MINOR) list (GET _${_PYTHON_PREFIX}_VERSIONS 2 ${_PYTHON_PREFIX}_VERSION_PATCH) if (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE) # Use interpreter version and ABI for future searches to ensure consistency set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}) execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETR_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; sys.stdout.write(sys.abiflags)" RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE _${_PYTHON_PREFIX}_ABIFLAGS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_${_PYTHON_PREFIX}_RESULT) # assunme ABI is not supported set (_${_PYTHON_PREFIX}_ABIFLAGS "") endif() endif() if (${_PYTHON_PREFIX}_Interpreter_FOUND) unset (_${_PYTHON_PREFIX}_Interpreter_REASON_FAILURE) # compute and save interpreter signature string (MD5 __${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_EXECUTABLE}") set (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE "${__${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}" CACHE INTERNAL "") if (NOT CMAKE_SIZEOF_VOID_P) # determine interpreter architecture execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; sys.stdout.write(str(sys.maxsize > 2**32))" RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE ${_PYTHON_PREFIX}_IS64BIT ERROR_VARIABLE ${_PYTHON_PREFIX}_IS64BIT) if (NOT _${_PYTHON_PREFIX}_RESULT) if (${_PYTHON_PREFIX}_IS64BIT) set (_${_PYTHON_PREFIX}_ARCH 64) set (_${_PYTHON_PREFIX}_ARCH2 64) else() set (_${_PYTHON_PREFIX}_ARCH 32) set (_${_PYTHON_PREFIX}_ARCH2 32) endif() endif() endif() # retrieve interpreter identity execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -V RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID ERROR_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID) if (NOT _${_PYTHON_PREFIX}_RESULT) if (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Anaconda") set (${_PYTHON_PREFIX}_INTERPRETER_ID "Anaconda") elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Enthought") set (${_PYTHON_PREFIX}_INTERPRETER_ID "Canopy") elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "PyPy ([0-9.]+)") set (${_PYTHON_PREFIX}_INTERPRETER_ID "PyPy") set (${_PYTHON_PREFIX}_PyPy_VERSION "${CMAKE_MATCH_1}") else() string (REGEX REPLACE "^([^ ]+).*" "\\1" ${_PYTHON_PREFIX}_INTERPRETER_ID "${${_PYTHON_PREFIX}_INTERPRETER_ID}") if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "Python") # try to get a more precise ID execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; sys.stdout.write(sys.copyright)" RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE ${_PYTHON_PREFIX}_COPYRIGHT ERROR_QUIET) if (${_PYTHON_PREFIX}_COPYRIGHT MATCHES "ActiveState") set (${_PYTHON_PREFIX}_INTERPRETER_ID "ActivePython") endif() endif() endif() else() set (${_PYTHON_PREFIX}_INTERPRETER_ID Python) endif() # retrieve various package installation directories execute_process (COMMAND ${_${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry:\n from distutils import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))\nexcept Exception:\n import sysconfig\n sys.stdout.write(';'.join([sysconfig.get_path('stdlib'),sysconfig.get_path('platstdlib'),sysconfig.get_path('purelib'),sysconfig.get_path('platlib')]))" RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS ERROR_QUIET) if (NOT _${_PYTHON_PREFIX}_RESULT) list (GET _${_PYTHON_PREFIX}_LIBPATHS 0 ${_PYTHON_PREFIX}_STDLIB) list (GET _${_PYTHON_PREFIX}_LIBPATHS 1 ${_PYTHON_PREFIX}_STDARCH) list (GET _${_PYTHON_PREFIX}_LIBPATHS 2 ${_PYTHON_PREFIX}_SITELIB) list (GET _${_PYTHON_PREFIX}_LIBPATHS 3 ${_PYTHON_PREFIX}_SITEARCH) else() unset (${_PYTHON_PREFIX}_STDLIB) unset (${_PYTHON_PREFIX}_STDARCH) unset (${_PYTHON_PREFIX}_SITELIB) unset (${_PYTHON_PREFIX}_SITEARCH) endif() _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI) # store properties in the cache to speed-up future searches set (_${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES "${${_PYTHON_PREFIX}_INTERPRETER_ID};${${_PYTHON_PREFIX}_VERSION_MAJOR};${${_PYTHON_PREFIX}_VERSION_MINOR};${${_PYTHON_PREFIX}_VERSION_PATCH};${_${_PYTHON_PREFIX}_ARCH};${_${_PYTHON_PREFIX}_ABIFLAGS};${${_PYTHON_PREFIX}_SOABI};${${_PYTHON_PREFIX}_STDLIB};${${_PYTHON_PREFIX}_STDARCH};${${_PYTHON_PREFIX}_SITELIB};${${_PYTHON_PREFIX}_SITEARCH}" CACHE INTERNAL "${_PYTHON_PREFIX} Properties") else() unset (_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE CACHE) unset (${_PYTHON_PREFIX}_INTERPRETER_ID) endif() endif() endif() if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE) set (${_PYTHON_PREFIX}_EXECUTABLE "${_${_PYTHON_PREFIX}_EXECUTABLE}" CACHE FILEPATH "${_PYTHON_PREFIX} Interpreter") endif() _python_mark_as_internal (_${_PYTHON_PREFIX}_EXECUTABLE _${_PYTHON_PREFIX}_INTERPRETER_PROPERTIES _${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE) endif() # second step, search for compiler (IronPython) if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_COMPILER) if (${_PYTHON_PREFIX}_FIND_REQUIRED_Compiler) list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_COMPILER) endif() if (NOT "IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS) unset (_${_PYTHON_PREFIX}_COMPILER CACHE) unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE) elseif (DEFINED ${_PYTHON_PREFIX}_COMPILER AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_COMPILER}") set (_${_PYTHON_PREFIX}_COMPILER "${${_PYTHON_PREFIX}_COMPILER}" CACHE INTERNAL "") elseif (DEFINED _${_PYTHON_PREFIX}_COMPILER) # compute compiler signature and check validity of definition string (MD5 __${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_COMPILER}") if (__${_PYTHON_PREFIX}_COMPILER_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_COMPILER_SIGNATURE) # check version validity if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) _python_validate_compiler (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} EXACT CHECK_EXISTS) elseif (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) _python_validate_compiler (IN_RANGE CHECK_EXISTS) elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION) _python_validate_compiler (VERSION ${${_PYTHON_PREFIX}_FIND_VERSION} CHECK_EXISTS) else() _python_validate_compiler (CHECK_EXISTS) endif() else() unset (_${_PYTHON_PREFIX}_COMPILER CACHE) unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE) endif() endif() if ("IronPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS AND NOT _${_PYTHON_PREFIX}_COMPILER) # IronPython specific artifacts # If IronPython interpreter is found, use its path unset (_${_PYTHON_PREFIX}_IRON_ROOT) if (${_PYTHON_PREFIX}_Interpreter_FOUND AND ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython") get_filename_component (_${_PYTHON_PREFIX}_IRON_ROOT "${${_PYTHON_PREFIX}_EXECUTABLE}" DIRECTORY) endif() if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION") _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES IMPLEMENTATIONS IronPython VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} COMPILER) _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES IMPLEMENTATIONS IronPython VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} COMPILER) _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS IMPLEMENTATIONS IronPython VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}) _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS IMPLEMENTATIONS IronPython VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}) set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS ${_${_PYTHON_PREFIX}_FIND_VERSION_EXACT}) if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE) elseif (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION) list (APPEND VERSION ${${_PYTHON_PREFIX}_FIND_VERSION}) endif() while (TRUE) # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() endif() # Windows registry if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() endif() # try using HINTS find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() # try using standard paths find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() endif() # Windows registry if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) _python_validate_compiler (${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() endif() break() endwhile() else() # try using root dir and registry set (_${_PYTHON_PREFIX}_VALIDATE_OPTIONS EXACT) if (${_PYTHON_PREFIX}_FIND_VERSION_RANGE) list (APPEND _${_PYTHON_PREFIX}_VALIDATE_OPTIONS IN_RANGE) endif() foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES IMPLEMENTATIONS IronPython VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} COMPILER) _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES IMPLEMENTATIONS IronPython VERSION ${_${_PYTHON_PREFIX}_FIND_VERSION} COMPILER) _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS IMPLEMENTATIONS IronPython VERSION ${_${_PYTHON_PREFIX}_VERSION}) _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS IMPLEMENTATIONS IronPython VERSION ${_${_PYTHON_PREFIX}_VERSION}) # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() endif() # Windows registry if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() endif() # try using HINTS find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() endif() # Windows registry if (CMAKE_HOST_WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} NAMES_PER_DIR PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_DEFAULT_PATH) _python_validate_compiler (VERSION ${_${_PYTHON_PREFIX}_VERSION} ${_${_PYTHON_PREFIX}_VALIDATE_OPTIONS}) if (_${_PYTHON_PREFIX}_COMPILER) break() endif() endif() endforeach() # no specific version found, re-try in standard paths _python_get_names (_${_PYTHON_PREFIX}_COMPILER_NAMES IMPLEMENTATIONS IronPython VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} COMPILER) _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES IMPLEMENTATIONS IronPython VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} COMPILER) find_program (_${_PYTHON_PREFIX}_COMPILER NAMES ${_${_PYTHON_PREFIX}_COMPILER_NAMES} HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) _python_validate_compiler () endif() endif() set (${_PYTHON_PREFIX}_COMPILER "${_${_PYTHON_PREFIX}_COMPILER}") if (_${_PYTHON_PREFIX}_COMPILER) # retrieve python environment version from compiler _python_get_launcher (_${_PYTHON_PREFIX}_COMPILER_LAUNCHER COMPILER) set (_${_PYTHON_PREFIX}_VERSION_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir") file (WRITE "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\n") execute_process (COMMAND ${_${_PYTHON_PREFIX}_COMPILER_LAUNCHER} "${_${_PYTHON_PREFIX}_COMPILER}" ${_${_PYTHON_PREFIX}_IRON_PYTHON_COMPILER_ARCH_FLAGS} /target:exe /embed "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py" WORKING_DIRECTORY "${_${_PYTHON_PREFIX}_VERSION_DIR}" OUTPUT_QUIET ERROR_QUIET) get_filename_component (_${_PYTHON_PREFIX}_IR_DIR "${_${_PYTHON_PREFIX}_COMPILER}" DIRECTORY) execute_process (COMMAND "${CMAKE_COMMAND}" -E env "MONO_PATH=${_${_PYTHON_PREFIX}_IR_DIR}" ${${_PYTHON_PREFIX}_DOTNET_LAUNCHER} "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.exe" WORKING_DIRECTORY "${_${_PYTHON_PREFIX}_VERSION_DIR}" RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE _${_PYTHON_PREFIX}_VERSION ERROR_QUIET) if (NOT _${_PYTHON_PREFIX}_RESULT) set (_${_PYTHON_PREFIX}_COMPILER_USABLE TRUE) string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${_${_PYTHON_PREFIX}_VERSION}") list (GET _${_PYTHON_PREFIX}_VERSIONS 0 _${_PYTHON_PREFIX}_VERSION_MAJOR) list (GET _${_PYTHON_PREFIX}_VERSIONS 1 _${_PYTHON_PREFIX}_VERSION_MINOR) list (GET _${_PYTHON_PREFIX}_VERSIONS 2 _${_PYTHON_PREFIX}_VERSION_PATCH) if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND) # set public version information set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION}) set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR}) set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR}) set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH}) endif() else() # compiler not usable set (_${_PYTHON_PREFIX}_COMPILER_USABLE FALSE) set (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE "Cannot run the compiler \"${_${_PYTHON_PREFIX}_COMPILER}\"") endif() file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}") endif() if (_${_PYTHON_PREFIX}_COMPILER AND _${_PYTHON_PREFIX}_COMPILER_USABLE) if (${_PYTHON_PREFIX}_Interpreter_FOUND) # Compiler must be compatible with interpreter if ("${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}" VERSION_EQUAL "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}") set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE) endif() elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE) # Use compiler version for future searches to ensure consistency set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}) endif() endif() if (${_PYTHON_PREFIX}_Compiler_FOUND) unset (_${_PYTHON_PREFIX}_Compiler_REASON_FAILURE) # compute and save compiler signature string (MD5 __${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${_${_PYTHON_PREFIX}_SIGNATURE}:${_${_PYTHON_PREFIX}_COMPILER}") set (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE "${__${_PYTHON_PREFIX}_COMPILER_SIGNATURE}" CACHE INTERNAL "") set (${_PYTHON_PREFIX}_COMPILER_ID IronPython) else() unset (_${_PYTHON_PREFIX}_COMPILER_SIGNATURE CACHE) unset (${_PYTHON_PREFIX}_COMPILER_ID) endif() if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE) set (${_PYTHON_PREFIX}_COMPILER "${_${_PYTHON_PREFIX}_COMPILER}" CACHE FILEPATH "${_PYTHON_PREFIX} Compiler") endif() _python_mark_as_internal (_${_PYTHON_PREFIX}_COMPILER _${_PYTHON_PREFIX}_COMPILER_SIGNATURE) endif() # third step, search for the development artifacts if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Module) if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS) list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES) endif() if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS) list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS) endif() endif() if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development.Embed) if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS) list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARIES) endif() if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_EMBED_ARTIFACTS) list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_INCLUDE_DIRS) endif() endif() if (_${_PYTHON_PREFIX}_REQUIRED_VARS) # Behavior change in CMake 3.14 list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_REQUIRED_VARS) endif () ## Development environment is not compatible with IronPython interpreter if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS OR "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) AND ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython") OR NOT ${_PYTHON_PREFIX}_Interpreter_FOUND)) if (${_PYTHON_PREFIX}_Interpreter_FOUND) # reduce possible implementations to the interpreter one if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "PyPy") set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS "PyPy") else() set (_${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS "CPython") endif() else() list (REMOVE_ITEM _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS "IronPython") endif() if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_LIBRARY_RELEASE _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE _${_PYTHON_PREFIX}_LIBRARY_DEBUG _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG) endif() if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_INCLUDE_DIR) endif() _python_check_development_signature (Module) _python_check_development_signature (Embed) if (DEFINED ${_PYTHON_PREFIX}_LIBRARY AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_LIBRARY}") set (_${_PYTHON_PREFIX}_LIBRARY_RELEASE "${${_PYTHON_PREFIX}_LIBRARY}" CACHE INTERNAL "") unset (_${_PYTHON_PREFIX}_LIBRARY_DEBUG CACHE) unset (_${_PYTHON_PREFIX}_INCLUDE_DIR CACHE) endif() if (DEFINED ${_PYTHON_PREFIX}_INCLUDE_DIR AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_INCLUDE_DIR}") set (_${_PYTHON_PREFIX}_INCLUDE_DIR "${${_PYTHON_PREFIX}_INCLUDE_DIR}" CACHE INTERNAL "") endif() # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES unset (_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES) if (DEFINED ${_PYTHON_PREFIX}_USE_STATIC_LIBS AND NOT WIN32) set(_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) if(${_PYTHON_PREFIX}_USE_STATIC_LIBS) set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) else() list (REMOVE_ITEM CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) endif() endif() if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE OR NOT _${_PYTHON_PREFIX}_INCLUDE_DIR) # if python interpreter is found, use it to look-up for artifacts # to ensure consistency between interpreter and development environments. # If not, try to locate a compatible config tool if ((NOT ${_PYTHON_PREFIX}_Interpreter_FOUND OR CMAKE_CROSSCOMPILING) AND "CPython" IN_LIST _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS) set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS) if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX) endif() if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION") _python_get_names (_${_PYTHON_PREFIX}_CONFIG_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} POSIX CONFIG) # Framework Paths _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS}) # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") find_program (_${_PYTHON_PREFIX}_CONFIG NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES bin NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() find_program (_${_PYTHON_PREFIX}_CONFIG NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} PATH_SUFFIXES bin) # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") find_program (_${_PYTHON_PREFIX}_CONFIG NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} NAMES_PER_DIR PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES bin NO_DEFAULT_PATH) endif() if (_${_PYTHON_PREFIX}_CONFIG) execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --help RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE __${_PYTHON_PREFIX}_HELP ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_${_PYTHON_PREFIX}_RESULT) # assume config tool is not usable unset (_${_PYTHON_PREFIX}_CONFIG CACHE) endif() endif() if (_${_PYTHON_PREFIX}_CONFIG) execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --abiflags RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE __${_PYTHON_PREFIX}_ABIFLAGS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_${_PYTHON_PREFIX}_RESULT) # assume ABI is not supported set (__${_PYTHON_PREFIX}_ABIFLAGS "") endif() if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT __${_PYTHON_PREFIX}_ABIFLAGS IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS) # Wrong ABI unset (_${_PYTHON_PREFIX}_CONFIG CACHE) endif() endif() if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE) # check that config tool match library architecture execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_${_PYTHON_PREFIX}_RESULT) unset (_${_PYTHON_PREFIX}_CONFIG CACHE) else() string(FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT) if (_${_PYTHON_PREFIX}_RESULT EQUAL -1) unset (_${_PYTHON_PREFIX}_CONFIG CACHE) endif() endif() endif() else() foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) # try to use pythonX.Y-config tool _python_get_names (_${_PYTHON_PREFIX}_CONFIG_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} POSIX CONFIG) # Framework Paths _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION}) # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") find_program (_${_PYTHON_PREFIX}_CONFIG NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES bin NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() find_program (_${_PYTHON_PREFIX}_CONFIG NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} PATH_SUFFIXES bin) # Apple frameworks handling if (CMAKE_HOST_APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") find_program (_${_PYTHON_PREFIX}_CONFIG NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} NAMES_PER_DIR PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES bin NO_DEFAULT_PATH) endif() unset (_${_PYTHON_PREFIX}_CONFIG_NAMES) if (_${_PYTHON_PREFIX}_CONFIG) execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --help RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE __${_PYTHON_PREFIX}_HELP ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_${_PYTHON_PREFIX}_RESULT) # assume config tool is not usable unset (_${_PYTHON_PREFIX}_CONFIG CACHE) endif() endif() if (NOT _${_PYTHON_PREFIX}_CONFIG) continue() endif() execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --abiflags RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE __${_PYTHON_PREFIX}_ABIFLAGS ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_${_PYTHON_PREFIX}_RESULT) # assume ABI is not supported set (__${_PYTHON_PREFIX}_ABIFLAGS "") endif() if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND NOT __${_PYTHON_PREFIX}_ABIFLAGS IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS) # Wrong ABI unset (_${_PYTHON_PREFIX}_CONFIG CACHE) continue() endif() if (_${_PYTHON_PREFIX}_CONFIG AND DEFINED CMAKE_LIBRARY_ARCHITECTURE) # check that config tool match library architecture execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (_${_PYTHON_PREFIX}_RESULT) unset (_${_PYTHON_PREFIX}_CONFIG CACHE) continue() endif() string (FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT) if (_${_PYTHON_PREFIX}_RESULT EQUAL -1) unset (_${_PYTHON_PREFIX}_CONFIG CACHE) continue() endif() endif() if (_${_PYTHON_PREFIX}_CONFIG) break() endif() endforeach() endif() endif() endif() if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) if ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT CMAKE_CROSSCOMPILING) OR _${_PYTHON_PREFIX}_CONFIG) # retrieve root install directory _python_get_config_var (_${_PYTHON_PREFIX}_PREFIX PREFIX) # enforce current ABI _python_get_config_var (_${_PYTHON_PREFIX}_ABIFLAGS ABIFLAGS) set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}") # retrieve library ## compute some paths and artifact names if (_${_PYTHON_PREFIX}_CONFIG) string (REGEX REPLACE "^.+python([0-9.]+)[a-z]*-config" "\\1" _${_PYTHON_PREFIX}_VERSION "${_${_PYTHON_PREFIX}_CONFIG}") else() set (_${_PYTHON_PREFIX}_VERSION "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}") endif() _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} LIBRARY) _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 POSIX LIBRARY) _python_get_config_var (_${_PYTHON_PREFIX}_CONFIGDIR CONFIGDIR) list (APPEND _${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_CONFIGDIR}") list (APPEND _${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() # Rely on HINTS and standard paths if interpreter or config tool failed to locate artifacts if (NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS) if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX) endif() if (_${_PYTHON_PREFIX}_FIND_STRATEGY STREQUAL "LOCATION") # library names _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} WIN32 POSIX LIBRARY) _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} WIN32 DEBUG) # Paths suffixes _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} LIBRARY) # Framework Paths _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_FIND_VERSIONS}) # Registry Paths _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_FIND_VERSIONS} ) if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() # search in HINTS locations find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}) else() unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS) endif() if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}) else() unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS) endif() # search in all default paths find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} NAMES_PER_DIR PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS} ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) else() foreach (_${_PYTHON_PREFIX}_LIB_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 POSIX LIBRARY) _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} WIN32 DEBUG) _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION}) _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION}) _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_LIB_VERSION} LIBRARY) if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() # search in HINTS locations find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}) else() unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS) endif() if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}) else() unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS) endif() # search in all default paths find_library (_${_PYTHON_PREFIX}_LIBRARY_RELEASE NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} NAMES_PER_DIR PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS} ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES}) if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE) break() endif() endforeach() endif() endif() endif() # finalize library version information _python_get_version (LIBRARY PREFIX _${_PYTHON_PREFIX}_) if (_${_PYTHON_PREFIX}_VERSION EQUAL "${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}") # not able to extract full version from library name if (${_PYTHON_PREFIX}_Interpreter_FOUND) # update from interpreter set (_${_PYTHON_PREFIX}_VERSION ${${_PYTHON_PREFIX}_VERSION}) set (_${_PYTHON_PREFIX}_VERSION_MAJOR ${${_PYTHON_PREFIX}_VERSION_MAJOR}) set (_${_PYTHON_PREFIX}_VERSION_MINOR ${${_PYTHON_PREFIX}_VERSION_MINOR}) set (_${_PYTHON_PREFIX}_VERSION_PATCH ${${_PYTHON_PREFIX}_VERSION_PATCH}) endif() endif() set (${_PYTHON_PREFIX}_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}") if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE AND NOT EXISTS "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}") set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the library \"${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}\"") set_property (CACHE _${_PYTHON_PREFIX}_LIBRARY_RELEASE PROPERTY VALUE "${_PYTHON_PREFIX}_LIBRARY_RELEASE-NOTFOUND") endif() set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) if (WIN32 AND _${_PYTHON_PREFIX}_LIBRARY_RELEASE) # search for debug library # use release library location as a hint _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 DEBUG) get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY) find_library (_${_PYTHON_PREFIX}_LIBRARY_DEBUG NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG} NAMES_PER_DIR HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS} NO_DEFAULT_PATH) # second try including CMAKE variables to catch-up non conventional layouts find_library (_${_PYTHON_PREFIX}_LIBRARY_DEBUG NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG} NAMES_PER_DIR NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() # retrieve runtime libraries if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE) _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 POSIX LIBRARY) get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY) get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY) _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} NAMES_PER_DIR HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS} PATH_SUFFIXES bin) endif() if (_${_PYTHON_PREFIX}_LIBRARY_DEBUG) _python_get_names (_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG VERSION ${_${_PYTHON_PREFIX}_VERSION} WIN32 DEBUG) get_filename_component (_${_PYTHON_PREFIX}_PATH "${_${_PYTHON_PREFIX}_LIBRARY_DEBUG}" DIRECTORY) get_filename_component (_${_PYTHON_PREFIX}_PATH2 "${_${_PYTHON_PREFIX}_PATH}" DIRECTORY) _python_find_runtime_library (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES_DEBUG} NAMES_PER_DIR HINTS "${_${_PYTHON_PREFIX}_PATH}" "${_${_PYTHON_PREFIX}_PATH2}" ${_${_PYTHON_PREFIX}_HINTS} PATH_SUFFIXES bin) endif() endif() if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) while (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR) if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS AND NOT _${_PYTHON_PREFIX}_LIBRARY_RELEASE) # Don't search for include dir if no library was founded break() endif() if ((${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT CMAKE_CROSSCOMPILING) OR _${_PYTHON_PREFIX}_CONFIG) _python_get_config_var (_${_PYTHON_PREFIX}_INCLUDE_DIRS INCLUDES) find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES} HINTS ${_${_PYTHON_PREFIX}_INCLUDE_DIRS} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() # Rely on HINTS and standard paths if interpreter or config tool failed to locate artifacts if (NOT _${_PYTHON_PREFIX}_INCLUDE_DIR) unset (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS) if (_${_PYTHON_PREFIX}_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$") set (_${_PYTHON_PREFIX}_VIRTUALENV_PATHS ENV VIRTUAL_ENV ENV CONDA_PREFIX) endif() unset (_${_PYTHON_PREFIX}_INCLUDE_HINTS) if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE) # Use the library's install prefix as a hint if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "^(.+/Frameworks/Python.framework/Versions/[0-9.]+)") list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}") elseif (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "^(.+)/lib(64|32)?/python[0-9.]+/config") list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}") elseif (DEFINED CMAKE_LIBRARY_ARCHITECTURE AND ${_${_PYTHON_PREFIX}_LIBRARY_RELEASE} MATCHES "^(.+)/lib/${CMAKE_LIBRARY_ARCHITECTURE}") list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}") else() # assume library is in a directory under root get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY) get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_PREFIX}" DIRECTORY) list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PREFIX}") endif() endif() _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION}) _python_get_registries (_${_PYTHON_PREFIX}_REGISTRY_PATHS VERSION ${_${_PYTHON_PREFIX}_VERSION}) _python_get_path_suffixes (_${_PYTHON_PREFIX}_PATH_SUFFIXES VERSION ${_${_PYTHON_PREFIX}_VERSION} INCLUDE) if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES} HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES} HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}) else() unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS) endif() if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}) else() unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS) endif() find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES} HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS} PATHS ${_${_PYTHON_PREFIX}_VIRTUALENV_PATHS} ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS} ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES ${_${_PYTHON_PREFIX}_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) endif() # search header file in standard locations find_path (_${_PYTHON_PREFIX}_INCLUDE_DIR NAMES ${_${_PYTHON_PREFIX}_INCLUDE_NAMES}) break() endwhile() set (${_PYTHON_PREFIX}_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}") if (_${_PYTHON_PREFIX}_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}") set (_${_PYTHON_PREFIX}_Development_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_INCLUDE_DIR}\"") set_property (CACHE _${_PYTHON_PREFIX}_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_INCLUDE_DIR-NOTFOUND") endif() if (_${_PYTHON_PREFIX}_INCLUDE_DIR) # retrieve version from header file _python_get_version (INCLUDE PREFIX _${_PYTHON_PREFIX}_INC_) if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE) if ("${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}" VERSION_EQUAL _${_PYTHON_PREFIX}_VERSION) # update versioning set (_${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_INC_VERSION}) set (_${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_INC_VERSION_PATCH}) endif() else() set (_${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_INC_VERSION}) set (_${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}) set (_${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}) set (_${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_INC_VERSION_PATCH}) endif() endif() endif() if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT ${_PYTHON_PREFIX}_Compiler_FOUND) # set public version information set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION}) set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR}) set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR}) set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH}) endif() # define public variables if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) set (${_PYTHON_PREFIX}_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_LIBRARY_DEBUG}") _python_select_library_configurations (${_PYTHON_PREFIX}) set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}") set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}") if (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE) set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}") elseif (_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG) set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}") else() set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${_PYTHON_PREFIX}_RUNTIME_LIBRARY-NOTFOUND") endif() _python_set_library_dirs (${_PYTHON_PREFIX}_LIBRARY_DIRS _${_PYTHON_PREFIX}_LIBRARY_RELEASE _${_PYTHON_PREFIX}_LIBRARY_DEBUG) if (UNIX) if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$") set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS ${${_PYTHON_PREFIX}_LIBRARY_DIRS}) endif() else() _python_set_library_dirs (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG) endif() endif() if (_${_PYTHON_PREFIX}_LIBRARY_RELEASE OR _${_PYTHON_PREFIX}_INCLUDE_DIR) if (${_PYTHON_PREFIX}_Interpreter_FOUND OR ${_PYTHON_PREFIX}_Compiler_FOUND) # development environment must be compatible with interpreter/compiler if ("${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}" VERSION_EQUAL "${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}" AND "${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}" VERSION_EQUAL "${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}") _python_set_development_module_found (Module) _python_set_development_module_found (Embed) endif() elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR AND "${_${_PYTHON_PREFIX}_INC_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_INC_VERSION_MINOR}" VERSION_EQUAL "${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR}") _python_set_development_module_found (Module) _python_set_development_module_found (Embed) endif() if (DEFINED _${_PYTHON_PREFIX}_FIND_ABI AND (NOT _${_PYTHON_PREFIX}_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS OR NOT _${_PYTHON_PREFIX}_INC_ABI IN_LIST _${_PYTHON_PREFIX}_ABIFLAGS)) set (${_PYTHON_PREFIX}_Development.Module_FOUND FALSE) set (${_PYTHON_PREFIX}_Development.Embed_FOUND FALSE) endif() endif() if (( ${_PYTHON_PREFIX}_Development.Module_FOUND AND ${_PYTHON_PREFIX}_Development.Embed_FOUND) OR (NOT "Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Development.Embed_FOUND) OR (NOT "Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Development.Module_FOUND)) unset (_${_PYTHON_PREFIX}_Development_REASON_FAILURE) endif() if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Development.Module_FOUND AND ${_PYTHON_PREFIX}_Development.Embed_FOUND) set (${_PYTHON_PREFIX}_Development_FOUND TRUE) endif() if ((${_PYTHON_PREFIX}_Development.Module_FOUND OR ${_PYTHON_PREFIX}_Development.Embed_FOUND) AND EXISTS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/PyPy.h") # retrieve PyPy version file (STRINGS "${_${_PYTHON_PREFIX}_INCLUDE_DIR}/patchlevel.h" ${_PYTHON_PREFIX}_PyPy_VERSION REGEX "^#define[ \t]+PYPY_VERSION[ \t]+\"[^\"]+\"") string (REGEX REPLACE "^#define[ \t]+PYPY_VERSION[ \t]+\"([^\"]+)\".*" "\\1" ${_PYTHON_PREFIX}_PyPy_VERSION "${${_PYTHON_PREFIX}_PyPy_VERSION}") endif() unset(${_PYTHON_PREFIX}_LINK_OPTIONS) if (${_PYTHON_PREFIX}_Development.Embed_FOUND AND APPLE AND ${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$") # rpath must be specified if python is part of a framework unset(_${_PYTHON_PREFIX}_is_prefix) foreach (_${_PYTHON_PREFIX}_implementation IN LISTS _${_PYTHON_PREFIX}_FIND_IMPLEMENTATIONS) foreach (_${_PYTHON_PREFIX}_framework IN LISTS _${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_implementation}_FRAMEWORKS) if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "^${_${_PYTHON_PREFIX}_framework}") get_filename_component (_${_PYTHON_PREFIX}_framework "${_${_PYTHON_PREFIX}_framework}" DIRECTORY) set (${_PYTHON_PREFIX}_LINK_OPTIONS "LINKER:-rpath,${_${_PYTHON_PREFIX}_framework}") break() endif() endforeach() if (_${_PYTHON_PREFIX}_is_prefix) break() endif() endforeach() unset(_${_PYTHON_PREFIX}_implementation) unset(_${_PYTHON_PREFIX}_framework) unset(_${_PYTHON_PREFIX}_is_prefix) endif() if (NOT DEFINED ${_PYTHON_PREFIX}_SOABI) _python_get_config_var (${_PYTHON_PREFIX}_SOABI SOABI) endif() _python_compute_development_signature (Module) _python_compute_development_signature (Embed) # Restore the original find library ordering if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES) set (CMAKE_FIND_LIBRARY_SUFFIXES ${_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES}) endif() if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE) if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) set (${_PYTHON_PREFIX}_LIBRARY "${_${_PYTHON_PREFIX}_LIBRARY_RELEASE}" CACHE FILEPATH "${_PYTHON_PREFIX} Library") endif() if ("INCLUDE_DIR" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_ARTIFACTS) set (${_PYTHON_PREFIX}_INCLUDE_DIR "${_${_PYTHON_PREFIX}_INCLUDE_DIR}" CACHE FILEPATH "${_PYTHON_PREFIX} Include Directory") endif() endif() _python_mark_as_internal (_${_PYTHON_PREFIX}_LIBRARY_RELEASE _${_PYTHON_PREFIX}_LIBRARY_DEBUG _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE _${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG _${_PYTHON_PREFIX}_INCLUDE_DIR _${_PYTHON_PREFIX}_CONFIG _${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE _${_PYTHON_PREFIX}_DEVELOPMENT_EMBED_SIGNATURE) endif() if (${_PYTHON_PREFIX}_FIND_REQUIRED_NumPy) list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS) endif() if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Interpreter_FOUND) list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR) if (DEFINED ${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR AND IS_ABSOLUTE "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}") set (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}" CACHE INTERNAL "") elseif (DEFINED _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR) # compute numpy signature. Depends on interpreter and development signatures string (MD5 __${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}:${_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE}:${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}") if (NOT __${_PYTHON_PREFIX}_NUMPY_SIGNATURE STREQUAL _${_PYTHON_PREFIX}_NUMPY_SIGNATURE OR NOT EXISTS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}") unset (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR CACHE) unset (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE CACHE) endif() endif() if (NOT _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR) execute_process(COMMAND ${${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry: import numpy; sys.stdout.write(numpy.get_include())\nexcept:pass\n" RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_PATH ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) if (NOT _${_PYTHON_PREFIX}_RESULT) find_path (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR NAMES "numpy/arrayobject.h" "numpy/numpyconfig.h" HINTS "${_${_PYTHON_PREFIX}_NumPy_PATH}" NO_DEFAULT_PATH) endif() endif() set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}") if(_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR AND NOT EXISTS "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}") set (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE "Cannot find the directory \"${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}\"") set_property (CACHE _${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR PROPERTY VALUE "${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR-NOTFOUND") endif() if (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR) execute_process (COMMAND ${${_PYTHON_PREFIX}_INTERPRETER_LAUNCHER} "${_${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys\ntry: import numpy; sys.stdout.write(numpy.__version__)\nexcept:pass\n" RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT OUTPUT_VARIABLE _${_PYTHON_PREFIX}_NumPy_VERSION) if (NOT _${_PYTHON_PREFIX}_RESULT) set (${_PYTHON_PREFIX}_NumPy_VERSION "${_${_PYTHON_PREFIX}_NumPy_VERSION}") else() unset (${_PYTHON_PREFIX}_NumPy_VERSION) endif() # final step: set NumPy founded only if Development.Module component is founded as well set(${_PYTHON_PREFIX}_NumPy_FOUND ${${_PYTHON_PREFIX}_Development.Module_FOUND}) else() set (${_PYTHON_PREFIX}_NumPy_FOUND FALSE) endif() if (${_PYTHON_PREFIX}_NumPy_FOUND) unset (_${_PYTHON_PREFIX}_NumPy_REASON_FAILURE) # compute and save numpy signature string (MD5 __${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${_${_PYTHON_PREFIX}_INTERPRETER_SIGNATURE}:${_${_PYTHON_PREFIX}_DEVELOPMENT_MODULE_SIGNATURE}:${${_PYTHON_PREFIX}_NumPyINCLUDE_DIR}") set (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE "${__${_PYTHON_PREFIX}_NUMPY_SIGNATURE}" CACHE INTERNAL "") else() unset (_${_PYTHON_PREFIX}_NUMPY_SIGNATURE CACHE) endif() if (${_PYTHON_PREFIX}_ARTIFACTS_INTERACTIVE) set (${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR "${_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR}" CACHE FILEPATH "${_PYTHON_PREFIX} NumPy Include Directory") endif() _python_mark_as_internal (_${_PYTHON_PREFIX}_NumPy_INCLUDE_DIR _${_PYTHON_PREFIX}_NUMPY_SIGNATURE) endif() # final validation if (${_PYTHON_PREFIX}_VERSION_MAJOR AND NOT ${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Found unsuitable major version \"${${_PYTHON_PREFIX}_VERSION_MAJOR}\", but required major version is exact version \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"") cmake_policy(POP) return() endif() unset (_${_PYTHON_PREFIX}_REASON_FAILURE) foreach (_${_PYTHON_PREFIX}_COMPONENT IN ITEMS Interpreter Compiler Development NumPy) if (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE) string (APPEND _${_PYTHON_PREFIX}_REASON_FAILURE "\n ${_${_PYTHON_PREFIX}_COMPONENT}: ${_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE}") unset (_${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_REASON_FAILURE) endif() endforeach() find_package_handle_standard_args (${_PYTHON_PREFIX} REQUIRED_VARS ${_${_PYTHON_PREFIX}_REQUIRED_VARS} VERSION_VAR ${_PYTHON_PREFIX}_VERSION HANDLE_COMPONENTS) # Create imported targets and helper functions if(_${_PYTHON_PREFIX}_CMAKE_ROLE STREQUAL "PROJECT") if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT TARGET ${_PYTHON_PREFIX}::Interpreter) add_executable (${_PYTHON_PREFIX}::Interpreter IMPORTED) set_property (TARGET ${_PYTHON_PREFIX}::Interpreter PROPERTY IMPORTED_LOCATION "${${_PYTHON_PREFIX}_EXECUTABLE}") endif() if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Compiler_FOUND AND NOT TARGET ${_PYTHON_PREFIX}::Compiler) add_executable (${_PYTHON_PREFIX}::Compiler IMPORTED) set_property (TARGET ${_PYTHON_PREFIX}::Compiler PROPERTY IMPORTED_LOCATION "${${_PYTHON_PREFIX}_COMPILER}") endif() if (("Development.Module" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Development.Module_FOUND) OR ("Development.Embed" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_Development.Embed_FOUND)) macro (__PYTHON_IMPORT_LIBRARY __name) if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$" OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE) set (_${_PYTHON_PREFIX}_LIBRARY_TYPE SHARED) else() set (_${_PYTHON_PREFIX}_LIBRARY_TYPE STATIC) endif() if (NOT TARGET ${__name}) add_library (${__name} ${_${_PYTHON_PREFIX}_LIBRARY_TYPE} IMPORTED) endif() set_property (TARGET ${__name} PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIRS}") if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE) # System manage shared libraries in two parts: import and runtime if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG) set_property (TARGET ${__name} PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG) set_target_properties (${__name} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" IMPORTED_IMPLIB_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}") set_target_properties (${__name} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" IMPORTED_IMPLIB_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}" IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}") else() set_target_properties (${__name} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_IMPLIB "${${_PYTHON_PREFIX}_LIBRARIES}" IMPORTED_LOCATION "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}") endif() else() if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG) set_property (TARGET ${__name} PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG) set_target_properties (${__name} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}") set_target_properties (${__name} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}") else() set_target_properties (${__name} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C" IMPORTED_LOCATION "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}") endif() endif() if (_${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL "STATIC") # extend link information with dependent libraries _python_get_config_var (_${_PYTHON_PREFIX}_LINK_LIBRARIES LIBS) if (_${_PYTHON_PREFIX}_LINK_LIBRARIES) set_property (TARGET ${__name} PROPERTY INTERFACE_LINK_LIBRARIES ${_${_PYTHON_PREFIX}_LINK_LIBRARIES}) endif() endif() if (${_PYTHON_PREFIX}_LINK_OPTIONS AND _${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL "SHARED") set_property (TARGET ${__name} PROPERTY INTERFACE_LINK_OPTIONS "${${_PYTHON_PREFIX}_LINK_OPTIONS}") endif() endmacro() if (${_PYTHON_PREFIX}_Development.Embed_FOUND) __python_import_library (${_PYTHON_PREFIX}::Python) endif() if (${_PYTHON_PREFIX}_Development.Module_FOUND) if ("LIBRARY" IN_LIST _${_PYTHON_PREFIX}_FIND_DEVELOPMENT_MODULE_ARTIFACTS) # On Windows/CYGWIN/MSYS, Python::Module is the same as Python::Python # but ALIAS cannot be used because the imported library is not GLOBAL. __python_import_library (${_PYTHON_PREFIX}::Module) else() if (NOT TARGET ${_PYTHON_PREFIX}::Module) add_library (${_PYTHON_PREFIX}::Module INTERFACE IMPORTED) endif() set_property (TARGET ${_PYTHON_PREFIX}::Module PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIRS}") # When available, enforce shared library generation with undefined symbols if (APPLE) set_property (TARGET ${_PYTHON_PREFIX}::Module PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-undefined,dynamic_lookup") endif() if (CMAKE_SYSTEM_NAME STREQUAL "SunOS") set_property (TARGET ${_PYTHON_PREFIX}::Module PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-z,nodefs") endif() if (CMAKE_SYSTEM_NAME STREQUAL "AIX") set_property (TARGET ${_PYTHON_PREFIX}::Module PROPERTY INTERFACE_LINK_OPTIONS "LINKER:-b,erok") endif() endif() endif() # # PYTHON_ADD_LIBRARY ( [STATIC|SHARED|MODULE] src1 src2 ... srcN) # It is used to build modules for python. # function (__${_PYTHON_PREFIX}_ADD_LIBRARY prefix name) cmake_parse_arguments (PARSE_ARGV 2 PYTHON_ADD_LIBRARY "STATIC;SHARED;MODULE;WITH_SOABI" "" "") if (PYTHON_ADD_LIBRARY_STATIC) set (type STATIC) elseif (PYTHON_ADD_LIBRARY_SHARED) set (type SHARED) else() set (type MODULE) endif() if (type STREQUAL "MODULE" AND NOT TARGET ${prefix}::Module) message (SEND_ERROR "${prefix}_ADD_LIBRARY: dependent target '${prefix}::Module' is not defined.\n Did you miss to request COMPONENT 'Development.Module'?") return() endif() if (NOT type STREQUAL "MODULE" AND NOT TARGET ${prefix}::Python) message (SEND_ERROR "${prefix}_ADD_LIBRARY: dependent target '${prefix}::Python' is not defined.\n Did you miss to request COMPONENT 'Development.Embed'?") return() endif() add_library (${name} ${type} ${PYTHON_ADD_LIBRARY_UNPARSED_ARGUMENTS}) get_property (type TARGET ${name} PROPERTY TYPE) if (type STREQUAL "MODULE_LIBRARY") target_link_libraries (${name} PRIVATE ${prefix}::Module) # customize library name to follow module name rules set_property (TARGET ${name} PROPERTY PREFIX "") if(CMAKE_SYSTEM_NAME STREQUAL "Windows") set_property (TARGET ${name} PROPERTY SUFFIX ".pyd") endif() if (PYTHON_ADD_LIBRARY_WITH_SOABI AND ${prefix}_SOABI) get_property (suffix TARGET ${name} PROPERTY SUFFIX) if (NOT suffix) set (suffix "${CMAKE_SHARED_MODULE_SUFFIX}") endif() set_property (TARGET ${name} PROPERTY SUFFIX ".${${prefix}_SOABI}${suffix}") endif() else() if (PYTHON_ADD_LIBRARY_WITH_SOABI) message (AUTHOR_WARNING "Find${prefix}: Option `WITH_SOABI` is only supported for `MODULE` library type.") endif() target_link_libraries (${name} PRIVATE ${prefix}::Python) endif() endfunction() endif() if ("NumPy" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS AND ${_PYTHON_PREFIX}_NumPy_FOUND AND NOT TARGET ${_PYTHON_PREFIX}::NumPy AND TARGET ${_PYTHON_PREFIX}::Module) add_library (${_PYTHON_PREFIX}::NumPy INTERFACE IMPORTED) set_property (TARGET ${_PYTHON_PREFIX}::NumPy PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_NumPy_INCLUDE_DIRS}") target_link_libraries (${_PYTHON_PREFIX}::NumPy INTERFACE ${_PYTHON_PREFIX}::Module) endif() endif() # final clean-up # Restore CMAKE_FIND_APPBUNDLE if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) set (CMAKE_FIND_APPBUNDLE ${_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE}) unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) else() unset (CMAKE_FIND_APPBUNDLE) endif() # Restore CMAKE_FIND_FRAMEWORK if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK) set (CMAKE_FIND_FRAMEWORK ${_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK}) unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK) else() unset (CMAKE_FIND_FRAMEWORK) endif() cmake_policy(POP) dune-common-2.8.0/cmake/modules/FindQuadMath.cmake000066400000000000000000000041311411343567400220100ustar00rootroot00000000000000#[=======================================================================[.rst: FindQuadMath ------------ Find the GCC Quad-Precision library This module checks if the used compiler has built-in support for QuadMath by compiling a small source file. Imported Targets ^^^^^^^^^^^^^^^^ This module provides the following imported targets, if found: ``QuadMath::QuadMath`` Library to link against if QuadMath should be used. Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``QuadMath_FOUND`` True if the Quad-Precision library was found. #]=======================================================================] # Add a feature summary for this package include(FeatureSummary) set_package_properties(QuadMath PROPERTIES DESCRIPTION "GCC Quad-Precision Math Library" URL "https://gcc.gnu.org/onlinedocs/libquadmath" ) # Check if QuadMath support is built into the compiler include(CheckCXXSourceCompiles) include(CMakePushCheckState) cmake_push_check_state() set(CMAKE_REQUIRED_LIBRARIES quadmath) if(${CMAKE_CXX_COMPILER_ID} STREQUAL GNU) set(CMAKE_REQUIRED_FLAGS "-fext-numeric-literals") endif() check_cxx_source_compiles(" #include int main () { __float128 r = 1.0q; r = strtoflt128(\"1.2345678\", NULL); return 0; }" QuadMath_COMPILES) cmake_pop_check_state() # Reset CMAKE_REQUIRED_XXX variables if(QuadMath_COMPILES) # Use additional variable for better report message set(QuadMath_VAR "(Supported by compiler)") endif() # Report that package was found include(FindPackageHandleStandardArgs) find_package_handle_standard_args(QuadMath DEFAULT_MSG QuadMath_VAR QuadMath_COMPILES ) # add imported target for quadmath if(QuadMath_FOUND AND NOT TARGET QuadMath::QuadMath) # Compiler supports QuadMath: Add appropriate linker flag add_library(QuadMath::QuadMath INTERFACE IMPORTED) target_link_libraries(QuadMath::QuadMath INTERFACE quadmath) target_compile_definitions(QuadMath::QuadMath INTERFACE _GLIBCXX_USE_FLOAT128 ) target_compile_options(QuadMath::QuadMath INTERFACE $<$:-fext-numeric-literals> ) endif() dune-common-2.8.0/cmake/modules/FindSphinx.cmake000066400000000000000000000017251411343567400215630ustar00rootroot00000000000000# .. cmake_module:: # # Find Sphinx - the python documentation tool # # You may set the following variables to modify the # behaviour of this module: # # :ref:`SPHINX_ROOT` # the path to look for sphinx with the highest priority # # The following variables are set by this module: # # :code:`SPHINX_FOUND` # whether Sphinx was found # # :code:`SPHINX_EXECUTABLE` # the path to the sphinx-build executable # # .. cmake_variable:: SPHINX_ROOT # # You may set this variable to have :ref:`FindSphinx` look # for the :code:`sphinx-build` executable in the given path # before inspecting system paths. # #TODO export version. find_program(SPHINX_EXECUTABLE NAMES sphinx-build PATHS ${SPHINX_ROOT} NO_DEFAULT_PATH) find_program(SPHINX_EXECUTABLE NAMES sphinx-build) include(FindPackageHandleStandardArgs) find_package_handle_standard_args( "Sphinx" DEFAULT_MSG SPHINX_EXECUTABLE ) dune-common-2.8.0/cmake/modules/FindSuiteSparse.cmake000066400000000000000000000236151411343567400225630ustar00rootroot00000000000000#[=======================================================================[.rst: FindSuiteSparse --------------- Find the SuiteSparse libraries like UMFPACK or SPQR. Use this module by invoking find_package with the form: find_package(SuiteSparse [] [EXACT] # Minimum or EXACT version e.g. 5.1 [REQUIRED] # Fail with error if SuiteSparse is not found [COMPONENTS ...] # SuiteSparse libraries by their canonical name # e.g. "UMFPACK" or "SPQR" [OPTIONAL_COMPONENTS ...] # Optional SuiteSparse libraries by their canonical name ) # e.g. "UMFPACK" or "SPQR" Components ^^^^^^^^^^ The SuiteSparse module allows to search for the following components ``CHOLMOD`` Supernodal Cholesky factorization. ``CSparse`` and ``CXSparse`` A Concise Sparse Matrix package. ``GraphBLAS`` Graph algorithms and primitives using semiring algebra. (SuiteSparse >= 5.6) ``KLU`` and ``BTF`` Sparse LU factorization, well-suited for circuit simulation. ``LDL`` A sparse LDL' factorization and solve package. ``Mongoose`` A graph partitioning library. (SuiteSparse >= 5.5) ``SPQR`` Multifrontal QR factorization. ``UMFPACK`` Multifrontal LU factorization. And ordering methods: ``AMD``, ``CAMD``, ``COLAMD``, and ``CCOLAMD``. Imported Targets ^^^^^^^^^^^^^^^^ This module provides the following imported targets, if found: ``SuiteSparse::SuiteSparse`` A meta library including all the requested optional or required components. ``SuiteSparse::`` Library and include directories for the found ````. Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``SuiteSparse_FOUND`` True if all the (required) components are found ``SuiteSparse__FOUND`` True if a searched ```` is found Input and Cache Variables ^^^^^^^^^^^^^^^^^^^^^^^^^ You may set the following variables to modify the behaviour of this module: ``SuiteSparse_ROOT`` The root directory of the SuiteSparse installation, containing subdirectories :code:`include/` and :code:`lib/` including the header files and libraries of SuiteSparse and its components, respectively. ``SUITESPARSE_INCLUDE_DIR`` The directory containing ``SuiteSparse_config.h``. ``SUITESPARSE_CONFIG_LIB`` The path to the suitesparseconfig library. #]=======================================================================] # text for feature summary include(FeatureSummary) set_package_properties("SuiteSparse" PROPERTIES DESCRIPTION "A suite of sparse matrix software" URL "http://faculty.cse.tamu.edu/davis/suitesparse.html" ) # find package dependencies first include(CMakeFindDependencyMacro) find_package(LAPACK QUIET) find_package(BLAS QUIET) # list of possible component names set(SUITESPARSE_COMPONENTS "AMD" "BTF" "CAMD" "CCOLAMD" "CHOLMOD" "COLAMD" "CSparse" "CXSparse" "KLU" "LDL" "SPQR" "UMFPACK") # Define required and optional component dependencies set(SUITESPARSE_CHOLDMOD_REQUIRED_DEPENDENCIES "AMD" "COLAMD" "CCOLAMD") set(SUITESPARSE_CHOLDMOD_REQUIRES_BLAS TRUE) set(SUITESPARSE_CHOLDMOD_REQUIRES_LAPACK TRUE) set(SUITESPARSE_KLU_REQUIRED_DEPENDENCIES "AMD" "COLAMD" "BTF") set(SUITESPARSE_KLU_OPTIONAL_DEPENDENCIES "CHOLMOD" "CAMD" "CCOLAMD") set(SUITESPARSE_SPQR_REQUIRED_DEPENDENCIES "CHOLMOD" "AMD" "COLAMD") set(SUITESPARSE_SPQR_REQUIRES_BLAS TRUE) set(SUITESPARSE_SPQR_REQUIRES_LAPACK TRUE) set(SUITESPARSE_UMFPACK_REQUIRED_DEPENDENCIES "AMD") set(SUITESPARSE_UMFPACK_OPTIONAL_DEPENDENCIES "CHOLMOD" "CAMD" "CCOLAMD" "COLAMD") set(SUITESPARSE_UMFPACK_REQUIRES_BLAS TRUE) # look for library suitesparseconfig find_library(SUITESPARSE_CONFIG_LIB "suitesparseconfig" PATH_SUFFIXES "SuiteSparse_config" ) # look for header file SuiteSparse_config.h find_path(SUITESPARSE_INCLUDE_DIR "SuiteSparse_config.h" PATH_SUFFIXES "suitesparse" "include" "SuiteSparse_config" ) get_filename_component(SUITESPARSE_LIB_DIR ${SUITESPARSE_CONFIG_LIB} DIRECTORY) mark_as_advanced(SUITESPARSE_INCLUDE_DIR SUITESPARSE_CONFIG_LIB) foreach(_component ${SUITESPARSE_COMPONENTS}) string(TOLOWER ${_component} _componentLower) # look for library of the component find_library(${_component}_LIBRARY "${_componentLower}" HINTS ${SUITESPARSE_LIB_DIR} PATH_SUFFIXES "${_component}/Lib" ) # look for header file of the component find_path(${_component}_INCLUDE_DIR "${_componentLower}.h" HINTS ${SUITESPARSE_INCLUDE_DIR} PATH_SUFFIXES "suitesparse" "include" "${_component}/Include" ) mark_as_advanced(${_component}_INCLUDE_DIR ${_component}_LIBRARY) endforeach() # Look for the header files that have different header file names find_path(SPQR_INCLUDE_DIR "SuiteSparseQR.hpp" HINTS ${SUITESPARSE_INCLUDE_DIR} PATH_SUFFIXES "suitesparse" "include" "SPQR/Include" ) find_path(Mongoose_INCLUDE_DIR "Mongoose.hpp" HINTS ${SUITESPARSE_INCLUDE_DIR} PATH_SUFFIXES "suitesparse" "include" "Mongoose/Include" ) find_path(GraphBLAS_INCLUDE_DIR "GraphBLAS.h" HINTS ${SUITESPARSE_INCLUDE_DIR} PATH_SUFFIXES "suitesparse" "include" "GraphBLAS/Include" ) # check version of SuiteSparse find_file(SUITESPARSE_CONFIG_FILE "SuiteSparse_config.h" HINTS ${SUITESPARSE_INCLUDE_DIR} NO_DEFAULT_PATH) if(SUITESPARSE_CONFIG_FILE) file(READ "${SUITESPARSE_CONFIG_FILE}" suitesparseconfig) string(REGEX REPLACE ".*#define SUITESPARSE_MAIN_VERSION[ ]+([0-9]+).*" "\\1" SUITESPARSE_MAJOR_VERSION "${suitesparseconfig}") string(REGEX REPLACE ".*#define SUITESPARSE_SUB_VERSION[ ]+([0-9]+).*" "\\1" SUITESPARSE_MINOR_VERSION "${suitesparseconfig}") string(REGEX REPLACE ".*#define SUITESPARSE_SUBSUB_VERSION[ ]+([0-9]+).*" "\\1" SUITESPARSE_PREFIX_VERSION "${suitesparseconfig}") if(SUITESPARSE_MAJOR_VERSION GREATER_EQUAL 0) set(SuiteSparse_VERSION "${SUITESPARSE_MAJOR_VERSION}") endif() if (SUITESPARSE_MINOR_VERSION GREATER_EQUAL 0) set(SuiteSparse_VERSION "${SuiteSparse_VERSION}.${SUITESPARSE_MINOR_VERSION}") endif() if (SUITESPARSE_PREFIX_VERSION GREATER_EQUAL 0) set(SuiteSparse_VERSION "${SuiteSparse_VERSION}.${SUITESPARSE_PREFIX_VERSION}") endif() endif() unset(SUITESPARSE_CONFIG_FILE CACHE) # check wether everything was found foreach(_component ${SUITESPARSE_COMPONENTS}) if(${_component}_LIBRARY AND ${_component}_INCLUDE_DIR) set(SuiteSparse_${_component}_FOUND TRUE) else() set(SuiteSparse_${_component}_FOUND FALSE) endif() endforeach(_component) # test for required dependencies foreach(_component ${SUITESPARSE_COMPONENTS}) foreach(_dependency ${SUITESPARSE_${_component}_REQUIRED_DEPENDENCIES}) if(NOT SuiteSparse_${_dependency}_FOUND) set(SuiteSparse_${_component}_FOUND FALSE) endif() endforeach(_dependency) endforeach(_component) # SPQR requires SuiteSparse >= 4.3 if(SPQR_LIBRARY) if(SuiteSparse_VERSION VERSION_LESS "4.3") set(SuiteSparse_SPQR_FOUND FALSE) endif() endif() # behave like a CMake module is supposed to behave include(FindPackageHandleStandardArgs) find_package_handle_standard_args("SuiteSparse" REQUIRED_VARS SUITESPARSE_CONFIG_LIB SUITESPARSE_INCLUDE_DIR BLAS_FOUND VERSION_VAR SuiteSparse_VERSION HANDLE_COMPONENTS ) # if both headers and library for all required components are found, # then create imported targets for all components if(SuiteSparse_FOUND) if(NOT TARGET SuiteSparse::SuiteSparse_config) add_library(SuiteSparse::SuiteSparse_config UNKNOWN IMPORTED) set_target_properties(SuiteSparse::SuiteSparse_config PROPERTIES IMPORTED_LOCATION ${SUITESPARSE_CONFIG_LIB} INTERFACE_INCLUDE_DIRECTORIES ${SUITESPARSE_INCLUDE_DIR} ) endif() # Define component imported-targets foreach(_component ${SUITESPARSE_COMPONENTS}) if(SuiteSparse_${_component}_FOUND AND NOT TARGET SuiteSparse::${_component}) add_library(SuiteSparse::${_component} UNKNOWN IMPORTED) set_target_properties(SuiteSparse::${_component} PROPERTIES IMPORTED_LOCATION ${${_component}_LIBRARY} INTERFACE_INCLUDE_DIRECTORIES ${${_component}_INCLUDE_DIR} INTERFACE_LINK_LIBRARIES SuiteSparse::SuiteSparse_config ) endif() endforeach(_component) foreach(_component ${SUITESPARSE_COMPONENTS}) # Link required dependencies foreach(_dependency ${SUITESPARSE_${_component}_REQUIRED_DEPENDENCIES}) target_link_libraries(SuiteSparse::${_component} INTERFACE SuiteSparse::${_dependency}) endforeach(_dependency) # Link found optional dependencies foreach(_dependency ${SUITESPARSE_${_component}_OPTIONAL_DEPENDENCIES}) if(SuiteSparse_${_dependency}_FOUND) target_link_libraries(SuiteSparse::${_component} INTERFACE SuiteSparse::${_dependency}) endif() endforeach(_dependency) # Link BLAS library if(SUITESPARSE_${_component}_REQUIRES_BLAS) if(TARGET BLAS::BLAS) target_link_libraries(SuiteSparse::${_component} INTERFACE BLAS::BLAS) else() target_link_libraries(SuiteSparse::${_component} INTERFACE ${BLAS_LINKER_FLAGS} ${BLAS_LIBRARIES}) endif() endif() # Link LAPACK library if(SUITESPARSE_${_component}_REQUIRES_LAPACK) if(TARGET LAPACK::LAPACK) target_link_libraries(SuiteSparse::${_component} INTERFACE LAPACK::LAPACK) else() target_link_libraries(SuiteSparse::${_component} INTERFACE ${LAPACK_LINKER_FLAGS} ${LAPACK_LIBRARIES}) endif() endif() endforeach(_component) # Combine all requested components to an imported target if(NOT TARGET SuiteSparse::SuiteSparse) add_library(SuiteSparse::SuiteSparse INTERFACE IMPORTED) target_link_libraries(SuiteSparse::SuiteSparse INTERFACE SuiteSparse::SuiteSparse_config) endif() foreach(_component ${SuiteSparse_FIND_COMPONENTS}) if(SuiteSparse_${_component}_FOUND) set(HAVE_SUITESPARSE_${_component} TRUE) target_link_libraries(SuiteSparse::SuiteSparse INTERFACE SuiteSparse::${_component}) endif() endforeach(_component) endif() dune-common-2.8.0/cmake/modules/FindTBB.cmake000066400000000000000000000055061411343567400207220ustar00rootroot00000000000000#[=======================================================================[.rst: FindTBB ------- Finds the Threading Building Blocks (TBB) library. This is a fallback implementation in case the TBB library does not provide itself a corresponding TBBConfig.cmake file. Imported Targets ^^^^^^^^^^^^^^^^ This module provides the following imported targets, if found: ``TBB::tbb`` Imported library to link against if TBB should be used. Result Variables ^^^^^^^^^^^^^^^^ This will define the following variables: ``TBB_FOUND`` True if the TBB library was found. Finding the TBB library ^^^^^^^^^^^^^^^^^^^^^^^ Two strategies are implemented for finding the TBB library: 1. Searching for the TBB cmake config file, typically named ``TBBConfig.cmake``. In recent TBB versions, this file can be created using a script provided by TBB itself. Simply set the variable ``TBB_DIR`` to the directory containing the config file in order to find TBB. 2. Using pkg-config to configure TBB. Therefore it is necessary to find the ``tbb.pc`` file. Several distributions provide this file directly. In order to point pkg-config to the location of that file, simply set the environmental variable ``PKG_CONFIG_PATH`` to include the directory containing the .pc file, or add this path to the ``CMAKE_PREFIX_PATH``. #]=======================================================================] # text for feature summary include(FeatureSummary) set_package_properties("TBB" PROPERTIES DESCRIPTION "Intel's Threading Building Blocks" ) # first, try to find TBBs cmake configuration find_package(TBB ${TBB_FIND_VERSION} QUIET CONFIG) if(TBB_FOUND AND TARGET TBB::tbb) message(STATUS "Found TBB: using configuration from TBB_DIR=${TBB_DIR} (found version \"${TBB_VERSION}\")") return() endif() # Add a backport of cmakes FindPkgConfig module if(${CMAKE_VERSION} VERSION_LESS "3.19.4") list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_CURRENT_LIST_DIR}/FindPkgConfig") endif() # second, try to find TBBs pkg-config file find_package(PkgConfig) if(PkgConfig_FOUND) if(TBB_FIND_VERSION) pkg_check_modules(PkgConfigTBB tbb>=${TBB_FIND_VERSION} QUIET IMPORTED_TARGET GLOBAL) else() pkg_check_modules(PkgConfigTBB tbb QUIET IMPORTED_TARGET GLOBAL) endif() endif() # check whether the static library was found if(PkgConfigTBB_STATIC_FOUND) set(_tbb PkgConfigTBB_STATIC) else() set(_tbb PkgConfigTBB) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args("TBB" REQUIRED_VARS ${_tbb}_LINK_LIBRARIES ${_tbb}_FOUND PkgConfig_FOUND VERSION_VAR ${_tbb}_VERSION FAIL_MESSAGE "Could NOT find TBB (set TBB_DIR to path containing TBBConfig.cmake or set PKG_CONFIG_PATH to include the location of the tbb.pc file)" ) if(${_tbb}_FOUND AND NOT TARGET TBB::tbb) add_library(TBB::tbb ALIAS PkgConfig::PkgConfigTBB) endif() dune-common-2.8.0/cmake/modules/Headercheck.cmake000066400000000000000000000102701411343567400216720ustar00rootroot00000000000000# .. cmake_variable:: ENABLE_HEADERCHECK # # Set this variable to TRUE if you want to use the CMake # reimplementation of the old autotools feaure :code:`make headercheck`. # There has been a couple of issues with this implementation in # the past, so it was deactivated by default. # include_guard(GLOBAL) # sets up a global property with the names of all header files # in the module and a global target depending on all checks macro(setup_headercheck) #glob for headers file(GLOB_RECURSE all_headers "*.hh") # strip hidden files string(REGEX REPLACE "[^;]*/\\.[^;/]*\\.hh;?" "" headers "${all_headers}") set_property(GLOBAL PROPERTY headercheck_list ${headers}) #define headercheck target dune_module_path(MODULE dune-common RESULT scriptdir SCRIPT_DIR) if(NOT TARGET headercheck) add_custom_target(headercheck ${CMAKE_COMMAND} -DENABLE_HEADERCHECK=${ENABLE_HEADERCHECK} -P ${scriptdir}/FinalizeHeadercheck.cmake WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) endif() endmacro(setup_headercheck) # these macros are used to exclude headers from make headercheck # call this from a CMakeLists.txt file with a list of headers in that directory macro(exclude_from_headercheck) #make this robust to argument being passed with or without "" string(REGEX REPLACE "[\ \n]+([^\ ])" ";\\1" list ${ARGV0}) set(list "${list};${ARGV}") get_property(headerlist GLOBAL PROPERTY headercheck_list) foreach(item ${list}) list(REMOVE_ITEM headerlist "${CMAKE_CURRENT_SOURCE_DIR}/${item}") endforeach() set_property(GLOBAL PROPERTY headercheck_list ${headerlist}) endmacro(exclude_from_headercheck) macro(exclude_dir_from_headercheck) file(GLOB list RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.hh") exclude_from_headercheck(${list}) endmacro(exclude_dir_from_headercheck) macro(exclude_subdir_from_headercheck DIRNAME) file(GLOB_RECURSE exlist "${CMAKE_CURRENT_SOURCE_DIR}/${DIRNAME}/*.hh") get_property(headerlist GLOBAL PROPERTY headercheck_list) foreach(item ${exlist}) list(REMOVE_ITEM headerlist "${item}") endforeach() set_property(GLOBAL PROPERTY headercheck_list ${headerlist}) endmacro(exclude_subdir_from_headercheck) macro(exclude_all_but_from_headercheck) file(GLOB excllist RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.hh") #make this robust to argument being passed with or without "" string(REGEX REPLACE "[\ \n]+([^\ \n])" ";\\1" list ${ARGV0}) set(list "${list};${ARGV}") foreach(item ${list}) list(REMOVE_ITEM excllist ${item}) endforeach() exclude_from_headercheck(${excllist}) endmacro(exclude_all_but_from_headercheck) # configure all headerchecks macro(finalize_headercheck) if(ENABLE_HEADERCHECK) get_property(headerlist GLOBAL PROPERTY headercheck_list) foreach(header ${headerlist}) #do some name conversion string(REGEX REPLACE ".*/([^/]*)" "\\1" simple ${header}) string(REPLACE ${PROJECT_SOURCE_DIR} "" rel ${header}) string(REGEX REPLACE "(.*)/[^/]*" "\\1" relpath ${rel}) string(REGEX REPLACE "/" "_" targname ${rel}) #generate the headercheck .cc file file(WRITE ${CMAKE_BINARY_DIR}/headercheck/${rel}.cc "#ifdef HAVE_CONFIG_H\n#include\n#endif\n#include<${simple}>\n#include<${simple}>\nint main(){return 0;}") # add target for the check of current header, this is implemented as a library # to prevent CMake from automatically trying to link the target, functionality # of macro try_compile() is unfortunately not availbale due to it not being scriptable. add_library(headercheck_${targname} STATIC EXCLUDE_FROM_ALL ${CMAKE_BINARY_DIR}/headercheck/${rel}.cc) add_dependencies(headercheck headercheck_${targname}) #add PKG_ALL_FLAGS and the directory where the header is located set_property(TARGET headercheck_${targname} APPEND_STRING PROPERTY COMPILE_FLAGS "-DHEADERCHECK -I${PROJECT_SOURCE_DIR}${relpath} -I${CMAKE_BINARY_DIR}") set_property(TARGET headercheck_${targname} PROPERTY ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/headercheck/${relpath}") add_dune_all_flags(headercheck_${targname}) unset(headercheck_${targname}_LIB_DEPENDS CACHE) endforeach(header ${headerlist}) endif() endmacro(finalize_headercheck) dune-common-2.8.0/cmake/modules/OverloadCompilerFlags.cmake000066400000000000000000000162441411343567400237360ustar00rootroot00000000000000# check whether the user wants to overload compile flags upon calling make # # Provides the following macros: # # initialize_compiler_script() : needs to be called before further flags are added to CMAKE_CXX_FLAGS # finalize_compiler_script() : needs to be called at the end of the cmake macros, e.g. in finalize_dune_project # # Those two macro calls are hooked into dune_project/finalize_dune_project. # # .. cmake_variable:: ALLOW_CXXFLAGS_OVERWRITE # # Setting this option will allow you to overload preprocessor definitions from # the command line, as it was possible naturally with the autotools build system. # This feature only works with a :code:`Unix Makefiles` based generator. You can # use it as: # # :code:`make CXXFLAGS="your flags" GRIDTYPE="grid type"` # # :code:`GRIDTYPE` can be anything defined in :code:`config.h` via the :ref:`dune_define_gridtype` macro from dune-grid. # Furthermore any CPP variable of the form :code:`-DVAR=VALUE` can be overloaded on the command line. # # .. note:: # If you don't know what this is or what it's good for, don't use it. # include_guard(GLOBAL) option(ALLOW_CXXFLAGS_OVERWRITE OFF) option(ALLOW_CFLAGS_OVERWRITE OFF) set(CXX_COMPILER_SCRIPT "${CMAKE_BINARY_DIR}/CXX_compiler.sh" ) set(C_COMPILER_SCRIPT "${CMAKE_BINARY_DIR}/C_compiler.sh" ) macro(find_extended_unix_commands) include(FindUnixCommands) set(FLAGSNAMES "ALLOW_CXXFLAGS_OVERWRITE and/or ALLOW_CFLAGS_OVERWRITE") find_program (GREP_PROGRAM grep) if(NOT GREP_PROGRAM) message( SEND_ERROR "grep not found, please disable ${FLAGSNAMES}") endif() find_program (SED_PROGRAM sed) if(NOT SED_PROGRAM) message( SEND_ERROR "sed not found, please disable ${FLAGSNAMES}") endif() find_program (CUT_PROGRAM cut) if(NOT CUT_PROGRAM) message( SEND_ERROR "cut not found, please disable ${FLAGSNAMES}") endif() find_program (ENV_PROGRAM env) if(NOT ENV_PROGRAM) message( SEND_ERROR "env not found, please disable ${FLAGSNAMES}") endif() find_program (ECHO_PROGRAM echo) if(NOT ECHO_PROGRAM) message( SEND_ERROR "echo not found, please disable ${FLAGSNAMES}") endif() find_program (CHMOD_PROGRAM chmod) if(NOT CHMOD_PROGRAM) message( SEND_ERROR "chmod not found, please disable ${FLAGSNAMES}") endif() mark_as_advanced(GREP_PROGRAM) mark_as_advanced(SED_PROGRAM) mark_as_advanced(CUT_PROGRAM) mark_as_advanced(ENV_PROGRAM) mark_as_advanced(ECHO_PROGRAM) mark_as_advanced(CHMOD_PROGRAM) endmacro(find_extended_unix_commands) # init compiler script and store CXX flags macro(initialize_compiler_script) if(ALLOW_CXXFLAGS_OVERWRITE AND (${CMAKE_GENERATOR} MATCHES ".*Unix Makefiles.*")) # check for unix commands necessary find_extended_unix_commands() # set CXXFLAGS as environment variable set( DEFAULT_CXXFLAGS ${CMAKE_CXX_FLAGS} CACHE STRING "default CXX flags") set( CMAKE_CXX_FLAGS "" ) set( DEFAULT_CXX_COMPILER ${CMAKE_CXX_COMPILER} ) set( CXX_COMPILER_SCRIPT_FILE "#!${BASH}\nexec ${CMAKE_CXX_COMPILER} \"\$@\"") file(WRITE ${CXX_COMPILER_SCRIPT} "${CXX_COMPILER_SCRIPT_FILE}") execute_process(COMMAND ${CHMOD_PROGRAM} 755 ${CXX_COMPILER_SCRIPT}) set(CMAKE_CXX_COMPILER ${CXX_COMPILER_SCRIPT}) endif() if(ALLOW_CFLAGS_OVERWRITE AND (${CMAKE_GENERATOR} MATCHES ".*Unix Makefiles.*")) # check for unix commands necessary find_extended_unix_commands() # set CFLAGS as environment variable set( DEFAULT_CFLAGS ${CMAKE_C_FLAGS} CACHE STRING "default C flags") set( CMAKE_C_FLAGS "" ) set( DEFAULT_C_COMPILER ${CMAKE_C_COMPILER} ) set( C_COMPILER_SCRIPT_FILE "#!${BASH}\nexec ${CMAKE_C_COMPILER} \"\$@\"") file(WRITE ${C_COMPILER_SCRIPT} "${C_COMPILER_SCRIPT_FILE}") execute_process(COMMAND ${CHMOD_PROGRAM} 755 ${C_COMPILER_SCRIPT}) set(CMAKE_C_COMPILER ${C_COMPILER_SCRIPT}) endif() endmacro() # finalize compiler script and write it macro(finalize_compiler_script) if(${CMAKE_GENERATOR} MATCHES ".*Unix Makefiles.*") # check CXX compiler if((ALLOW_CXXFLAGS_OVERWRITE)) set(COMPILERS "CXX") endif() # check C compiler if((ALLOW_CFLAGS_OVERWRITE)) set(COMPILERS ${COMPILERS} "C") endif() # for the found compilers for flag overloading generate compiler script foreach(COMP ${COMPILERS}) set( COMPILER_SCRIPT_FILE "#!${BASH}\nSED=${SED_PROGRAM}\nGREP=${GREP_PROGRAM}") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\nCUT=${CUT_PROGRAM}\nENV=${ENV_PROGRAM}\nECHO=${ECHO_PROGRAM}") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\n# store flags\nFLAGS=\"\$@\"") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\nMAKE_EXECUTABLE_NEW=0\n") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\nif [ \"\$${COMP}FLAGS\" == \"\" ]; then\n # default ${COMP} flags\n ${COMP}FLAGS=\"${DEFAULT_CXXFLAGS}\"\nfi\n") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\nif [ \"\$EXTRA_${COMP}FLAGS\" != \"\" ]; then\n # extra ${COMP} flags\n ${COMP}FLAGS=\"$${COMP}FLAGS $EXTRA_${COMP}FLAGS\"\nfi\n") # only for CXX we need to scan config.h for GRIDTYPE if( ${COMP} STREQUAL "CXX" ) set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\nGRIDS=\nCONFIG_H=${CMAKE_BINARY_DIR}/config.h") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\nif [ \"\$GRIDTYPE\" != \"\" ]; then") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\n GRIDS=`\$GREP \"defined USED_[A-Z_]*_GRIDTYPE\" \$CONFIG_H | \$SED 's/\\(.*defined USED\\_\\)\\(.*\\)\\(\\_GRIDTYPE*\\)/\\2/g'`\nfi\n") endif() set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\nOLDFLAGS=\$FLAGS\nFLAGS=") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\nfor FLAG in \$OLDFLAGS; do") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\n NEWFLAG=\$FLAG\n VARNAME=`\$ECHO \$FLAG | \$GREP \"\\-D\" | \$SED 's/-D//g'`") # only for CXX we have GRIDTYPE if( ${COMP} STREQUAL "CXX" ) set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\n for GRID in \$GRIDS; do\n if [ \"\$VARNAME\" == \"\$GRID\" ]; then\n NEWFLAG=\"-D\$GRIDTYPE\"\n break\n fi\n done") endif() set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\n VARNAME=`\$ECHO \$VARNAME | \$GREP \"=\" | \$CUT -d \"=\" -f 1`") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\n if [ \"\$VARNAME\" != \"\" ]; then\n VAR=`\$ENV | \$GREP \$VARNAME`\n if [ \"\$VAR\" != \"\" ]; then") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\n # add variable from environment to flags list\n NEWFLAG=\"-D\$VARNAME=\${!VARNAME}\"\n fi\n fi") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\n FLAGS=\"\$FLAGS \$NEWFLAG\"\ndone") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\n\$ECHO \"${DEFAULT_${COMP}_COMPILER} \$${COMP}FLAGS \$FLAGS\"") set( COMPILER_SCRIPT_FILE "${COMPILER_SCRIPT_FILE}\nexec ${DEFAULT_${COMP}_COMPILER} \$${COMP}FLAGS \$FLAGS") message("-- Generating ${COMP} compiler script for ${COMP}FLAGS overloading on command line") if( ${COMP} STREQUAL "CXX" ) file(WRITE ${CXX_COMPILER_SCRIPT} "${COMPILER_SCRIPT_FILE}") else() file(WRITE ${C_COMPILER_SCRIPT} "${COMPILER_SCRIPT_FILE}") endif() endforeach() endif() endmacro() dune-common-2.8.0/cmake/modules/UseInkscape.cmake000066400000000000000000000027251411343567400217240ustar00rootroot00000000000000# Module that provides conversion routines using inkscape # # .. cmake_function:: inkscape_generate_png_from_svg # # .. cmake_param:: OUTPUT_DIR # :single: # # The output directory for the generated png files. # Defaults to the current build directory. # # .. cmake_param:: pngfiles # :single: # :positional: # :required: # # The files that should be converted. # # .. cmake_param:: DPI # :single: # # dpi value for the generated image (default: 90) # # TODO Switch to named arguments! # include_guard(GLOBAL) include(CMakeParseArguments) function(inkscape_generate_png_from_svg) if(NOT INKSCAPE) return() endif() cmake_parse_arguments(INKSCAPE "" "OUTPUT_DIR;DPI" "" ${ARGN}) if(NOT INKSCAPE_OUTPUT_DIR) set(INKSCAPE_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) endif() if(NOT INKSCAPE_DPI) set(INKSCAPE_DPI 90) endif() foreach(pic ${INKSCAPE_UNPARSED_ARGUMENTS}) string(REGEX REPLACE "\\.[a-zA-Z]+" ".svg" input ${pic}) if( INKSCAPE_NEW_VERSION ) execute_process( COMMAND ${INKSCAPE} --export-dpi=${INKSCAPE_DPI} --export-type=png --export-filename=${pic} ${CMAKE_CURRENT_SOURCE_DIR}/${input} WORKING_DIRECTORY ${INKSCAPE_OUTPUT_DIR}) else() execute_process( COMMAND ${INKSCAPE} -z --export-dpi=${INKSCAPE_DPI} -e ${pic} ${CMAKE_CURRENT_SOURCE_DIR}/${input} WORKING_DIRECTORY ${INKSCAPE_OUTPUT_DIR}) endif() endforeach() endfunction() dune-common-2.8.0/cmake/modules/UseLatexMk.cmake000066400000000000000000000262261411343567400215360ustar00rootroot00000000000000# UseLatexMk.cmake is a CMake module to build Latex documents # from CMake. # # add_latex_document(SOURCE texsource # [TARGET target] # [EXCLUDE_FROM_ALL] # [REQUIRED] # [FATHER_TARGET father1 [father2 ...]] # [RCFILE rcfile1 [rcfile2 ...]] # [INSTALL destination] # [BUILD_ON_INSTALL] # ) # # The arguments: # SOURCE # Required argument with a single tex source that defines the document to be built # TARGET # An optional target name, defaults to a suitable mangling of the given source and its path. # An additional target with _clean appended will be added as well, which cleans the output # and all auxiliary files. # EXCLUDE_FROM_ALL # Set this to avoid the target from being built by default. If the FATHER_TARGET # parameter is set, this option is automatically set. # REQUIRED # Set this option to issue a fatal error if the document could not # be built. By default it is only skipped. # FATHER_TARGET # A list of meta-targets that should trigger a rebuild of this target (like "make doc"). # The targets are expected to exist already. Specifying any such targets will automatically add the # above EXCLUDE_FROM_ALL option. # RCFILE # A list configuration file to customize the latexmk build process. These are read by latexmk # *after* the automatically generated rc file in the indicated order. Note that latexmk rcfiles # override any previous settings. # You may also use CMake variables within @'s (like @CMAKE_CURRENT_BINARY_DIR@) and have # them replaced with the matching CMake variables (see cmake's configure_file command). # Note, that this is a powerful, but advanced feature. For details on what can be achieved # see the latexmk manual. Note, that triggering non-PDF builds through latexmkrc files might # cause problems with other features of UseLatexMk. # INSTALL # Set this option to an install directory to create an installation rule for this document. # BUILD_ON_INSTALL # Set this option, if you want to trigger a build of this document during installation. # # Furthermore, UseLatexMk defines a CMake target clean_latex which cleans the build tree from # all PDF output and all auxiliary files. Note, that (at least for the Unix Makefiles generator) # it is not possible to connect this process with the builtin clean target. # # Please note the following security restriction: # # UseLatexMk relies on latexmk separating input and output directory correctly. # This includes using an absolute path for the output directory. On some TeX # systems this requires the disabling of a security measure by setting `openout_any = a`. # From the latexmk documentation: # # Commonly, the directory specified for output files is a subdirectory of the current working direc- # tory. However, if you specify some other directory, e.g., "/tmp/foo" or "../output", be aware that # this could cause problems, e.g., with makeindex or bibtex. This is because modern versions of # these programs, by default, will refuse to work when they find that they are asked to write to a file # in a directory that appears not to be the current working directory or one of its subdirectories. This # is part of security measures by the whole TeX system that try to prevent malicious or errant TeX # documents from incorrectly messing with a user’s files. If for $out_dir or $aux_dir you really do # need to specify an absolute pathname (e.g., "/tmp/foo") or a path (e.g., "../output") that includes a # higher-level directory, and you need to use makeindex or bibtex, then you need to disable the secu- # rity measures (and assume any risks). One way of doing this is to temporarily set an operating # system environment variable openout_any to "a" (as in "all"), to override the default "paranoid" # setting. # # UseLatexMk.cmake allows to reenable the TeX security measure by setting LATEXMK_PARANOID to TRUE # through cmake -D, but it is not guaranteed to work correctly in that case. # # For further informations, visit https://github.com/dokempf/UseLatexMk # # # Copyright (c) 2017, Dominic Kempf, Steffen Müthing # # All rights reserved. # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # * 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. # # * Neither the name of the Universität Heidelberg nor the names of its # contributors may be used to endorse or promote products derived from this # software without specific prior written permission. # # 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 HOLDER 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. # include_guard(GLOBAL) # Find LATEX and LatexMk find_package(LATEX) find_package(LatexMk) # Find the latexmkrc template file shipped alongside UseLatexMk.cmake find_file(LATEXMKRC_TEMPLATE latexmkrc.cmake HINTS ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${PROJECT_SOURCE_DIR} ${PROJECT_SOURCE_DIR}/cmake ${PROJECT_SOURCE_DIR}/cmake/modules NO_CMAKE_FIND_ROOT_PATH ) # Add the clean_latex target if(TARGET clean_latex) message(WARNING "clean_latex target already exists. UseLatexMk attaches clean rules to it!") else() add_custom_target(clean_latex) endif() set(LATEXMK_SOURCES_BUILD_FROM) function(add_latex_document) # Parse the input parameters to the function set(OPTION REQUIRED EXCLUDE_FROM_ALL BUILD_ON_INSTALL) set(SINGLE SOURCE TARGET INSTALL) set(MULTI FATHER_TARGET RCFILE) include(CMakeParseArguments) cmake_parse_arguments(LMK "${OPTION}" "${SINGLE}" "${MULTI}" ${ARGN}) if(LMK_UNPARSED_ARGUMENTS) message("add_latex_document: Unparsed arguments! This often indicates typos in named arguments.") endif() # Apply default arguments and check for required arguments if(NOT LMK_SOURCE) message(FATAL_ERROR "No tex source specified for add_latex_document!") endif() if(NOT LMK_TARGET) # Construct a nice target name from the source file get_filename_component(LMK_TARGET ${LMK_SOURCE} ABSOLUTE) file(RELATIVE_PATH LMK_TARGET ${PROJECT_SOURCE_DIR} ${LMK_TARGET}) string(REPLACE "/" "_" LMK_TARGET ${LMK_TARGET}) string(REPLACE "." "_" LMK_TARGET ${LMK_TARGET}) endif() if(LMK_FATHER_TARGET) set(LMK_EXCLUDE_FROM_ALL TRUE) endif() if(LMK_BUILD_ON_INSTALL AND (NOT LMK_INSTALL)) message(WARNING "Specified to build on installation, but not installing!") endif() # Verify that each source is used exactly once set(ABS_SOURCE ${LMK_SOURCE}) if(NOT IS_ABSOLUTE ${ABS_SOURCE}) get_filename_component(ABS_SOURCE ${ABS_SOURCE} ABSOLUTE) endif() list(FIND LATEXMK_SOURCES_BUILD_FROM ${ABS_SOURCE} ALREADY_BUILT) if(NOT "${ALREADY_BUILT}" STREQUAL "-1") message(FATAL_ERROR "UseLatexMk: You are building twice from the same source, which is unsupported!") endif() set(LATEXMK_SOURCES_BUILD_FROM ${LATEXMK_SOURCES_BUILD_FROM} ${ABS_SOURCE} PARENT_SCOPE) # Check the existence of the latexmk executable and skip/fail if not present if(NOT (LATEXMK_FOUND AND PDFLATEX_COMPILER)) if(LMK_REQUIRED) message(FATAL_ERROR "Some Latex documents were required by the project, but LATEX or LatexMk were not found!") else() return() endif() endif() # Determine the output name get_filename_component(output ${LMK_SOURCE} NAME_WE) set(OUTPUT_PDF ${CMAKE_CURRENT_BINARY_DIR}/${output}.pdf) # Inspect the EXCLUDE_FROM_ALL option if(LMK_EXCLUDE_FROM_ALL) set(ALL_OPTION "") else() set(ALL_OPTION "ALL") endif() # Generate a latexmkrc file for this project if(NOT LATEXMKRC_TEMPLATE) message("Fatal error: The latexmkrc template file could not be found. Consider adding its path to CMAKE_MODULE_PATH") endif() set(LATEXMKRC_FILE "${CMAKE_CURRENT_BINARY_DIR}/${LMK_TARGET}.latexmkrc") configure_file(${LATEXMKRC_TEMPLATE} ${LATEXMKRC_FILE} @ONLY) set(LATEXMKRC_OPTIONS -r ${LATEXMKRC_FILE}) # Process additional latexmkrc files foreach(rcfile ${LMK_RCFILE}) get_filename_component(rcfile_base ${rcfile} NAME) set(LATEXMKRC_FILE "${CMAKE_CURRENT_BINARY_DIR}/${LMK_TARGET}_${rcfile_base}") configure_file(${rcfile} ${LATEXMKRC_FILE} @ONLY) set(LATEXMKRC_OPTIONS ${LATEXMKRC_OPTIONS} -r ${LATEXMKRC_FILE}) endforeach() # Add the BYPRODUCTS parameter, if the CMake version supports it set(BYPRODUCTS_PARAMETER "") if (CMAKE_VERSION VERSION_GREATER "3.2") set(BYPRODUCTS_PARAMETER BYPRODUCTS ${OUTPUT_PDF}) endif() # Maybe allow latexmk the use of absolute paths if(NOT LATEXMK_PARANOID) set($ENV{openout_any} "a") endif() # Call the latexmk executable # NB: Using add_custom_target here results in the target always being outofdate. # This offloads the dependency tracking from cmake to latexmk. This is an # intentional decision of UseLatexMk to avoid listing dependencies of the tex source. add_custom_target(${LMK_TARGET} ${ALL_OPTION} COMMAND ${LATEXMK_EXECUTABLE} ${LATEXMKRC_OPTIONS} ${LMK_SOURCE} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMENT "Building PDF from ${LMK_SOURCE}..." ${BYPRODUCTS_PARAMETER} ) # Add dependencies to father targets foreach(father ${LMK_FATHER_TARGET}) if(NOT TARGET ${father}) message(FATAL_ERROR "The target given to add_latex_documents FATHER_TARGET parameter does not exist") endif() add_dependencies(${father} ${LMK_TARGET}) endforeach() # Add installation rules if(LMK_BUILD_ON_INSTALL) install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} --build . --target ${LMK_TARGET} --config $)") endif() if(LMK_INSTALL) install(FILES ${OUTPUT_PDF} DESTINATION ${LMK_INSTALL} OPTIONAL) endif() # Add a clean up rule to the clean_latex target add_custom_target(${LMK_TARGET}_clean COMMAND ${LATEXMK_EXECUTABLE} -C ${LATEXMKRC_OPTIONS} ${LMK_SOURCE} WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" COMMENT "Cleaning build results from target ${LMK_TARGET}" ) add_dependencies(clean_latex ${LMK_TARGET}_clean) endfunction() dune-common-2.8.0/cmake/modules/latexmkrc.cmake000066400000000000000000000007701411343567400215020ustar00rootroot00000000000000# .latexmkrc generated by CMake from UseLatexMk.cmake starts here $bibtex = "@BIBTEX_COMPILER@ %O %S"; $dvips = "@DVIPS_CONVERTER@ %O -o %D %S"; $latex = "@LATEX_COMPILER@ %O %S"; $make = "@CMAKE_MAKE_COMMAND@"; $makeindex = "@MAKEINDEX_COMPILER@ %O -o %D %S"; $out_dir = "@CMAKE_CURRENT_BINARY_DIR@"; $pdf_mode = 1; $pdflatex = "@PDFLATEX_COMPILER@ -shell-escape -interaction=nonstopmode %O %S"; $ps2pdf = "@PS2PDF_CONVERTER@ %O %S %D"; # .latexmkrc generated by CMake from UseLatexMk.cmake ends here dune-common-2.8.0/cmake/pkg/000077500000000000000000000000001411343567400156135ustar00rootroot00000000000000dune-common-2.8.0/cmake/pkg/dune-common-config.cmake.in000066400000000000000000000021611411343567400227060ustar00rootroot00000000000000if(NOT @DUNE_MOD_NAME@_FOUND) @PACKAGE_INIT@ #import the target get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH) include("${_dir}/@DUNE_MOD_NAME@-targets.cmake") #report other information set_and_check(@DUNE_MOD_NAME@_PREFIX "${PACKAGE_PREFIX_DIR}") set_and_check(@DUNE_MOD_NAME@_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@") set(@DUNE_MOD_NAME@_CXX_FLAGS "@CMAKE_CXX_FLAGS@") set(@DUNE_MOD_NAME@_CXX_FLAGS_DEBUG "@CMAKE_CXX_FLAGS_DEBUG@") set(@DUNE_MOD_NAME@_CXX_FLAGS_MINSIZEREL "@CMAKE_CXX_FLAGS_MINSIZEREL@") set(@DUNE_MOD_NAME@_CXX_FLAGS_RELEASE "@CMAKE_CXX_FLAGS_RELEASE@") set(@DUNE_MOD_NAME@_CXX_FLAGS_RELWITHDEBINFO "@CMAKE_CXX_FLAGS_RELWITHDEBINFO@") set(@DUNE_MOD_NAME@_LIBRARIES "dunecommon") set_and_check(@DUNE_MOD_NAME@_SCRIPT_DIR "@PACKAGE_SCRIPT_DIR@") set_and_check(DOXYSTYLE_FILE "@PACKAGE_DOXYSTYLE_DIR@/Doxystyle") set_and_check(DOXYGENMACROS_FILE "@PACKAGE_DOXYSTYLE_DIR@/doxygen-macros") set(@DUNE_MOD_NAME@_DEPENDS "@DUNE_DEPENDS@") set(@DUNE_MOD_NAME@_SUGGESTS "@DUNE_SUGGESTS@") set_and_check(@DUNE_MOD_NAME@_MODULE_PATH "@PACKAGE_DUNE_INSTALL_MODULEDIR@") endif(NOT @DUNE_MOD_NAME@_FOUND) dune-common-2.8.0/cmake/scripts/000077500000000000000000000000001411343567400165215ustar00rootroot00000000000000dune-common-2.8.0/cmake/scripts/CMakeLists.txt000066400000000000000000000007371411343567400212700ustar00rootroot00000000000000# Install non-executable scripts install(FILES conf.py.in CreateDoxyFile.cmake envdetect.py FinalizeHeadercheck.cmake index.rst.in InstallFile.cmake main77.cc.in module_library.cc.in pyversion.py RunDoxygen.cmake sphinx_cmake_dune.py DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/dune/cmake/scripts) # Install executable programs install(PROGRAMS extract_cmake_data.py run-in-dune-env.sh.in DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/dune/cmake/scripts ) dune-common-2.8.0/cmake/scripts/CreateDoxyFile.cmake000066400000000000000000000013141411343567400223710ustar00rootroot00000000000000# For now we just support appending Doxyfile and Doxylocal file(READ ${DOXYSTYLE} file_contents) file(WRITE Doxyfile.in ${file_contents}) # Write the list of predefined C preprocessor macros file(READ ${DOXYGENMACROS} file_contents) file(APPEND Doxyfile.in ${file_contents}) if(DOXYLOCAL) file(READ ${DOXYLOCAL} file_contents) endif() file(APPEND Doxyfile.in ${file_contents}) # configure_file does not work as it insists an existing input file, which in our # needs to be generated first. # Therefore we read the Doxyfile.in and replace the variables using string(CONFIGURE) # and then write the file. file(READ Doxyfile.in file_contents) string(CONFIGURE ${file_contents} output) file(WRITE Doxyfile ${output}) dune-common-2.8.0/cmake/scripts/FinalizeHeadercheck.cmake000066400000000000000000000011651411343567400233760ustar00rootroot00000000000000# this is script is called at the end of all header checks if(ENABLE_HEADERCHECK) message("Headerchecks finished! Rerun CMake if a new file has not been checked!") else() message("The headercheck feature is currently disabled. You can enable it by adding ENABLE_HEADERCHECK=1 to your cmake flags.") endif() #message("Running make clean on headercheck targets...") #this cleans the build directory from pollution through headerchecks but prevents caching... :/ #file(GLOB_RECURSE list "./CMakeFiles/headercheck_*/cmake_clean.cmake") #foreach(item ${list}) # execute_process(COMMAND ${CMAKE_COMMAND} -P ${item}) #endforeach()dune-common-2.8.0/cmake/scripts/InstallFile.cmake000066400000000000000000000003621411343567400217320ustar00rootroot00000000000000 # Somehow variable list get destroyed when calling cmake (; is replaced with # whitespace character. Undo this change string(REGEX REPLACE "([a-zA-Z0-9]) ([/a-zA-Z0-9])" "\\1;\\2" files "${FILES}") file(INSTALL ${files} DESTINATION ${DIR}) dune-common-2.8.0/cmake/scripts/RunDoxygen.cmake000066400000000000000000000001701411343567400216230ustar00rootroot00000000000000execute_process(COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile OUTPUT_FILE doxygen.log ERROR_FILE doxygen.log TIMEOUT 3600) dune-common-2.8.0/cmake/scripts/conf.py.in000066400000000000000000000012261411343567400204260ustar00rootroot00000000000000import sys sys.path.append('@DUNE_SPHINX_EXT_PATH@') extensions = ['sphinx_cmake_dune'] # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = "classic" html_theme_options = { "rightsidebar": "true", "relbarbgcolor": "#eeeeee", "relbartextcolor": "#353B44", "relbarlinkcolor": "#353B44", "headbgcolor": "white", "headtextcolor": "#353B44", "linkcolor": "#337AB7", "visitedlinkcolor": "#337AB7", "textcolor": "#353B44", "footerbgcolor": "white", "footertextcolor": "#353B44", "codebgcolor": "#eeeeee", } html_sidebars = {'**': []} html_title = "" dune-common-2.8.0/cmake/scripts/envdetect.py000066400000000000000000000014521411343567400210560ustar00rootroot00000000000000# A python script that determines whether the current interpreter is # running inside a virtual environment. For discussion of the implemented # methods, see http://stackoverflow.com/questions/1871549 # # Meant to be run from DunePythonCommonMacros.cmake. For that reason, it # exits with either 1 or 0, where 1 indicates that the interpreter # runs inside a virtualenv # import sys # If sys.real_prefix exists, this is a virtualenv set up with the virtualenv package real_prefix = hasattr(sys, 'real_prefix') if real_prefix: sys.exit(1) # If a virtualenv is set up with pyvenv, we check for equality of base_prefix and prefix if hasattr(sys, 'base_prefix'): sys.exit(sys.prefix != sys.base_prefix) # If none of the above conditions triggered, this is probably no virtualenv interpreter sys.exit(0)dune-common-2.8.0/cmake/scripts/extract_cmake_data.py000077500000000000000000000100631411343567400227010ustar00rootroot00000000000000#!/usr/bin/env python """ This script will parse a cmake module and extract some rst documentation from it. This might not be as elegant as writing a Sphinx domain or using a custom extension with cmake related directives, but it provides a straightforward working way. This is used by dune-common to generate the build system documentation. Users do not want to use this!!! """ from __future__ import print_function import argparse import errno import os import re def get_args(): parser = argparse.ArgumentParser() parser.add_argument('-b', '--builddir', help='The directory where to place the produced output', required=True) parser.add_argument('-m', '--module', help='The module to parse', required=True) return vars(parser.parse_args()) def write_line(f, line): if len(line) > 2: f.write(line[2:]) else: f.write('\n') def makedirs_if_not_exists(path): # Python3's os.makedirs has exist_ok=True, but this is still Python2... try: os.makedirs(path) except OSError as e: if e.errno != errno.EEXIST: raise def read_module(args=get_args()): modname = os.path.splitext(os.path.basename(args['module']))[0] modpath = os.path.join(args['builddir'], 'modules') makedirs_if_not_exists(modpath) modfile = os.path.join(modpath, modname + '.rst') with open(args['module'], 'r') as i: # mod = open(modfile, 'w') # # Write the first block into the module rst file # mod.write(".. _" + modname + ":\n\n") # mod.write(modname + "\n") # mod.write("="*len(modname) + "\n\n") # listHeader = False o = None for l in i: if not l.startswith('#'): return if l.startswith('# .. cmake_function'): if o: o.close() cmdpath = os.path.join(args['builddir'], 'commands') makedirs_if_not_exists(cmdpath) try: cmd = re.findall(r'# .. cmake_function:: (.*)', l)[0] except IndexError as e: print("CMake doc syntax error in {}: cannot parse function on line {}".format(args['module'], l)) raise e cmdfile = os.path.join(cmdpath, cmd + ".rst") # if not listHeader: # mod.write("\nThis module defines the following functions or macros:\n\n") # listHeader = True # mod.write("* :ref:`{}`\n".format(cmd)) o = open(cmdfile, 'w') o.write(".. _" + cmd + ":\n\n") o.write(cmd + "\n") o.write("="*len(cmd) + "\n\n") write_line(o, l) elif l.startswith('# .. cmake_variable'): if o: o.close() varpath = os.path.join(args['builddir'], 'variables') makedirs_if_not_exists(varpath) try: var = re.findall(r'# .. cmake_variable:: (.*)', l)[0] except IndexError as e: print("CMake doc syntax error in {}: cannot parse variable on line".format(args['module'], l)) raise e varfile = os.path.join(varpath, var + ".rst") o = open(varfile, 'w') o.write(".. _" + var + ":\n\n") o.write(var + "\n") o.write("="*len(var) + "\n\n") write_line(o, l) elif l.startswith('# .. cmake_module'): if o: o.close() modpath = os.path.join(args['builddir'], 'modules') makedirs_if_not_exists(modpath) modfile = os.path.join(modpath, modname + ".rst") o = open(modfile, 'w') o.write(".. _" + modname + ":\n\n") o.write(modname + "\n") o.write("="*len(modname) + "\n\n") write_line(o, l) else: if o: write_line(o, l) # Parse the given arguments read_module() dune-common-2.8.0/cmake/scripts/index.rst.in000066400000000000000000000007671411343567400210010ustar00rootroot00000000000000.. title:: @PROJECT_NAME@ CMake reference .. role:: cmake(code) :language: cmake Introduction ============ .. toctree:: :maxdepth: 2 @CMAKE_DOC_DEPENDENCIES@ .. _variableref: Input Variable reference ======================== .. toctree:: :maxdepth: 1 :glob: variables/* .. _commandref: Command reference ================= .. toctree:: :maxdepth: 1 :glob: commands/* .. _moduleref: Module reference ================ .. toctree:: :maxdepth: 1 :glob: modules/* dune-common-2.8.0/cmake/scripts/main77.cc.in000066400000000000000000000002661411343567400205430ustar00rootroot00000000000000#include int main() { std::cout << "This test was skipped because it failed the following CMake Conditions:" << std::endl; ${FAILED_CONDITION_PRINTING} return 77; } dune-common-2.8.0/cmake/scripts/module_library.cc.in000066400000000000000000000003751411343567400224530ustar00rootroot00000000000000#include std::size_t ${module_lib_mangled}_version() { return ${ProjectVersionMajor} * 10000 + ${ProjectVersionMinor} * 100 + ${ProjectVersionRevision}; } std::string ${module_lib_mangled}_version_string() { return "${ProjectVersion}"; } dune-common-2.8.0/cmake/scripts/pyversion.py000066400000000000000000000021431411343567400211310ustar00rootroot00000000000000# This python script tries to figure out the version of a given python # package. This is only intended to be used from DunePythonFindPackage.cmake # # There is no unified way of specifying the version of a python package. This # script implements some methods. For discussion on the implemented methods see # http://stackoverflow.com/questions/20180543 # import sys # Load the module passed as argument (this avoids the need for a template # to be configured to put the package name inhere) modstr = sys.argv[1] module = __import__(modstr) # The most common mechanism is module.__version__ if hasattr(module, '__version__'): sys.stdout.write(module.__version__) sys.exit(0) # Alternative implementation: through pip (pip itself implement pip.__version__, # so we never get here, when checking the version of pip itself), only works if # package name and distribution name are the same import pkg_resources for package in pkg_resources.working_set: if package.project_name == modstr and package.has_version(): sys.stdout.write(package.version) sys.exit(0) # Give up on this one sys.exit(1) dune-common-2.8.0/cmake/scripts/run-in-dune-env.sh.in000077500000000000000000000001011411343567400224040ustar00rootroot00000000000000#!@BASH@ source @DUNE_PYTHON_VIRTUALENV_PATH@/bin/activate "$@" dune-common-2.8.0/cmake/scripts/sphinx_cmake_dune.py000066400000000000000000000147571411343567400225750ustar00rootroot00000000000000""" A cmake extension for Sphinx tailored for the Dune project. This is used during `make doc` to build the build system documentation. """ from docutils import nodes from docutils.parsers.rst import Directive from itertools import chain class CMakeParamNode(nodes.Element): pass class CMakeBriefNode(nodes.Element): pass class CMakeFunction(Directive): # We do require the name to be an argument required_arguments = 1 optional_arguments = 0 final_argument_whitespace = False has_content = True def run(self): env = self.state.document.settings.env # Parse the content of the directive recursively node = nodes.Element() node.document = self.state.document self.state.nested_parse(self.content, self.content_offset, node) brief_nodes = [] output_nodes = [] positional_params = [] required_params = {} optional_params = {} for child in node: if isinstance(child, CMakeParamNode): if child["positional"]: positional_params.append(child) elif child["required"]: required_params[child["name"]] = child else: optional_params[child["name"]] = child elif isinstance(child, CMakeBriefNode): par = nodes.paragraph() self.state.nested_parse(child['content'], self.content_offset, par) brief_nodes.append(par) else: output_nodes.append(child) def render_required(paramnode): if paramnode["multi"]: sl.append(" "*5 + paramnode['name'] + ' ' + paramnode['argname'] + '1 [' + paramnode['argname'] + '2 ...]\n') if paramnode["single"]: sl.append(" "*5 + paramnode['name'] + ' ' + paramnode['argname'] + '\n') if paramnode["option"]: sl.append(" "*5 + paramnode['name'] + '\n') if paramnode["special"]: sl.append(" "*5 + paramnode['argname'] + '\n') def render_optional(paramnode): if paramnode["multi"]: sl.append(' '*4 + '[' + paramnode['name'] + ' ' + paramnode['argname'] + '1 [' + paramnode['argname'] + '2 ...]' + ']\n') if paramnode["single"]: sl.append(" "*4 + '['+ paramnode['name'] + ' ' + paramnode['argname'] + ']\n') if paramnode["option"]: sl.append(" "*4 + '['+ paramnode['name'] + ']\n') if paramnode["special"]: sl.append(" "*4 + '['+ paramnode['argname'] + ']\n') # Build the content of the box sl = [self.arguments[0] + '(\n'] for paramnode in positional_params: if paramnode["required"]: render_required(paramnode) else: render_optional(paramnode) for rp, paramnode in required_params.items(): render_required(paramnode) for op, paramnode in optional_params.items(): render_optional(paramnode) sl.append(")\n") lb = nodes.literal_block(''.join(sl), ''.join(sl)) brief_nodes.append(lb) dl = nodes.definition_list() for paramnode in chain(positional_params, required_params.values(), optional_params.values()): dli = nodes.definition_list_item() dl += dli dlit = nodes.term(text=paramnode["name"]) dli += dlit dlic = nodes.definition() dli += dlic self.state.nested_parse(paramnode['content'], self.content_offset, dlic) # add the parameter list to the output brief_nodes.append(dl) return brief_nodes + output_nodes class CMakeBrief(Directive): required_arguments = 0 optional_arguments = 0 final_argument_whitespace = False has_content = True def run(self): node = CMakeBriefNode() node['content'] = self.content return [node] class CMakeParam(Directive): # We do require the name to be an argument required_arguments = 1 optional_arguments = 0 final_argument_whitespace = False option_spec = {'argname' : lambda s: s, 'multi': lambda s: True, 'option': lambda s: True, 'positional' : lambda s: True, 'required': lambda s: True, 'single': lambda s: True, 'special': lambda s: True } has_content = True def run(self): node = CMakeParamNode() # set defaults: node['name'] = self.arguments[0] node['single'] = self.options.get('single', False) node['multi'] = self.options.get('multi', False) node['option'] = self.options.get('option', False) node['special'] = self.options.get('special', False) node['positional'] = self.options.get('positional', False) node['required'] = self.options.get('required', False) node['argname'] = self.options.get('argname', self.arguments[0].lower() if self.arguments[0].lower()[-1:] != 's' else self.arguments[0].lower()[:-1]) node['content'] = self.content if node['positional']: node['argname'] = '' return [node] class CMakeVariable(Directive): # We do require the name to be an argument required_arguments = 1 optional_arguments = 0 final_argument_whitespace = False option_spec = {'argname' : lambda s: s, 'multi': lambda s: True, 'option': lambda s: True, 'positional' : lambda s: True, 'required': lambda s: True, 'single': lambda s: True } has_content = True def run(self): node = nodes.paragraph() self.state.nested_parse(self.content, self.content_offset, node) return [node] class CMakeModule(Directive): required_arguments = 0 optional_arguments = 0 final_argument_whitespace = False has_content = True def run(self): node = nodes.paragraph() self.state.nested_parse(self.content, self.content_offset, node) return [node] def setup(app): app.add_node(CMakeBriefNode) app.add_node(CMakeParamNode) app.add_directive('cmake_module', CMakeModule) app.add_directive('cmake_brief', CMakeBrief) app.add_directive('cmake_function', CMakeFunction) app.add_directive('cmake_param', CMakeParam) app.add_directive('cmake_variable', CMakeVariable) return {'version': '0.1'} dune-common-2.8.0/config.h.cmake000066400000000000000000000144351411343567400164560ustar00rootroot00000000000000/* begin dune-common put the definitions for config.h specific to your project here. Everything above will be overwritten */ /* begin private */ /* Define to the version of dune-common */ #define DUNE_COMMON_VERSION "${DUNE_COMMON_VERSION}" /* Define to the major version of dune-common */ #define DUNE_COMMON_VERSION_MAJOR ${DUNE_COMMON_VERSION_MAJOR} /* Define to the minor version of dune-common */ #define DUNE_COMMON_VERSION_MINOR ${DUNE_COMMON_VERSION_MINOR} /* Define to the revision of dune-common */ #define DUNE_COMMON_VERSION_REVISION ${DUNE_COMMON_VERSION_REVISION} /* Standard debug streams with a level below will collapse to doing nothing */ #define DUNE_MINIMAL_DEBUG_LEVEL ${DUNE_MINIMAL_DEBUG_LEVEL} /* does the compiler support __attribute__((deprecated))? */ #cmakedefine HAS_ATTRIBUTE_DEPRECATED 1 /* does the compiler support __attribute__((deprecated("message"))? */ #cmakedefine HAS_ATTRIBUTE_DEPRECATED_MSG 1 /* does the compiler support __attribute__((unused))? */ #cmakedefine HAS_ATTRIBUTE_UNUSED 1 /* does the standard library provide experimental::make_array() ? */ #cmakedefine DUNE_HAVE_CXX_EXPERIMENTAL_MAKE_ARRAY 1 /* does the standard library provide experimental::is_detected ? */ #cmakedefine DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED 1 /* does the standard library provide identity ? */ #cmakedefine DUNE_HAVE_CXX_STD_IDENTITY 1 /* Define if you have a BLAS library. */ #cmakedefine HAVE_BLAS 1 /* Define if you have LAPACK library. */ #cmakedefine HAVE_LAPACK 1 /* Define if you have the MPI library. */ #cmakedefine HAVE_MPI ENABLE_MPI /* Deactivate cxx bindings for MPI */ #if defined(HAVE_MPI) && HAVE_MPI #define MPICH_SKIP_MPICXX 1 #define OMPI_SKIP_MPICXX 1 #define MPI_NO_CPPBIND 1 #define MPIPP_H #define _MPICC_H #endif /* Define if you have the GNU GMP library. The value should be ENABLE_GMP to facilitate activating and deactivating GMP using compile flags. */ #cmakedefine HAVE_GMP ENABLE_GMP /* Define if you have the GCC Quad-Precision library. The value should be ENABLE_QUADMATH to facilitate activating and deactivating QuadMath using compile flags. */ #cmakedefine HAVE_QUADMATH ENABLE_QUADMATH /* Define if you have the Vc library. The value should be ENABLE_VC to facilitate activating and deactivating Vc using compile flags. */ #cmakedefine HAVE_VC ENABLE_VC /* Define to 1 if you have the Threading Building Blocks (TBB) library */ #cmakedefine HAVE_TBB 1 /* begin private */ /* Name of package */ #define PACKAGE "dune-common" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "@DUNE_MAINTAINER@" /* Define to the full name of this package. */ #define PACKAGE_NAME "@DUNE_MOD_NAME@" /* Define to the full name and version of this package. */ #define PACKAGE_STRING "@DUNE_MOD_NAME@ @DUNE_MOD_VERSION@" /* Define to the one symbol short name of this package. */ #define PACKAGE_TARNAME "@DUNE_MOD_NAME@" /* Define to the home page for this package. */ #define PACKAGE_URL "@DUNE_MOD_URL@" /* Define to the version of this package. */ #define PACKAGE_VERSION "@DUNE_MOD_VERSION@" /* Version number of package */ #define VERSION "@DUNE_MOD_VERSION@" /* end private */ /* old feature support macros which were tested until 2.7, kept around for one more release */ /* As these are now always supported due to the new compiler requirements, they are directly */ /* defined without an explicit test. */ #define DUNE_HAVE_CXX_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1 #define DUNE_HAVE_CXX_OPTIONAL 1 #define DUNE_HAVE_CXX_VARIANT 1 #define DUNE_SUPPORTS_CXX_THROW_IN_CONSTEXPR 1 #define DUNE_HAVE_C_ALIGNED_ALLOC 1 #define DUNE_HAVE_CXX_BOOL_CONSTANT 1 #define DUNE_HAVE_CXX_EXPERIMENTAL_BOOL_CONSTANT 0 #define DUNE_HAVE_HEADER_EXPERIMENTAL_TYPE_TRAITS 0 #define DUNE_HAVE_CXX_APPLY 1 #define DUNE_HAVE_CXX_EXPERIMENTAL_APPLY 0 #define HAVE_IS_INDEXABLE_SUPPORT 1 /* Define to ENABLE_UMFPACK if the UMFPack library is available */ #cmakedefine HAVE_UMFPACK ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse library is available */ #cmakedefine HAVE_SUITESPARSE ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's AMD library is available */ #cmakedefine HAVE_SUITESPARSE_AMD ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's BTF library is available */ #cmakedefine HAVE_SUITESPARSE_BTF ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's CAMD library is available */ #cmakedefine HAVE_SUITESPARSE_CAMD ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's CCOLAMD library is available */ #cmakedefine HAVE_SUITESPARSE_CCOLAMD ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's CHOLMOD library is available */ #cmakedefine HAVE_SUITESPARSE_CHOLMOD ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's COLAMD library is available */ #cmakedefine HAVE_SUITESPARSE_COLAMD ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's CXSPARSE library is available */ #cmakedefine HAVE_SUITESPARSE_CXSPARSE ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's KLU library is available */ #cmakedefine HAVE_SUITESPARSE_KLU ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's LDL library is available */ #cmakedefine HAVE_SUITESPARSE_LDL ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's RBIO library is available */ #cmakedefine HAVE_SUITESPARSE_RBIO ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's SPQR library is available and if it's version is at least 4.3 */ #cmakedefine HAVE_SUITESPARSE_SPQR ENABLE_SUITESPARSE /* Define to ENABLE_SUITESPARSE if the SuiteSparse's UMFPACK library is available */ #cmakedefine HAVE_SUITESPARSE_UMFPACK ENABLE_SUITESPARSE /* Define to 1 if METIS is available */ #cmakedefine HAVE_METIS 1 /* Define to 1 if the Scotch replacement for METIS is used. */ #cmakedefine HAVE_SCOTCH_METIS 1 /* Define to 1 if you have the ParMETIS library. */ #cmakedefine HAVE_PARMETIS 1 /* Define to 1 if the PTScotch replacement for ParMETIS is used. */ #cmakedefine HAVE_PTSCOTCH_PARMETIS 1 /* Define to 1 if PT-Scotch is available */ #cmakedefine HAVE_PTSCOTCH 1 /* Used to call lapack functions */ #cmakedefine LAPACK_NEEDS_UNDERLINE /* end dune-common Everything below here will be overwritten */ dune-common-2.8.0/doc/000077500000000000000000000000001411343567400145175ustar00rootroot00000000000000dune-common-2.8.0/doc/CMakeLists.txt000066400000000000000000000002711411343567400172570ustar00rootroot00000000000000add_subdirectory("doxygen") add_subdirectory("buildsystem") add_subdirectory("comm") install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dunecontrol.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) dune-common-2.8.0/doc/buildsystem/000077500000000000000000000000001411343567400170635ustar00rootroot00000000000000dune-common-2.8.0/doc/buildsystem/CMakeLists.txt000066400000000000000000000003321411343567400216210ustar00rootroot00000000000000# Install the buildsystem documentation defined in dune-common install(FILES dune-common.rst DESTINATION ${CMAKE_INSTALL_DOCDIR}) # Also always build the CMake API documentation in dune-common dune_cmake_sphinx_doc() dune-common-2.8.0/doc/buildsystem/dune-common.rst000066400000000000000000000407651411343567400220520ustar00rootroot00000000000000=========== dune-common =========== .. _whatis: What is CMake anyway? ===================== CMake... - is an open source build system tool developed at KITware. - offers a one-tool-solution to all building tasks, like configuring, building, linking, testing and packaging. - is a build system generator: It supports a set of backends called *generators* - is portable - is controlled by ONE rather simple language You can install CMake through your favorite package manager or downloading source code from `KITWare `_ The minimum required version to build Dune with CMake is 3.13. .. _howtouse: How do I use Dune with CMake? ============================= The build process is controlled by the script :code:`dunecontrol`, located in :code:`dune-common/bin`. There is a compatibility layer that will translate all the configure flags from your opts file into the corresponding CMake flags. While this is a great tool to determine how to do the transition, in the long run you should switch to a CMake-only approach. :code:`dunecontrol` will pickup the variable :code:`CMAKE_FLAGS` from your opts file and use it as command line options for any call to CMake. There, you can define variables for the configure process with CMake's :code:`-D` option; just as with the C pre-processor. The most important part of the configure flags is to tell the build system where to look for external libraries. You can browse the :ref:`variableref` section of this documentation for a list of variables that are picked up by the Dune CMake build system. .. _whatfiles: What files in a dune module belong to the CMake build system? ============================================================= Every directory in a project contains a file called :code:`CMakeLists.txt`, which is written in the CMake language. You can think of these as a distributed configure script. Upon configure, the top-level :code:`CMakeLists.txt` is executed. Whenever an :ref:`add_subdirectory` command is encountered, the :code:`CMakeLists.txt` file of that sub-directory is executed. The top-level :code:`CMakeLists.txt` file is special, because it sets up the entire Dune module correctly. You should not delete the auto-generated parts of it. Additionally, a Dune module can export some cmake modules. A cmake module is a file that contains one or more build system macros meant for downstream use. If a module provides modules, they can be found in the subfolder :code:`cmake/modules`. The module :code:`dune-foo/cmake/modules/DuneFooMacros.cmake` in a module :code:`dune-foo` is special however: Its contents are always executed when configuring the module :code:`dune-foo` or any other Dune module, that requires or suggests the module :code:`dune-foo`. This is the perfect place to put your checks for external packages, see below. The file :code:`config.h.cmake` defines a template for the section of :code:`config.h`, that is generated by the module. .. _flags: How do I modify the flags and linked libraries of a given target? ================================================================= Again, there are multiple ways to do this. The Dune build system offers macros to make this task as easy as possible. For each external module, there is a macro :code:`add_dune_*_flags`. Those macros should cover most flags. Example usage: .. code-block:: cmake add_executable(foo foo.cc) add_dune_umfpack_flags(foo) add_dune_mpi_flags(foo) There is also the macro :ref:`add_dune_all_flags`, which uses the same flag registry mechanism as the simplified build system in section :ref:`simplified`. If you want to fully control the configuration of the targets, you can do so. Build system entities such as targets, directories and tests do have so called properties in CMake. You can access and modify those properties via the commands :code:`get_property` and :code:`set_property`. You can for example use those to modify a targets :code:`COMPILE_DEFINITIONS` or :code:`INCLUDE_DIRECTORIES` property: .. code-block:: cmake add_executable(foo foo.cc) set_property(TARGET foo APPEND PROPERTY COMPILE_DEFINITIONS ) set_property(TARGET foo APPEND PROPERTY INCLUDE_DIRECTORIES ) For a full list of properties, check the manual: .. code-block:: bash cmake --help-property-list Manually linking libraries can be done through the :code:`target_link_libraries` command instead of manually tweaking properties. .. _external: How do I link against external libraries, that are not checked for by Dune? =========================================================================== While there might be many solutions that make your application work, there is only one clean solution to this: You have to provide a find module for the package. A find module is a CMake module that follows a specific naming scheme: For an external package called :code:`SomePackage` it is called :code:`FindSomePackage.cmake`. Note that CMake treats package names case sensitive. If CMake encounters a :code:`find_package(SomePackage)` line, it searches its module include paths for this find module. A good read to get started writing a find module is `this page `_ in the CMake wiki. Depending on how common your external package is, you may not even need to write the find module on your own. You can have a look at the list of find modules shipped by CMake or simply search the internet for the module name and profit from other open-source project's work. It is considered good style to also provide a macro :code:`add_dune_somepackage_flags`. .. _outofsource: What is an out-of-source build? =============================== An out-of-source build does leave the version-controlled source tree untouched and puts all files that are generated by the build process into a different directory -- the build directory. The build directory does mirror your source tree's structure as seen in the following. Assume the following source directory structure: :: dune-foo/ CMakeLists.txt dune/ foo/ CMakeLists.txt src/ CMakeLists.txt The generated build directory will have the following structure, where the directory :code:`build-cmake` is a subdirectory of the source directory: :: build-cmake/ Makefile dune/ foo/ Makefile src/ Makefile Using the :code:`Unix Makefiles` generator, your Makefiles are generated in the build tree, so that is where you have to call :code:`make`. There are multiple advantages with this approach, such as a clear separation between version controlled and generated files and you can have multiple out-of-source builds with different configurations at the same time. Out-of-source builds are the default with CMake. In-source builds are strongly discouraged. By default, a subfolder :code:`build-cmake` is generated within each dune module and is used as a build directory. You can customize this folder through the :code:`--builddir` option of :code:`dunecontrol`. Give an absolute path to the :code:`--builddir` option, you will get something like this: :: build/ dune-common/ Makefile dune-foo/ Makefile So, instead of one build directory in every dune module, you will be able to collect all build directories in one directory. This makes it much easier to have multiple build directories and to remove build directories. .. _simplified: What is the simplified build system and how do I use it? ======================================================== Dune offers a simplified build system, where all flags are added to all targets and all libraries are linked to all targets. You can enable the feature by calling :ref:`dune_enable_all_packages` in the top-level :code:`CMakeLists.txt` file of your project, before you add any subdirectories. This will modify all targets in the directory of the :code:`CMakeLists.txt`, where you put this, and also in all subdirectories. The compile flags for all found external packages are added to those targets and the target is linked against all found external libraries. To use this while using custom external packages, you have to register your flags to the mechanism. Also, some special care has to be given, if your module does build one or more library which targets within the module do link against. Carefully read the following documentation in those cases: * :ref:`dune_enable_all_packages` * :ref:`dune_register_package_flags` * :ref:`dune_library_add_sources` .. _compiler: How do I change my compiler and compiler flags? =============================================== In general, there are multiple ways to do this: * Setting the CMake variables :ref:`CMAKE__COMPILER` (with :code:`LANG` being :code:`C` or :code:`CXX`) from the opts file, e.g. via :code:`CMAKE_FLAGS="-DCMAKE_CXX_COMPILER=otherc++"`. * Setting those variables within the project with the :code:`set` command * Setting the environment variables :code:`CC`, :code:`CXX`, :code:`FC` etc. The first option is the recommended way. Whenever you change your compiler, you should delete all build directories. For some CMake versions, there is a known CMake bug, that requires you to give an absolute path to your compiler, but Dune will issue a warning, if you violate that. You can modify your default compiler flags by setting the variables :ref:`CMAKE__FLAGS` in your opts file (again with :code:`LANG` being :code:`C` or :code:`CXX`). .. _symlink: How should I handle ini and grid files in an out-of-source-build setup? ======================================================================= Such files are under version control, but they are needed in the build directory. There are some CMake functions targeting this issue: * :ref:`dune_symlink_to_source_tree` * :ref:`dune_symlink_to_source_files` * :ref:`dune_add_copy_command` * :ref:`dune_add_copy_dependency` * :ref:`dune_add_copy_target` The simplest way to solve the problem is to set the variable :ref:`DUNE_SYMLINK_TO_SOURCE_TREE` to your opts file. This will execute :ref:`dune_symlink_to_source_tree` in your top-level :code:`CMakeLists.txt`. This will add a symlink :code:`src_dir` to all subdirectories of the build directory, which points to the corresponding directory of the source tree. This will only work on platforms that support symlinking. .. _ides: How do I use CMake with IDEs? ============================= As already said, CMake is merely a build system generator with multiple backends (called a generator). Using IDEs requires a different generator. Check :code:`cmake --help` for a list of generators. You can then add the :code:`-G` to the :code:`CMAKE_FLAGS` in your opts file. Note that the generator name has to match character by character, including case and spaces. To configure highlighting of CMake errors in Emacs' compilation mode, include the following in your :code:`~./emacs` (see the `Emacs bug `_): .. code-block:: elisp (setq compilation-error-regexp-alist-alist `((cmake "^CMake \\(?:Error\\|\\(Warning\\)\\) at \\(.*\\):\\([1-9][0-9]*\\) ([^)]+):$" 2 3 nil (1)) (cmake-info "^ \\(?: \\*\\)?\\(.*\\):\\([1-9][0-9]*\\) ([^)]+)$" 2 3 nil 0) . ,compilation-error-regexp-alist-alist)) Then customize the option :code:`compilation-error-regexp-alist` and add the two predefined symbols :code:`cmake` and :code:`cmake-info` to the list. .. _cxxflags: I usually modify my CXXFLAGS upon calling make. How can I do this in CMake? =========================================================================== This violates the CMake philosophy and there is no clean solution to achieve it. The CMake-ish solution would be to have for each configuration one out-of-source build. We have nevertheless implemented a workaround. It can be enable by setting the variable :ref:`ALLOW_CXXFLAGS_OVERWRITE` in your opts file. You can then type: .. code-block:: bash make CXXFLAGS="" Furthermore any C pre-processor variable of the form :code:`-DVAR=` can be overloaded on the command line and the grid type can be set via :code:`GRIDTYPE=""`. Note this only works with generators that are based on Makefiles and several Unix tools like bash must be available. .. _test: How do I run the test suite from CMake? ======================================= The built-in target to run the tests is called :code:`test` instead of Autotools' :code:`check`. It is a mere wrapper around CMake's own testing tool CTest. You can check :code:`ctest --help` for a lot of useful options, such as choosing the set of tests to be run by matching regular expressions or showing the output of failed tests. The test programs are not built automatically. You need to build them manually before running them using :code:`make build_tests`. The Dune test suite also defines tests that run in parallel. You may set an upper bound to the number of cores in use for a single test by setting :ref:`DUNE_MAX_TEST_CORES`. .. _disable: Can I disable an external dependency? ===================================== To disable an external dependency :code:`Foo`, add :: -DCMAKE_DISABLE_FIND_PACKAGE_Foo=TRUE to your opts file. The name of the dependency is case sensitive but there is no canonical naming scheme. See the output of configure to get the right name. Make sure to not use cached configure results by deleting the cache file or the build directory, cf. :ref:`troubleshoot`. .. _parallel: How do I switch between parallel and sequential builds? ======================================================= Dune builds with CMake are parallel if and only if MPI is found. To have a sequential build despite an installed MPI library, you have to explicitly disable the corresponding find module by setting :: -DCMAKE_DISABLE_FIND_PACKAGE_MPI=TRUE in the :code:`CMAKE_FLAGS` of your opts file, as described in section :ref:`disable`. .. _headercheck: Why is it not possible anymore to do make headercheck? ====================================================== The headercheck feature has been disabled by default. You can enable it by setting the CMake variable :ref:`ENABLE_HEADERCHECK` through your opts file. This step has been necessary, because of the large amount of additional file the headercheck adds to the build directory. A better implementation has not been found yet, because it simply does not fit the CMake philosophy. .. _packages: How do I create tarballs or packages? ===================================== To create source code packages, also known as tarballs, run `git archive` within your module's Git repository. There is no default way to create binary packages like Deb or RPM packages. You can use the Open Build Service for openSuse RPMs and related distributions. Or create packages according to the distribution of your choice like the tools around dpkg-buildpackage and debuild for Debian. CMake has a packaging tool CPack, but with CPack you are on your own. In the past, our results based on CPack were not satisfying. .. _dune-python: How does the Dune build system handle Python? ============================================= dune-common contains a build system extension to handle many python-related aspects. You can read more on this in the module description :ref:`DunePythonCommonMacros` and the pieces of documentation mentioned inthere. .. _troubleshoot: How do I troubleshoot? ====================== CMake caches aggressively which makes it bad at recognizing changed configurations. To trigger a fresh run of configure, you can delete the :code:`CMakeCache.txt` file from the build directory and maybe save some compilation time afterward. Whenever you experience any problems, your first step should be to delete all build directories. Nice trick: :: dunecontrol exec "rm -rf build-cmake" This will remove all build directories from all DUNE modules. Later on you can get an error log from the file :code:`CMakeError.log` in the :code:`CMakeFiles` subdirectory of your build directory. This is what you should send to the mailing list alongside the description of your setup and efforts to help us help you. Where can I get help? ===================== The CMake manual is available on the command line: * :code:`cmake --help-command-list` * :code:`cmake --help-command ` * :code:`cmake --help-property-list` * :code:`cmake --help-property ` * :code:`cmake --help-module-list` * :code:`cmake --help-module ` To get help on which variables are picked up by CMake, there is a CMake wiki page collecting them. Of course, there is also Google, StackOverflow and the CMake Mailing list (archive). For problems specific to DUNE's build system, ask on our mailing lists. dune-common-2.8.0/doc/buildsystem/examples/000077500000000000000000000000001411343567400207015ustar00rootroot00000000000000dune-common-2.8.0/doc/buildsystem/examples/Toolchain-Ubuntu-mingw32.cmake000066400000000000000000000025161411343567400263730ustar00rootroot00000000000000# Sample toolchain file for building for Windows from an Ubuntu Linux system. # # Typical usage: # *) install cross compiler: `sudo apt-get install mingw-w64 g++-mingw-w64` # *) cd build # *) cmake -DCMAKE_TOOLCHAIN_FILE=~/Toolchain-Ubuntu-mingw32.cmake .. set(CMAKE_SYSTEM_NAME Windows) set(TOOLCHAIN_PREFIX i686-w64-mingw32) # cross compilers to use for C and C++ set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc-posix) set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++-posix) set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran-posix) set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres) # enable to generate fully static binaries # set(CMAKE_EXE_LINKER_FLAGS "-static -static-libgcc -static-libstdc++" CACHE STRING "executable linker flags") # target environment on the build host system # set 1st to dir with the cross compiler's C/C++ headers/libs set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}) # modify default behavior of FIND_XXX() commands to # search for headers/libs in the target environment and # search for programs in the build host environment set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # enable/disable some hardware specific feature set(THREADS_PTHREAD_ARG "-pthread") set(STDTHREAD_LINK_FLAGS "-pthread") set(STDTHREAD_WORKS true) dune-common-2.8.0/doc/buildsystem/examples/opts.mingw32000066400000000000000000000001531411343567400230750ustar00rootroot00000000000000BUILDDIR=build-mingw CMAKE_FLAGS="-DCMAKE_TOOLCHAIN_FILE=$PATH_dune_common/Toolchain-Ubuntu-mingw32.cmake" dune-common-2.8.0/doc/comm/000077500000000000000000000000001411343567400154525ustar00rootroot00000000000000dune-common-2.8.0/doc/comm/CMakeLists.txt000066400000000000000000000007251411343567400202160ustar00rootroot00000000000000add_executable(poosc08 "poosc08.cc") target_link_libraries(poosc08 PUBLIC "dunecommon") add_executable(poosc08_test "poosc08_test.cc") target_link_libraries(poosc08_test PUBLIC "dunecommon") add_executable(indexset "indexset.cc") target_link_libraries(indexset PUBLIC "dunecommon") add_dune_mpi_flags("poosc08;poosc08_test;indexset") dune_add_latex_document( SOURCE communication.tex FATHER_TARGET doc BUILD_ON_INSTALL INSTALL ${CMAKE_INSTALL_DOCDIR}/comm) dune-common-2.8.0/doc/comm/buildindexset.hh000066400000000000000000000024441411343567400206420ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef BUILDINDEXSET_HH #define BUILDINDEXSET_HH #include #include /** * @brief Flag for marking the indices. */ enum Flag {owner, overlap}; // The type of local index we use typedef Dune::ParallelLocalIndex LocalIndex; /** * @brief Add indices to the example index set. * @param indexSet The index set to build. */ template void build(C& comm, Dune::ParallelIndexSet& indexSet) { // The rank of our process int rank=comm.rank(); // Indicate that we add or remove indices. indexSet.beginResize(); if(rank==0) { indexSet.add(0, LocalIndex(0,overlap,true)); indexSet.add(2, LocalIndex(1,owner,true)); indexSet.add(6, LocalIndex(2,owner,true)); indexSet.add(3, LocalIndex(3,owner,true)); indexSet.add(5, LocalIndex(4,owner,true)); } if(rank==1) { indexSet.add(0, LocalIndex(0,owner,true)); indexSet.add(1, LocalIndex(1,owner,true)); indexSet.add(7, LocalIndex(2,owner,true)); indexSet.add(5, LocalIndex(3,overlap,true)); indexSet.add(4, LocalIndex(4,owner,true)); } // Modification is over indexSet.endResize(); } #endif dune-common-2.8.0/doc/comm/communication.bib000066400000000000000000000053251411343567400210020ustar00rootroot00000000000000@InProceedings{ISTL, author = {Markus Blatt and Peter Bastian}, title = {The Iterative Solver Template Library}, booktitle = {Applied Parallel Computing. State of the Art in Scientific Computing}, editor = {Bo K\r{a}gstr\"om and Erik Elmroth and Jack Dongarra and Jerzy Wa\'sniewski}, year = 2007, volume = 4699, series = {Lecture Notes in Computer Science}, publisher = {Springer}, pages = {666--675} } @Article{dune08-1, author = {Peter Bastian and Markus Blatt and Andreas Dedner and Christian Engwer and Robert Kl\"ofkorn and Mario Ohlberger and Oliver Sander}, title = { A generic grid interface for parallel and adaptive scientific computing. Part I: abstract framework}, journal = {Computing}, year = 2008, volume = 82, number = {2--3}, pages = {103--119} } @Article{dune08-2, author = {Peter Bastian and Markus Blatt and Andreas Dedner and Christian Engwer and Robert Kl\"ofkorn and Ralf Kornhuber and Mario Ohlberger and Oliver Sander}, title = { A generic grid interface for parallel and adaptive scientific computing. Part II: implementation and test in DUNE}, journal = {Computing}, year = 2008, volume = 82, number = {2--3} , pages = {121--138} } @Article{ISTLParallel, author = {Markus Blatt and Peter Bastian}, title = {On the Generic Parallelisation of Iterative Solvers for the Finite Element Method}, journal = {Int. J. Computational Science and Engineering}, volume = {4}, number = {1}, pages = {56--69}, year = 2008 } @Misc{DuneWeb, author = {DUNE}, howpublished = {\texttt{http://www.dune-project.org/}} } @Misc{boost_mpi, author = {D. Gregor and M. Troyer}, title = {{B}oost.{M}{P}{I}}, howpublished = {\texttt{http://www.boost.org/}}, year = 2006 } @PhdThesis{gerlach02:janus, author = {Jens Gerlach}, title = {Domain Engineering and Generic Programming for Parallel Scientific Computing}, school = {TU Berlin}, year = {2002} } @InProceedings{giloi95:_promot, author = {W.K. Giloi and M. Kessler and A. Schramm}, title = {PROMOTER: A High Level, Object-Parallel Programming Language}, booktitle = {Proceedings of the International Conference on High Performance Computing}, year = {1995}, address = {New Dehli, India}, month = {December} } @inproceedings{nolte00:_taco, author = {J\"{o}rg Nolte and Mitsuhisa Sato and Yutaka Ishikawa}, title = {TACO -- Dynamic Distributed Collections with Templates and Topologies}, booktitle = {Euro-Par '00: Proceedings from the 6th International Euro-Par Conference on Parallel Processing}, year = {2000}, isbn = {3-540-67956-1}, pages = {1071--1080}, publisher = {Springer-Verlag}, address = {London, UK}, }dune-common-2.8.0/doc/comm/communication.tex000066400000000000000000000576521411343567400210600ustar00rootroot00000000000000\documentclass[11pt]{article} \usepackage{multicol} \usepackage{ifthen} \usepackage{amsthm} \usepackage{amsmath} \usepackage{amsfonts} \usepackage{color} \usepackage{graphicx} \usepackage{hyperref} \usepackage{psfrag} \usepackage{subfigure} \usepackage[dvips]{epsfig} \usepackage[dvips]{graphicx} \usepackage[a4paper,body={148mm,240mm,nohead}]{geometry} \usepackage[ansinew]{inputenc} \usepackage{tikz} \usepackage{listings} \lstset{language=C++, basicstyle=\ttfamily, stringstyle=\ttfamily, commentstyle=\it, extendedchars=true} \newtheorem{theorem}{Theorem}[section] \newtheorem{lemma}[theorem]{Lemma} \theoremstyle{definition} \newtheorem{definition}[theorem]{Definition} \newtheorem{class}[theorem]{Class} \newtheorem{algorithm}[theorem]{Algorithm} \theoremstyle{remark} \newtheorem{remark}[theorem]{Remark} \newcommand{\C}{\mathbb{C}} \newcommand{\R}{\mathbb{R}} \newcommand{\N}{\mathbb{N}} \newcommand{\Z}{\mathbb{Z}} \newcommand{\Q}{\mathbb{Q}} \newcommand{\K}{\mathbb{K}} \newcommand{\loc}{\mbox{loc}} \title{Communication within the Iterative Solver Template Library (ISTL)\thanks{Part of the Distributed and Unified Numerics Environment (DUNE) which is available from the site \texttt{http://www.dune-project.org/}}} \author{% Markus Blatt\\ Interdisziplinäres Zentrum für Wissenschaftliches Rechnen,\\ Universität Heidelberg, Im Neuenheimer Feld 368, D-69120 Heidelberg, \\ email: \texttt{Markus.Blatt@iwr.uni-heidelberg.de}} \date{April 27, 2005} \begin{document} \maketitle \begin{abstract} This document describes usage and interface of the classes meant for setting up the communication within a parallel program using ISTL. As most of the communication in distributed program occur in the same pattern it is often more efficient (and of course more easy for the programmer) to build the communication pattern once in the program and then use multiple times (e.~g. at each iteration step of an iterative solver). \end{abstract} \begin{multicols}{2} {\small\tableofcontents} \end{multicols} \section{Introduction} \label{sec:introduction} When using the data parallel programming model a set of processes works collectively on the same set of finite data objects. These might be elements of a finite element grid or vector entries in a linear algebra computation. Each process works on different partitions of the global data. Only for this partition it computes updated values. In large scale parallel codes it is advisable to store the data partition in a local data structure directly in the local memory of the process. Due to data dependencies the process needs to access data in the partition of other processes, too. This can either be done by communicating these values on demand between the processes whenever they are accessed. This results in data structures that are aware of the data distribution. Or by augmenting the partition of the process such that it additionally includes the data values that the other values depend on. Note that now the partitioning is not disjoint any more but overlapping. Of course the values other processes compute for need to be updated using communication at so called synchronisation points of the algorithm In the latter case the data structures do not need to know anything about the data distribution. This demands more effort from the parallel algorithm designer to make sure that the data used for computations is valid, i.e. contains an updated value if another process computes the data for it. Still it allows for fewer synchronisation points in the algorithms as even in collective operations all input data may already be updated from other processes due to a previous operation. Between the necessary synchronisation points one can take advantage of the fast local memory access. Consider representing a random access container $x$ on a set of processes ${\cal P}=\{0, \ldots, P-1\}$. It is represented by individual pieces $x^p$, where $x^p$ is the piece stored on process $p$ of the $P$ processes participating in the calculation. Although the global representation of the container is not available on any process, a process $p$ needs to know how the entries of its local piece $x^p$ correspond to the entries of the global container $x$, which would be used in a sequential program. \section{Communication Software Components} \label{sec:comm-softw-comp} From an abstract point of view a random access container $x: I \rightarrow K$ provides a mapping from an index set $I \subset \N_0$ onto a set of objects $K$. Note that we do not require $I$ to be consecutive. The piece $x_p$ of the container $x$ stored on process $p$ is a mapping $x_p:I_p \rightarrow K$, where $I_p \subset I$. Due to efficiency the entries of $x_p$ should be stored consecutively in memory. This means that for the local computation the data must be addressable by a consecutive index starting from $0$. When using adaptive discretisation methods there might be the need to reorder the indices after adding and/or deleting some of the discretisation points. Therefore this index does not need to be persistent and can easily be changed. We will call this index {\em\index{local index}local index}. For the communication phases of our algorithms these locally stored entries must also be addressable by a global identifier. It is used to store the received values at and to retrieve the values to be sent from the correct local position in the consecutive memory chunk. To ease the addition and removal of discretisation points this global identifier has to be persistent but does not need to be consecutive. We will call this global identifier {\em\index{global index}global index}. \subsection{ParallelIndexSet} Let $I \subset \N_0$ be an arbitrary, not necessarily consecutive, index set identifying all discretisation points of the computation. Furthermore, let $$({I}_p)_{p\in {\cal P}}, \quad \bigcup\limits_{p \in {\cal P}} {I}_p = I$$ be an overlapping decomposition of the global index set $I$ into the sets of indices ${I}_p$ corresponding to the global indices of the values stored locally in the chunk of process $p$. Then the class \begin{lstlisting}{} template class ParallelIndexSet; \end{lstlisting} realises the one to one mapping $$ \gamma_p\::\: {I}_p \longrightarrow {I}^{\loc}_p := [0, n_p) $$ of the globally unique index onto the local index. The template parameter \lstinline!TG! is the type of the global index and \lstinline!TL! is the type of the local index. The only prerequisite of \lstinline!TG! is that objects of this type are comparable using the less-than-operator \lstinline! class ParallelLocalIndex; \end{lstlisting} as the type for the local index of class \lstinline!ParallelIndexSet!. Here the template parameter \lstinline!TA! is the type of the attributes used, e.g. an enumeration \lstinline!Flags! defined by \begin{lstlisting} enum Flags {owner, ghost}; \end{lstlisting} where \lstinline!owner! marks the indices $k \in I_p$ owned by process $p$ and \lstinline!ghost! the indices $k\not\in I_p$ owned by other processes. As an example let us look at an array distributed between two processes. In Figure \ref{fig:redistarray} one can see the array $a$ as it appears in a sequential program. Below there are two different distributions of that array. The local views $s_0$ and $s_1$ are the parts process $0$ and $1$ store in the case that $a$ is divided into two blocks. The local views $t_0$ and $t_1$ are the parts of $a$ that process $0$ and $1$ store in the case that $a$ is divided into 4 blocks and process $0$ stores the first and third block and process $1$ the second and fourth block. The decompositions have an overlap of one and the indices have the attributes \lstinline!owner! and \lstinline!ghost! visualised by white and shaded cells, respectively. The index sets $I_s$ and $I_t$ corresponding to the decompositions $s_p$ and $t_p$, $p \in \{0,1\}$, are shown in Figure \ref{fig:redistindex} as sets of triples $(g,l,a)$. Here $g$ is the global index, $l$ is the local index and $a$ is the attribute (either o for \lstinline!owner! or {g} for \lstinline!ghost!). \begin{figure} \centering \begin{tikzpicture} \draw (0,3.3) ellipse (2.2cm and 1.5cm) node [align=center,yshift=0.2cm] {$I_s$\\(0,0,o) (1,1,o)\\(2,2,o) (3,3,o) (4,4,o)\\(5,5,o) (6,6,g)}; \draw (0,0) ellipse (2.2cm and 1.5cm) node [align=center,yshift=0.2cm] {$I_t$\\(0,0,o) (1,1,o) (2,2,o)\\(3,3,g) (5,4,g) (6,5,o)\\(7,6,o) (8,7,o) (9,8,g)}; \draw (2.5,-2.7) -- ++(0,7.5); \draw (5,3.3) ellipse (2.2cm and 1.5cm) node [align=center,yshift=0.2cm] {$I_s$\\(5,0,g) (6,1,o)\\(7,2,o) (8,3,o) (9,4,o)\\(10,5,o) (11,6,o)}; \draw (5,0) ellipse (2.2cm and 1.5cm) node [align=center,yshift=0.2cm] {$I_t$\\(2,0,g) (3,1,o) (4,2,o)\\(5,3,o) (6,4,g) (8,5,g)\\(9,6,o) (10,7,o) (11,8,o)}; \node at (0,-2.2) {Processor 0}; \node at (5,-2.2) {Processor 1}; \end{tikzpicture} \caption{Index sets for array redistribution} \label{fig:redistindex} \end{figure} \begin{figure*} \tikzset{ box/.style={ draw, shape=rectangle, minimum width=1.5em, minimum height=1.5em, anchor=base, inner sep=0pt, }, overlap/.style={fill=black!25!white}, } \newcommand{\interior}[1]{% \tikz[baseline={(0,0)}]\node[box]{#1};% } \newcommand{\overlap}[1]{% \tikz[baseline={(0,0)}]\node[box,overlap]{#1};% } \def\mc{\multicolumn}% \newcommand{\leader}[1]{\makebox[2em][r]{#1 }}% \renewcommand{\arraystretch}{2}% \centering \begin{tabular}{r|l} \mc2c{global array} \\ \mc2c{\leader{a:}% \foreach\i in {0,...,11} {\interior{\i}}} \\ \mc2c{local views} \\ \leader{$s_0$:}% \foreach\i in {0,...,5} {\interior{\i}}% \foreach\i in {6} {\overlap {\i}} & \leader{$s_1$:}% \foreach\i in {5} {\overlap {\i}}% \foreach\i in {6,...,11} {\interior{\i}} \\ \leader{$t_0$:}% \foreach\i in {0,1,2} {\interior{\i}}% \foreach\i in {3,5} {\overlap {\i}}% \foreach\i in {6,7,8} {\interior{\i}}% \foreach\i in {9} {\overlap {\i}} & \leader{$t_1$:}% \foreach\i in {2} {\overlap {\i}}% \foreach\i in {3,4,5} {\interior{\i}}% \foreach\i in {6,8} {\overlap {\i}}% \foreach\i in {9,10,11} {\interior{\i}} \\ \mc1c{Processor 0} & \mc1{|c}{Processor 1} \\ \end{tabular} \caption{Redistributed array} \label{fig:redistarray} \end{figure*} The following code snippet demonstrates how to set up the index set $I_s$ on process $0$: \lstinputlisting[linerange={53-57,59-61,67-67}]{poosc08_test.cc} \subsection{Remote Indices} \label{sec:remote-indices} To set up communication between the processes every process needs to know which indices are also known to other processes and which attributes are attached to them on the remote side. There are scenarios where data is exchanged between different index sets, e.g. if the data is agglomerated on lesser processes or redistributed. Therefore communication is allowed to occur between different decompositions of the same index set. Let $I \subset \N$ be the global index set and $$ (I^s_p)_{p\in{\cal P}},\quad \bigcup_{p\in{\cal P}} I^s_p = I,\quad \text{ and } \quad (I^t_p)_{p\in{\cal P}}, \quad\bigcup_{p\in{\cal P}} I^t_p = I $$ be two overlapping decompositions of the same index set $I$. Then an instance of class \lstinline!RemoteIndices! on process $p \in {\cal P}$ stores the sets of triples \begin{equation} \label{eq:ri_s_set} \begin{split} r_{p \rightarrow q}^{s} = \{ (g,(l,a),b) \,|\, g \in I^s_q \wedge g \in I_p^t, l=\gamma_p^s(g), a = \alpha_p^s(l), b = \alpha_q^t(\gamma_q^t(g))\} \end{split} \end{equation} and \begin{equation} \label{eq:ri_t_set} \begin{split} r_{p \rightarrow q}^{t} = \{ (g,(l,a),b) \,|\, g \in I^s_q \wedge g \in I_p^t, l=\gamma_p^t(g), a = \alpha_p^t(l), b = \alpha_p^s(\gamma_p^s(g))\}\,, \end{split} \end{equation} for all $q\in{\cal P}$. Here $\alpha^s_p$ and $\alpha^t_p$ denote the mapping of local indices on process $p$ onto attributes for the index set $I^s_p$ and $I^t_p$ as realised by \lstinline!ParallelLocalIndex!. Note that the sets $r_{p \rightarrow q}^{s}$ and $r_{p \rightarrow q}^{t}$ will only be nonempty if the processes $p$ and $q$ manage overlapping index sets. For our example in Figure \ref{fig:redistarray} and Figure \ref{fig:redistindex} the interface between $I_s$ and $I_t$ on process $0$ is: \begin{align*} r_{0\rightarrow 0}^{s} = \{&(0,(0,o),o), (1,(1,o),o), (2,(2,o),o), (3,(3,o),g), (5,(5,o),g), (6,(6,g),o)\}\\ r_{0\rightarrow 0}^{t} = \{&(0,(0,o),o), (1,(1,o),o), (2,(2,o),o), (3,(3,g),o), (5,(4,g),o), (6,(5,o),g)\}\\ r_{0\rightarrow 1}^{s} = \{&(2(2,o),g), (3,(3,o),o), (4,(4,o),o), (5,(5,o),o), (6,(6,g),g)\}\\ r_{0\rightarrow 1}^{t} = \{&(5,(4,g),g), (6,(5,o),o), (7,(6,o),o), (8,(7,o),o), (9,(8,g),o)\} \end{align*} This information can either be calculated automatically by communicating all indices in a ring or set up by hand if the user has this information available. Assuming that \lstinline!sis! is the index set $I_s$ and \lstinline!tis! the index set $I_t$ set up as described in the previous subsection and \lstinline!comm! is an MPI communicator then the simple call \lstinputlisting[linerange={83-84}]{poosc08_test.cc} on all processes automatically calculates this information and stores it in \lstinline!riRedist!. For a parallel calculation on the local views $s_0$ and $s_1$ calling \lstinputlisting[linerange={86-87}]{poosc08_test.cc} on all processes builds the necessary information in \lstinline!riS!. \subsection{Communication Interface} \label{sec:comm-interf} With the information provided by class \lstinline!RemoteIndices! the user can set up arbitrary communication interfaces. These interfaces are realised in \lstinline!template class Interface!, where the template parameter \lstinline!T! is the custom type of the \lstinline!ParallelIndexSet! representing the index sets. Using the attributes attached to the indices by \lstinline!ParallelLocalIndex! the user can select subsets of the indices for exchanging data, e.g. send data from indices marked as \lstinline!owner! to indices marked as \lstinline!ghost!. Basically the interface on process $p$ manages two sets for each process $q$ it shares common indices with: $$ i_{p\rightarrow q}^{s} = \{ l | (g,(l,a),b) \in r_{p\rightarrow q}^{s} | a \in A_s \wedge b \in A_t\} $$ and $$ i_{p\rightarrow q}^{t} = \{ l | (g, (l,a), b) \in r_{p\rightarrow q}^{t} | a \in A_t \wedge b \in A_s\}\,, $$ where $A_s$ and $A_t$ are the attributes marking the indices where the source and target of the communication will be, respectively. In our example these sets on process $0$ will be stored for communication if $A_s=\{o\}$ and $A_t=\{o, g\}$: \begin{align*} i_{0\rightarrow 0}^{s} = \{0, 1, 3, 5\}\quad & \quad i_{0\rightarrow 0}^{t} = \{0, 1, 3, 4\}\\ i_{0\rightarrow 1}^{s} = \{2, 3, 4, 5\}\quad & \quad i_{0\rightarrow 1}^{t} = \{5, 6, 7, 8\}\,. \end{align*} The following code snippet would build the interface above in \lstinline!infRedist! as well as the interface \lstinline!infS! to communicate between indices marked as \lstinline!owner! and \lstinline!ghost! on the local array views $s_0$ and $s_1$: \lstinputlisting[linerange={89-97}]{poosc08_test.cc} \subsection{Communicator} \label{sec:communicator} Using the classes from the previous sections all information about the communication is available and we are set to communicate data values of arbitrary container types. The only prerequisite for the container type is that its values are addressable via \lstinline!operator[](size_t index)!. This should be safe to assume. An important feature of our communicators is that we are not only able to send one data item per index, but also different numbers of data elements (of the same type) for each index. This is supported in a generic way by the traits class \lstinline!template struct CommPolicy! describing the container type \lstinline!V!. The \lstinline!typedef IndexedType! is the atomic type to be communicated and \lstinline!typedef IndexedTypeFlag! is either \lstinline!SizeOne! if there is only one data item per index or \lstinline!VariableSize! if the number of data items per index is variable. The default implementation works for all array-like containers which provide only one data item per index. For all other containers the user has to provide its own custom specialisation. %For the vector classes of ISTL (up to two block levels) %those specialisations are already implemented. The class \lstinline!template class BufferedCommunicator! performs the actual communication. The template parameter \lstinline!T! describes the type of the parallel index set. It uses the information about the communication interface provided by an object of class \lstinline!Interface! to set up communication buffers for a container containing a specific data type. It is also responsible for gathering the data before and scattering the data after the communication step. The strict separation of the interface description from the actual buffering and communication allows for reusing the interface information with various different container and data types. Before the communication can start one has to call the \lstinline!build! method with the data source and target containers as well as the communication interface as arguments. Assuming \lstinline!s! and \lstinline!t! as arrays $s_i$ and $t_i$, respectively, then \lstinputlisting[linerange=103-106]{poosc08_test.cc} demonstrates how to set up the communicator \lstinline!bCommRedist! for the array redistribution and \lstinline!bComm! for a parallel calculation on the local views $s_i$. The \lstinline!build! function calculates the size of the messages to send to other processes and allocates buffers for the send and receive actions. The representatives \lstinline!s! and \lstinline!t! are needed to get the number of data values at each index in the case of variable numbers of data items per index. Note that, due to the generic programming techniques used, the compiler knows if the number of data points is constant for each index and will apply a specialised algorithm for calculating the message size without querying neither \lstinline!s! nor \lstinline!t!. Clean up of allocated resources is done either by calling the method \lstinline!free()! or automatically in the destructor. The actual communication takes place if one of the methods \lstinline!forward! and \lstinline!backward! is called. In our case in \lstinline!bCommRedist! the \lstinline!forward! method sends data from the local views $s_i$ to the local views $t_i$ according to the interface information and the \lstinline!backward! method in the opposite direction. The following code snippet first redistributes the local views $s_i$ of the global array to the local views $t_i$ and performs some calculation on this representation. Afterwards the result is communicated backwards. \lstinputlisting[linerange=110-113]{poosc08_test.cc} Note that both methods have a different template parameter, either \lstinline!CopyData! or \lstinline!AddData!. These are policies for gathering and scattering the data items. The former just copies the data from and to the location. The latter copies from the source location but adds the received data items to the target entries. Assuming our data is stored in simple C-arrays \lstinline!AddData! could be implemented like this: \lstinputlisting[linerange=16-27]{poosc08_test.cc} Note that arbitrary manipulations can be applied to the communicated data in both methods. For containers with multiple data items associated with one index the methods \lstinline!gather! and \lstinline!scatter! must have an additional integer argument specifying the sub-index. \section{Collective Communication} \label{sec:collective-communication} While communicating entries of array-like structures is a prominent task in scientific computing codes one must not neglect collective communication operations, like gathering and scattering data from and to all processes, respectively, or waiting for other processes. An abstraction for these operations is crucial for decoupling the communication from the parallel programming paradigm used. Therefore we designed \lstinline!template class CollectiveCommunication! which provides information of the underlying parallel programming paradigm as well as the collective communication operations as known from MPI. See Table \ref{tab:col-comm} for a list of all functions. \begin{table*}%[b] \centering \begin{tabular}{p{.5\textwidth}|p{.4\textwidth}} Function&Description\\\hline\hline \lstinline!int rank()!&Get the rank of the process\\ \lstinline!int size()!&Get the number of processes\\ \lstinline!template T sum (T& in)!& Compute global sum\\ \lstinline!template T prod (T& in)!&Compute global product\\ \lstinline!template T min (T& in)!&Compute global minimum\\ \lstinline!template T max (T& in)!&Compute global maximum\\ \lstinline!void barrier()!& Wait for all processes.\\ \lstinline!template int broadcast (T* inout, int len, int root)! & Broadcast an array from root to all other processes\\ \lstinline!template int gather (T* in, T* out, int len, int root)!& Gather arrays at a root process\\ \lstinline!template int allreduce(Type* in, Type* out, int len)!& Combine values from all processes on all processes. Combine function is given with \lstinline!BinaryFunction! \end{tabular} \caption{Collective Communication Functions} \label{tab:col-comm} \end{table*} Currently there is a default implementation for sequential programs as well as a specialisation working with MPI. This approach allows for running parallel programs sequentially without any parallel overhead simply by choosing the sequential specialisation at compile time. Note that the interface is far more convenient to use than the C++ interface of MPI. The latter is a simple wrapper around the C implementation without taking advantage of the power of generic programming. The collective communication classes were developed before the release of Boost.MPI \cite{boost_mpi}. In contrast to Boost.MPI it was never meant as a full generic implementation of all MPI functions. Instead it is restricted to the most basic subset of collective operations needed to implement finite element methods and iterative solver using the previously described components. This lean interface should make it possible to easily port this approach to thread based parallelisation as well as other parallelisation paradigms. This would allow code to easily switch between different paradigms \bibliographystyle{plainnat} \bibliography{communication} \end{document} dune-common-2.8.0/doc/comm/figures/000077500000000000000000000000001411343567400171165ustar00rootroot00000000000000dune-common-2.8.0/doc/comm/figures/darray.eps000066400000000000000000000141131411343567400211110ustar00rootroot00000000000000%!PS-Adobe-2.0 EPSF-2.0 %%Title: ../eps/darray.eps %%Creator: fig2dev Version 3.2 Patchlevel 1 %%CreationDate: Thu Mar 4 15:25:17 1999 %%For: peter@speedo (Peter Bastian) %%Orientation: Portrait %%BoundingBox: 0 0 345 260 %%Pages: 0 %%BeginSetup %%EndSetup %%Magnification: 1.0000 %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -130.0 296.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n -1000 5689 m -1000 -1000 l 8527 -1000 l 8527 5689 l cp clip 0.06299 0.06299 sc % Polyline 7.500 slw n 5265 3105 m 7515 3105 l 7515 3780 l 5265 3780 l cp gs col0 s gr % Polyline n 5670 3105 m 5670 3780 l gs col0 s gr % Polyline n 6120 3105 m 6120 3780 l gs col0 s gr % Polyline n 6570 3105 m 6570 3780 l gs col0 s gr % Polyline n 7020 3105 m 7020 3780 l gs col0 s gr /Times-Roman ff 180.00 scf sf 5400 4050 m gs 1 -1 sc (0) col0 sh gr /Times-Roman ff 180.00 scf sf 6300 4050 m gs 1 -1 sc (2) col0 sh gr /Times-Roman ff 180.00 scf sf 6750 4050 m gs 1 -1 sc (3) col0 sh gr /Times-Roman ff 180.00 scf sf 7245 4050 m gs 1 -1 sc (4) col0 sh gr /Times-Roman ff 180.00 scf sf 5850 4050 m gs 1 -1 sc (1) col0 sh gr % Polyline n 2340 3105 m 4590 3105 l 4590 3780 l 2340 3780 l cp gs col0 s gr % Polyline n 2745 3105 m 2745 3780 l gs col0 s gr % Polyline n 3195 3105 m 3195 3780 l gs col0 s gr % Polyline n 3645 3105 m 3645 3780 l gs col0 s gr % Polyline n 4095 3105 m 4095 3780 l gs col0 s gr /Times-Roman ff 180.00 scf sf 2475 4050 m gs 1 -1 sc (0) col0 sh gr /Times-Roman ff 180.00 scf sf 3375 4050 m gs 1 -1 sc (2) col0 sh gr /Times-Roman ff 180.00 scf sf 3825 4050 m gs 1 -1 sc (3) col0 sh gr /Times-Roman ff 180.00 scf sf 4320 4050 m gs 1 -1 sc (4) col0 sh gr /Times-Roman ff 180.00 scf sf 2925 4050 m gs 1 -1 sc (1) col0 sh gr /Times-Roman ff 180.00 scf sf 2970 4320 m gs 1 -1 sc (local indices) col0 sh gr /Times-Roman ff 180.00 scf sf 2475 4635 m gs 1 -1 sc (local array in processor 0) col0 sh gr % Polyline n 3150 1215 m 6750 1215 l 6750 1890 l 3150 1890 l cp gs col0 s gr % Polyline n 4950 1215 m 4950 1890 l gs col0 s gr % Polyline n 4050 1215 m 4050 1890 l gs col0 s gr % Polyline n 3600 1215 m 3600 1890 l gs col0 s gr % Polyline n 4500 1215 m 4500 1890 l gs col0 s gr % Polyline n 5850 1215 m 5850 1890 l gs col0 s gr % Polyline n 5400 1215 m 5400 1890 l gs col0 s gr % Polyline n 6300 1215 m 6300 1890 l gs col0 s gr % Polyline n 2520 3105 m 3375 1890 l gs col0 s gr % Polyline n 2970 3105 m 4230 1890 l gs col0 s gr % Polyline n 3375 3105 m 6030 1890 l gs col0 s gr % Polyline n 3825 3105 m 4725 1890 l gs col0 s gr % Polyline n 5490 3105 m 3465 1890 l gs col0 s gr % Polyline n 5850 3105 m 3870 1890 l gs col0 s gr % Polyline n 6345 3105 m 6525 1890 l gs col0 s gr % Polyline n 6795 3105 m 5625 1890 l gs col0 s gr % Polyline n 7290 3105 m 5175 1890 l gs col0 s gr % Polyline n 4320 3105 m 5535 1890 l gs col0 s gr /Times-Roman ff 180.00 scf sf 3285 1035 m gs 1 -1 sc (0) col0 sh gr /Times-Roman ff 180.00 scf sf 3735 1035 m gs 1 -1 sc (1) col0 sh gr /Times-Roman ff 180.00 scf sf 4230 1035 m gs 1 -1 sc (2) col0 sh gr /Times-Roman ff 180.00 scf sf 4680 1035 m gs 1 -1 sc (3) col0 sh gr /Times-Roman ff 180.00 scf sf 5085 1035 m gs 1 -1 sc (4) col0 sh gr /Times-Roman ff 180.00 scf sf 5535 1035 m gs 1 -1 sc (5) col0 sh gr /Times-Roman ff 180.00 scf sf 5985 1035 m gs 1 -1 sc (6) col0 sh gr /Times-Roman ff 180.00 scf sf 6435 1035 m gs 1 -1 sc (7) col0 sh gr /Times-Roman ff 180.00 scf sf 5940 4320 m gs 1 -1 sc (local indices) col0 sh gr /Times-Roman ff 180.00 scf sf 5490 4635 m gs 1 -1 sc (local array in processor 1) col0 sh gr /Times-Roman ff 180.00 scf sf 3825 720 m gs 1 -1 sc (global array with global indices) col0 sh gr /Times-Italic ff 180.00 scf sf 2880 1665 m gs 1 -1 sc (a:) col0 sh gr /Times-Italic ff 180.00 scf sf 2070 3555 m gs 1 -1 sc (a0:) col0 sh gr /Times-Italic ff 180.00 scf sf 4995 3555 m gs 1 -1 sc (a1:) col0 sh gr $F2psEnd rs dune-common-2.8.0/doc/comm/figures/distindex.eps000066400000000000000000005671361411343567400216440ustar00rootroot00000000000000%!PS-Adobe-3.0 EPSF-3.0 %%Creator: inkscape 0.44.1 %%Pages: 1 %%Orientation: Portrait %%BoundingBox: -5 414 276 601 %%HiResBoundingBox: -5.9999911 414 276 600.4 %%DocumentMedia: plain 596 842 0 () () %%EndComments %%Page: 1 1 0 842 translate 0.8 -0.8 scale gsave [1 0 0 1 0 0] concat gsave 0 0 0 setrgbcolor newpath 11.34082 347.36218 moveto 10.730139 348.41037 10.276689 349.44715 9.9804688 350.47253 curveto 9.6842421 351.49793 9.5361303 352.53699 9.5361328 353.58972 curveto 9.5361303 354.64246 9.6842421 355.68608 9.9804688 356.72058 curveto 10.281247 357.75053 10.734697 358.78731 11.34082 359.83093 curveto 10.24707 359.83093 lineto 9.563474 358.75997 9.0507792 357.70723 8.7089844 356.67273 curveto 8.3717434 355.63823 8.2031238 354.61056 8.203125 353.58972 curveto 8.2031238 352.57345 8.3717434 351.55034 8.7089844 350.52039 curveto 9.0462219 349.49045 9.5589167 348.43771 10.24707 347.36218 curveto 11.34082 347.36218 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 15.155273 356.82312 moveto 19.974609 356.82312 lineto 19.974609 357.98523 lineto 13.494141 357.98523 lineto 13.494141 356.82312 lineto 14.018228 356.2808 14.731443 355.55392 15.633789 354.64246 curveto 16.540686 353.72644 17.110347 353.13628 17.342773 352.87195 curveto 17.784825 352.37521 18.092442 351.95594 18.265625 351.61414 curveto 18.443353 351.26779 18.53222 350.92827 18.532227 350.59558 curveto 18.53222 350.05327 18.340814 349.61121 17.958008 349.26941 curveto 17.579747 348.92762 17.085282 348.75672 16.474609 348.75671 curveto 16.041663 348.75672 15.583656 348.83192 15.100586 348.9823 curveto 14.622068 349.1327 14.109373 349.36056 13.5625 349.66589 curveto 13.5625 348.27136 lineto 14.118488 348.04806 14.638019 347.87945 15.121094 347.7655 curveto 15.604164 347.65158 16.04622 347.59461 16.447266 347.5946 curveto 17.504552 347.59461 18.34765 347.85894 18.976562 348.38757 curveto 19.605462 348.91623 19.919914 349.62261 19.919922 350.50671 curveto 19.919914 350.92599 19.840162 351.32475 19.680664 351.703 curveto 19.525709 352.07671 19.240879 352.51876 18.826172 353.02917 curveto 18.712233 353.16134 18.349929 353.54415 17.739258 354.17761 curveto 17.128576 354.80652 16.267249 355.68836 15.155273 356.82312 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 23.023438 356.2489 moveto 24.46582 356.2489 lineto 24.46582 357.42468 lineto 23.344727 359.61218 lineto 22.462891 359.61218 lineto 23.023438 357.42468 lineto 23.023438 356.2489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 28.526367 356.82312 moveto 33.345703 356.82312 lineto 33.345703 357.98523 lineto 26.865234 357.98523 lineto 26.865234 356.82312 lineto 27.389321 356.2808 28.102537 355.55392 29.004883 354.64246 curveto 29.91178 353.72644 30.481441 353.13628 30.713867 352.87195 curveto 31.155919 352.37521 31.463536 351.95594 31.636719 351.61414 curveto 31.814447 351.26779 31.903314 350.92827 31.90332 350.59558 curveto 31.903314 350.05327 31.711908 349.61121 31.329102 349.26941 curveto 30.950841 348.92762 30.456376 348.75672 29.845703 348.75671 curveto 29.412757 348.75672 28.954749 348.83192 28.47168 348.9823 curveto 27.993162 349.1327 27.480467 349.36056 26.933594 349.66589 curveto 26.933594 348.27136 lineto 27.489582 348.04806 28.009112 347.87945 28.492188 347.7655 curveto 28.975257 347.65158 29.417314 347.59461 29.818359 347.5946 curveto 30.875646 347.59461 31.718744 347.85894 32.347656 348.38757 curveto 32.976555 348.91623 33.291008 349.62261 33.291016 350.50671 curveto 33.291008 350.92599 33.211256 351.32475 33.051758 351.703 curveto 32.896803 352.07671 32.611972 352.51876 32.197266 353.02917 curveto 32.083327 353.16134 31.721023 353.54415 31.110352 354.17761 curveto 30.49967 354.80652 29.638343 355.68836 28.526367 356.82312 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 36.394531 356.2489 moveto 37.836914 356.2489 lineto 37.836914 357.42468 lineto 36.71582 359.61218 lineto 35.833984 359.61218 lineto 36.394531 357.42468 lineto 36.394531 356.2489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 43.49707 351.21082 moveto 42.822588 351.21082 42.289385 351.47514 41.897461 352.00378 curveto 41.505532 352.52788 41.309568 353.24793 41.30957 354.16394 curveto 41.309568 355.07996 41.503253 355.80229 41.890625 356.33093 curveto 42.282549 356.85502 42.81803 357.11707 43.49707 357.11707 curveto 44.166987 357.11707 44.697911 356.85274 45.089844 356.3241 curveto 45.481765 355.79545 45.677728 355.0754 45.677734 354.16394 curveto 45.677728 353.25704 45.481765 352.53927 45.089844 352.01062 curveto 44.697911 351.47742 44.166987 351.21082 43.49707 351.21082 curveto 43.49707 350.14441 moveto 44.590815 350.14442 45.449864 350.49989 46.074219 351.21082 curveto 46.69856 351.92176 47.010734 352.90613 47.010742 354.16394 curveto 47.010734 355.4172 46.69856 356.40157 46.074219 357.11707 curveto 45.449864 357.828 44.590815 358.18347 43.49707 358.18347 curveto 42.39876 358.18347 41.537433 357.828 40.913086 357.11707 curveto 40.293293 356.40157 39.983398 355.4172 39.983398 354.16394 curveto 39.983398 352.90613 40.293293 351.92176 40.913086 351.21082 curveto 41.537433 350.49989 42.39876 350.14442 43.49707 350.14441 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 48.890625 347.36218 moveto 49.984375 347.36218 lineto 50.667966 348.43771 51.178382 349.49045 51.515625 350.52039 curveto 51.857418 351.55034 52.028316 352.57345 52.02832 353.58972 curveto 52.028316 354.61056 51.857418 355.63823 51.515625 356.67273 curveto 51.178382 357.70723 50.667966 358.75997 49.984375 359.83093 curveto 48.890625 359.83093 lineto 49.496743 358.78731 49.947914 357.75053 50.244141 356.72058 curveto 50.544919 355.68608 50.69531 354.64246 50.695312 353.58972 curveto 50.69531 352.53699 50.544919 351.49793 50.244141 350.47253 curveto 49.947914 349.44715 49.496743 348.41037 48.890625 347.36218 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 32.34082 327.36218 moveto 31.730139 328.41037 31.276689 329.44715 30.980469 330.47253 curveto 30.684242 331.49793 30.53613 332.53699 30.536133 333.58972 curveto 30.53613 334.64246 30.684242 335.68608 30.980469 336.72058 curveto 31.281247 337.75053 31.734697 338.78731 32.34082 339.83093 curveto 31.24707 339.83093 lineto 30.563474 338.75997 30.050779 337.70723 29.708984 336.67273 curveto 29.371743 335.63823 29.203124 334.61056 29.203125 333.58972 curveto 29.203124 332.57345 29.371743 331.55034 29.708984 330.52039 curveto 30.046222 329.49045 30.558917 328.43771 31.24707 327.36218 curveto 32.34082 327.36218 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 37.918945 328.68835 moveto 37.208004 328.68836 36.672523 329.03927 36.3125 329.74109 curveto 35.957029 330.43836 35.779295 331.48882 35.779297 332.89246 curveto 35.779295 334.29155 35.957029 335.342 36.3125 336.04382 curveto 36.672523 336.74109 37.208004 337.08972 37.918945 337.08972 curveto 38.634435 337.08972 39.169916 336.74109 39.525391 336.04382 curveto 39.88541 335.342 40.065423 334.29155 40.06543 332.89246 curveto 40.065423 331.48882 39.88541 330.43836 39.525391 329.74109 curveto 39.169916 329.03927 38.634435 328.68836 37.918945 328.68835 curveto 37.918945 327.5946 moveto 39.06282 327.59461 39.93554 328.04806 40.537109 328.95496 curveto 41.143221 329.85731 41.446281 331.16981 41.446289 332.89246 curveto 41.446281 334.61056 41.143221 335.92306 40.537109 336.82996 curveto 39.93554 337.7323 39.06282 338.18347 37.918945 338.18347 curveto 36.775062 338.18347 35.900063 337.7323 35.293945 336.82996 curveto 34.692382 335.92306 34.391601 334.61056 34.391602 332.89246 curveto 34.391601 331.16981 34.692382 329.85731 35.293945 328.95496 curveto 35.900063 328.04806 36.775062 327.59461 37.918945 327.5946 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 44.023438 336.2489 moveto 45.46582 336.2489 lineto 45.46582 337.42468 lineto 44.344727 339.61218 lineto 43.462891 339.61218 lineto 44.023438 337.42468 lineto 44.023438 336.2489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 51.290039 328.68835 moveto 50.579098 328.68836 50.043617 329.03927 49.683594 329.74109 curveto 49.328123 330.43836 49.150388 331.48882 49.150391 332.89246 curveto 49.150388 334.29155 49.328123 335.342 49.683594 336.04382 curveto 50.043617 336.74109 50.579098 337.08972 51.290039 337.08972 curveto 52.005529 337.08972 52.54101 336.74109 52.896484 336.04382 curveto 53.256504 335.342 53.436517 334.29155 53.436523 332.89246 curveto 53.436517 331.48882 53.256504 330.43836 52.896484 329.74109 curveto 52.54101 329.03927 52.005529 328.68836 51.290039 328.68835 curveto 51.290039 327.5946 moveto 52.433914 327.59461 53.306634 328.04806 53.908203 328.95496 curveto 54.514315 329.85731 54.817375 331.16981 54.817383 332.89246 curveto 54.817375 334.61056 54.514315 335.92306 53.908203 336.82996 curveto 53.306634 337.7323 52.433914 338.18347 51.290039 338.18347 curveto 50.146156 338.18347 49.271156 337.7323 48.665039 336.82996 curveto 48.063475 335.92306 47.762694 334.61056 47.762695 332.89246 curveto 47.762694 331.16981 48.063475 329.85731 48.665039 328.95496 curveto 49.271156 328.04806 50.146156 327.59461 51.290039 327.5946 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 57.394531 336.2489 moveto 58.836914 336.2489 lineto 58.836914 337.42468 lineto 57.71582 339.61218 lineto 56.833984 339.61218 lineto 57.394531 337.42468 lineto 57.394531 336.2489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 64.49707 331.21082 moveto 63.822588 331.21082 63.289385 331.47514 62.897461 332.00378 curveto 62.505532 332.52788 62.309568 333.24793 62.30957 334.16394 curveto 62.309568 335.07996 62.503253 335.80229 62.890625 336.33093 curveto 63.282549 336.85502 63.81803 337.11707 64.49707 337.11707 curveto 65.166987 337.11707 65.697911 336.85274 66.089844 336.3241 curveto 66.481765 335.79545 66.677728 335.0754 66.677734 334.16394 curveto 66.677728 333.25704 66.481765 332.53927 66.089844 332.01062 curveto 65.697911 331.47742 65.166987 331.21082 64.49707 331.21082 curveto 64.49707 330.14441 moveto 65.590815 330.14442 66.449864 330.49989 67.074219 331.21082 curveto 67.69856 331.92176 68.010734 332.90613 68.010742 334.16394 curveto 68.010734 335.4172 67.69856 336.40157 67.074219 337.11707 curveto 66.449864 337.828 65.590815 338.18347 64.49707 338.18347 curveto 63.39876 338.18347 62.537433 337.828 61.913086 337.11707 curveto 61.293293 336.40157 60.983398 335.4172 60.983398 334.16394 curveto 60.983398 332.90613 61.293293 331.92176 61.913086 331.21082 curveto 62.537433 330.49989 63.39876 330.14442 64.49707 330.14441 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 69.890625 327.36218 moveto 70.984375 327.36218 lineto 71.667966 328.43771 72.178382 329.49045 72.515625 330.52039 curveto 72.857418 331.55034 73.028316 332.57345 73.02832 333.58972 curveto 73.028316 334.61056 72.857418 335.63823 72.515625 336.67273 curveto 72.178382 337.70723 71.667966 338.75997 70.984375 339.83093 curveto 69.890625 339.83093 lineto 70.496743 338.78731 70.947914 337.75053 71.244141 336.72058 curveto 71.544919 335.68608 71.69531 334.64246 71.695312 333.58972 curveto 71.69531 332.53699 71.544919 331.49793 71.244141 330.47253 curveto 70.947914 329.44715 70.496743 328.41037 69.890625 327.36218 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 77.683594 328.36218 moveto 77.072913 329.41037 76.619463 330.44715 76.323242 331.47253 curveto 76.027016 332.49793 75.878904 333.53699 75.878906 334.58972 curveto 75.878904 335.64246 76.027016 336.68608 76.323242 337.72058 curveto 76.62402 338.75053 77.07747 339.78731 77.683594 340.83093 curveto 76.589844 340.83093 lineto 75.906247 339.75997 75.393553 338.70723 75.051758 337.67273 curveto 74.714517 336.63823 74.545897 335.61056 74.545898 334.58972 curveto 74.545897 333.57345 74.714517 332.55034 75.051758 331.52039 curveto 75.388995 330.49045 75.90169 329.43771 76.589844 328.36218 curveto 77.683594 328.36218 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 80.547852 337.82312 moveto 82.803711 337.82312 lineto 82.803711 330.03699 lineto 80.349609 330.52917 lineto 80.349609 329.27136 lineto 82.790039 328.77917 lineto 84.170898 328.77917 lineto 84.170898 337.82312 lineto 86.426758 337.82312 lineto 86.426758 338.98523 lineto 80.547852 338.98523 lineto 80.547852 337.82312 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 89.366211 337.2489 moveto 90.808594 337.2489 lineto 90.808594 338.42468 lineto 89.6875 340.61218 lineto 88.805664 340.61218 lineto 89.366211 338.42468 lineto 89.366211 337.2489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 93.918945 337.82312 moveto 96.174805 337.82312 lineto 96.174805 330.03699 lineto 93.720703 330.52917 lineto 93.720703 329.27136 lineto 96.161133 328.77917 lineto 97.541992 328.77917 lineto 97.541992 337.82312 lineto 99.797852 337.82312 lineto 99.797852 338.98523 lineto 93.918945 338.98523 lineto 93.918945 337.82312 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 102.7373 337.2489 moveto 104.17969 337.2489 lineto 104.17969 338.42468 lineto 103.05859 340.61218 lineto 102.17676 340.61218 lineto 102.7373 338.42468 lineto 102.7373 337.2489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 109.83984 332.21082 moveto 109.16536 332.21082 108.63216 332.47514 108.24023 333.00378 curveto 107.8483 333.52788 107.65234 334.24793 107.65234 335.16394 curveto 107.65234 336.07996 107.84603 336.80229 108.2334 337.33093 curveto 108.62532 337.85502 109.1608 338.11707 109.83984 338.11707 curveto 110.50976 338.11707 111.04068 337.85274 111.43262 337.3241 curveto 111.82454 336.79545 112.0205 336.0754 112.02051 335.16394 curveto 112.0205 334.25704 111.82454 333.53927 111.43262 333.01062 curveto 111.04068 332.47742 110.50976 332.21082 109.83984 332.21082 curveto 109.83984 331.14441 moveto 110.93359 331.14442 111.79264 331.49989 112.41699 332.21082 curveto 113.04133 332.92176 113.35351 333.90613 113.35352 335.16394 curveto 113.35351 336.4172 113.04133 337.40157 112.41699 338.11707 curveto 111.79264 338.828 110.93359 339.18347 109.83984 339.18347 curveto 108.74153 339.18347 107.88021 338.828 107.25586 338.11707 curveto 106.63607 337.40157 106.32617 336.4172 106.32617 335.16394 curveto 106.32617 333.90613 106.63607 332.92176 107.25586 332.21082 curveto 107.88021 331.49989 108.74153 331.14442 109.83984 331.14441 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 115.2334 328.36218 moveto 116.32715 328.36218 lineto 117.01074 329.43771 117.52116 330.49045 117.8584 331.52039 curveto 118.20019 332.55034 118.37109 333.57345 118.37109 334.58972 curveto 118.37109 335.61056 118.20019 336.63823 117.8584 337.67273 curveto 117.52116 338.70723 117.01074 339.75997 116.32715 340.83093 curveto 115.2334 340.83093 lineto 115.83952 339.78731 116.29069 338.75053 116.58691 337.72058 curveto 116.88769 336.68608 117.03808 335.64246 117.03809 334.58972 curveto 117.03808 333.53699 116.88769 332.49793 116.58691 331.47253 curveto 116.29069 330.44715 115.83952 329.41037 115.2334 328.36218 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 56.84082 347.36218 moveto 56.230139 348.41037 55.776689 349.44715 55.480469 350.47253 curveto 55.184242 351.49793 55.03613 352.53699 55.036133 353.58972 curveto 55.03613 354.64246 55.184242 355.68608 55.480469 356.72058 curveto 55.781247 357.75053 56.234697 358.78731 56.84082 359.83093 curveto 55.74707 359.83093 lineto 55.063474 358.75997 54.550779 357.70723 54.208984 356.67273 curveto 53.871743 355.63823 53.703124 354.61056 53.703125 353.58972 curveto 53.703124 352.57345 53.871743 351.55034 54.208984 350.52039 curveto 54.546222 349.49045 55.058917 348.43771 55.74707 347.36218 curveto 56.84082 347.36218 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 63.649414 352.4823 moveto 64.310215 352.62358 64.825188 352.91753 65.194336 353.36414 curveto 65.568026 353.81075 65.754875 354.36219 65.754883 355.01843 curveto 65.754875 356.0256 65.408521 356.80489 64.71582 357.35632 curveto 64.023106 357.90776 63.038732 358.18347 61.762695 358.18347 curveto 61.334307 358.18347 60.89225 358.14018 60.436523 358.05359 curveto 59.98535 357.97156 59.518228 357.84623 59.035156 357.67761 curveto 59.035156 356.3446 lineto 59.417967 356.56791 59.837238 356.73653 60.292969 356.85046 curveto 60.748695 356.9644 61.224932 357.02136 61.72168 357.02136 curveto 62.58756 357.02136 63.246088 356.85047 63.697266 356.50867 curveto 64.152989 356.16687 64.380853 355.67013 64.380859 355.01843 curveto 64.380853 354.41687 64.168939 353.94747 63.745117 353.61023 curveto 63.325841 353.26844 62.74023 353.09754 61.988281 353.09753 curveto 60.798828 353.09753 lineto 60.798828 351.96277 lineto 62.042969 351.96277 lineto 62.722 351.96277 63.241531 351.82833 63.601562 351.55945 curveto 63.961583 351.28602 64.141595 350.89409 64.141602 350.38367 curveto 64.141595 349.85959 63.954747 349.45855 63.581055 349.18054 curveto 63.211909 348.898 62.680985 348.75672 61.988281 348.75671 curveto 61.610022 348.75672 61.204424 348.79774 60.771484 348.87976 curveto 60.338539 348.9618 59.862303 349.08941 59.342773 349.26257 curveto 59.342773 348.0321 lineto 59.86686 347.88628 60.356768 347.77691 60.8125 347.70398 curveto 61.272783 347.63107 61.705725 347.59461 62.111328 347.5946 curveto 63.1595 347.59461 63.988926 347.83387 64.599609 348.31238 curveto 65.210279 348.78635 65.515617 349.42892 65.515625 350.24011 curveto 65.515617 350.80522 65.353834 351.28374 65.030273 351.67566 curveto 64.706699 352.06303 64.246413 352.33191 63.649414 352.4823 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 68.523438 356.2489 moveto 69.96582 356.2489 lineto 69.96582 357.42468 lineto 68.844727 359.61218 lineto 67.962891 359.61218 lineto 68.523438 357.42468 lineto 68.523438 356.2489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 77.020508 352.4823 moveto 77.681309 352.62358 78.196282 352.91753 78.56543 353.36414 curveto 78.93912 353.81075 79.125969 354.36219 79.125977 355.01843 curveto 79.125969 356.0256 78.779615 356.80489 78.086914 357.35632 curveto 77.3942 357.90776 76.409826 358.18347 75.133789 358.18347 curveto 74.7054 358.18347 74.263343 358.14018 73.807617 358.05359 curveto 73.356443 357.97156 72.889321 357.84623 72.40625 357.67761 curveto 72.40625 356.3446 lineto 72.789061 356.56791 73.208331 356.73653 73.664062 356.85046 curveto 74.119789 356.9644 74.596025 357.02136 75.092773 357.02136 curveto 75.958654 357.02136 76.617182 356.85047 77.068359 356.50867 curveto 77.524082 356.16687 77.751947 355.67013 77.751953 355.01843 curveto 77.751947 354.41687 77.540033 353.94747 77.116211 353.61023 curveto 76.696935 353.26844 76.111323 353.09754 75.359375 353.09753 curveto 74.169922 353.09753 lineto 74.169922 351.96277 lineto 75.414062 351.96277 lineto 76.093094 351.96277 76.612625 351.82833 76.972656 351.55945 curveto 77.332676 351.28602 77.512689 350.89409 77.512695 350.38367 curveto 77.512689 349.85959 77.32584 349.45855 76.952148 349.18054 curveto 76.583003 348.898 76.052079 348.75672 75.359375 348.75671 curveto 74.981116 348.75672 74.575518 348.79774 74.142578 348.87976 curveto 73.709633 348.9618 73.233397 349.08941 72.713867 349.26257 curveto 72.713867 348.0321 lineto 73.237954 347.88628 73.727862 347.77691 74.183594 347.70398 curveto 74.643877 347.63107 75.076819 347.59461 75.482422 347.5946 curveto 76.530594 347.59461 77.36002 347.83387 77.970703 348.31238 curveto 78.581373 348.78635 78.886711 349.42892 78.886719 350.24011 curveto 78.886711 350.80522 78.724928 351.28374 78.401367 351.67566 curveto 78.077793 352.06303 77.617507 352.33191 77.020508 352.4823 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 81.894531 356.2489 moveto 83.336914 356.2489 lineto 83.336914 357.42468 lineto 82.21582 359.61218 lineto 81.333984 359.61218 lineto 81.894531 357.42468 lineto 81.894531 356.2489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 88.99707 351.21082 moveto 88.322588 351.21082 87.789385 351.47514 87.397461 352.00378 curveto 87.005532 352.52788 86.809568 353.24793 86.80957 354.16394 curveto 86.809568 355.07996 87.003253 355.80229 87.390625 356.33093 curveto 87.782549 356.85502 88.31803 357.11707 88.99707 357.11707 curveto 89.666987 357.11707 90.197911 356.85274 90.589844 356.3241 curveto 90.981765 355.79545 91.177728 355.0754 91.177734 354.16394 curveto 91.177728 353.25704 90.981765 352.53927 90.589844 352.01062 curveto 90.197911 351.47742 89.666987 351.21082 88.99707 351.21082 curveto 88.99707 350.14441 moveto 90.090815 350.14442 90.949864 350.49989 91.574219 351.21082 curveto 92.19856 351.92176 92.510734 352.90613 92.510742 354.16394 curveto 92.510734 355.4172 92.19856 356.40157 91.574219 357.11707 curveto 90.949864 357.828 90.090815 358.18347 88.99707 358.18347 curveto 87.89876 358.18347 87.037433 357.828 86.413086 357.11707 curveto 85.793293 356.40157 85.483398 355.4172 85.483398 354.16394 curveto 85.483398 352.90613 85.793293 351.92176 86.413086 351.21082 curveto 87.037433 350.49989 87.89876 350.14442 88.99707 350.14441 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 94.390625 347.36218 moveto 95.484375 347.36218 lineto 96.167966 348.43771 96.678382 349.49045 97.015625 350.52039 curveto 97.357418 351.55034 97.528316 352.57345 97.52832 353.58972 curveto 97.528316 354.61056 97.357418 355.63823 97.015625 356.67273 curveto 96.678382 357.70723 96.167966 358.75997 95.484375 359.83093 curveto 94.390625 359.83093 lineto 94.996743 358.78731 95.447914 357.75053 95.744141 356.72058 curveto 96.044919 355.68608 96.19531 354.64246 96.195312 353.58972 curveto 96.19531 352.53699 96.044919 351.49793 95.744141 350.47253 curveto 95.447914 349.44715 94.996743 348.41037 94.390625 347.36218 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 102.34082 348.36218 moveto 101.73014 349.41037 101.27669 350.44715 100.98047 351.47253 curveto 100.68424 352.49793 100.53613 353.53699 100.53613 354.58972 curveto 100.53613 355.64246 100.68424 356.68608 100.98047 357.72058 curveto 101.28125 358.75053 101.7347 359.78731 102.34082 360.83093 curveto 101.24707 360.83093 lineto 100.56347 359.75997 100.05078 358.70723 99.708984 357.67273 curveto 99.371743 356.63823 99.203124 355.61056 99.203125 354.58972 curveto 99.203124 353.57345 99.371743 352.55034 99.708984 351.52039 curveto 100.04622 350.49045 100.55892 349.43771 101.24707 348.36218 curveto 102.34082 348.36218 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 108.75977 349.9823 moveto 105.27344 355.43054 lineto 108.75977 355.43054 lineto 108.75977 349.9823 lineto 108.39746 348.77917 moveto 110.13379 348.77917 lineto 110.13379 355.43054 lineto 111.58984 355.43054 lineto 111.58984 356.57898 lineto 110.13379 356.57898 lineto 110.13379 358.98523 lineto 108.75977 358.98523 lineto 108.75977 356.57898 lineto 104.15234 356.57898 lineto 104.15234 355.24597 lineto 108.39746 348.77917 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 114.02344 357.2489 moveto 115.46582 357.2489 lineto 115.46582 358.42468 lineto 114.34473 360.61218 lineto 113.46289 360.61218 lineto 114.02344 358.42468 lineto 114.02344 357.2489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 122.13086 349.9823 moveto 118.64453 355.43054 lineto 122.13086 355.43054 lineto 122.13086 349.9823 lineto 121.76855 348.77917 moveto 123.50488 348.77917 lineto 123.50488 355.43054 lineto 124.96094 355.43054 lineto 124.96094 356.57898 lineto 123.50488 356.57898 lineto 123.50488 358.98523 lineto 122.13086 358.98523 lineto 122.13086 356.57898 lineto 117.52344 356.57898 lineto 117.52344 355.24597 lineto 121.76855 348.77917 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 127.39453 357.2489 moveto 128.83691 357.2489 lineto 128.83691 358.42468 lineto 127.71582 360.61218 lineto 126.83398 360.61218 lineto 127.39453 358.42468 lineto 127.39453 357.2489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 134.49707 352.21082 moveto 133.82259 352.21082 133.28938 352.47514 132.89746 353.00378 curveto 132.50553 353.52788 132.30957 354.24793 132.30957 355.16394 curveto 132.30957 356.07996 132.50325 356.80229 132.89062 357.33093 curveto 133.28255 357.85502 133.81803 358.11707 134.49707 358.11707 curveto 135.16699 358.11707 135.69791 357.85274 136.08984 357.3241 curveto 136.48176 356.79545 136.67773 356.0754 136.67773 355.16394 curveto 136.67773 354.25704 136.48176 353.53927 136.08984 353.01062 curveto 135.69791 352.47742 135.16699 352.21082 134.49707 352.21082 curveto 134.49707 351.14441 moveto 135.59081 351.14442 136.44986 351.49989 137.07422 352.21082 curveto 137.69856 352.92176 138.01073 353.90613 138.01074 355.16394 curveto 138.01073 356.4172 137.69856 357.40157 137.07422 358.11707 curveto 136.44986 358.828 135.59081 359.18347 134.49707 359.18347 curveto 133.39876 359.18347 132.53743 358.828 131.91309 358.11707 curveto 131.29329 357.40157 130.9834 356.4172 130.9834 355.16394 curveto 130.9834 353.90613 131.29329 352.92176 131.91309 352.21082 curveto 132.53743 351.49989 133.39876 351.14442 134.49707 351.14441 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 139.89062 348.36218 moveto 140.98438 348.36218 lineto 141.66797 349.43771 142.17838 350.49045 142.51562 351.52039 curveto 142.85742 352.55034 143.02832 353.57345 143.02832 354.58972 curveto 143.02832 355.61056 142.85742 356.63823 142.51562 357.67273 curveto 142.17838 358.70723 141.66797 359.75997 140.98438 360.83093 curveto 139.89062 360.83093 lineto 140.49674 359.78731 140.94791 358.75053 141.24414 357.72058 curveto 141.54492 356.68608 141.69531 355.64246 141.69531 354.58972 curveto 141.69531 353.53699 141.54492 352.49793 141.24414 351.47253 curveto 140.94791 350.44715 140.49674 349.41037 139.89062 348.36218 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 27.34082 371.86218 moveto 26.730139 372.91037 26.276689 373.94715 25.980469 374.97253 curveto 25.684242 375.99793 25.53613 377.03699 25.536133 378.08972 curveto 25.53613 379.14246 25.684242 380.18608 25.980469 381.22058 curveto 26.281247 382.25053 26.734697 383.28731 27.34082 384.33093 curveto 26.24707 384.33093 lineto 25.563474 383.25997 25.050779 382.20723 24.708984 381.17273 curveto 24.371743 380.13823 24.203124 379.11056 24.203125 378.08972 curveto 24.203124 377.07345 24.371743 376.05034 24.708984 375.02039 curveto 25.046222 373.99045 25.558917 372.93771 26.24707 371.86218 curveto 27.34082 371.86218 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 29.979492 372.27917 moveto 35.400391 372.27917 lineto 35.400391 373.44128 lineto 31.244141 373.44128 lineto 31.244141 375.94324 lineto 31.444658 375.87488 31.645179 375.82475 31.845703 375.79285 curveto 32.04622 375.7564 32.246741 375.73817 32.447266 375.73816 curveto 33.586583 375.73817 34.488926 376.05034 35.154297 376.67468 curveto 35.819654 377.29904 36.152336 378.14441 36.152344 379.21082 curveto 36.152336 380.30912 35.81054 381.16362 35.126953 381.77429 curveto 34.443353 382.38041 33.479487 382.68347 32.235352 382.68347 curveto 31.806963 382.68347 31.369463 382.64701 30.922852 382.5741 curveto 30.480792 382.50118 30.022785 382.39181 29.548828 382.24597 curveto 29.548828 380.85828 lineto 29.958983 381.08159 30.382811 381.24793 30.820312 381.3573 curveto 31.25781 381.46668 31.720374 381.52136 32.208008 381.52136 curveto 32.996415 381.52136 33.620763 381.31401 34.081055 380.89929 curveto 34.541335 380.48458 34.771478 379.92176 34.771484 379.21082 curveto 34.771478 378.49988 34.541335 377.93706 34.081055 377.52234 curveto 33.620763 377.10763 32.996415 376.90027 32.208008 376.90027 curveto 31.838864 376.90027 31.469724 376.94129 31.100586 377.02332 curveto 30.736 377.10535 30.362303 377.23296 29.979492 377.40613 curveto 29.979492 372.27917 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 39.023438 380.7489 moveto 40.46582 380.7489 lineto 40.46582 381.92468 lineto 39.344727 384.11218 lineto 38.462891 384.11218 lineto 39.023438 381.92468 lineto 39.023438 380.7489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 43.350586 372.27917 moveto 48.771484 372.27917 lineto 48.771484 373.44128 lineto 44.615234 373.44128 lineto 44.615234 375.94324 lineto 44.815752 375.87488 45.016273 375.82475 45.216797 375.79285 curveto 45.417314 375.7564 45.617835 375.73817 45.818359 375.73816 curveto 46.957677 375.73817 47.86002 376.05034 48.525391 376.67468 curveto 49.190748 377.29904 49.52343 378.14441 49.523438 379.21082 curveto 49.52343 380.30912 49.181633 381.16362 48.498047 381.77429 curveto 47.814447 382.38041 46.850581 382.68347 45.606445 382.68347 curveto 45.178057 382.68347 44.740557 382.64701 44.293945 382.5741 curveto 43.851886 382.50118 43.393879 382.39181 42.919922 382.24597 curveto 42.919922 380.85828 lineto 43.330077 381.08159 43.753904 381.24793 44.191406 381.3573 curveto 44.628903 381.46668 45.091468 381.52136 45.579102 381.52136 curveto 46.367508 381.52136 46.991857 381.31401 47.452148 380.89929 curveto 47.912429 380.48458 48.142572 379.92176 48.142578 379.21082 curveto 48.142572 378.49988 47.912429 377.93706 47.452148 377.52234 curveto 46.991857 377.10763 46.367508 376.90027 45.579102 376.90027 curveto 45.209958 376.90027 44.840817 376.94129 44.47168 377.02332 curveto 44.107094 377.10535 43.733397 377.23296 43.350586 377.40613 curveto 43.350586 372.27917 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 52.394531 380.7489 moveto 53.836914 380.7489 lineto 53.836914 381.92468 lineto 52.71582 384.11218 lineto 51.833984 384.11218 lineto 52.394531 381.92468 lineto 52.394531 380.7489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 59.49707 375.71082 moveto 58.822588 375.71082 58.289385 375.97514 57.897461 376.50378 curveto 57.505532 377.02788 57.309568 377.74793 57.30957 378.66394 curveto 57.309568 379.57996 57.503253 380.30229 57.890625 380.83093 curveto 58.282549 381.35502 58.81803 381.61707 59.49707 381.61707 curveto 60.166987 381.61707 60.697911 381.35274 61.089844 380.8241 curveto 61.481765 380.29545 61.677728 379.5754 61.677734 378.66394 curveto 61.677728 377.75704 61.481765 377.03927 61.089844 376.51062 curveto 60.697911 375.97742 60.166987 375.71082 59.49707 375.71082 curveto 59.49707 374.64441 moveto 60.590815 374.64442 61.449864 374.99989 62.074219 375.71082 curveto 62.69856 376.42176 63.010734 377.40613 63.010742 378.66394 curveto 63.010734 379.9172 62.69856 380.90157 62.074219 381.61707 curveto 61.449864 382.328 60.590815 382.68347 59.49707 382.68347 curveto 58.39876 382.68347 57.537433 382.328 56.913086 381.61707 curveto 56.293293 380.90157 55.983398 379.9172 55.983398 378.66394 curveto 55.983398 377.40613 56.293293 376.42176 56.913086 375.71082 curveto 57.537433 374.99989 58.39876 374.64442 59.49707 374.64441 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 64.890625 371.86218 moveto 65.984375 371.86218 lineto 66.667966 372.93771 67.178382 373.99045 67.515625 375.02039 curveto 67.857418 376.05034 68.028316 377.07345 68.02832 378.08972 curveto 68.028316 379.11056 67.857418 380.13823 67.515625 381.17273 curveto 67.178382 382.20723 66.667966 383.25997 65.984375 384.33093 curveto 64.890625 384.33093 lineto 65.496743 383.28731 65.947914 382.25053 66.244141 381.22058 curveto 66.544919 380.18608 66.69531 379.14246 66.695312 378.08972 curveto 66.69531 377.03699 66.544919 375.99793 66.244141 374.97253 curveto 65.947914 373.94715 65.496743 372.91037 64.890625 371.86218 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 75.84082 370.86218 moveto 75.230139 371.91037 74.776689 372.94715 74.480469 373.97253 curveto 74.184242 374.99793 74.03613 376.03699 74.036133 377.08972 curveto 74.03613 378.14246 74.184242 379.18608 74.480469 380.22058 curveto 74.781247 381.25053 75.234697 382.28731 75.84082 383.33093 curveto 74.74707 383.33093 lineto 74.063474 382.25997 73.550779 381.20723 73.208984 380.17273 curveto 72.871743 379.13823 72.703124 378.11056 72.703125 377.08972 curveto 72.703124 376.07345 72.871743 375.05034 73.208984 374.02039 curveto 73.546222 372.99045 74.058917 371.93771 74.74707 370.86218 curveto 75.84082 370.86218 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 81.589844 375.83191 moveto 80.970048 375.83191 80.477861 376.04383 80.113281 376.46765 curveto 79.753252 376.89148 79.57324 377.47254 79.573242 378.21082 curveto 79.57324 378.94454 79.753252 379.5256 80.113281 379.95398 curveto 80.477861 380.37781 80.970048 380.58972 81.589844 380.58972 curveto 82.20963 380.58972 82.699539 380.37781 83.05957 379.95398 curveto 83.424147 379.5256 83.606439 378.94454 83.606445 378.21082 curveto 83.606439 377.47254 83.424147 376.89148 83.05957 376.46765 curveto 82.699539 376.04383 82.20963 375.83191 81.589844 375.83191 curveto 84.331055 371.50476 moveto 84.331055 372.76257 lineto 83.984694 372.59852 83.633782 372.47319 83.27832 372.3866 curveto 82.927403 372.30002 82.57877 372.25672 82.232422 372.25671 curveto 81.320959 372.25672 80.623694 372.56434 80.140625 373.17957 curveto 79.662107 373.79481 79.388669 374.72449 79.320312 375.96863 curveto 79.58919 375.57215 79.926429 375.26909 80.332031 375.05945 curveto 80.737626 374.84526 81.184241 374.73817 81.671875 374.73816 curveto 82.69726 374.73817 83.506178 375.05034 84.098633 375.67468 curveto 84.69563 376.29448 84.994133 377.13986 84.994141 378.21082 curveto 84.994133 379.25899 84.684237 380.09981 84.064453 380.73328 curveto 83.444655 381.36674 82.619786 381.68347 81.589844 381.68347 curveto 80.409502 381.68347 79.507159 381.2323 78.882812 380.32996 curveto 78.258462 379.42306 77.946288 378.11056 77.946289 376.39246 curveto 77.946288 374.77918 78.3291 373.49403 79.094727 372.53699 curveto 79.860349 371.57541 80.888017 371.09461 82.177734 371.0946 curveto 82.524083 371.09461 82.872715 371.12879 83.223633 371.19714 curveto 83.579095 371.26551 83.948235 371.36805 84.331055 371.50476 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 87.523438 379.7489 moveto 88.96582 379.7489 lineto 88.96582 380.92468 lineto 87.844727 383.11218 lineto 86.962891 383.11218 lineto 87.523438 380.92468 lineto 87.523438 379.7489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 94.960938 375.83191 moveto 94.341142 375.83191 93.848955 376.04383 93.484375 376.46765 curveto 93.124346 376.89148 92.944333 377.47254 92.944336 378.21082 curveto 92.944333 378.94454 93.124346 379.5256 93.484375 379.95398 curveto 93.848955 380.37781 94.341142 380.58972 94.960938 380.58972 curveto 95.580724 380.58972 96.070632 380.37781 96.430664 379.95398 curveto 96.795241 379.5256 96.977532 378.94454 96.977539 378.21082 curveto 96.977532 377.47254 96.795241 376.89148 96.430664 376.46765 curveto 96.070632 376.04383 95.580724 375.83191 94.960938 375.83191 curveto 97.702148 371.50476 moveto 97.702148 372.76257 lineto 97.355787 372.59852 97.004876 372.47319 96.649414 372.3866 curveto 96.298497 372.30002 95.949864 372.25672 95.603516 372.25671 curveto 94.692053 372.25672 93.994788 372.56434 93.511719 373.17957 curveto 93.0332 373.79481 92.759763 374.72449 92.691406 375.96863 curveto 92.960284 375.57215 93.297523 375.26909 93.703125 375.05945 curveto 94.10872 374.84526 94.555334 374.73817 95.042969 374.73816 curveto 96.068354 374.73817 96.877272 375.05034 97.469727 375.67468 curveto 98.066724 376.29448 98.365226 377.13986 98.365234 378.21082 curveto 98.365226 379.25899 98.055331 380.09981 97.435547 380.73328 curveto 96.815749 381.36674 95.99088 381.68347 94.960938 381.68347 curveto 93.780596 381.68347 92.878253 381.2323 92.253906 380.32996 curveto 91.629556 379.42306 91.317382 378.11056 91.317383 376.39246 curveto 91.317382 374.77918 91.700194 373.49403 92.46582 372.53699 curveto 93.231442 371.57541 94.259111 371.09461 95.548828 371.0946 curveto 95.895177 371.09461 96.243809 371.12879 96.594727 371.19714 curveto 96.950189 371.26551 97.319329 371.36805 97.702148 371.50476 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 100.89453 379.7489 moveto 102.33691 379.7489 lineto 102.33691 380.92468 lineto 101.21582 383.11218 lineto 100.33398 383.11218 lineto 100.89453 380.92468 lineto 100.89453 379.7489 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 110.06836 377.56824 moveto 110.06835 376.65678 109.87923 375.9504 109.50098 375.4491 curveto 109.12727 374.9478 108.60091 374.69715 107.92188 374.69714 curveto 107.24739 374.69715 106.72103 374.9478 106.34277 375.4491 curveto 105.96907 375.9504 105.78222 376.65678 105.78223 377.56824 curveto 105.78222 378.47514 105.96907 379.17924 106.34277 379.68054 curveto 106.72103 380.18185 107.24739 380.4325 107.92188 380.4325 curveto 108.60091 380.4325 109.12727 380.18185 109.50098 379.68054 curveto 109.87923 379.17924 110.06835 378.47514 110.06836 377.56824 curveto 111.32617 380.53503 moveto 111.32616 381.83842 111.03678 382.80684 110.45801 383.44031 curveto 109.87923 384.07833 108.99283 384.39734 107.79883 384.39734 curveto 107.35677 384.39734 106.93978 384.36316 106.54785 384.2948 curveto 106.15592 384.23099 105.77539 384.13073 105.40625 383.99402 curveto 105.40625 382.77039 lineto 105.77539 382.97091 106.13997 383.11902 106.5 383.21472 curveto 106.86002 383.31042 107.22688 383.35827 107.60059 383.35828 curveto 108.42545 383.35827 109.04296 383.1418 109.45312 382.70886 curveto 109.86328 382.28048 110.06835 381.63106 110.06836 380.76062 curveto 110.06836 380.13855 lineto 109.80859 380.58972 109.47591 380.92696 109.07031 381.15027 curveto 108.66471 381.37358 108.17936 381.48523 107.61426 381.48523 curveto 106.67545 381.48523 105.91894 381.12748 105.34473 380.41199 curveto 104.77051 379.69649 104.4834 378.74858 104.4834 377.56824 curveto 104.4834 376.38335 104.77051 375.43315 105.34473 374.71765 curveto 105.91894 374.00216 106.67545 373.64442 107.61426 373.64441 curveto 108.17936 373.64442 108.66471 373.75607 109.07031 373.97937 curveto 109.47591 374.20268 109.80859 374.53992 110.06836 374.99109 curveto 110.06836 373.82898 lineto 111.32617 373.82898 lineto 111.32617 380.53503 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 113.71875 370.86218 moveto 114.8125 370.86218 lineto 115.49609 371.93771 116.00651 372.99045 116.34375 374.02039 curveto 116.68554 375.05034 116.85644 376.07345 116.85645 377.08972 curveto 116.85644 378.11056 116.68554 379.13823 116.34375 380.17273 curveto 116.00651 381.20723 115.49609 382.25997 114.8125 383.33093 curveto 113.71875 383.33093 lineto 114.32487 382.28731 114.77604 381.25053 115.07227 380.22058 curveto 115.37304 379.18608 115.52343 378.14246 115.52344 377.08972 curveto 115.52343 376.03699 115.37304 374.99793 115.07227 373.97253 curveto 114.77604 372.94715 114.32487 371.91037 113.71875 370.86218 curveto fill grestore gsave [1.04082 0 0 0.999696 -220.2817 5.106745] concat 0 0 0 setrgbcolor [] 0 setdash 1.5 setlinewidth 0 setlinejoin 0 setlinecap newpath 349.5 351.36218 moveto 349.5 378.68618 319.484 400.86218 282.5 400.86218 curveto 245.516 400.86218 215.5 378.68618 215.5 351.36218 curveto 215.5 324.03818 245.516 301.86218 282.5 301.86218 curveto 319.484 301.86218 349.5 324.03818 349.5 351.36218 curveto closepath stroke grestore gsave 0 0 0 setrgbcolor newpath 66.874023 311.95789 moveto 68.254883 311.95789 lineto 68.254883 322.16394 lineto 66.874023 322.16394 lineto 66.874023 311.95789 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 75.829102 314.73328 moveto 75.829102 315.92273 lineto 75.473627 315.74044 75.104487 315.60373 74.72168 315.51257 curveto 74.338862 315.42143 73.942378 315.37586 73.532227 315.37585 curveto 72.907874 315.37586 72.438474 315.47156 72.124023 315.66296 curveto 71.814125 315.85438 71.659178 316.14149 71.65918 316.52429 curveto 71.659178 316.81596 71.770831 317.04611 71.994141 317.21472 curveto 72.217445 317.37879 72.666338 317.53602 73.34082 317.6864 curveto 73.771484 317.7821 lineto 74.664709 317.97351 75.298171 318.24467 75.671875 318.59558 curveto 76.050124 318.94194 76.239251 319.42729 76.239258 320.05164 curveto 76.239251 320.76257 75.956699 321.3254 75.391602 321.74011 curveto 74.831049 322.15483 74.058589 322.36218 73.074219 322.36218 curveto 72.664059 322.36218 72.235674 322.32117 71.789062 322.23914 curveto 71.347003 322.16166 70.879882 322.04317 70.387695 321.88367 curveto 70.387695 320.58484 lineto 70.852538 320.82638 71.310545 321.00867 71.761719 321.13171 curveto 72.212888 321.2502 72.659502 321.30945 73.101562 321.30945 curveto 73.694006 321.30945 74.149735 321.20919 74.46875 321.00867 curveto 74.787755 320.80359 74.94726 320.51648 74.947266 320.14734 curveto 74.94726 319.80554 74.831049 319.5435 74.598633 319.36121 curveto 74.370763 319.17892 73.867183 319.00346 73.087891 318.83484 curveto 72.650391 318.7323 lineto 71.871092 318.56824 71.308267 318.31759 70.961914 317.98035 curveto 70.615559 317.63855 70.442382 317.17143 70.442383 316.57898 curveto 70.442382 315.85893 70.69759 315.30294 71.208008 314.91101 curveto 71.718422 314.51909 72.443031 314.32313 73.381836 314.32312 curveto 73.846675 314.32313 74.284175 314.35731 74.694336 314.42566 curveto 75.104487 314.49403 75.482742 314.59657 75.829102 314.73328 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 6.3125 439.27167 moveto 5.7018192 440.31985 5.2483691 441.35664 4.9521484 442.38202 curveto 4.6559218 443.40742 4.50781 444.44648 4.5078125 445.49921 curveto 4.50781 446.55194 4.6559218 447.59556 4.9521484 448.63007 curveto 5.2529264 449.66001 5.7063765 450.6968 6.3125 451.74042 curveto 5.21875 451.74042 lineto 4.5351537 450.66945 4.0224589 449.61672 3.6806641 448.58221 curveto 3.3434231 447.54771 3.1748035 446.52004 3.1748047 445.49921 curveto 3.1748035 444.48294 3.3434231 443.45982 3.6806641 442.42987 curveto 4.0179016 441.39993 4.5305964 440.3472 5.21875 439.27167 curveto 6.3125 439.27167 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 11.890625 440.59784 moveto 11.179684 440.59785 10.644203 440.94876 10.28418 441.65057 curveto 9.9287084 442.34785 9.7509743 443.3983 9.7509766 444.80194 curveto 9.7509743 446.20103 9.9287084 447.25149 10.28418 447.95331 curveto 10.644203 448.65057 11.179684 448.99921 11.890625 448.99921 curveto 12.606115 448.99921 13.141596 448.65057 13.49707 447.95331 curveto 13.85709 447.25149 14.037103 446.20103 14.037109 444.80194 curveto 14.037103 443.3983 13.85709 442.34785 13.49707 441.65057 curveto 13.141596 440.94876 12.606115 440.59785 11.890625 440.59784 curveto 11.890625 439.50409 moveto 13.0345 439.5041 13.90722 439.95755 14.508789 440.86444 curveto 15.114901 441.76679 15.417961 443.07929 15.417969 444.80194 curveto 15.417961 446.52004 15.114901 447.83254 14.508789 448.73944 curveto 13.90722 449.64178 13.0345 450.09296 11.890625 450.09296 curveto 10.746741 450.09296 9.8717424 449.64178 9.265625 448.73944 curveto 8.6640613 447.83254 8.3632803 446.52004 8.3632812 444.80194 curveto 8.3632803 443.07929 8.6640613 441.76679 9.265625 440.86444 curveto 9.8717424 439.95755 10.746741 439.5041 11.890625 439.50409 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 17.995117 448.15839 moveto 19.4375 448.15839 lineto 19.4375 449.33417 lineto 18.316406 451.52167 lineto 17.43457 451.52167 lineto 17.995117 449.33417 lineto 17.995117 448.15839 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 25.261719 440.59784 moveto 24.550778 440.59785 24.015296 440.94876 23.655273 441.65057 curveto 23.299802 442.34785 23.122068 443.3983 23.12207 444.80194 curveto 23.122068 446.20103 23.299802 447.25149 23.655273 447.95331 curveto 24.015296 448.65057 24.550778 448.99921 25.261719 448.99921 curveto 25.977208 448.99921 26.51269 448.65057 26.868164 447.95331 curveto 27.228184 447.25149 27.408197 446.20103 27.408203 444.80194 curveto 27.408197 443.3983 27.228184 442.34785 26.868164 441.65057 curveto 26.51269 440.94876 25.977208 440.59785 25.261719 440.59784 curveto 25.261719 439.50409 moveto 26.405593 439.5041 27.278314 439.95755 27.879883 440.86444 curveto 28.485995 441.76679 28.789055 443.07929 28.789062 444.80194 curveto 28.789055 446.52004 28.485995 447.83254 27.879883 448.73944 curveto 27.278314 449.64178 26.405593 450.09296 25.261719 450.09296 curveto 24.117835 450.09296 23.242836 449.64178 22.636719 448.73944 curveto 22.035155 447.83254 21.734374 446.52004 21.734375 444.80194 curveto 21.734374 443.07929 22.035155 441.76679 22.636719 440.86444 curveto 23.242836 439.95755 24.117835 439.5041 25.261719 439.50409 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 31.366211 448.15839 moveto 32.808594 448.15839 lineto 32.808594 449.33417 lineto 31.6875 451.52167 lineto 30.805664 451.52167 lineto 31.366211 449.33417 lineto 31.366211 448.15839 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 38.46875 443.1203 moveto 37.794267 443.12031 37.261065 443.38463 36.869141 443.91327 curveto 36.477211 444.43736 36.281248 445.15741 36.28125 446.07343 curveto 36.281248 446.98944 36.474933 447.71177 36.862305 448.24042 curveto 37.254229 448.76451 37.78971 449.02655 38.46875 449.02655 curveto 39.138667 449.02655 39.669591 448.76223 40.061523 448.23358 curveto 40.453444 447.70494 40.649408 446.98489 40.649414 446.07343 curveto 40.649408 445.16653 40.453444 444.44876 40.061523 443.9201 curveto 39.669591 443.38691 39.138667 443.12031 38.46875 443.1203 curveto 38.46875 442.05389 moveto 39.562495 442.0539 40.421543 442.40937 41.045898 443.1203 curveto 41.67024 443.83124 41.982414 444.81562 41.982422 446.07343 curveto 41.982414 447.32668 41.67024 448.31106 41.045898 449.02655 curveto 40.421543 449.73749 39.562495 450.09296 38.46875 450.09296 curveto 37.37044 450.09296 36.509112 449.73749 35.884766 449.02655 curveto 35.264973 448.31106 34.955077 447.32668 34.955078 446.07343 curveto 34.955077 444.81562 35.264973 443.83124 35.884766 443.1203 curveto 36.509112 442.40937 37.37044 442.0539 38.46875 442.05389 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 43.862305 439.27167 moveto 44.956055 439.27167 lineto 45.639646 440.3472 46.150062 441.39993 46.487305 442.42987 curveto 46.829097 443.45982 46.999996 444.48294 47 445.49921 curveto 46.999996 446.52004 46.829097 447.54771 46.487305 448.58221 curveto 46.150062 449.61672 45.639646 450.66945 44.956055 451.74042 curveto 43.862305 451.74042 lineto 44.468423 450.6968 44.919594 449.66001 45.21582 448.63007 curveto 45.516599 447.59556 45.666989 446.55194 45.666992 445.49921 curveto 45.666989 444.44648 45.516599 443.40742 45.21582 442.38202 curveto 44.919594 441.35664 44.468423 440.31985 43.862305 439.27167 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 51.951172 439.27167 moveto 51.340491 440.31985 50.887041 441.35664 50.59082 442.38202 curveto 50.294594 443.40742 50.146482 444.44648 50.146484 445.49921 curveto 50.146482 446.55194 50.294594 447.59556 50.59082 448.63007 curveto 50.891598 449.66001 51.345048 450.6968 51.951172 451.74042 curveto 50.857422 451.74042 lineto 50.173826 450.66945 49.661131 449.61672 49.319336 448.58221 curveto 48.982095 447.54771 48.813475 446.52004 48.813477 445.49921 curveto 48.813475 444.48294 48.982095 443.45982 49.319336 442.42987 curveto 49.656573 441.39993 50.169268 440.3472 50.857422 439.27167 curveto 51.951172 439.27167 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 54.81543 448.7326 moveto 57.071289 448.7326 lineto 57.071289 440.94647 lineto 54.617188 441.43866 lineto 54.617188 440.18085 lineto 57.057617 439.68866 lineto 58.438477 439.68866 lineto 58.438477 448.7326 lineto 60.694336 448.7326 lineto 60.694336 449.89471 lineto 54.81543 449.89471 lineto 54.81543 448.7326 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 63.633789 448.15839 moveto 65.076172 448.15839 lineto 65.076172 449.33417 lineto 63.955078 451.52167 lineto 63.073242 451.52167 lineto 63.633789 449.33417 lineto 63.633789 448.15839 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 68.186523 448.7326 moveto 70.442383 448.7326 lineto 70.442383 440.94647 lineto 67.988281 441.43866 lineto 67.988281 440.18085 lineto 70.428711 439.68866 lineto 71.80957 439.68866 lineto 71.80957 448.7326 lineto 74.06543 448.7326 lineto 74.06543 449.89471 lineto 68.186523 449.89471 lineto 68.186523 448.7326 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 77.004883 448.15839 moveto 78.447266 448.15839 lineto 78.447266 449.33417 lineto 77.326172 451.52167 lineto 76.444336 451.52167 lineto 77.004883 449.33417 lineto 77.004883 448.15839 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 84.107422 443.1203 moveto 83.432939 443.12031 82.899737 443.38463 82.507812 443.91327 curveto 82.115883 444.43736 81.91992 445.15741 81.919922 446.07343 curveto 81.91992 446.98944 82.113604 447.71177 82.500977 448.24042 curveto 82.892901 448.76451 83.428382 449.02655 84.107422 449.02655 curveto 84.777339 449.02655 85.308263 448.76223 85.700195 448.23358 curveto 86.092116 447.70494 86.288079 446.98489 86.288086 446.07343 curveto 86.288079 445.16653 86.092116 444.44876 85.700195 443.9201 curveto 85.308263 443.38691 84.777339 443.12031 84.107422 443.1203 curveto 84.107422 442.05389 moveto 85.201166 442.0539 86.060215 442.40937 86.68457 443.1203 curveto 87.308912 443.83124 87.621086 444.81562 87.621094 446.07343 curveto 87.621086 447.32668 87.308912 448.31106 86.68457 449.02655 curveto 86.060215 449.73749 85.201166 450.09296 84.107422 450.09296 curveto 83.009111 450.09296 82.147784 449.73749 81.523438 449.02655 curveto 80.903645 448.31106 80.593749 447.32668 80.59375 446.07343 curveto 80.593749 444.81562 80.903645 443.83124 81.523438 443.1203 curveto 82.147784 442.40937 83.009111 442.0539 84.107422 442.05389 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 89.500977 439.27167 moveto 90.594727 439.27167 lineto 91.278317 440.3472 91.788734 441.39993 92.125977 442.42987 curveto 92.467769 443.45982 92.638668 444.48294 92.638672 445.49921 curveto 92.638668 446.52004 92.467769 447.54771 92.125977 448.58221 curveto 91.788734 449.61672 91.278317 450.66945 90.594727 451.74042 curveto 89.500977 451.74042 lineto 90.107095 450.6968 90.558266 449.66001 90.854492 448.63007 curveto 91.155271 447.59556 91.305661 446.55194 91.305664 445.49921 curveto 91.305661 444.44648 91.155271 443.40742 90.854492 442.38202 curveto 90.558266 441.35664 90.107095 440.31985 89.500977 439.27167 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 51.951172 458.80682 moveto 51.340491 459.85501 50.887041 460.89179 50.59082 461.91718 curveto 50.294594 462.94257 50.146482 463.98163 50.146484 465.03436 curveto 50.146482 466.0871 50.294594 467.13072 50.59082 468.16522 curveto 50.891598 469.19517 51.345048 470.23195 51.951172 471.27557 curveto 50.857422 471.27557 lineto 50.173826 470.20461 49.661131 469.15188 49.319336 468.11737 curveto 48.982095 467.08287 48.813475 466.0552 48.813477 465.03436 curveto 48.813475 464.01809 48.982095 462.99498 49.319336 461.96503 curveto 49.656573 460.93509 50.169268 459.88235 50.857422 458.80682 curveto 51.951172 458.80682 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 54.589844 459.22382 moveto 60.010742 459.22382 lineto 60.010742 460.38593 lineto 55.854492 460.38593 lineto 55.854492 462.88788 lineto 56.05501 462.81953 56.255531 462.7694 56.456055 462.73749 curveto 56.656572 462.70104 56.857093 462.68281 57.057617 462.6828 curveto 58.196935 462.68281 59.099278 462.99498 59.764648 463.61932 curveto 60.430006 464.24368 60.762688 465.08905 60.762695 466.15546 curveto 60.762688 467.25377 60.420891 468.10826 59.737305 468.71893 curveto 59.053705 469.32505 58.089839 469.62811 56.845703 469.62811 curveto 56.417314 469.62811 55.979815 469.59165 55.533203 469.51874 curveto 55.091144 469.44582 54.633136 469.33645 54.15918 469.19061 curveto 54.15918 467.80292 lineto 54.569334 468.02623 54.993162 468.19257 55.430664 468.30194 curveto 55.868161 468.41132 56.330726 468.466 56.818359 468.466 curveto 57.606766 468.466 58.231115 468.25865 58.691406 467.84393 curveto 59.151687 467.42922 59.38183 466.8664 59.381836 466.15546 curveto 59.38183 465.44452 59.151687 464.8817 58.691406 464.46698 curveto 58.231115 464.05227 57.606766 463.84492 56.818359 463.84491 curveto 56.449215 463.84492 56.080075 463.88593 55.710938 463.96796 curveto 55.346352 464.04999 54.972654 464.1776 54.589844 464.35077 curveto 54.589844 459.22382 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 63.633789 467.69354 moveto 65.076172 467.69354 lineto 65.076172 468.86932 lineto 63.955078 471.05682 lineto 63.073242 471.05682 lineto 63.633789 468.86932 lineto 63.633789 467.69354 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 71.741211 460.42694 moveto 68.254883 465.87518 lineto 71.741211 465.87518 lineto 71.741211 460.42694 lineto 71.378906 459.22382 moveto 73.115234 459.22382 lineto 73.115234 465.87518 lineto 74.571289 465.87518 lineto 74.571289 467.02362 lineto 73.115234 467.02362 lineto 73.115234 469.42987 lineto 71.741211 469.42987 lineto 71.741211 467.02362 lineto 67.133789 467.02362 lineto 67.133789 465.69061 lineto 71.378906 459.22382 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 77.004883 467.69354 moveto 78.447266 467.69354 lineto 78.447266 468.86932 lineto 77.326172 471.05682 lineto 76.444336 471.05682 lineto 77.004883 468.86932 lineto 77.004883 467.69354 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 86.178711 465.51288 moveto 86.178705 464.60142 85.989577 463.89505 85.611328 463.39374 curveto 85.237625 462.89244 84.711258 462.64179 84.032227 462.64178 curveto 83.357744 462.64179 82.831377 462.89244 82.453125 463.39374 curveto 82.079425 463.89505 81.892576 464.60142 81.892578 465.51288 curveto 81.892576 466.41978 82.079425 467.12388 82.453125 467.62518 curveto 82.831377 468.12649 83.357744 468.37714 84.032227 468.37714 curveto 84.711258 468.37714 85.237625 468.12649 85.611328 467.62518 curveto 85.989577 467.12388 86.178705 466.41978 86.178711 465.51288 curveto 87.436523 468.47968 moveto 87.436516 469.78306 87.147128 470.75148 86.568359 471.38495 curveto 85.989577 472.02297 85.103185 472.34198 83.90918 472.34198 curveto 83.467119 472.34198 83.050127 472.3078 82.658203 472.23944 curveto 82.266274 472.17564 81.88574 472.07538 81.516602 471.93866 curveto 81.516602 470.71503 lineto 81.88574 470.91555 82.250323 471.06366 82.610352 471.15936 curveto 82.970374 471.25506 83.337236 471.30292 83.710938 471.30292 curveto 84.535803 471.30292 85.153315 471.08644 85.563477 470.6535 curveto 85.973627 470.22512 86.178705 469.5757 86.178711 468.70526 curveto 86.178711 468.08319 lineto 85.918939 468.53436 85.586257 468.8716 85.180664 469.09491 curveto 84.77506 469.31822 84.289709 469.42987 83.724609 469.42987 curveto 82.785804 469.42987 82.029295 469.07212 81.455078 468.35663 curveto 80.880858 467.64114 80.593749 466.69322 80.59375 465.51288 curveto 80.593749 464.32799 80.880858 463.37779 81.455078 462.66229 curveto 82.029295 461.94681 82.785804 461.58906 83.724609 461.58905 curveto 84.289709 461.58906 84.77506 461.70071 85.180664 461.92401 curveto 85.586257 462.14733 85.918939 462.48457 86.178711 462.93573 curveto 86.178711 461.77362 lineto 87.436523 461.77362 lineto 87.436523 468.47968 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 89.829102 458.80682 moveto 90.922852 458.80682 lineto 91.606442 459.88235 92.116859 460.93509 92.454102 461.96503 curveto 92.795894 462.99498 92.966793 464.01809 92.966797 465.03436 curveto 92.966793 466.0552 92.795894 467.08287 92.454102 468.11737 curveto 92.116859 469.15188 91.606442 470.20461 90.922852 471.27557 curveto 89.829102 471.27557 lineto 90.43522 470.23195 90.886391 469.19517 91.182617 468.16522 curveto 91.483396 467.13072 91.633786 466.0871 91.633789 465.03436 curveto 91.633786 463.98163 91.483396 462.94257 91.182617 461.91718 curveto 90.886391 460.89179 90.43522 459.85501 89.829102 458.80682 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 97.405273 439.73846 moveto 96.794593 440.78665 96.341143 441.82343 96.044922 442.84882 curveto 95.748695 443.87421 95.600583 444.91327 95.600586 445.966 curveto 95.600583 447.01874 95.748695 448.06236 96.044922 449.09686 curveto 96.3457 450.12681 96.79915 451.16359 97.405273 452.20721 curveto 96.311523 452.20721 lineto 95.627927 451.13625 95.115232 450.08352 94.773438 449.04901 curveto 94.436197 448.01451 94.267577 446.98684 94.267578 445.966 curveto 94.267577 444.94973 94.436197 443.92662 94.773438 442.89667 curveto 95.110675 441.86673 95.62337 440.81399 96.311523 439.73846 curveto 97.405273 439.73846 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 101.21973 449.1994 moveto 106.03906 449.1994 lineto 106.03906 450.36151 lineto 99.558594 450.36151 lineto 99.558594 449.1994 lineto 100.08268 448.65709 100.7959 447.9302 101.69824 447.01874 curveto 102.60514 446.10273 103.1748 445.51256 103.40723 445.24823 curveto 103.84928 444.75149 104.1569 444.33222 104.33008 443.99042 curveto 104.50781 443.64407 104.59667 443.30455 104.59668 442.97186 curveto 104.59667 442.42955 104.40527 441.9875 104.02246 441.64569 curveto 103.6442 441.3039 103.14973 441.133 102.53906 441.133 curveto 102.10612 441.133 101.64811 441.2082 101.16504 441.35858 curveto 100.68652 441.50898 100.17383 441.73685 99.626953 442.04218 curveto 99.626953 440.64764 lineto 100.18294 440.42435 100.70247 440.25573 101.18555 440.14178 curveto 101.66862 440.02786 102.11067 439.9709 102.51172 439.97089 curveto 103.56901 439.9709 104.4121 440.23522 105.04102 440.76385 curveto 105.66991 441.29251 105.98437 441.99889 105.98438 442.883 curveto 105.98437 443.30227 105.90462 443.70104 105.74512 444.07928 curveto 105.59016 444.45299 105.30533 444.89505 104.89062 445.40546 curveto 104.77669 445.53762 104.41438 445.92043 103.80371 446.55389 curveto 103.19303 447.1828 102.3317 448.06464 101.21973 449.1994 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 109.08789 448.62518 moveto 110.53027 448.62518 lineto 110.53027 449.80096 lineto 109.40918 451.98846 lineto 108.52734 451.98846 lineto 109.08789 449.80096 lineto 109.08789 448.62518 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 114.59082 449.1994 moveto 119.41016 449.1994 lineto 119.41016 450.36151 lineto 112.92969 450.36151 lineto 112.92969 449.1994 lineto 113.45377 448.65709 114.16699 447.9302 115.06934 447.01874 curveto 115.97623 446.10273 116.54589 445.51256 116.77832 445.24823 curveto 117.22037 444.75149 117.52799 444.33222 117.70117 443.99042 curveto 117.8789 443.64407 117.96777 443.30455 117.96777 442.97186 curveto 117.96777 442.42955 117.77636 441.9875 117.39355 441.64569 curveto 117.01529 441.3039 116.52083 441.133 115.91016 441.133 curveto 115.47721 441.133 115.0192 441.2082 114.53613 441.35858 curveto 114.05762 441.50898 113.54492 441.73685 112.99805 442.04218 curveto 112.99805 440.64764 lineto 113.55403 440.42435 114.07357 440.25573 114.55664 440.14178 curveto 115.03971 440.02786 115.48177 439.9709 115.88281 439.97089 curveto 116.9401 439.9709 117.7832 440.23522 118.41211 440.76385 curveto 119.04101 441.29251 119.35546 441.99889 119.35547 442.883 curveto 119.35546 443.30227 119.27571 443.70104 119.11621 444.07928 curveto 118.96126 444.45299 118.67643 444.89505 118.26172 445.40546 curveto 118.14778 445.53762 117.78548 445.92043 117.1748 446.55389 curveto 116.56412 447.1828 115.7028 448.06464 114.59082 449.1994 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 122.45898 448.62518 moveto 123.90137 448.62518 lineto 123.90137 449.80096 lineto 122.78027 451.98846 lineto 121.89844 451.98846 lineto 122.45898 449.80096 lineto 122.45898 448.62518 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 129.56152 443.5871 moveto 128.88704 443.5871 128.35384 443.85143 127.96191 444.38007 curveto 127.56998 444.90416 127.37402 445.62421 127.37402 446.54022 curveto 127.37402 447.45624 127.56771 448.17857 127.95508 448.70721 curveto 128.347 449.2313 128.88248 449.49335 129.56152 449.49335 curveto 130.23144 449.49335 130.76236 449.22903 131.1543 448.70038 curveto 131.54622 448.17173 131.74218 447.45168 131.74219 446.54022 curveto 131.74218 445.63333 131.54622 444.91555 131.1543 444.3869 curveto 130.76236 443.85371 130.23144 443.5871 129.56152 443.5871 curveto 129.56152 442.52069 moveto 130.65527 442.5207 131.51432 442.87617 132.13867 443.5871 curveto 132.76301 444.29804 133.07519 445.28241 133.0752 446.54022 curveto 133.07519 447.79348 132.76301 448.77785 132.13867 449.49335 curveto 131.51432 450.20428 130.65527 450.55975 129.56152 450.55975 curveto 128.46321 450.55975 127.60189 450.20428 126.97754 449.49335 curveto 126.35775 448.77785 126.04785 447.79348 126.04785 446.54022 curveto 126.04785 445.28241 126.35775 444.29804 126.97754 443.5871 curveto 127.60189 442.87617 128.46321 442.5207 129.56152 442.52069 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 134.95508 439.73846 moveto 136.04883 439.73846 lineto 136.73242 440.81399 137.24284 441.86673 137.58008 442.89667 curveto 137.92187 443.92662 138.09277 444.94973 138.09277 445.966 curveto 138.09277 446.98684 137.92187 448.01451 137.58008 449.04901 curveto 137.24284 450.08352 136.73242 451.13625 136.04883 452.20721 curveto 134.95508 452.20721 lineto 135.5612 451.16359 136.01237 450.12681 136.30859 449.09686 curveto 136.60937 448.06236 136.75976 447.01874 136.75977 445.966 curveto 136.75976 444.91327 136.60937 443.87421 136.30859 442.84882 curveto 136.01237 441.82343 135.5612 440.78665 134.95508 439.73846 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 5.1376953 458.27362 moveto 4.5270145 459.32181 4.0735644 460.35859 3.7773438 461.38397 curveto 3.4811171 462.40937 3.3330053 463.44843 3.3330078 464.50116 curveto 3.3330053 465.5539 3.4811171 466.59752 3.7773438 467.63202 curveto 4.0781217 468.66197 4.5315718 469.69875 5.1376953 470.74237 curveto 4.0439453 470.74237 lineto 3.360349 469.67141 2.8476542 468.61867 2.5058594 467.58417 curveto 2.1686184 466.54966 1.9999988 465.522 2 464.50116 curveto 1.9999988 463.48489 2.1686184 462.46178 2.5058594 461.43182 curveto 2.8430969 460.40188 3.3557917 459.34915 4.0439453 458.27362 curveto 5.1376953 458.27362 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 11.946289 463.39374 moveto 12.60709 463.53502 13.122063 463.82896 13.491211 464.27557 curveto 13.864901 464.72219 14.05175 465.27362 14.051758 465.92987 curveto 14.05175 466.93703 13.705396 467.71633 13.012695 468.26776 curveto 12.319981 468.81919 11.335607 469.09491 10.05957 469.09491 curveto 9.6311815 469.09491 9.1891247 469.05162 8.7333984 468.96503 curveto 8.2822245 468.883 7.8151026 468.75767 7.3320312 468.58905 curveto 7.3320312 467.25604 lineto 7.7148423 467.47935 8.1341127 467.64797 8.5898438 467.7619 curveto 9.0455701 467.87584 9.5218066 467.9328 10.018555 467.9328 curveto 10.884435 467.9328 11.542963 467.7619 11.994141 467.4201 curveto 12.449864 467.07831 12.677728 466.58157 12.677734 465.92987 curveto 12.677728 465.32831 12.465814 464.85891 12.041992 464.52167 curveto 11.622716 464.17988 11.037105 464.00898 10.285156 464.00897 curveto 9.0957031 464.00897 lineto 9.0957031 462.87421 lineto 10.339844 462.87421 lineto 11.018875 462.87421 11.538406 462.73977 11.898438 462.47089 curveto 12.258458 462.19746 12.43847 461.80553 12.438477 461.2951 curveto 12.43847 460.77102 12.251622 460.36998 11.87793 460.09198 curveto 11.508784 459.80944 10.97786 459.66816 10.285156 459.66815 curveto 9.9068974 459.66816 9.5012988 459.70918 9.0683594 459.7912 curveto 8.6354143 459.87324 8.1591778 460.00084 7.6396484 460.17401 curveto 7.6396484 458.94354 lineto 8.1637351 458.79772 8.6536434 458.68834 9.109375 458.61542 curveto 9.5696582 458.54251 10.0026 458.50605 10.408203 458.50604 curveto 11.456375 458.50605 12.285801 458.74531 12.896484 459.22382 curveto 13.507154 459.69778 13.812492 460.34036 13.8125 461.15155 curveto 13.812492 461.71666 13.650709 462.19518 13.327148 462.5871 curveto 13.003574 462.97447 12.543288 463.24335 11.946289 463.39374 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 16.820312 467.16034 moveto 18.262695 467.16034 lineto 18.262695 468.33612 lineto 17.141602 470.52362 lineto 16.259766 470.52362 lineto 16.820312 468.33612 lineto 16.820312 467.16034 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 25.317383 463.39374 moveto 25.978184 463.53502 26.493157 463.82896 26.862305 464.27557 curveto 27.235995 464.72219 27.422844 465.27362 27.422852 465.92987 curveto 27.422844 466.93703 27.07649 467.71633 26.383789 468.26776 curveto 25.691075 468.81919 24.706701 469.09491 23.430664 469.09491 curveto 23.002275 469.09491 22.560218 469.05162 22.104492 468.96503 curveto 21.653318 468.883 21.186196 468.75767 20.703125 468.58905 curveto 20.703125 467.25604 lineto 21.085936 467.47935 21.505206 467.64797 21.960938 467.7619 curveto 22.416664 467.87584 22.8929 467.9328 23.389648 467.9328 curveto 24.255529 467.9328 24.914057 467.7619 25.365234 467.4201 curveto 25.820957 467.07831 26.048822 466.58157 26.048828 465.92987 curveto 26.048822 465.32831 25.836908 464.85891 25.413086 464.52167 curveto 24.99381 464.17988 24.408198 464.00898 23.65625 464.00897 curveto 22.466797 464.00897 lineto 22.466797 462.87421 lineto 23.710938 462.87421 lineto 24.389969 462.87421 24.9095 462.73977 25.269531 462.47089 curveto 25.629551 462.19746 25.809564 461.80553 25.80957 461.2951 curveto 25.809564 460.77102 25.622715 460.36998 25.249023 460.09198 curveto 24.879878 459.80944 24.348954 459.66816 23.65625 459.66815 curveto 23.277991 459.66816 22.872393 459.70918 22.439453 459.7912 curveto 22.006508 459.87324 21.530272 460.00084 21.010742 460.17401 curveto 21.010742 458.94354 lineto 21.534829 458.79772 22.024737 458.68834 22.480469 458.61542 curveto 22.940752 458.54251 23.373694 458.50605 23.779297 458.50604 curveto 24.827469 458.50605 25.656895 458.74531 26.267578 459.22382 curveto 26.878248 459.69778 27.183586 460.34036 27.183594 461.15155 curveto 27.183586 461.71666 27.021803 462.19518 26.698242 462.5871 curveto 26.374668 462.97447 25.914382 463.24335 25.317383 463.39374 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 30.191406 467.16034 moveto 31.633789 467.16034 lineto 31.633789 468.33612 lineto 30.512695 470.52362 lineto 29.630859 470.52362 lineto 30.191406 468.33612 lineto 30.191406 467.16034 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 39.365234 464.97968 moveto 39.365228 464.06822 39.176101 463.36184 38.797852 462.86053 curveto 38.424148 462.35924 37.897782 462.10859 37.21875 462.10858 curveto 36.544267 462.10859 36.017901 462.35924 35.639648 462.86053 curveto 35.265948 463.36184 35.079099 464.06822 35.079102 464.97968 curveto 35.079099 465.88658 35.265948 466.59068 35.639648 467.09198 curveto 36.017901 467.59328 36.544267 467.84393 37.21875 467.84393 curveto 37.897782 467.84393 38.424148 467.59328 38.797852 467.09198 curveto 39.176101 466.59068 39.365228 465.88658 39.365234 464.97968 curveto 40.623047 467.94647 moveto 40.623039 469.24986 40.333652 470.21828 39.754883 470.85175 curveto 39.176101 471.48976 38.289708 471.80877 37.095703 471.80878 curveto 36.653642 471.80877 36.23665 471.77459 35.844727 471.70624 curveto 35.452797 471.64243 35.072264 471.54217 34.703125 471.40546 curveto 34.703125 470.18182 lineto 35.072264 470.38234 35.436847 470.53045 35.796875 470.62616 curveto 36.156898 470.72186 36.52376 470.76971 36.897461 470.76971 curveto 37.722326 470.76971 38.339838 470.55324 38.75 470.1203 curveto 39.16015 469.69191 39.365228 469.0425 39.365234 468.17206 curveto 39.365234 467.54999 lineto 39.105463 468.00116 38.772781 468.3384 38.367188 468.56171 curveto 37.961584 468.78501 37.476233 468.89667 36.911133 468.89667 curveto 35.972328 468.89667 35.215818 468.53892 34.641602 467.82343 curveto 34.067382 467.10793 33.780273 466.16002 33.780273 464.97968 curveto 33.780273 463.79478 34.067382 462.84459 34.641602 462.12909 curveto 35.215818 461.4136 35.972328 461.05586 36.911133 461.05585 curveto 37.476233 461.05586 37.961584 461.16751 38.367188 461.39081 curveto 38.772781 461.61412 39.105463 461.95136 39.365234 462.40253 curveto 39.365234 461.24042 lineto 40.623047 461.24042 lineto 40.623047 467.94647 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 43.015625 458.27362 moveto 44.109375 458.27362 lineto 44.792966 459.34915 45.303382 460.40188 45.640625 461.43182 curveto 45.982418 462.46178 46.153316 463.48489 46.15332 464.50116 curveto 46.153316 465.522 45.982418 466.54966 45.640625 467.58417 curveto 45.303382 468.61867 44.792966 469.67141 44.109375 470.74237 curveto 43.015625 470.74237 lineto 43.621743 469.69875 44.072914 468.66197 44.369141 467.63202 curveto 44.669919 466.59752 44.82031 465.5539 44.820312 464.50116 curveto 44.82031 463.44843 44.669919 462.40937 44.369141 461.38397 curveto 44.072914 460.35859 43.621743 459.32181 43.015625 458.27362 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 98.233398 458.80682 moveto 97.622718 459.85501 97.169268 460.89179 96.873047 461.91718 curveto 96.57682 462.94257 96.428708 463.98163 96.428711 465.03436 curveto 96.428708 466.0871 96.57682 467.13072 96.873047 468.16522 curveto 97.173825 469.19517 97.627275 470.23195 98.233398 471.27557 curveto 97.139648 471.27557 lineto 96.456052 470.20461 95.943357 469.15188 95.601562 468.11737 curveto 95.264322 467.08287 95.095702 466.0552 95.095703 465.03436 curveto 95.095702 464.01809 95.264322 462.99498 95.601562 461.96503 curveto 95.9388 460.93509 96.451495 459.88235 97.139648 458.80682 curveto 98.233398 458.80682 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 103.98242 463.77655 moveto 103.36263 463.77656 102.87044 463.98847 102.50586 464.41229 curveto 102.14583 464.83613 101.96582 465.41718 101.96582 466.15546 curveto 101.96582 466.88918 102.14583 467.47024 102.50586 467.89862 curveto 102.87044 468.32245 103.36263 468.53436 103.98242 468.53436 curveto 104.60221 468.53436 105.09212 468.32245 105.45215 467.89862 curveto 105.81673 467.47024 105.99902 466.88918 105.99902 466.15546 curveto 105.99902 465.41718 105.81673 464.83613 105.45215 464.41229 curveto 105.09212 463.98847 104.60221 463.77656 103.98242 463.77655 curveto 106.72363 459.4494 moveto 106.72363 460.70721 lineto 106.37727 460.54316 106.02636 460.41784 105.6709 460.33124 curveto 105.31998 460.24466 104.97135 460.20136 104.625 460.20135 curveto 103.71354 460.20136 103.01627 460.50898 102.5332 461.12421 curveto 102.05468 461.73945 101.78125 462.66914 101.71289 463.91327 curveto 101.98177 463.51679 102.31901 463.21373 102.72461 463.00409 curveto 103.1302 462.7899 103.57682 462.68281 104.06445 462.6828 curveto 105.08984 462.68281 105.89876 462.99498 106.49121 463.61932 curveto 107.08821 464.23912 107.38671 465.0845 107.38672 466.15546 curveto 107.38671 467.20364 107.07682 468.04446 106.45703 468.67792 curveto 105.83723 469.31138 105.01236 469.62811 103.98242 469.62811 curveto 102.80208 469.62811 101.89974 469.17694 101.27539 468.2746 curveto 100.65104 467.3677 100.33887 466.0552 100.33887 464.3371 curveto 100.33887 462.72382 100.72168 461.43867 101.4873 460.48163 curveto 102.25293 459.52005 103.2806 459.03926 104.57031 459.03925 curveto 104.91666 459.03926 105.26529 459.07344 105.61621 459.14178 curveto 105.97167 459.21015 106.34081 459.31269 106.72363 459.4494 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 109.91602 467.69354 moveto 111.3584 467.69354 lineto 111.3584 468.86932 lineto 110.2373 471.05682 lineto 109.35547 471.05682 lineto 109.91602 468.86932 lineto 109.91602 467.69354 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 114.24316 459.22382 moveto 119.66406 459.22382 lineto 119.66406 460.38593 lineto 115.50781 460.38593 lineto 115.50781 462.88788 lineto 115.70833 462.81953 115.90885 462.7694 116.10938 462.73749 curveto 116.30989 462.70104 116.51041 462.68281 116.71094 462.6828 curveto 117.85026 462.68281 118.7526 462.99498 119.41797 463.61932 curveto 120.08333 464.24368 120.41601 465.08905 120.41602 466.15546 curveto 120.41601 467.25377 120.07421 468.10826 119.39062 468.71893 curveto 118.70703 469.32505 117.74316 469.62811 116.49902 469.62811 curveto 116.07063 469.62811 115.63314 469.59165 115.18652 469.51874 curveto 114.74446 469.44582 114.28646 469.33645 113.8125 469.19061 curveto 113.8125 467.80292 lineto 114.22265 468.02623 114.64648 468.19257 115.08398 468.30194 curveto 115.52148 468.41132 115.98405 468.466 116.47168 468.466 curveto 117.26009 468.466 117.88443 468.25865 118.34473 467.84393 curveto 118.80501 467.42922 119.03515 466.8664 119.03516 466.15546 curveto 119.03515 465.44452 118.80501 464.8817 118.34473 464.46698 curveto 117.88443 464.05227 117.26009 463.84492 116.47168 463.84491 curveto 116.10254 463.84492 115.7334 463.88593 115.36426 463.96796 curveto 114.99967 464.04999 114.62597 464.1776 114.24316 464.35077 curveto 114.24316 459.22382 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 123.28711 467.69354 moveto 124.72949 467.69354 lineto 124.72949 468.86932 lineto 123.6084 471.05682 lineto 122.72656 471.05682 lineto 123.28711 468.86932 lineto 123.28711 467.69354 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 130.38965 462.65546 moveto 129.71517 462.65546 129.18196 462.91979 128.79004 463.44843 curveto 128.39811 463.97252 128.20215 464.69257 128.20215 465.60858 curveto 128.20215 466.5246 128.39583 467.24693 128.7832 467.77557 curveto 129.17513 468.29966 129.71061 468.56171 130.38965 468.56171 curveto 131.05957 468.56171 131.59049 468.29738 131.98242 467.76874 curveto 132.37434 467.24009 132.57031 466.52004 132.57031 465.60858 curveto 132.57031 464.70169 132.37434 463.98391 131.98242 463.45526 curveto 131.59049 462.92206 131.05957 462.65546 130.38965 462.65546 curveto 130.38965 461.58905 moveto 131.48339 461.58906 132.34244 461.94453 132.9668 462.65546 curveto 133.59114 463.3664 133.90331 464.35077 133.90332 465.60858 curveto 133.90331 466.86184 133.59114 467.84621 132.9668 468.56171 curveto 132.34244 469.27264 131.48339 469.62811 130.38965 469.62811 curveto 129.29134 469.62811 128.43001 469.27264 127.80566 468.56171 curveto 127.18587 467.84621 126.87598 466.86184 126.87598 465.60858 curveto 126.87598 464.35077 127.18587 463.3664 127.80566 462.65546 curveto 128.43001 461.94453 129.29134 461.58906 130.38965 461.58905 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 135.7832 458.80682 moveto 136.87695 458.80682 lineto 137.56054 459.88235 138.07096 460.93509 138.4082 461.96503 curveto 138.75 462.99498 138.92089 464.01809 138.9209 465.03436 curveto 138.92089 466.0552 138.75 467.08287 138.4082 468.11737 curveto 138.07096 469.15188 137.56054 470.20461 136.87695 471.27557 curveto 135.7832 471.27557 lineto 136.38932 470.23195 136.84049 469.19517 137.13672 468.16522 curveto 137.4375 467.13072 137.58789 466.0871 137.58789 465.03436 curveto 137.58789 463.98163 137.4375 462.94257 137.13672 461.91718 curveto 136.84049 460.89179 136.38932 459.85501 135.7832 458.80682 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 4.1689453 477.84198 moveto 3.5582645 478.89017 3.1048144 479.92695 2.8085938 480.95233 curveto 2.5123671 481.97773 2.3642553 483.01679 2.3642578 484.06952 curveto 2.3642553 485.12226 2.5123671 486.16588 2.8085938 487.20038 curveto 3.1093717 488.23033 3.5628218 489.26711 4.1689453 490.31073 curveto 3.0751953 490.31073 lineto 2.391599 489.23977 1.8789042 488.18703 1.5371094 487.15253 curveto 1.1998684 486.11802 1.0312488 485.09036 1.03125 484.06952 curveto 1.0312488 483.05325 1.1998684 482.03014 1.5371094 481.00018 curveto 1.8743469 479.97024 2.3870417 478.91751 3.0751953 477.84198 curveto 4.1689453 477.84198 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 6.4453125 478.25897 moveto 13.007812 478.25897 lineto 13.007812 478.84686 lineto 9.3027344 488.46503 lineto 7.8603516 488.46503 lineto 11.34668 479.42108 lineto 6.4453125 479.42108 lineto 6.4453125 478.25897 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 15.851562 486.7287 moveto 17.293945 486.7287 lineto 17.293945 487.90448 lineto 16.172852 490.09198 lineto 15.291016 490.09198 lineto 15.851562 487.90448 lineto 15.851562 486.7287 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 23.289062 482.81171 moveto 22.669267 482.81171 22.17708 483.02363 21.8125 483.44745 curveto 21.452471 483.87128 21.272458 484.45234 21.272461 485.19061 curveto 21.272458 485.92434 21.452471 486.50539 21.8125 486.93378 curveto 22.17708 487.35761 22.669267 487.56952 23.289062 487.56952 curveto 23.908849 487.56952 24.398757 487.35761 24.758789 486.93378 curveto 25.123366 486.50539 25.305657 485.92434 25.305664 485.19061 curveto 25.305657 484.45234 25.123366 483.87128 24.758789 483.44745 curveto 24.398757 483.02363 23.908849 482.81171 23.289062 482.81171 curveto 26.030273 478.48456 moveto 26.030273 479.74237 lineto 25.683912 479.57832 25.333001 479.45299 24.977539 479.36639 curveto 24.626622 479.27981 24.277989 479.23652 23.931641 479.23651 curveto 23.020178 479.23652 22.322913 479.54414 21.839844 480.15936 curveto 21.361325 480.7746 21.087888 481.70429 21.019531 482.94843 curveto 21.288409 482.55195 21.625648 482.24889 22.03125 482.03925 curveto 22.436845 481.82506 22.883459 481.71796 23.371094 481.71796 curveto 24.396479 481.71796 25.205397 482.03014 25.797852 482.65448 curveto 26.394849 483.27428 26.693351 484.11965 26.693359 485.19061 curveto 26.693351 486.23879 26.383456 487.07961 25.763672 487.71307 curveto 25.143874 488.34654 24.319005 488.66327 23.289062 488.66327 curveto 22.108721 488.66327 21.206378 488.2121 20.582031 487.30975 curveto 19.957681 486.40285 19.645507 485.09036 19.645508 483.37225 curveto 19.645507 481.75898 20.028319 480.47382 20.793945 479.51678 curveto 21.559567 478.55521 22.587236 478.07441 23.876953 478.0744 curveto 24.223302 478.07441 24.571934 478.10859 24.922852 478.17694 curveto 25.278314 478.24531 25.647454 478.34785 26.030273 478.48456 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 29.222656 486.7287 moveto 30.665039 486.7287 lineto 30.665039 487.90448 lineto 29.543945 490.09198 lineto 28.662109 490.09198 lineto 29.222656 487.90448 lineto 29.222656 486.7287 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 36.325195 481.69061 moveto 35.650713 481.69062 35.11751 481.95494 34.725586 482.48358 curveto 34.333657 483.00768 34.137693 483.72773 34.137695 484.64374 curveto 34.137693 485.55976 34.331378 486.28209 34.71875 486.81073 curveto 35.110674 487.33482 35.646155 487.59686 36.325195 487.59686 curveto 36.995112 487.59686 37.526036 487.33254 37.917969 486.80389 curveto 38.30989 486.27525 38.505853 485.5552 38.505859 484.64374 curveto 38.505853 483.73684 38.30989 483.01907 37.917969 482.49042 curveto 37.526036 481.95722 36.995112 481.69062 36.325195 481.69061 curveto 36.325195 480.62421 moveto 37.41894 480.62421 38.277989 480.97968 38.902344 481.69061 curveto 39.526685 482.40156 39.838859 483.38593 39.838867 484.64374 curveto 39.838859 485.897 39.526685 486.88137 38.902344 487.59686 curveto 38.277989 488.3078 37.41894 488.66327 36.325195 488.66327 curveto 35.226885 488.66327 34.365558 488.3078 33.741211 487.59686 curveto 33.121418 486.88137 32.811523 485.897 32.811523 484.64374 curveto 32.811523 483.38593 33.121418 482.40156 33.741211 481.69061 curveto 34.365558 480.97968 35.226885 480.62421 36.325195 480.62421 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 41.71875 477.84198 moveto 42.8125 477.84198 lineto 43.496091 478.91751 44.006507 479.97024 44.34375 481.00018 curveto 44.685543 482.03014 44.856441 483.05325 44.856445 484.06952 curveto 44.856441 485.09036 44.685543 486.11802 44.34375 487.15253 curveto 44.006507 488.18703 43.496091 489.23977 42.8125 490.31073 curveto 41.71875 490.31073 lineto 42.324868 489.26711 42.776039 488.23033 43.072266 487.20038 curveto 43.373044 486.16588 43.523435 485.12226 43.523438 484.06952 curveto 43.523435 483.01679 43.373044 481.97773 43.072266 480.95233 curveto 42.776039 479.92695 42.324868 478.89017 41.71875 477.84198 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 51.951172 478.34198 moveto 51.340491 479.39017 50.887041 480.42695 50.59082 481.45233 curveto 50.294594 482.47773 50.146482 483.51679 50.146484 484.56952 curveto 50.146482 485.62226 50.294594 486.66588 50.59082 487.70038 curveto 50.891598 488.73033 51.345048 489.76711 51.951172 490.81073 curveto 50.857422 490.81073 lineto 50.173826 489.73977 49.661131 488.68703 49.319336 487.65253 curveto 48.982095 486.61802 48.813475 485.59036 48.813477 484.56952 curveto 48.813475 483.55325 48.982095 482.53014 49.319336 481.50018 curveto 49.656573 480.47024 50.169268 479.41751 50.857422 478.34198 curveto 51.951172 478.34198 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 57.529297 484.11835 moveto 56.873043 484.11835 56.355791 484.29381 55.977539 484.64471 curveto 55.603839 484.99563 55.41699 485.4787 55.416992 486.09393 curveto 55.41699 486.70917 55.603839 487.19224 55.977539 487.54315 curveto 56.355791 487.89406 56.873043 488.06952 57.529297 488.06952 curveto 58.185542 488.06952 58.702794 487.89406 59.081055 487.54315 curveto 59.459304 487.18768 59.648431 486.70461 59.648438 486.09393 curveto 59.648431 485.4787 59.459304 484.99563 59.081055 484.64471 curveto 58.707351 484.29381 58.190099 484.11835 57.529297 484.11835 curveto 56.148438 483.53046 moveto 55.555987 483.38463 55.093422 483.10891 54.760742 482.70331 curveto 54.432616 482.29772 54.268553 481.80325 54.268555 481.21991 curveto 54.268553 480.40416 54.557941 479.75931 55.136719 479.28534 curveto 55.720049 478.81139 56.517575 478.57441 57.529297 478.5744 curveto 58.545567 478.57441 59.343093 478.81139 59.921875 479.28534 curveto 60.500644 479.75931 60.790031 480.40416 60.790039 481.21991 curveto 60.790031 481.80325 60.62369 482.29772 60.291016 482.70331 curveto 59.962884 483.10891 59.504876 483.38463 58.916992 483.53046 curveto 59.58235 483.68541 60.099602 483.98847 60.46875 484.43964 curveto 60.84244 484.89081 61.029289 485.44224 61.029297 486.09393 curveto 61.029289 487.08287 60.726229 487.84166 60.120117 488.3703 curveto 59.518548 488.89895 58.654942 489.16327 57.529297 489.16327 curveto 56.403643 489.16327 55.537758 488.89895 54.931641 488.3703 curveto 54.330077 487.84166 54.029296 487.08287 54.029297 486.09393 curveto 54.029296 485.44224 54.216145 484.89081 54.589844 484.43964 curveto 54.96354 483.98847 55.483071 483.68541 56.148438 483.53046 curveto 55.642578 481.34979 moveto 55.642576 481.87845 55.806638 482.29088 56.134766 482.5871 curveto 56.467445 482.88333 56.932288 483.03144 57.529297 483.03143 curveto 58.12174 483.03144 58.584304 482.88333 58.916992 482.5871 curveto 59.254226 482.29088 59.422845 481.87845 59.422852 481.34979 curveto 59.422845 480.82115 59.254226 480.40872 58.916992 480.11249 curveto 58.584304 479.81627 58.12174 479.66816 57.529297 479.66815 curveto 56.932288 479.66816 56.467445 479.81627 56.134766 480.11249 curveto 55.806638 480.40872 55.642576 480.82115 55.642578 481.34979 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 63.633789 487.2287 moveto 65.076172 487.2287 lineto 65.076172 488.40448 lineto 63.955078 490.59198 lineto 63.073242 490.59198 lineto 63.633789 488.40448 lineto 63.633789 487.2287 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 67.598633 478.75897 moveto 74.161133 478.75897 lineto 74.161133 479.34686 lineto 70.456055 488.96503 lineto 69.013672 488.96503 lineto 72.5 479.92108 lineto 67.598633 479.92108 lineto 67.598633 478.75897 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 77.004883 487.2287 moveto 78.447266 487.2287 lineto 78.447266 488.40448 lineto 77.326172 490.59198 lineto 76.444336 490.59198 lineto 77.004883 488.40448 lineto 77.004883 487.2287 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 84.107422 482.19061 moveto 83.432939 482.19062 82.899737 482.45494 82.507812 482.98358 curveto 82.115883 483.50768 81.91992 484.22773 81.919922 485.14374 curveto 81.91992 486.05976 82.113604 486.78209 82.500977 487.31073 curveto 82.892901 487.83482 83.428382 488.09686 84.107422 488.09686 curveto 84.777339 488.09686 85.308263 487.83254 85.700195 487.30389 curveto 86.092116 486.77525 86.288079 486.0552 86.288086 485.14374 curveto 86.288079 484.23684 86.092116 483.51907 85.700195 482.99042 curveto 85.308263 482.45722 84.777339 482.19062 84.107422 482.19061 curveto 84.107422 481.12421 moveto 85.201166 481.12421 86.060215 481.47968 86.68457 482.19061 curveto 87.308912 482.90156 87.621086 483.88593 87.621094 485.14374 curveto 87.621086 486.397 87.308912 487.38137 86.68457 488.09686 curveto 86.060215 488.8078 85.201166 489.16327 84.107422 489.16327 curveto 83.009111 489.16327 82.147784 488.8078 81.523438 488.09686 curveto 80.903645 487.38137 80.593749 486.397 80.59375 485.14374 curveto 80.593749 483.88593 80.903645 482.90156 81.523438 482.19061 curveto 82.147784 481.47968 83.009111 481.12421 84.107422 481.12421 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 89.500977 478.34198 moveto 90.594727 478.34198 lineto 91.278317 479.41751 91.788734 480.47024 92.125977 481.50018 curveto 92.467769 482.53014 92.638668 483.55325 92.638672 484.56952 curveto 92.638668 485.59036 92.467769 486.61802 92.125977 487.65253 curveto 91.788734 488.68703 91.278317 489.73977 90.594727 490.81073 curveto 89.500977 490.81073 lineto 90.107095 489.76711 90.558266 488.73033 90.854492 487.70038 curveto 91.155271 486.66588 91.305661 485.62226 91.305664 484.56952 curveto 91.305661 483.51679 91.155271 482.47773 90.854492 481.45233 curveto 90.558266 480.42695 90.107095 479.39017 89.500977 478.34198 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 96.905273 479.30878 moveto 96.294593 480.35696 95.841143 481.39375 95.544922 482.41913 curveto 95.248695 483.44453 95.100583 484.48359 95.100586 485.53632 curveto 95.100583 486.58905 95.248695 487.63267 95.544922 488.66718 curveto 95.8457 489.69712 96.29915 490.73391 96.905273 491.77753 curveto 95.811523 491.77753 lineto 95.127927 490.70656 94.615232 489.65383 94.273438 488.61932 curveto 93.936197 487.58482 93.767577 486.55715 93.767578 485.53632 curveto 93.767577 484.52005 93.936197 483.49693 94.273438 482.46698 curveto 94.610675 481.43704 95.12337 480.38431 95.811523 479.30878 curveto 96.905273 479.30878 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 99.571289 489.71991 moveto 99.571289 488.4621 lineto 99.917641 488.62616 100.26855 488.75149 100.62402 488.83807 curveto 100.97949 488.92466 101.32812 488.96796 101.66992 488.96796 curveto 102.58138 488.96796 103.27636 488.66262 103.75488 488.05194 curveto 104.23795 487.43671 104.51367 486.50474 104.58203 485.25604 curveto 104.3177 485.64797 103.98274 485.94875 103.57715 486.15839 curveto 103.17154 486.36803 102.72265 486.47284 102.23047 486.47284 curveto 101.20963 486.47284 100.40071 486.16523 99.803711 485.54999 curveto 99.211262 484.9302 98.915038 484.08482 98.915039 483.01385 curveto 98.915038 481.96569 99.224934 481.12487 99.844727 480.49139 curveto 100.46452 479.85794 101.28938 479.54121 102.31934 479.5412 curveto 103.49967 479.54121 104.39973 479.99466 105.01953 480.90155 curveto 105.64387 481.8039 105.95605 483.1164 105.95605 484.83905 curveto 105.95605 486.44778 105.57323 487.73293 104.80762 488.69452 curveto 104.04654 489.65155 103.02115 490.13007 101.73145 490.13007 curveto 101.38509 490.13007 101.03418 490.09589 100.67871 490.02753 curveto 100.32324 489.95917 99.9541 489.85663 99.571289 489.71991 curveto 102.31934 485.39276 moveto 102.93912 485.39277 103.42903 485.18085 103.78906 484.75702 curveto 104.15364 484.3332 104.33593 483.75214 104.33594 483.01385 curveto 104.33593 482.28014 104.15364 481.70136 103.78906 481.27753 curveto 103.42903 480.84915 102.93912 480.63496 102.31934 480.63495 curveto 101.69954 480.63496 101.20735 480.84915 100.84277 481.27753 curveto 100.48274 481.70136 100.30273 482.28014 100.30273 483.01385 curveto 100.30273 483.75214 100.48274 484.3332 100.84277 484.75702 curveto 101.20735 485.18085 101.69954 485.39277 102.31934 485.39276 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 108.58789 488.1955 moveto 110.03027 488.1955 lineto 110.03027 489.37128 lineto 108.90918 491.55878 lineto 108.02734 491.55878 lineto 108.58789 489.37128 lineto 108.58789 488.1955 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 115.85449 485.08514 moveto 115.19824 485.08515 114.68099 485.2606 114.30273 485.61151 curveto 113.92903 485.96243 113.74219 486.4455 113.74219 487.06073 curveto 113.74219 487.67597 113.92903 488.15904 114.30273 488.50995 curveto 114.68099 488.86086 115.19824 489.03632 115.85449 489.03632 curveto 116.51074 489.03632 117.02799 488.86086 117.40625 488.50995 curveto 117.7845 488.15448 117.97363 487.67141 117.97363 487.06073 curveto 117.97363 486.4455 117.7845 485.96243 117.40625 485.61151 curveto 117.03255 485.2606 116.51529 485.08515 115.85449 485.08514 curveto 114.47363 484.49725 moveto 113.88118 484.35143 113.41862 484.07571 113.08594 483.6701 curveto 112.75781 483.26451 112.59375 482.77005 112.59375 482.18671 curveto 112.59375 481.37096 112.88314 480.7261 113.46191 480.25214 curveto 114.04524 479.77819 114.84277 479.54121 115.85449 479.5412 curveto 116.87076 479.54121 117.66829 479.77819 118.24707 480.25214 curveto 118.82584 480.7261 119.11523 481.37096 119.11523 482.18671 curveto 119.11523 482.77005 118.94889 483.26451 118.61621 483.6701 curveto 118.28808 484.07571 117.83007 484.35143 117.24219 484.49725 curveto 117.90755 484.65221 118.4248 484.95527 118.79395 485.40643 curveto 119.16764 485.85761 119.35448 486.40904 119.35449 487.06073 curveto 119.35448 488.04966 119.05142 488.80845 118.44531 489.3371 curveto 117.84374 489.86574 116.98014 490.13007 115.85449 490.13007 curveto 114.72884 490.13007 113.86295 489.86574 113.25684 489.3371 curveto 112.65527 488.80845 112.35449 488.04966 112.35449 487.06073 curveto 112.35449 486.40904 112.54134 485.85761 112.91504 485.40643 curveto 113.28874 484.95527 113.80827 484.65221 114.47363 484.49725 curveto 113.96777 482.31659 moveto 113.96777 482.84524 114.13183 483.25768 114.45996 483.55389 curveto 114.79264 483.85012 115.25748 483.99824 115.85449 483.99823 curveto 116.44694 483.99824 116.9095 483.85012 117.24219 483.55389 curveto 117.57942 483.25768 117.74804 482.84524 117.74805 482.31659 curveto 117.74804 481.78795 117.57942 481.37552 117.24219 481.07928 curveto 116.9095 480.78307 116.44694 480.63496 115.85449 480.63495 curveto 115.25748 480.63496 114.79264 480.78307 114.45996 481.07928 curveto 114.13183 481.37552 113.96777 481.78795 113.96777 482.31659 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 121.95898 488.1955 moveto 123.40137 488.1955 lineto 123.40137 489.37128 lineto 122.28027 491.55878 lineto 121.39844 491.55878 lineto 121.95898 489.37128 lineto 121.95898 488.1955 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 131.13281 486.01483 moveto 131.13281 485.10338 130.94368 484.397 130.56543 483.89569 curveto 130.19173 483.3944 129.66536 483.14374 128.98633 483.14374 curveto 128.31185 483.14374 127.78548 483.3944 127.40723 483.89569 curveto 127.03353 484.397 126.84668 485.10338 126.84668 486.01483 curveto 126.84668 486.92174 127.03353 487.62584 127.40723 488.12714 curveto 127.78548 488.62844 128.31185 488.87909 128.98633 488.87909 curveto 129.66536 488.87909 130.19173 488.62844 130.56543 488.12714 curveto 130.94368 487.62584 131.13281 486.92174 131.13281 486.01483 curveto 132.39062 488.98163 moveto 132.39062 490.28501 132.10123 491.25344 131.52246 491.8869 curveto 130.94368 492.52492 130.05729 492.84393 128.86328 492.84393 curveto 128.42122 492.84393 128.00423 492.80975 127.6123 492.74139 curveto 127.22038 492.67759 126.83984 492.57733 126.4707 492.44061 curveto 126.4707 491.21698 lineto 126.83984 491.4175 127.20442 491.56561 127.56445 491.66132 curveto 127.92448 491.75702 128.29134 491.80487 128.66504 491.80487 curveto 129.4899 491.80487 130.10742 491.5884 130.51758 491.15546 curveto 130.92773 490.72707 131.13281 490.07766 131.13281 489.20721 curveto 131.13281 488.58514 lineto 130.87304 489.03632 130.54036 489.37356 130.13477 489.59686 curveto 129.72916 489.82017 129.24381 489.93182 128.67871 489.93182 curveto 127.73991 489.93182 126.9834 489.57408 126.40918 488.85858 curveto 125.83496 488.14309 125.54785 487.19517 125.54785 486.01483 curveto 125.54785 484.82994 125.83496 483.87975 126.40918 483.16425 curveto 126.9834 482.44876 127.73991 482.09101 128.67871 482.091 curveto 129.24381 482.09101 129.72916 482.20266 130.13477 482.42596 curveto 130.54036 482.64928 130.87304 482.98652 131.13281 483.43768 curveto 131.13281 482.27557 lineto 132.39062 482.27557 lineto 132.39062 488.98163 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 134.7832 479.30878 moveto 135.87695 479.30878 lineto 136.56054 480.38431 137.07096 481.43704 137.4082 482.46698 curveto 137.75 483.49693 137.92089 484.52005 137.9209 485.53632 curveto 137.92089 486.55715 137.75 487.58482 137.4082 488.61932 curveto 137.07096 489.65383 136.56054 490.70656 135.87695 491.77753 curveto 134.7832 491.77753 lineto 135.38932 490.73391 135.84049 489.69712 136.13672 488.66718 curveto 136.4375 487.63267 136.58789 486.58905 136.58789 485.53632 curveto 136.58789 484.48359 136.4375 483.44453 136.13672 482.41913 curveto 135.84049 481.39375 135.38932 480.35696 134.7832 479.30878 curveto fill grestore gsave [1.209899 0 0 0.857509 -38.19343 49.51799] concat 0 0 0 setrgbcolor [] 0 setdash 1.5 setlinewidth 0 setlinejoin 0 setlinecap newpath 154.5 482.61218 moveto 154.5 515.59418 125.716 542.36218 90.25 542.36218 curveto 54.784 542.36218 26 515.59418 26 482.61218 curveto 26 449.63018 54.784 422.86218 90.25 422.86218 curveto 125.716 422.86218 154.5 449.63018 154.5 482.61218 curveto closepath stroke grestore gsave 0 0 0 setrgbcolor newpath 67.874023 420.15613 moveto 69.254883 420.15613 lineto 69.254883 430.36218 lineto 67.874023 430.36218 lineto 67.874023 420.15613 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 73.192383 420.5321 moveto 73.192383 422.70593 lineto 75.783203 422.70593 lineto 75.783203 423.68347 lineto 73.192383 423.68347 lineto 73.192383 427.83972 lineto 73.19238 428.46407 73.27669 428.86511 73.445312 429.04285 curveto 73.618487 429.22058 73.967119 429.30945 74.491211 429.30945 curveto 75.783203 429.30945 lineto 75.783203 430.36218 lineto 74.491211 430.36218 lineto 73.520505 430.36218 72.850584 430.18217 72.481445 429.82214 curveto 72.112303 429.45756 71.927733 428.79675 71.927734 427.83972 curveto 71.927734 423.68347 lineto 71.004883 423.68347 lineto 71.004883 422.70593 lineto 71.927734 422.70593 lineto 71.927734 420.5321 lineto 73.192383 420.5321 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 59.254883 524.79089 moveto 59.254883 528.62585 lineto 60.991211 528.62585 lineto 61.633784 528.62586 62.130528 528.45952 62.481445 528.12683 curveto 62.83235 527.79415 63.007806 527.3202 63.007812 526.70496 curveto 63.007806 526.09429 62.83235 525.62261 62.481445 525.28992 curveto 62.130528 524.95724 61.633784 524.7909 60.991211 524.79089 curveto 59.254883 524.79089 lineto 57.874023 523.65613 moveto 60.991211 523.65613 lineto 62.135086 523.65614 62.998691 523.9159 63.582031 524.43542 curveto 64.169914 524.95041 64.463859 525.70692 64.463867 526.70496 curveto 64.463859 527.71212 64.169914 528.47319 63.582031 528.98816 curveto 62.998691 529.50314 62.135086 529.76062 60.991211 529.76062 curveto 59.254883 529.76062 lineto 59.254883 533.86218 lineto 57.874023 533.86218 lineto 57.874023 523.65613 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 69.399414 524.56531 moveto 68.688473 524.56532 68.152992 524.91623 67.792969 525.61804 curveto 67.437498 526.31532 67.259763 527.36577 67.259766 528.76941 curveto 67.259763 530.1685 67.437498 531.21896 67.792969 531.92078 curveto 68.152992 532.61804 68.688473 532.96668 69.399414 532.96667 curveto 70.114904 532.96668 70.650385 532.61804 71.005859 531.92078 curveto 71.365879 531.21896 71.545892 530.1685 71.545898 528.76941 curveto 71.545892 527.36577 71.365879 526.31532 71.005859 525.61804 curveto 70.650385 524.91623 70.114904 524.56532 69.399414 524.56531 curveto 69.399414 523.47156 moveto 70.543289 523.47157 71.416009 523.92502 72.017578 524.83191 curveto 72.62369 525.73426 72.92675 527.04676 72.926758 528.76941 curveto 72.92675 530.48751 72.62369 531.80001 72.017578 532.70691 curveto 71.416009 533.60925 70.543289 534.06042 69.399414 534.06042 curveto 68.255531 534.06042 67.380531 533.60925 66.774414 532.70691 curveto 66.17285 531.80001 65.872069 530.48751 65.87207 528.76941 curveto 65.872069 527.04676 66.17285 525.73426 66.774414 524.83191 curveto 67.380531 523.92502 68.255531 523.47157 69.399414 523.47156 curveto fill grestore gsave [1.063088 0 0 0.999533 -49.82231 5.914079] concat 0 0 0 setrgbcolor [] 0 setdash 1.5 setlinewidth 0 setlinejoin 0 setlinecap newpath 349.5 351.36218 moveto 349.5 378.68618 319.484 400.86218 282.5 400.86218 curveto 245.516 400.86218 215.5 378.68618 215.5 351.36218 curveto 215.5 324.03818 245.516 301.86218 282.5 301.86218 curveto 319.484 301.86218 349.5 324.03818 349.5 351.36218 curveto closepath stroke grestore gsave 0 0 0 setrgbcolor newpath 205.85547 329.61218 moveto 205.24479 330.66037 204.79134 331.69715 204.49512 332.72253 curveto 204.19889 333.74793 204.05078 334.78699 204.05078 335.83972 curveto 204.05078 336.89246 204.19889 337.93608 204.49512 338.97058 curveto 204.7959 340.00053 205.24935 341.03731 205.85547 342.08093 curveto 204.76172 342.08093 lineto 204.07812 341.00997 203.56543 339.95723 203.22363 338.92273 curveto 202.88639 337.88823 202.71777 336.86056 202.71777 335.83972 curveto 202.71777 334.82345 202.88639 333.80034 203.22363 332.77039 curveto 203.56087 331.74045 204.07357 330.68771 204.76172 329.61218 curveto 205.85547 329.61218 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 208.49414 330.02917 moveto 213.91504 330.02917 lineto 213.91504 331.19128 lineto 209.75879 331.19128 lineto 209.75879 333.69324 lineto 209.95931 333.62488 210.15983 333.57475 210.36035 333.54285 curveto 210.56087 333.5064 210.76139 333.48817 210.96191 333.48816 curveto 212.10123 333.48817 213.00357 333.80034 213.66895 334.42468 curveto 214.3343 335.04904 214.66698 335.89441 214.66699 336.96082 curveto 214.66698 338.05912 214.32519 338.91362 213.6416 339.52429 curveto 212.958 340.13041 211.99414 340.43347 210.75 340.43347 curveto 210.32161 340.43347 209.88411 340.39701 209.4375 340.3241 curveto 208.99544 340.25118 208.53743 340.14181 208.06348 339.99597 curveto 208.06348 338.60828 lineto 208.47363 338.83159 208.89746 338.99793 209.33496 339.1073 curveto 209.77246 339.21668 210.23502 339.27136 210.72266 339.27136 curveto 211.51106 339.27136 212.13541 339.06401 212.5957 338.64929 curveto 213.05598 338.23458 213.28613 337.67176 213.28613 336.96082 curveto 213.28613 336.24988 213.05598 335.68706 212.5957 335.27234 curveto 212.13541 334.85763 211.51106 334.65027 210.72266 334.65027 curveto 210.35351 334.65027 209.98437 334.69129 209.61523 334.77332 curveto 209.25065 334.85535 208.87695 334.98296 208.49414 335.15613 curveto 208.49414 330.02917 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 217.53809 338.4989 moveto 218.98047 338.4989 lineto 218.98047 339.67468 lineto 217.85938 341.86218 lineto 216.97754 341.86218 lineto 217.53809 339.67468 lineto 217.53809 338.4989 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 224.80469 330.93835 moveto 224.09375 330.93836 223.55827 331.28927 223.19824 331.99109 curveto 222.84277 332.68836 222.66504 333.73882 222.66504 335.14246 curveto 222.66504 336.54155 222.84277 337.592 223.19824 338.29382 curveto 223.55827 338.99109 224.09375 339.33972 224.80469 339.33972 curveto 225.52018 339.33972 226.05566 338.99109 226.41113 338.29382 curveto 226.77115 337.592 226.95117 336.54155 226.95117 335.14246 curveto 226.95117 333.73882 226.77115 332.68836 226.41113 331.99109 curveto 226.05566 331.28927 225.52018 330.93836 224.80469 330.93835 curveto 224.80469 329.8446 moveto 225.94856 329.84461 226.82128 330.29806 227.42285 331.20496 curveto 228.02896 332.10731 228.33202 333.41981 228.33203 335.14246 curveto 228.33202 336.86056 228.02896 338.17306 227.42285 339.07996 curveto 226.82128 339.9823 225.94856 340.43347 224.80469 340.43347 curveto 223.6608 340.43347 222.7858 339.9823 222.17969 339.07996 curveto 221.57812 338.17306 221.27734 336.86056 221.27734 335.14246 curveto 221.27734 333.41981 221.57812 332.10731 222.17969 331.20496 curveto 222.7858 330.29806 223.6608 329.84461 224.80469 329.8446 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 230.90918 338.4989 moveto 232.35156 338.4989 lineto 232.35156 339.67468 lineto 231.23047 341.86218 lineto 230.34863 341.86218 lineto 230.90918 339.67468 lineto 230.90918 338.4989 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 240.08301 336.31824 moveto 240.083 335.40678 239.89387 334.7004 239.51562 334.1991 curveto 239.14192 333.6978 238.61556 333.44715 237.93652 333.44714 curveto 237.26204 333.44715 236.73567 333.6978 236.35742 334.1991 curveto 235.98372 334.7004 235.79687 335.40678 235.79688 336.31824 curveto 235.79687 337.22514 235.98372 337.92924 236.35742 338.43054 curveto 236.73567 338.93185 237.26204 339.1825 237.93652 339.1825 curveto 238.61556 339.1825 239.14192 338.93185 239.51562 338.43054 curveto 239.89387 337.92924 240.083 337.22514 240.08301 336.31824 curveto 241.34082 339.28503 moveto 241.34081 340.58842 241.05142 341.55684 240.47266 342.19031 curveto 239.89387 342.82833 239.00748 343.14734 237.81348 343.14734 curveto 237.37142 343.14734 236.95442 343.11316 236.5625 343.0448 curveto 236.17057 342.98099 235.79004 342.88073 235.4209 342.74402 curveto 235.4209 341.52039 lineto 235.79004 341.72091 236.15462 341.86902 236.51465 341.96472 curveto 236.87467 342.06042 237.24153 342.10827 237.61523 342.10828 curveto 238.4401 342.10827 239.05761 341.8918 239.46777 341.45886 curveto 239.87792 341.03048 240.083 340.38106 240.08301 339.51062 curveto 240.08301 338.88855 lineto 239.82324 339.33972 239.49055 339.67696 239.08496 339.90027 curveto 238.67936 340.12358 238.19401 340.23523 237.62891 340.23523 curveto 236.6901 340.23523 235.93359 339.87748 235.35938 339.16199 curveto 234.78516 338.44649 234.49805 337.49858 234.49805 336.31824 curveto 234.49805 335.13335 234.78516 334.18315 235.35938 333.46765 curveto 235.93359 332.75216 236.6901 332.39442 237.62891 332.39441 curveto 238.19401 332.39442 238.67936 332.50607 239.08496 332.72937 curveto 239.49055 332.95268 239.82324 333.28992 240.08301 333.74109 curveto 240.08301 332.57898 lineto 241.34082 332.57898 lineto 241.34082 339.28503 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 243.7334 329.61218 moveto 244.82715 329.61218 lineto 245.51074 330.68771 246.02116 331.74045 246.3584 332.77039 curveto 246.70019 333.80034 246.87109 334.82345 246.87109 335.83972 curveto 246.87109 336.86056 246.70019 337.88823 246.3584 338.92273 curveto 246.02116 339.95723 245.51074 341.00997 244.82715 342.08093 curveto 243.7334 342.08093 lineto 244.33952 341.03731 244.79069 340.00053 245.08691 338.97058 curveto 245.38769 337.93608 245.53808 336.89246 245.53809 335.83972 curveto 245.53808 334.78699 245.38769 333.74793 245.08691 332.72253 curveto 244.79069 331.69715 244.33952 330.66037 243.7334 329.61218 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 253.34082 328.61218 moveto 252.73014 329.66037 252.27669 330.69715 251.98047 331.72253 curveto 251.68424 332.74793 251.53613 333.78699 251.53613 334.83972 curveto 251.53613 335.89246 251.68424 336.93608 251.98047 337.97058 curveto 252.28125 339.00053 252.7347 340.03731 253.34082 341.08093 curveto 252.24707 341.08093 lineto 251.56347 340.00997 251.05078 338.95723 250.70898 337.92273 curveto 250.37174 336.88823 250.20312 335.86056 250.20312 334.83972 curveto 250.20312 333.82345 250.37174 332.80034 250.70898 331.77039 curveto 251.04622 330.74045 251.55892 329.68771 252.24707 328.61218 curveto 253.34082 328.61218 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 259.08984 333.58191 moveto 258.47005 333.58191 257.97786 333.79383 257.61328 334.21765 curveto 257.25325 334.64148 257.07324 335.22254 257.07324 335.96082 curveto 257.07324 336.69454 257.25325 337.2756 257.61328 337.70398 curveto 257.97786 338.12781 258.47005 338.33972 259.08984 338.33972 curveto 259.70963 338.33972 260.19954 338.12781 260.55957 337.70398 curveto 260.92415 337.2756 261.10644 336.69454 261.10645 335.96082 curveto 261.10644 335.22254 260.92415 334.64148 260.55957 334.21765 curveto 260.19954 333.79383 259.70963 333.58191 259.08984 333.58191 curveto 261.83105 329.25476 moveto 261.83105 330.51257 lineto 261.48469 330.34852 261.13378 330.22319 260.77832 330.1366 curveto 260.4274 330.05002 260.07877 330.00672 259.73242 330.00671 curveto 258.82096 330.00672 258.12369 330.31434 257.64062 330.92957 curveto 257.16211 331.54481 256.88867 332.47449 256.82031 333.71863 curveto 257.08919 333.32215 257.42643 333.01909 257.83203 332.80945 curveto 258.23763 332.59526 258.68424 332.48817 259.17188 332.48816 curveto 260.19726 332.48817 261.00618 332.80034 261.59863 333.42468 curveto 262.19563 334.04448 262.49413 334.88986 262.49414 335.96082 curveto 262.49413 337.00899 262.18424 337.84981 261.56445 338.48328 curveto 260.94465 339.11674 260.11979 339.43347 259.08984 339.43347 curveto 257.9095 339.43347 257.00716 338.9823 256.38281 338.07996 curveto 255.75846 337.17306 255.44629 335.86056 255.44629 334.14246 curveto 255.44629 332.52918 255.8291 331.24403 256.59473 330.28699 curveto 257.36035 329.32541 258.38802 328.84461 259.67773 328.8446 curveto 260.02408 328.84461 260.37272 328.87879 260.72363 328.94714 curveto 261.07909 329.01551 261.44824 329.11805 261.83105 329.25476 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 265.02344 337.4989 moveto 266.46582 337.4989 lineto 266.46582 338.67468 lineto 265.34473 340.86218 lineto 264.46289 340.86218 lineto 265.02344 338.67468 lineto 265.02344 337.4989 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 269.57617 338.07312 moveto 271.83203 338.07312 lineto 271.83203 330.28699 lineto 269.37793 330.77917 lineto 269.37793 329.52136 lineto 271.81836 329.02917 lineto 273.19922 329.02917 lineto 273.19922 338.07312 lineto 275.45508 338.07312 lineto 275.45508 339.23523 lineto 269.57617 339.23523 lineto 269.57617 338.07312 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 278.39453 337.4989 moveto 279.83691 337.4989 lineto 279.83691 338.67468 lineto 278.71582 340.86218 lineto 277.83398 340.86218 lineto 278.39453 338.67468 lineto 278.39453 337.4989 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 285.49707 332.46082 moveto 284.82259 332.46082 284.28938 332.72514 283.89746 333.25378 curveto 283.50553 333.77788 283.30957 334.49793 283.30957 335.41394 curveto 283.30957 336.32996 283.50325 337.05229 283.89062 337.58093 curveto 284.28255 338.10502 284.81803 338.36707 285.49707 338.36707 curveto 286.16699 338.36707 286.69791 338.10274 287.08984 337.5741 curveto 287.48176 337.04545 287.67773 336.3254 287.67773 335.41394 curveto 287.67773 334.50704 287.48176 333.78927 287.08984 333.26062 curveto 286.69791 332.72742 286.16699 332.46082 285.49707 332.46082 curveto 285.49707 331.39441 moveto 286.59081 331.39442 287.44986 331.74989 288.07422 332.46082 curveto 288.69856 333.17176 289.01073 334.15613 289.01074 335.41394 curveto 289.01073 336.6672 288.69856 337.65157 288.07422 338.36707 curveto 287.44986 339.078 286.59081 339.43347 285.49707 339.43347 curveto 284.39876 339.43347 283.53743 339.078 282.91309 338.36707 curveto 282.29329 337.65157 281.9834 336.6672 281.9834 335.41394 curveto 281.9834 334.15613 282.29329 333.17176 282.91309 332.46082 curveto 283.53743 331.74989 284.39876 331.39442 285.49707 331.39441 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 290.89062 328.61218 moveto 291.98438 328.61218 lineto 292.66797 329.68771 293.17838 330.74045 293.51562 331.77039 curveto 293.85742 332.80034 294.02832 333.82345 294.02832 334.83972 curveto 294.02832 335.86056 293.85742 336.88823 293.51562 337.92273 curveto 293.17838 338.95723 292.66797 340.00997 291.98438 341.08093 curveto 290.89062 341.08093 lineto 291.49674 340.03731 291.94791 339.00053 292.24414 337.97058 curveto 292.54492 336.93608 292.69531 335.89246 292.69531 334.83972 curveto 292.69531 333.78699 292.54492 332.74793 292.24414 331.72253 curveto 291.94791 330.69715 291.49674 329.66037 290.89062 328.61218 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 188.1377 350.98914 moveto 187.52701 352.03732 187.07356 353.07411 186.77734 354.09949 curveto 186.48112 355.12488 186.33301 356.16395 186.33301 357.21667 curveto 186.33301 358.26941 186.48112 359.31303 186.77734 360.34753 curveto 187.07812 361.37748 187.53157 362.41427 188.1377 363.45789 curveto 187.04395 363.45789 lineto 186.36035 362.38692 185.84765 361.33419 185.50586 360.29968 curveto 185.16862 359.26518 185 358.23751 185 357.21667 curveto 185 356.2004 185.16862 355.17729 185.50586 354.14734 curveto 185.8431 353.1174 186.35579 352.06467 187.04395 350.98914 curveto 188.1377 350.98914 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 190.41406 351.40613 moveto 196.97656 351.40613 lineto 196.97656 351.99402 lineto 193.27148 361.61218 lineto 191.8291 361.61218 lineto 195.31543 352.56824 lineto 190.41406 352.56824 lineto 190.41406 351.40613 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 199.82031 359.87585 moveto 201.2627 359.87585 lineto 201.2627 361.05164 lineto 200.1416 363.23914 lineto 199.25977 363.23914 lineto 199.82031 361.05164 lineto 199.82031 359.87585 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 205.32324 360.45007 moveto 210.14258 360.45007 lineto 210.14258 361.61218 lineto 203.66211 361.61218 lineto 203.66211 360.45007 lineto 204.1862 359.90776 204.89941 359.18087 205.80176 358.26941 curveto 206.70865 357.3534 207.27832 356.76323 207.51074 356.4989 curveto 207.95279 356.00216 208.26041 355.58289 208.43359 355.24109 curveto 208.61132 354.89474 208.70019 354.55522 208.7002 354.22253 curveto 208.70019 353.68022 208.50878 353.23817 208.12598 352.89636 curveto 207.74772 352.55457 207.25325 352.38368 206.64258 352.38367 curveto 206.20963 352.38368 205.75162 352.45887 205.26855 352.60925 curveto 204.79004 352.75965 204.27734 352.98752 203.73047 353.29285 curveto 203.73047 351.89832 lineto 204.28646 351.67502 204.80599 351.5064 205.28906 351.39246 curveto 205.77213 351.27853 206.21419 351.22157 206.61523 351.22156 curveto 207.67252 351.22157 208.51562 351.48589 209.14453 352.01453 curveto 209.77343 352.54318 210.08788 353.24956 210.08789 354.13367 curveto 210.08788 354.55294 210.00813 354.95171 209.84863 355.32996 curveto 209.69368 355.70366 209.40885 356.14572 208.99414 356.65613 curveto 208.8802 356.78829 208.5179 357.17111 207.90723 357.80457 curveto 207.29654 358.43347 206.43522 359.31531 205.32324 360.45007 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 213.19141 359.87585 moveto 214.63379 359.87585 lineto 214.63379 361.05164 lineto 213.5127 363.23914 lineto 212.63086 363.23914 lineto 213.19141 361.05164 lineto 213.19141 359.87585 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 220.29395 354.83777 moveto 219.61946 354.83778 219.08626 355.1021 218.69434 355.63074 curveto 218.30241 356.15483 218.10644 356.87488 218.10645 357.79089 curveto 218.10644 358.70691 218.30013 359.42924 218.6875 359.95789 curveto 219.07942 360.48198 219.61491 360.74402 220.29395 360.74402 curveto 220.96386 360.74402 221.49479 360.4797 221.88672 359.95105 curveto 222.27864 359.42241 222.4746 358.70235 222.47461 357.79089 curveto 222.4746 356.884 222.27864 356.16622 221.88672 355.63757 curveto 221.49479 355.10438 220.96386 354.83778 220.29395 354.83777 curveto 220.29395 353.77136 moveto 221.38769 353.77137 222.24674 354.12684 222.87109 354.83777 curveto 223.49544 355.54871 223.80761 356.53309 223.80762 357.79089 curveto 223.80761 359.04415 223.49544 360.02853 222.87109 360.74402 curveto 222.24674 361.45496 221.38769 361.81042 220.29395 361.81042 curveto 219.19563 361.81042 218.33431 361.45496 217.70996 360.74402 curveto 217.09017 360.02853 216.78027 359.04415 216.78027 357.79089 curveto 216.78027 356.53309 217.09017 355.54871 217.70996 354.83777 curveto 218.33431 354.12684 219.19563 353.77137 220.29395 353.77136 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 225.6875 350.98914 moveto 226.78125 350.98914 lineto 227.46484 352.06467 227.97526 353.1174 228.3125 354.14734 curveto 228.65429 355.17729 228.82519 356.2004 228.8252 357.21667 curveto 228.82519 358.23751 228.65429 359.26518 228.3125 360.29968 curveto 227.97526 361.33419 227.46484 362.38692 226.78125 363.45789 curveto 225.6875 363.45789 lineto 226.29362 362.41427 226.74479 361.37748 227.04102 360.34753 curveto 227.34179 359.31303 227.49218 358.26941 227.49219 357.21667 curveto 227.49218 356.16395 227.34179 355.12488 227.04102 354.09949 curveto 226.74479 353.07411 226.29362 352.03732 225.6875 350.98914 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 232.84082 350.48914 moveto 232.23014 351.53732 231.77669 352.57411 231.48047 353.59949 curveto 231.18424 354.62488 231.03613 355.66395 231.03613 356.71667 curveto 231.03613 357.76941 231.18424 358.81303 231.48047 359.84753 curveto 231.78125 360.87748 232.2347 361.91427 232.84082 362.95789 curveto 231.74707 362.95789 lineto 231.06347 361.88692 230.55078 360.83419 230.20898 359.79968 curveto 229.87174 358.76518 229.70312 357.73751 229.70312 356.71667 curveto 229.70312 355.7004 229.87174 354.67729 230.20898 353.64734 curveto 230.54622 352.6174 231.05892 351.56467 231.74707 350.48914 curveto 232.84082 350.48914 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 238.41895 356.2655 moveto 237.76269 356.26551 237.24544 356.44096 236.86719 356.79187 curveto 236.49349 357.14279 236.30664 357.62586 236.30664 358.24109 curveto 236.30664 358.85633 236.49349 359.3394 236.86719 359.69031 curveto 237.24544 360.04122 237.76269 360.21668 238.41895 360.21667 curveto 239.07519 360.21668 239.59244 360.04122 239.9707 359.69031 curveto 240.34895 359.33484 240.53808 358.85177 240.53809 358.24109 curveto 240.53808 357.62586 240.34895 357.14279 239.9707 356.79187 curveto 239.597 356.44096 239.07975 356.26551 238.41895 356.2655 curveto 237.03809 355.67761 moveto 236.44564 355.53178 235.98307 355.25607 235.65039 354.85046 curveto 235.32226 354.44487 235.1582 353.95041 235.1582 353.36707 curveto 235.1582 352.55132 235.44759 351.90646 236.02637 351.4325 curveto 236.6097 350.95855 237.40722 350.72157 238.41895 350.72156 curveto 239.43522 350.72157 240.23274 350.95855 240.81152 351.4325 curveto 241.39029 351.90646 241.67968 352.55132 241.67969 353.36707 curveto 241.67968 353.95041 241.51334 354.44487 241.18066 354.85046 curveto 240.85253 355.25607 240.39452 355.53178 239.80664 355.67761 curveto 240.472 355.83257 240.98925 356.13563 241.3584 356.58679 curveto 241.73209 357.03797 241.91894 357.5894 241.91895 358.24109 curveto 241.91894 359.23002 241.61588 359.98881 241.00977 360.51746 curveto 240.4082 361.0461 239.54459 361.31042 238.41895 361.31042 curveto 237.29329 361.31042 236.42741 361.0461 235.82129 360.51746 curveto 235.21973 359.98881 234.91894 359.23002 234.91895 358.24109 curveto 234.91894 357.5894 235.10579 357.03797 235.47949 356.58679 curveto 235.85319 356.13563 236.37272 355.83257 237.03809 355.67761 curveto 236.53223 353.49695 moveto 236.53222 354.0256 236.69629 354.43804 237.02441 354.73425 curveto 237.35709 355.03048 237.82194 355.17859 238.41895 355.17859 curveto 239.01139 355.17859 239.47395 355.03048 239.80664 354.73425 curveto 240.14387 354.43804 240.31249 354.0256 240.3125 353.49695 curveto 240.31249 352.96831 240.14387 352.55588 239.80664 352.25964 curveto 239.47395 351.96343 239.01139 351.81532 238.41895 351.81531 curveto 237.82194 351.81532 237.35709 351.96343 237.02441 352.25964 curveto 236.69629 352.55588 236.53222 352.96831 236.53223 353.49695 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 244.52344 359.37585 moveto 245.96582 359.37585 lineto 245.96582 360.55164 lineto 244.84473 362.73914 lineto 243.96289 362.73914 lineto 244.52344 360.55164 lineto 244.52344 359.37585 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 253.02051 355.60925 moveto 253.68131 355.75053 254.19628 356.04448 254.56543 356.49109 curveto 254.93912 356.93771 255.12597 357.48914 255.12598 358.14539 curveto 255.12597 359.15255 254.77961 359.93185 254.08691 360.48328 curveto 253.3942 361.03471 252.40983 361.31042 251.13379 361.31042 curveto 250.7054 361.31042 250.26334 361.26713 249.80762 361.18054 curveto 249.35644 361.09851 248.88932 360.97319 248.40625 360.80457 curveto 248.40625 359.47156 lineto 248.78906 359.69487 249.20833 359.86349 249.66406 359.97742 curveto 250.11979 360.09135 250.59603 360.14832 251.09277 360.14832 curveto 251.95865 360.14832 252.61718 359.97742 253.06836 359.63562 curveto 253.52408 359.29383 253.75195 358.79708 253.75195 358.14539 curveto 253.75195 357.54383 253.54003 357.07443 253.11621 356.73718 curveto 252.69693 356.39539 252.11132 356.22449 251.35938 356.22449 curveto 250.16992 356.22449 lineto 250.16992 355.08972 lineto 251.41406 355.08972 lineto 252.09309 355.08973 252.61262 354.95529 252.97266 354.6864 curveto 253.33268 354.41297 253.51269 354.02104 253.5127 353.51062 curveto 253.51269 352.98654 253.32584 352.5855 252.95215 352.3075 curveto 252.583 352.02495 252.05208 351.88368 251.35938 351.88367 curveto 250.98112 351.88368 250.57552 351.92469 250.14258 352.00671 curveto 249.70963 352.08875 249.2334 352.21636 248.71387 352.38953 curveto 248.71387 351.15906 lineto 249.23795 351.01323 249.72786 350.90386 250.18359 350.83093 curveto 250.64388 350.75803 251.07682 350.72157 251.48242 350.72156 curveto 252.53059 350.72157 253.36002 350.96083 253.9707 351.43933 curveto 254.58137 351.9133 254.88671 352.55588 254.88672 353.36707 curveto 254.88671 353.93218 254.72493 354.41069 254.40137 354.80261 curveto 254.07779 355.18999 253.61751 355.45887 253.02051 355.60925 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 257.89453 359.37585 moveto 259.33691 359.37585 lineto 259.33691 360.55164 lineto 258.21582 362.73914 lineto 257.33398 362.73914 lineto 257.89453 360.55164 lineto 257.89453 359.37585 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 264.99707 354.33777 moveto 264.32259 354.33778 263.78938 354.6021 263.39746 355.13074 curveto 263.00553 355.65483 262.80957 356.37488 262.80957 357.29089 curveto 262.80957 358.20691 263.00325 358.92924 263.39062 359.45789 curveto 263.78255 359.98198 264.31803 360.24402 264.99707 360.24402 curveto 265.66699 360.24402 266.19791 359.9797 266.58984 359.45105 curveto 266.98176 358.92241 267.17773 358.20235 267.17773 357.29089 curveto 267.17773 356.384 266.98176 355.66622 266.58984 355.13757 curveto 266.19791 354.60438 265.66699 354.33778 264.99707 354.33777 curveto 264.99707 353.27136 moveto 266.09081 353.27137 266.94986 353.62684 267.57422 354.33777 curveto 268.19856 355.04871 268.51073 356.03309 268.51074 357.29089 curveto 268.51073 358.54415 268.19856 359.52853 267.57422 360.24402 curveto 266.94986 360.95496 266.09081 361.31042 264.99707 361.31042 curveto 263.89876 361.31042 263.03743 360.95496 262.41309 360.24402 curveto 261.79329 359.52853 261.4834 358.54415 261.4834 357.29089 curveto 261.4834 356.03309 261.79329 355.04871 262.41309 354.33777 curveto 263.03743 353.62684 263.89876 353.27137 264.99707 353.27136 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 270.39062 350.48914 moveto 271.48438 350.48914 lineto 272.16797 351.56467 272.67838 352.6174 273.01562 353.64734 curveto 273.35742 354.67729 273.52832 355.7004 273.52832 356.71667 curveto 273.52832 357.73751 273.35742 358.76518 273.01562 359.79968 curveto 272.67838 360.83419 272.16797 361.88692 271.48438 362.95789 curveto 270.39062 362.95789 lineto 270.99674 361.91427 271.44791 360.87748 271.74414 359.84753 curveto 272.04492 358.81303 272.19531 357.76941 272.19531 356.71667 curveto 272.19531 355.66395 272.04492 354.62488 271.74414 353.59949 curveto 271.44791 352.57411 270.99674 351.53732 270.39062 350.48914 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 278.84082 350.64343 moveto 278.23014 351.69162 277.77669 352.7284 277.48047 353.75378 curveto 277.18424 354.77918 277.03613 355.81824 277.03613 356.87097 curveto 277.03613 357.92371 277.18424 358.96733 277.48047 360.00183 curveto 277.78125 361.03178 278.2347 362.06856 278.84082 363.11218 curveto 277.74707 363.11218 lineto 277.06347 362.04122 276.55078 360.98848 276.20898 359.95398 curveto 275.87174 358.91948 275.70312 357.89181 275.70312 356.87097 curveto 275.70312 355.8547 275.87174 354.83159 276.20898 353.80164 curveto 276.54622 352.7717 277.05892 351.71896 277.74707 350.64343 curveto 278.84082 350.64343 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 281.50684 361.05457 moveto 281.50684 359.79675 lineto 281.85319 359.96082 282.2041 360.08614 282.55957 360.17273 curveto 282.91504 360.25932 283.26367 360.30261 283.60547 360.30261 curveto 284.51692 360.30261 285.21191 359.99728 285.69043 359.3866 curveto 286.1735 358.77136 286.44921 357.8394 286.51758 356.5907 curveto 286.25325 356.98263 285.91829 357.28341 285.5127 357.49304 curveto 285.10709 357.70268 284.6582 357.8075 284.16602 357.8075 curveto 283.14518 357.8075 282.33626 357.49988 281.73926 356.88464 curveto 281.14681 356.26486 280.85059 355.41948 280.85059 354.34851 curveto 280.85059 353.30034 281.16048 352.45952 281.78027 351.82605 curveto 282.40006 351.1926 283.22493 350.87586 284.25488 350.87585 curveto 285.43522 350.87586 286.33528 351.32931 286.95508 352.23621 curveto 287.57942 353.13856 287.89159 354.45106 287.8916 356.17371 curveto 287.89159 357.78243 287.50878 359.06759 286.74316 360.02917 curveto 285.98209 360.98621 284.9567 361.46472 283.66699 361.46472 curveto 283.32063 361.46472 282.96972 361.43054 282.61426 361.36218 curveto 282.25879 361.29382 281.88965 361.19128 281.50684 361.05457 curveto 284.25488 356.72742 moveto 284.87467 356.72742 285.36458 356.51551 285.72461 356.09167 curveto 286.08919 355.66785 286.27148 355.0868 286.27148 354.34851 curveto 286.27148 353.61479 286.08919 353.03602 285.72461 352.61218 curveto 285.36458 352.18381 284.87467 351.96961 284.25488 351.9696 curveto 283.63509 351.96961 283.1429 352.18381 282.77832 352.61218 curveto 282.41829 353.03602 282.23828 353.61479 282.23828 354.34851 curveto 282.23828 355.0868 282.41829 355.66785 282.77832 356.09167 curveto 283.1429 356.51551 283.63509 356.72742 284.25488 356.72742 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 290.52344 359.53015 moveto 291.96582 359.53015 lineto 291.96582 360.70593 lineto 290.84473 362.89343 lineto 289.96289 362.89343 lineto 290.52344 360.70593 lineto 290.52344 359.53015 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 298.63086 352.26355 moveto 295.14453 357.71179 lineto 298.63086 357.71179 lineto 298.63086 352.26355 lineto 298.26855 351.06042 moveto 300.00488 351.06042 lineto 300.00488 357.71179 lineto 301.46094 357.71179 lineto 301.46094 358.86023 lineto 300.00488 358.86023 lineto 300.00488 361.26648 lineto 298.63086 361.26648 lineto 298.63086 358.86023 lineto 294.02344 358.86023 lineto 294.02344 357.52722 lineto 298.26855 351.06042 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 303.89453 359.53015 moveto 305.33691 359.53015 lineto 305.33691 360.70593 lineto 304.21582 362.89343 lineto 303.33398 362.89343 lineto 303.89453 360.70593 lineto 303.89453 359.53015 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 310.99707 354.49207 moveto 310.32259 354.49207 309.78938 354.75639 309.39746 355.28503 curveto 309.00553 355.80913 308.80957 356.52918 308.80957 357.44519 curveto 308.80957 358.36121 309.00325 359.08354 309.39062 359.61218 curveto 309.78255 360.13627 310.31803 360.39832 310.99707 360.39832 curveto 311.66699 360.39832 312.19791 360.13399 312.58984 359.60535 curveto 312.98176 359.0767 313.17773 358.35665 313.17773 357.44519 curveto 313.17773 356.53829 312.98176 355.82052 312.58984 355.29187 curveto 312.19791 354.75867 311.66699 354.49207 310.99707 354.49207 curveto 310.99707 353.42566 moveto 312.09081 353.42567 312.94986 353.78114 313.57422 354.49207 curveto 314.19856 355.20301 314.51073 356.18738 314.51074 357.44519 curveto 314.51073 358.69845 314.19856 359.68282 313.57422 360.39832 curveto 312.94986 361.10925 312.09081 361.46472 310.99707 361.46472 curveto 309.89876 361.46472 309.03743 361.10925 308.41309 360.39832 curveto 307.79329 359.68282 307.4834 358.69845 307.4834 357.44519 curveto 307.4834 356.18738 307.79329 355.20301 308.41309 354.49207 curveto 309.03743 353.78114 309.89876 353.42567 310.99707 353.42566 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 316.39062 350.64343 moveto 317.48438 350.64343 lineto 318.16797 351.71896 318.67838 352.7717 319.01562 353.80164 curveto 319.35742 354.83159 319.52832 355.8547 319.52832 356.87097 curveto 319.52832 357.89181 319.35742 358.91948 319.01562 359.95398 curveto 318.67838 360.98848 318.16797 362.04122 317.48438 363.11218 curveto 316.39062 363.11218 lineto 316.99674 362.06856 317.44791 361.03178 317.74414 360.00183 curveto 318.04492 358.96733 318.19531 357.92371 318.19531 356.87097 curveto 318.19531 355.81824 318.04492 354.77918 317.74414 353.75378 curveto 317.44791 352.7284 316.99674 351.69162 316.39062 350.64343 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 197.1377 371.14343 moveto 196.52701 372.19162 196.07356 373.2284 195.77734 374.25378 curveto 195.48112 375.27918 195.33301 376.31824 195.33301 377.37097 curveto 195.33301 378.42371 195.48112 379.46733 195.77734 380.50183 curveto 196.07812 381.53178 196.53157 382.56856 197.1377 383.61218 curveto 196.04395 383.61218 lineto 195.36035 382.54122 194.84765 381.48848 194.50586 380.45398 curveto 194.16862 379.41948 194 378.39181 194 377.37097 curveto 194 376.3547 194.16862 375.33159 194.50586 374.30164 curveto 194.8431 373.2717 195.35579 372.21896 196.04395 371.14343 curveto 197.1377 371.14343 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 200.00195 380.60437 moveto 202.25781 380.60437 lineto 202.25781 372.81824 lineto 199.80371 373.31042 lineto 199.80371 372.05261 lineto 202.24414 371.56042 lineto 203.625 371.56042 lineto 203.625 380.60437 lineto 205.88086 380.60437 lineto 205.88086 381.76648 lineto 200.00195 381.76648 lineto 200.00195 380.60437 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 211.62988 372.4696 moveto 210.91894 372.46961 210.38346 372.82052 210.02344 373.52234 curveto 209.66797 374.21961 209.49023 375.27007 209.49023 376.67371 curveto 209.49023 378.0728 209.66797 379.12325 210.02344 379.82507 curveto 210.38346 380.52234 210.91894 380.87097 211.62988 380.87097 curveto 212.34537 380.87097 212.88085 380.52234 213.23633 379.82507 curveto 213.59635 379.12325 213.77636 378.0728 213.77637 376.67371 curveto 213.77636 375.27007 213.59635 374.21961 213.23633 373.52234 curveto 212.88085 372.82052 212.34537 372.46961 211.62988 372.4696 curveto 211.62988 371.37585 moveto 212.77376 371.37586 213.64648 371.82931 214.24805 372.73621 curveto 214.85416 373.63856 215.15722 374.95106 215.15723 376.67371 curveto 215.15722 378.39181 214.85416 379.70431 214.24805 380.61121 curveto 213.64648 381.51355 212.77376 381.96472 211.62988 381.96472 curveto 210.486 381.96472 209.611 381.51355 209.00488 380.61121 curveto 208.40332 379.70431 208.10254 378.39181 208.10254 376.67371 curveto 208.10254 374.95106 208.40332 373.63856 209.00488 372.73621 curveto 209.611 371.82931 210.486 371.37586 211.62988 371.37585 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 217.73438 380.03015 moveto 219.17676 380.03015 lineto 219.17676 381.20593 lineto 218.05566 383.39343 lineto 217.17383 383.39343 lineto 217.73438 381.20593 lineto 217.73438 380.03015 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 222.06152 371.56042 moveto 227.48242 371.56042 lineto 227.48242 372.72253 lineto 223.32617 372.72253 lineto 223.32617 375.22449 lineto 223.52669 375.15613 223.72721 375.106 223.92773 375.0741 curveto 224.12825 375.03765 224.32877 375.01942 224.5293 375.01941 curveto 225.66861 375.01942 226.57096 375.33159 227.23633 375.95593 curveto 227.90169 376.58029 228.23437 377.42566 228.23438 378.49207 curveto 228.23437 379.59037 227.89257 380.44487 227.20898 381.05554 curveto 226.52538 381.66166 225.56152 381.96472 224.31738 381.96472 curveto 223.88899 381.96472 223.45149 381.92826 223.00488 381.85535 curveto 222.56282 381.78243 222.10482 381.67306 221.63086 381.52722 curveto 221.63086 380.13953 lineto 222.04101 380.36284 222.46484 380.52918 222.90234 380.63855 curveto 223.33984 380.74793 223.80241 380.80261 224.29004 380.80261 curveto 225.07845 380.80261 225.70279 380.59526 226.16309 380.18054 curveto 226.62337 379.76583 226.85351 379.20301 226.85352 378.49207 curveto 226.85351 377.78113 226.62337 377.21831 226.16309 376.80359 curveto 225.70279 376.38888 225.07845 376.18152 224.29004 376.18152 curveto 223.9209 376.18152 223.55175 376.22254 223.18262 376.30457 curveto 222.81803 376.3866 222.44433 376.51421 222.06152 376.68738 curveto 222.06152 371.56042 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 231.10547 380.03015 moveto 232.54785 380.03015 lineto 232.54785 381.20593 lineto 231.42676 383.39343 lineto 230.54492 383.39343 lineto 231.10547 381.20593 lineto 231.10547 380.03015 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 238.20801 374.99207 moveto 237.53353 374.99207 237.00032 375.25639 236.6084 375.78503 curveto 236.21647 376.30913 236.02051 377.02918 236.02051 377.94519 curveto 236.02051 378.86121 236.21419 379.58354 236.60156 380.11218 curveto 236.99349 380.63627 237.52897 380.89832 238.20801 380.89832 curveto 238.87792 380.89832 239.40885 380.63399 239.80078 380.10535 curveto 240.1927 379.5767 240.38867 378.85665 240.38867 377.94519 curveto 240.38867 377.03829 240.1927 376.32052 239.80078 375.79187 curveto 239.40885 375.25867 238.87792 374.99207 238.20801 374.99207 curveto 238.20801 373.92566 moveto 239.30175 373.92567 240.1608 374.28114 240.78516 374.99207 curveto 241.4095 375.70301 241.72167 376.68738 241.72168 377.94519 curveto 241.72167 379.19845 241.4095 380.18282 240.78516 380.89832 curveto 240.1608 381.60925 239.30175 381.96472 238.20801 381.96472 curveto 237.1097 381.96472 236.24837 381.60925 235.62402 380.89832 curveto 235.00423 380.18282 234.69434 379.19845 234.69434 377.94519 curveto 234.69434 376.68738 235.00423 375.70301 235.62402 374.99207 curveto 236.24837 374.28114 237.1097 373.92567 238.20801 373.92566 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 243.60156 371.14343 moveto 244.69531 371.14343 lineto 245.3789 372.21896 245.88932 373.2717 246.22656 374.30164 curveto 246.56836 375.33159 246.73925 376.3547 246.73926 377.37097 curveto 246.73925 378.39181 246.56836 379.41948 246.22656 380.45398 curveto 245.88932 381.48848 245.3789 382.54122 244.69531 383.61218 curveto 243.60156 383.61218 lineto 244.20768 382.56856 244.65885 381.53178 244.95508 380.50183 curveto 245.25586 379.46733 245.40625 378.42371 245.40625 377.37097 curveto 245.40625 376.31824 245.25586 375.27918 244.95508 374.25378 curveto 244.65885 373.2284 244.20768 372.19162 243.60156 371.14343 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 252.1377 371.98914 moveto 251.52701 373.03732 251.07356 374.07411 250.77734 375.09949 curveto 250.48112 376.12488 250.33301 377.16395 250.33301 378.21667 curveto 250.33301 379.26941 250.48112 380.31303 250.77734 381.34753 curveto 251.07812 382.37748 251.53157 383.41427 252.1377 384.45789 curveto 251.04395 384.45789 lineto 250.36035 383.38692 249.84765 382.33419 249.50586 381.29968 curveto 249.16862 380.26518 249 379.23751 249 378.21667 curveto 249 377.2004 249.16862 376.17729 249.50586 375.14734 curveto 249.8431 374.1174 250.35579 373.06467 251.04395 371.98914 curveto 252.1377 371.98914 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 255.00195 381.45007 moveto 257.25781 381.45007 lineto 257.25781 373.66394 lineto 254.80371 374.15613 lineto 254.80371 372.89832 lineto 257.24414 372.40613 lineto 258.625 372.40613 lineto 258.625 381.45007 lineto 260.88086 381.45007 lineto 260.88086 382.61218 lineto 255.00195 382.61218 lineto 255.00195 381.45007 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 263.91602 381.45007 moveto 266.17188 381.45007 lineto 266.17188 373.66394 lineto 263.71777 374.15613 lineto 263.71777 372.89832 lineto 266.1582 372.40613 lineto 267.53906 372.40613 lineto 267.53906 381.45007 lineto 269.79492 381.45007 lineto 269.79492 382.61218 lineto 263.91602 382.61218 lineto 263.91602 381.45007 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 272.73438 380.87585 moveto 274.17676 380.87585 lineto 274.17676 382.05164 lineto 273.05566 384.23914 lineto 272.17383 384.23914 lineto 272.73438 382.05164 lineto 272.73438 380.87585 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 280.17188 376.95886 moveto 279.55208 376.95887 279.05989 377.17078 278.69531 377.5946 curveto 278.33528 378.01844 278.15527 378.59949 278.15527 379.33777 curveto 278.15527 380.0715 278.33528 380.65255 278.69531 381.08093 curveto 279.05989 381.50476 279.55208 381.71668 280.17188 381.71667 curveto 280.79166 381.71668 281.28157 381.50476 281.6416 381.08093 curveto 282.00618 380.65255 282.18847 380.0715 282.18848 379.33777 curveto 282.18847 378.59949 282.00618 378.01844 281.6416 377.5946 curveto 281.28157 377.17078 280.79166 376.95887 280.17188 376.95886 curveto 282.91309 372.63171 moveto 282.91309 373.88953 lineto 282.56672 373.72547 282.21581 373.60015 281.86035 373.51355 curveto 281.50943 373.42697 281.1608 373.38368 280.81445 373.38367 curveto 279.90299 373.38368 279.20573 373.69129 278.72266 374.30652 curveto 278.24414 374.92176 277.9707 375.85145 277.90234 377.09558 curveto 278.17122 376.6991 278.50846 376.39604 278.91406 376.1864 curveto 279.31966 375.97222 279.76627 375.86512 280.25391 375.86511 curveto 281.27929 375.86512 282.08821 376.17729 282.68066 376.80164 curveto 283.27766 377.42143 283.57616 378.26681 283.57617 379.33777 curveto 283.57616 380.38595 283.26627 381.22677 282.64648 381.86023 curveto 282.02669 382.49369 281.20182 382.81042 280.17188 382.81042 curveto 278.99153 382.81042 278.08919 382.35925 277.46484 381.45691 curveto 276.84049 380.55001 276.52832 379.23751 276.52832 377.51941 curveto 276.52832 375.90613 276.91113 374.62098 277.67676 373.66394 curveto 278.44238 372.70236 279.47005 372.22157 280.75977 372.22156 curveto 281.10611 372.22157 281.45475 372.25575 281.80566 372.3241 curveto 282.16113 372.39247 282.53027 372.49501 282.91309 372.63171 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 286.10547 380.87585 moveto 287.54785 380.87585 lineto 287.54785 382.05164 lineto 286.42676 384.23914 lineto 285.54492 384.23914 lineto 286.10547 382.05164 lineto 286.10547 380.87585 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 293.20801 375.83777 moveto 292.53353 375.83778 292.00032 376.1021 291.6084 376.63074 curveto 291.21647 377.15483 291.02051 377.87488 291.02051 378.79089 curveto 291.02051 379.70691 291.21419 380.42924 291.60156 380.95789 curveto 291.99349 381.48198 292.52897 381.74402 293.20801 381.74402 curveto 293.87792 381.74402 294.40885 381.4797 294.80078 380.95105 curveto 295.1927 380.42241 295.38867 379.70235 295.38867 378.79089 curveto 295.38867 377.884 295.1927 377.16622 294.80078 376.63757 curveto 294.40885 376.10438 293.87792 375.83778 293.20801 375.83777 curveto 293.20801 374.77136 moveto 294.30175 374.77137 295.1608 375.12684 295.78516 375.83777 curveto 296.4095 376.54871 296.72167 377.53309 296.72168 378.79089 curveto 296.72167 380.04415 296.4095 381.02853 295.78516 381.74402 curveto 295.1608 382.45496 294.30175 382.81042 293.20801 382.81042 curveto 292.1097 382.81042 291.24837 382.45496 290.62402 381.74402 curveto 290.00423 381.02853 289.69434 380.04415 289.69434 378.79089 curveto 289.69434 377.53309 290.00423 376.54871 290.62402 375.83777 curveto 291.24837 375.12684 292.1097 374.77137 293.20801 374.77136 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 298.60156 371.98914 moveto 299.69531 371.98914 lineto 300.3789 373.06467 300.88932 374.1174 301.22656 375.14734 curveto 301.56836 376.17729 301.73925 377.2004 301.73926 378.21667 curveto 301.73925 379.23751 301.56836 380.26518 301.22656 381.29968 curveto 300.88932 382.33419 300.3789 383.38692 299.69531 384.45789 curveto 298.60156 384.45789 lineto 299.20768 383.41427 299.65885 382.37748 299.95508 381.34753 curveto 300.25586 380.31303 300.40625 379.26941 300.40625 378.21667 curveto 300.40625 377.16395 300.25586 376.12488 299.95508 375.09949 curveto 299.65885 374.07411 299.20768 373.03732 298.60156 371.98914 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 238.37402 312.40613 moveto 239.75488 312.40613 lineto 239.75488 322.61218 lineto 238.37402 322.61218 lineto 238.37402 312.40613 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 247.3291 315.18152 moveto 247.3291 316.37097 lineto 246.97363 316.18869 246.60449 316.05197 246.22168 315.96082 curveto 245.83886 315.86968 245.44238 315.8241 245.03223 315.8241 curveto 244.40787 315.8241 243.93847 315.91981 243.62402 316.11121 curveto 243.31413 316.30262 243.15918 316.58973 243.15918 316.97253 curveto 243.15918 317.26421 243.27083 317.49435 243.49414 317.66296 curveto 243.71745 317.82703 244.16634 317.98426 244.84082 318.13464 curveto 245.27148 318.23035 lineto 246.16471 318.42176 246.79817 318.69292 247.17188 319.04382 curveto 247.55012 319.39018 247.73925 319.87553 247.73926 320.49988 curveto 247.73925 321.21082 247.4567 321.77364 246.8916 322.18835 curveto 246.33105 322.60307 245.55859 322.81042 244.57422 322.81042 curveto 244.16406 322.81042 243.73567 322.76941 243.28906 322.68738 curveto 242.847 322.6099 242.37988 322.49141 241.8877 322.33191 curveto 241.8877 321.03308 lineto 242.35254 321.27462 242.81055 321.45691 243.26172 321.57996 curveto 243.71289 321.69845 244.1595 321.75769 244.60156 321.75769 curveto 245.19401 321.75769 245.64974 321.65743 245.96875 321.45691 curveto 246.28776 321.25183 246.44726 320.96472 246.44727 320.59558 curveto 246.44726 320.25379 246.33105 319.99174 246.09863 319.80945 curveto 245.87076 319.62716 245.36718 319.4517 244.58789 319.28308 curveto 244.15039 319.18054 lineto 243.37109 319.01648 242.80827 318.76583 242.46191 318.42859 curveto 242.11556 318.0868 241.94238 317.61967 241.94238 317.02722 curveto 241.94238 316.30718 242.19759 315.75119 242.70801 315.35925 curveto 243.21842 314.96733 243.94303 314.77137 244.88184 314.77136 curveto 245.34668 314.77137 245.78418 314.80555 246.19434 314.8739 curveto 246.60449 314.94227 246.98274 315.04481 247.3291 315.18152 curveto fill grestore gsave [1 0 0 1 3.250285 1] concat gsave 0 0 0 setrgbcolor newpath 180.84082 436.23914 moveto 180.23014 437.28732 179.77669 438.32411 179.48047 439.34949 curveto 179.18424 440.37488 179.03613 441.41395 179.03613 442.46667 curveto 179.03613 443.51941 179.18424 444.56303 179.48047 445.59753 curveto 179.78125 446.62748 180.2347 447.66427 180.84082 448.70789 curveto 179.74707 448.70789 lineto 179.06347 447.63692 178.55078 446.58419 178.20898 445.54968 curveto 177.87174 444.51518 177.70312 443.48751 177.70312 442.46667 curveto 177.70312 441.4504 177.87174 440.42729 178.20898 439.39734 curveto 178.54622 438.3674 179.05892 437.31467 179.74707 436.23914 curveto 180.84082 436.23914 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 184.65527 445.70007 moveto 189.47461 445.70007 lineto 189.47461 446.86218 lineto 182.99414 446.86218 lineto 182.99414 445.70007 lineto 183.51823 445.15776 184.23144 444.43087 185.13379 443.51941 curveto 186.04069 442.6034 186.61035 442.01323 186.84277 441.7489 curveto 187.28483 441.25216 187.59244 440.83289 187.76562 440.49109 curveto 187.94335 440.14474 188.03222 439.80522 188.03223 439.47253 curveto 188.03222 438.93022 187.84081 438.48817 187.45801 438.14636 curveto 187.07975 437.80457 186.58528 437.63368 185.97461 437.63367 curveto 185.54166 437.63368 185.08366 437.70887 184.60059 437.85925 curveto 184.12207 438.00965 183.60937 438.23752 183.0625 438.54285 curveto 183.0625 437.14832 lineto 183.61849 436.92502 184.13802 436.7564 184.62109 436.64246 curveto 185.10416 436.52853 185.54622 436.47157 185.94727 436.47156 curveto 187.00455 436.47157 187.84765 436.73589 188.47656 437.26453 curveto 189.10546 437.79318 189.41991 438.49956 189.41992 439.38367 curveto 189.41991 439.80294 189.34016 440.20171 189.18066 440.57996 curveto 189.02571 440.95366 188.74088 441.39572 188.32617 441.90613 curveto 188.21223 442.03829 187.84993 442.42111 187.23926 443.05457 curveto 186.62858 443.68347 185.76725 444.56531 184.65527 445.70007 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 192.52344 445.12585 moveto 193.96582 445.12585 lineto 193.96582 446.30164 lineto 192.84473 448.48914 lineto 191.96289 448.48914 lineto 192.52344 446.30164 lineto 192.52344 445.12585 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 199.79004 437.56531 moveto 199.0791 437.56532 198.54362 437.91623 198.18359 438.61804 curveto 197.82812 439.31532 197.65039 440.36577 197.65039 441.76941 curveto 197.65039 443.1685 197.82812 444.21896 198.18359 444.92078 curveto 198.54362 445.61804 199.0791 445.96668 199.79004 445.96667 curveto 200.50553 445.96668 201.04101 445.61804 201.39648 444.92078 curveto 201.7565 444.21896 201.93652 443.1685 201.93652 441.76941 curveto 201.93652 440.36577 201.7565 439.31532 201.39648 438.61804 curveto 201.04101 437.91623 200.50553 437.56532 199.79004 437.56531 curveto 199.79004 436.47156 moveto 200.93391 436.47157 201.80663 436.92502 202.4082 437.83191 curveto 203.01432 438.73426 203.31737 440.04676 203.31738 441.76941 curveto 203.31737 443.48751 203.01432 444.80001 202.4082 445.70691 curveto 201.80663 446.60925 200.93391 447.06042 199.79004 447.06042 curveto 198.64616 447.06042 197.77116 446.60925 197.16504 445.70691 curveto 196.56348 444.80001 196.26269 443.48751 196.2627 441.76941 curveto 196.26269 440.04676 196.56348 438.73426 197.16504 437.83191 curveto 197.77116 436.92502 198.64616 436.47157 199.79004 436.47156 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 205.89453 445.12585 moveto 207.33691 445.12585 lineto 207.33691 446.30164 lineto 206.21582 448.48914 lineto 205.33398 448.48914 lineto 205.89453 446.30164 lineto 205.89453 445.12585 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 215.06836 442.94519 moveto 215.06835 442.03374 214.87923 441.32736 214.50098 440.82605 curveto 214.12727 440.32475 213.60091 440.0741 212.92188 440.0741 curveto 212.24739 440.0741 211.72103 440.32475 211.34277 440.82605 curveto 210.96907 441.32736 210.78222 442.03374 210.78223 442.94519 curveto 210.78222 443.85209 210.96907 444.5562 211.34277 445.0575 curveto 211.72103 445.5588 212.24739 445.80945 212.92188 445.80945 curveto 213.60091 445.80945 214.12727 445.5588 214.50098 445.0575 curveto 214.87923 444.5562 215.06835 443.85209 215.06836 442.94519 curveto 216.32617 445.91199 moveto 216.32616 447.21537 216.03678 448.1838 215.45801 448.81726 curveto 214.87923 449.45528 213.99283 449.77429 212.79883 449.77429 curveto 212.35677 449.77429 211.93978 449.74011 211.54785 449.67175 curveto 211.15592 449.60795 210.77539 449.50769 210.40625 449.37097 curveto 210.40625 448.14734 lineto 210.77539 448.34786 211.13997 448.49597 211.5 448.59167 curveto 211.86002 448.68738 212.22688 448.73523 212.60059 448.73523 curveto 213.42545 448.73523 214.04296 448.51876 214.45312 448.08582 curveto 214.86328 447.65743 215.06835 447.00802 215.06836 446.13757 curveto 215.06836 445.5155 lineto 214.80859 445.96668 214.47591 446.30391 214.07031 446.52722 curveto 213.66471 446.75053 213.17936 446.86218 212.61426 446.86218 curveto 211.67545 446.86218 210.91894 446.50444 210.34473 445.78894 curveto 209.77051 445.07345 209.4834 444.12553 209.4834 442.94519 curveto 209.4834 441.7603 209.77051 440.81011 210.34473 440.0946 curveto 210.91894 439.37912 211.67545 439.02137 212.61426 439.02136 curveto 213.17936 439.02137 213.66471 439.13302 214.07031 439.35632 curveto 214.47591 439.57964 214.80859 439.91688 215.06836 440.36804 curveto 215.06836 439.20593 lineto 216.32617 439.20593 lineto 216.32617 445.91199 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 218.71875 436.23914 moveto 219.8125 436.23914 lineto 220.49609 437.31467 221.00651 438.3674 221.34375 439.39734 curveto 221.68554 440.42729 221.85644 441.4504 221.85645 442.46667 curveto 221.85644 443.48751 221.68554 444.51518 221.34375 445.54968 curveto 221.00651 446.58419 220.49609 447.63692 219.8125 448.70789 curveto 218.71875 448.70789 lineto 219.32487 447.66427 219.77604 446.62748 220.07227 445.59753 curveto 220.37304 444.56303 220.52343 443.51941 220.52344 442.46667 curveto 220.52343 441.41395 220.37304 440.37488 220.07227 439.34949 curveto 219.77604 438.32411 219.32487 437.28732 218.71875 436.23914 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 228.53711 436.77234 moveto 227.92643 437.82053 227.47298 438.85731 227.17676 439.88269 curveto 226.88053 440.90809 226.73242 441.94715 226.73242 442.99988 curveto 226.73242 444.05262 226.88053 445.09623 227.17676 446.13074 curveto 227.47754 447.16069 227.93099 448.19747 228.53711 449.24109 curveto 227.44336 449.24109 lineto 226.75976 448.17012 226.24707 447.11739 225.90527 446.08289 curveto 225.56803 445.04838 225.39941 444.02071 225.39941 442.99988 curveto 225.39941 441.98361 225.56803 440.9605 225.90527 439.93054 curveto 226.24251 438.9006 226.75521 437.84787 227.44336 436.77234 curveto 228.53711 436.77234 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 235.3457 441.89246 moveto 236.0065 442.03374 236.52148 442.32768 236.89062 442.77429 curveto 237.26432 443.22091 237.45116 443.77234 237.45117 444.42859 curveto 237.45116 445.43575 237.10481 446.21505 236.41211 446.76648 curveto 235.71939 447.31791 234.73502 447.59363 233.45898 447.59363 curveto 233.0306 447.59363 232.58854 447.55033 232.13281 447.46375 curveto 231.68164 447.38171 231.21452 447.25639 230.73145 447.08777 curveto 230.73145 445.75476 lineto 231.11426 445.97807 231.53353 446.14669 231.98926 446.26062 curveto 232.44498 446.37455 232.92122 446.43152 233.41797 446.43152 curveto 234.28385 446.43152 234.94238 446.26062 235.39355 445.91882 curveto 235.84928 445.57703 236.07714 445.08028 236.07715 444.42859 curveto 236.07714 443.82703 235.86523 443.35763 235.44141 443.02039 curveto 235.02213 442.67859 234.43652 442.5077 233.68457 442.50769 curveto 232.49512 442.50769 lineto 232.49512 441.37292 lineto 233.73926 441.37292 lineto 234.41829 441.37293 234.93782 441.23849 235.29785 440.9696 curveto 235.65787 440.69617 235.83788 440.30425 235.83789 439.79382 curveto 235.83788 439.26974 235.65104 438.8687 235.27734 438.5907 curveto 234.9082 438.30816 234.37727 438.16688 233.68457 438.16687 curveto 233.30631 438.16688 232.90071 438.20789 232.46777 438.28992 curveto 232.03483 438.37196 231.55859 438.49956 231.03906 438.67273 curveto 231.03906 437.44226 lineto 231.56315 437.29644 232.05306 437.18706 232.50879 437.11414 curveto 232.96907 437.04123 233.40201 437.00477 233.80762 437.00476 curveto 234.85579 437.00477 235.68522 437.24403 236.2959 437.72253 curveto 236.90657 438.1965 237.21191 438.83908 237.21191 439.65027 curveto 237.21191 440.21538 237.05012 440.6939 236.72656 441.08582 curveto 236.40299 441.47319 235.9427 441.74207 235.3457 441.89246 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 240.21973 445.65906 moveto 241.66211 445.65906 lineto 241.66211 446.83484 lineto 240.54102 449.02234 lineto 239.65918 449.02234 lineto 240.21973 446.83484 lineto 240.21973 445.65906 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 244.77246 446.23328 moveto 247.02832 446.23328 lineto 247.02832 438.44714 lineto 244.57422 438.93933 lineto 244.57422 437.68152 lineto 247.01465 437.18933 lineto 248.39551 437.18933 lineto 248.39551 446.23328 lineto 250.65137 446.23328 lineto 250.65137 447.39539 lineto 244.77246 447.39539 lineto 244.77246 446.23328 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 253.59082 445.65906 moveto 255.0332 445.65906 lineto 255.0332 446.83484 lineto 253.91211 449.02234 lineto 253.03027 449.02234 lineto 253.59082 446.83484 lineto 253.59082 445.65906 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 260.69336 440.62097 moveto 260.01888 440.62098 259.48567 440.8853 259.09375 441.41394 curveto 258.70182 441.93803 258.50586 442.65809 258.50586 443.5741 curveto 258.50586 444.49012 258.69954 445.21245 259.08691 445.74109 curveto 259.47884 446.26518 260.01432 446.52722 260.69336 446.52722 curveto 261.36328 446.52722 261.8942 446.2629 262.28613 445.73425 curveto 262.67805 445.20561 262.87402 444.48556 262.87402 443.5741 curveto 262.87402 442.6672 262.67805 441.94943 262.28613 441.42078 curveto 261.8942 440.88758 261.36328 440.62098 260.69336 440.62097 curveto 260.69336 439.55457 moveto 261.7871 439.55457 262.64615 439.91004 263.27051 440.62097 curveto 263.89485 441.33192 264.20702 442.31629 264.20703 443.5741 curveto 264.20702 444.82735 263.89485 445.81173 263.27051 446.52722 curveto 262.64615 447.23816 261.7871 447.59363 260.69336 447.59363 curveto 259.59505 447.59363 258.73372 447.23816 258.10938 446.52722 curveto 257.48958 445.81173 257.17969 444.82735 257.17969 443.5741 curveto 257.17969 442.31629 257.48958 441.33192 258.10938 440.62097 curveto 258.73372 439.91004 259.59505 439.55457 260.69336 439.55457 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 266.08691 436.77234 moveto 267.18066 436.77234 lineto 267.86425 437.84787 268.37467 438.9006 268.71191 439.93054 curveto 269.05371 440.9605 269.22461 441.98361 269.22461 442.99988 curveto 269.22461 444.02071 269.05371 445.04838 268.71191 446.08289 curveto 268.37467 447.11739 267.86425 448.17012 267.18066 449.24109 curveto 266.08691 449.24109 lineto 266.69303 448.19747 267.1442 447.16069 267.44043 446.13074 curveto 267.74121 445.09623 267.8916 444.05262 267.8916 442.99988 curveto 267.8916 441.94715 267.74121 440.90809 267.44043 439.88269 curveto 267.1442 438.85731 266.69303 437.82053 266.08691 436.77234 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 275.5498 436.77234 moveto 274.93912 437.82053 274.48567 438.85731 274.18945 439.88269 curveto 273.89323 440.90809 273.74511 441.94715 273.74512 442.99988 curveto 273.74511 444.05262 273.89323 445.09623 274.18945 446.13074 curveto 274.49023 447.16069 274.94368 448.19747 275.5498 449.24109 curveto 274.45605 449.24109 lineto 273.77246 448.17012 273.25976 447.11739 272.91797 446.08289 curveto 272.58073 445.04838 272.41211 444.02071 272.41211 442.99988 curveto 272.41211 441.98361 272.58073 440.9605 272.91797 439.93054 curveto 273.25521 438.9006 273.7679 437.84787 274.45605 436.77234 curveto 275.5498 436.77234 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 281.96875 438.39246 moveto 278.48242 443.8407 lineto 281.96875 443.8407 lineto 281.96875 438.39246 lineto 281.60645 437.18933 moveto 283.34277 437.18933 lineto 283.34277 443.8407 lineto 284.79883 443.8407 lineto 284.79883 444.98914 lineto 283.34277 444.98914 lineto 283.34277 447.39539 lineto 281.96875 447.39539 lineto 281.96875 444.98914 lineto 277.36133 444.98914 lineto 277.36133 443.65613 lineto 281.60645 437.18933 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 287.23242 445.65906 moveto 288.6748 445.65906 lineto 288.6748 446.83484 lineto 287.55371 449.02234 lineto 286.67188 449.02234 lineto 287.23242 446.83484 lineto 287.23242 445.65906 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 292.73535 446.23328 moveto 297.55469 446.23328 lineto 297.55469 447.39539 lineto 291.07422 447.39539 lineto 291.07422 446.23328 lineto 291.59831 445.69096 292.31152 444.96407 293.21387 444.05261 curveto 294.12076 443.1366 294.69043 442.54643 294.92285 442.2821 curveto 295.3649 441.78537 295.67252 441.36609 295.8457 441.02429 curveto 296.02343 440.67794 296.1123 440.33843 296.1123 440.00574 curveto 296.1123 439.46343 295.92089 439.02137 295.53809 438.67957 curveto 295.15983 438.33778 294.66536 438.16688 294.05469 438.16687 curveto 293.62174 438.16688 293.16373 438.24207 292.68066 438.39246 curveto 292.20215 438.54286 291.68945 438.77072 291.14258 439.07605 curveto 291.14258 437.68152 lineto 291.69857 437.45822 292.2181 437.2896 292.70117 437.17566 curveto 293.18424 437.06174 293.6263 437.00477 294.02734 437.00476 curveto 295.08463 437.00477 295.92773 437.26909 296.55664 437.79773 curveto 297.18554 438.32638 297.49999 439.03276 297.5 439.91687 curveto 297.49999 440.33615 297.42024 440.73491 297.26074 441.11316 curveto 297.10579 441.48686 296.82096 441.92892 296.40625 442.43933 curveto 296.29231 442.5715 295.93001 442.95431 295.31934 443.58777 curveto 294.70865 444.21668 293.84733 445.09851 292.73535 446.23328 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 300.60352 445.65906 moveto 302.0459 445.65906 lineto 302.0459 446.83484 lineto 300.9248 449.02234 lineto 300.04297 449.02234 lineto 300.60352 446.83484 lineto 300.60352 445.65906 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 307.70605 440.62097 moveto 307.03157 440.62098 306.49837 440.8853 306.10645 441.41394 curveto 305.71452 441.93803 305.51855 442.65809 305.51855 443.5741 curveto 305.51855 444.49012 305.71224 445.21245 306.09961 445.74109 curveto 306.49153 446.26518 307.02701 446.52722 307.70605 446.52722 curveto 308.37597 446.52722 308.9069 446.2629 309.29883 445.73425 curveto 309.69075 445.20561 309.88671 444.48556 309.88672 443.5741 curveto 309.88671 442.6672 309.69075 441.94943 309.29883 441.42078 curveto 308.9069 440.88758 308.37597 440.62098 307.70605 440.62097 curveto 307.70605 439.55457 moveto 308.7998 439.55457 309.65885 439.91004 310.2832 440.62097 curveto 310.90754 441.33192 311.21972 442.31629 311.21973 443.5741 curveto 311.21972 444.82735 310.90754 445.81173 310.2832 446.52722 curveto 309.65885 447.23816 308.7998 447.59363 307.70605 447.59363 curveto 306.60774 447.59363 305.74642 447.23816 305.12207 446.52722 curveto 304.50228 445.81173 304.19238 444.82735 304.19238 443.5741 curveto 304.19238 442.31629 304.50228 441.33192 305.12207 440.62097 curveto 305.74642 439.91004 306.60774 439.55457 307.70605 439.55457 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 313.09961 436.77234 moveto 314.19336 436.77234 lineto 314.87695 437.84787 315.38737 438.9006 315.72461 439.93054 curveto 316.0664 440.9605 316.2373 441.98361 316.2373 442.99988 curveto 316.2373 444.02071 316.0664 445.04838 315.72461 446.08289 curveto 315.38737 447.11739 314.87695 448.17012 314.19336 449.24109 curveto 313.09961 449.24109 lineto 313.70573 448.19747 314.1569 447.16069 314.45312 446.13074 curveto 314.7539 445.09623 314.90429 444.05262 314.9043 442.99988 curveto 314.90429 441.94715 314.7539 440.90809 314.45312 439.88269 curveto 314.1569 438.85731 313.70573 437.82053 313.09961 436.77234 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 181.16895 456.3075 moveto 180.55826 457.35568 180.10481 458.39246 179.80859 459.41785 curveto 179.51237 460.44324 179.36426 461.48231 179.36426 462.53503 curveto 179.36426 463.58777 179.51237 464.63139 179.80859 465.66589 curveto 180.10937 466.69584 180.56282 467.73262 181.16895 468.77625 curveto 180.0752 468.77625 lineto 179.3916 467.70528 178.8789 466.65255 178.53711 465.61804 curveto 178.19987 464.58354 178.03125 463.55587 178.03125 462.53503 curveto 178.03125 461.51876 178.19987 460.49565 178.53711 459.4657 curveto 178.87435 458.43576 179.38704 457.38303 180.0752 456.3075 curveto 181.16895 456.3075 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 183.80762 456.72449 moveto 189.22852 456.72449 lineto 189.22852 457.8866 lineto 185.07227 457.8866 lineto 185.07227 460.38855 lineto 185.27278 460.3202 185.4733 460.27007 185.67383 460.23816 curveto 185.87435 460.20171 186.07487 460.18348 186.27539 460.18347 curveto 187.41471 460.18348 188.31705 460.49565 188.98242 461.12 curveto 189.64778 461.74435 189.98046 462.58973 189.98047 463.65613 curveto 189.98046 464.75444 189.63866 465.60893 188.95508 466.2196 curveto 188.27148 466.82572 187.30761 467.12878 186.06348 467.12878 curveto 185.63509 467.12878 185.19759 467.09233 184.75098 467.01941 curveto 184.30892 466.94649 183.85091 466.83712 183.37695 466.69128 curveto 183.37695 465.30359 lineto 183.78711 465.5269 184.21094 465.69324 184.64844 465.80261 curveto 185.08593 465.91199 185.5485 465.96668 186.03613 465.96667 curveto 186.82454 465.96668 187.44889 465.75932 187.90918 465.3446 curveto 188.36946 464.92989 188.5996 464.36707 188.59961 463.65613 curveto 188.5996 462.94519 188.36946 462.38237 187.90918 461.96765 curveto 187.44889 461.55294 186.82454 461.34559 186.03613 461.34558 curveto 185.66699 461.34559 185.29785 461.3866 184.92871 461.46863 curveto 184.56413 461.55066 184.19043 461.67827 183.80762 461.85144 curveto 183.80762 456.72449 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 192.85156 465.19421 moveto 194.29395 465.19421 lineto 194.29395 466.37 lineto 193.17285 468.5575 lineto 192.29102 468.5575 lineto 192.85156 466.37 lineto 192.85156 465.19421 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 201.34863 461.42761 moveto 202.00943 461.56889 202.52441 461.86284 202.89355 462.30945 curveto 203.26725 462.75607 203.45409 463.3075 203.4541 463.96375 curveto 203.45409 464.97091 203.10774 465.7502 202.41504 466.30164 curveto 201.72232 466.85307 200.73795 467.12878 199.46191 467.12878 curveto 199.03353 467.12878 198.59147 467.08549 198.13574 466.9989 curveto 197.68457 466.91687 197.21745 466.79154 196.73438 466.62292 curveto 196.73438 465.28992 lineto 197.11719 465.51323 197.53646 465.68185 197.99219 465.79578 curveto 198.44791 465.90971 198.92415 465.96668 199.4209 465.96667 curveto 200.28678 465.96668 200.94531 465.79578 201.39648 465.45398 curveto 201.85221 465.11218 202.08007 464.61544 202.08008 463.96375 curveto 202.08007 463.36219 201.86816 462.89279 201.44434 462.55554 curveto 201.02506 462.21375 200.43945 462.04285 199.6875 462.04285 curveto 198.49805 462.04285 lineto 198.49805 460.90808 lineto 199.74219 460.90808 lineto 200.42122 460.90809 200.94075 460.77365 201.30078 460.50476 curveto 201.6608 460.23133 201.84081 459.8394 201.84082 459.32898 curveto 201.84081 458.8049 201.65397 458.40386 201.28027 458.12585 curveto 200.91113 457.84331 200.3802 457.70204 199.6875 457.70203 curveto 199.30924 457.70204 198.90364 457.74305 198.4707 457.82507 curveto 198.03776 457.90711 197.56152 458.03472 197.04199 458.20789 curveto 197.04199 456.97742 lineto 197.56608 456.83159 198.05599 456.72222 198.51172 456.64929 curveto 198.972 456.57639 199.40494 456.53993 199.81055 456.53992 curveto 200.85872 456.53993 201.68815 456.77918 202.29883 457.25769 curveto 202.9095 457.73166 203.21484 458.37424 203.21484 459.18542 curveto 203.21484 459.75054 203.05305 460.22905 202.72949 460.62097 curveto 202.40592 461.00835 201.94563 461.27723 201.34863 461.42761 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 206.22266 465.19421 moveto 207.66504 465.19421 lineto 207.66504 466.37 lineto 206.54395 468.5575 lineto 205.66211 468.5575 lineto 206.22266 466.37 lineto 206.22266 465.19421 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 213.3252 460.15613 moveto 212.65071 460.15613 212.11751 460.42046 211.72559 460.9491 curveto 211.33366 461.47319 211.13769 462.19324 211.1377 463.10925 curveto 211.13769 464.02527 211.33138 464.7476 211.71875 465.27625 curveto 212.11067 465.80033 212.64616 466.06238 213.3252 466.06238 curveto 213.99511 466.06238 214.52604 465.79806 214.91797 465.26941 curveto 215.30989 464.74077 215.50585 464.02071 215.50586 463.10925 curveto 215.50585 462.20236 215.30989 461.48458 214.91797 460.95593 curveto 214.52604 460.42274 213.99511 460.15613 213.3252 460.15613 curveto 213.3252 459.08972 moveto 214.41894 459.08973 215.27799 459.4452 215.90234 460.15613 curveto 216.52669 460.86707 216.83886 461.85145 216.83887 463.10925 curveto 216.83886 464.36251 216.52669 465.34688 215.90234 466.06238 curveto 215.27799 466.77332 214.41894 467.12878 213.3252 467.12878 curveto 212.22688 467.12878 211.36556 466.77332 210.74121 466.06238 curveto 210.12142 465.34688 209.81152 464.36251 209.81152 463.10925 curveto 209.81152 461.85145 210.12142 460.86707 210.74121 460.15613 curveto 211.36556 459.4452 212.22688 459.08973 213.3252 459.08972 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 218.71875 456.3075 moveto 219.8125 456.3075 lineto 220.49609 457.38303 221.00651 458.43576 221.34375 459.4657 curveto 221.68554 460.49565 221.85644 461.51876 221.85645 462.53503 curveto 221.85644 463.55587 221.68554 464.58354 221.34375 465.61804 curveto 221.00651 466.65255 220.49609 467.70528 219.8125 468.77625 curveto 218.71875 468.77625 lineto 219.32487 467.73262 219.77604 466.69584 220.07227 465.66589 curveto 220.37304 464.63139 220.52343 463.58777 220.52344 462.53503 curveto 220.52343 461.48231 220.37304 460.44324 220.07227 459.41785 curveto 219.77604 458.39246 219.32487 457.35568 218.71875 456.3075 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 228.20898 455.77429 moveto 227.5983 456.82248 227.14485 457.85926 226.84863 458.88464 curveto 226.55241 459.91004 226.40429 460.9491 226.4043 462.00183 curveto 226.40429 463.05457 226.55241 464.09819 226.84863 465.13269 curveto 227.14941 466.16264 227.60286 467.19942 228.20898 468.24304 curveto 227.11523 468.24304 lineto 226.43164 467.17208 225.91894 466.11934 225.57715 465.08484 curveto 225.23991 464.05034 225.07129 463.02267 225.07129 462.00183 curveto 225.07129 460.98556 225.23991 459.96245 225.57715 458.9325 curveto 225.91439 457.90256 226.42708 456.84982 227.11523 455.77429 curveto 228.20898 455.77429 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 233.95801 460.74402 moveto 233.33821 460.74402 232.84603 460.95594 232.48145 461.37976 curveto 232.12142 461.80359 231.9414 462.38465 231.94141 463.12292 curveto 231.9414 463.85665 232.12142 464.43771 232.48145 464.86609 curveto 232.84603 465.28992 233.33821 465.50183 233.95801 465.50183 curveto 234.57779 465.50183 235.0677 465.28992 235.42773 464.86609 curveto 235.79231 464.43771 235.9746 463.85665 235.97461 463.12292 curveto 235.9746 462.38465 235.79231 461.80359 235.42773 461.37976 curveto 235.0677 460.95594 234.57779 460.74402 233.95801 460.74402 curveto 236.69922 456.41687 moveto 236.69922 457.67468 lineto 236.35286 457.51063 236.00195 457.3853 235.64648 457.29871 curveto 235.29557 457.21213 234.94693 457.16883 234.60059 457.16882 curveto 233.68912 457.16883 232.99186 457.47645 232.50879 458.09167 curveto 232.03027 458.70692 231.75683 459.6366 231.68848 460.88074 curveto 231.95735 460.48426 232.29459 460.1812 232.7002 459.97156 curveto 233.10579 459.75737 233.5524 459.65028 234.04004 459.65027 curveto 235.06542 459.65028 235.87434 459.96245 236.4668 460.58679 curveto 237.06379 461.20659 237.3623 462.05197 237.3623 463.12292 curveto 237.3623 464.1711 237.0524 465.01192 236.43262 465.64539 curveto 235.81282 466.27885 234.98795 466.59558 233.95801 466.59558 curveto 232.77767 466.59558 231.87532 466.14441 231.25098 465.24207 curveto 230.62663 464.33517 230.31445 463.02267 230.31445 461.30457 curveto 230.31445 459.69129 230.69726 458.40614 231.46289 457.4491 curveto 232.22851 456.48752 233.25618 456.00672 234.5459 456.00671 curveto 234.89225 456.00672 235.24088 456.0409 235.5918 456.10925 curveto 235.94726 456.17762 236.3164 456.28016 236.69922 456.41687 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 239.8916 464.66101 moveto 241.33398 464.66101 lineto 241.33398 465.83679 lineto 240.21289 468.02429 lineto 239.33105 468.02429 lineto 239.8916 465.83679 lineto 239.8916 464.66101 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 247.99902 457.39441 moveto 244.5127 462.84265 lineto 247.99902 462.84265 lineto 247.99902 457.39441 lineto 247.63672 456.19128 moveto 249.37305 456.19128 lineto 249.37305 462.84265 lineto 250.8291 462.84265 lineto 250.8291 463.99109 lineto 249.37305 463.99109 lineto 249.37305 466.39734 lineto 247.99902 466.39734 lineto 247.99902 463.99109 lineto 243.3916 463.99109 lineto 243.3916 462.65808 lineto 247.63672 456.19128 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 253.2627 464.66101 moveto 254.70508 464.66101 lineto 254.70508 465.83679 lineto 253.58398 468.02429 lineto 252.70215 468.02429 lineto 253.2627 465.83679 lineto 253.2627 464.66101 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 262.43652 462.48035 moveto 262.43652 461.56889 262.24739 460.86251 261.86914 460.36121 curveto 261.49544 459.85991 260.96907 459.60926 260.29004 459.60925 curveto 259.61556 459.60926 259.08919 459.85991 258.71094 460.36121 curveto 258.33724 460.86251 258.15039 461.56889 258.15039 462.48035 curveto 258.15039 463.38725 258.33724 464.09135 258.71094 464.59265 curveto 259.08919 465.09395 259.61556 465.34461 260.29004 465.3446 curveto 260.96907 465.34461 261.49544 465.09395 261.86914 464.59265 curveto 262.24739 464.09135 262.43652 463.38725 262.43652 462.48035 curveto 263.69434 465.44714 moveto 263.69433 466.75053 263.40494 467.71895 262.82617 468.35242 curveto 262.24739 468.99044 261.361 469.30945 260.16699 469.30945 curveto 259.72493 469.30945 259.30794 469.27527 258.91602 469.20691 curveto 258.52409 469.1431 258.14355 469.04284 257.77441 468.90613 curveto 257.77441 467.6825 lineto 258.14355 467.88301 258.50814 468.03113 258.86816 468.12683 curveto 259.22819 468.22253 259.59505 468.27038 259.96875 468.27039 curveto 260.79362 468.27038 261.41113 468.05391 261.82129 467.62097 curveto 262.23144 467.19259 262.43652 466.54317 262.43652 465.67273 curveto 262.43652 465.05066 lineto 262.17675 465.50183 261.84407 465.83907 261.43848 466.06238 curveto 261.03287 466.28569 260.54752 466.39734 259.98242 466.39734 curveto 259.04362 466.39734 258.28711 466.03959 257.71289 465.3241 curveto 257.13867 464.6086 256.85156 463.66069 256.85156 462.48035 curveto 256.85156 461.29546 257.13867 460.34526 257.71289 459.62976 curveto 258.28711 458.91427 259.04362 458.55653 259.98242 458.55652 curveto 260.54752 458.55653 261.03287 458.66818 261.43848 458.89148 curveto 261.84407 459.11479 262.17675 459.45203 262.43652 459.9032 curveto 262.43652 458.74109 lineto 263.69434 458.74109 lineto 263.69434 465.44714 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 266.08691 455.77429 moveto 267.18066 455.77429 lineto 267.86425 456.84982 268.37467 457.90256 268.71191 458.9325 curveto 269.05371 459.96245 269.22461 460.98556 269.22461 462.00183 curveto 269.22461 463.02267 269.05371 464.05034 268.71191 465.08484 curveto 268.37467 466.11934 267.86425 467.17208 267.18066 468.24304 curveto 266.08691 468.24304 lineto 266.69303 467.19942 267.1442 466.16264 267.44043 465.13269 curveto 267.74121 464.09819 267.8916 463.05457 267.8916 462.00183 curveto 267.8916 460.9491 267.74121 459.91004 267.44043 458.88464 curveto 267.1442 457.85926 266.69303 456.82248 266.08691 455.77429 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 275.57715 455.77429 moveto 274.96647 456.82248 274.51302 457.85926 274.2168 458.88464 curveto 273.92057 459.91004 273.77246 460.9491 273.77246 462.00183 curveto 273.77246 463.05457 273.92057 464.09819 274.2168 465.13269 curveto 274.51757 466.16264 274.97102 467.19942 275.57715 468.24304 curveto 274.4834 468.24304 lineto 273.7998 467.17208 273.28711 466.11934 272.94531 465.08484 curveto 272.60807 464.05034 272.43945 463.02267 272.43945 462.00183 curveto 272.43945 460.98556 272.60807 459.96245 272.94531 458.9325 curveto 273.28255 457.90256 273.79524 456.84982 274.4834 455.77429 curveto 275.57715 455.77429 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 281.15527 461.55066 moveto 280.49902 461.55066 279.98177 461.72612 279.60352 462.07703 curveto 279.22982 462.42794 279.04297 462.91101 279.04297 463.52625 curveto 279.04297 464.14148 279.22982 464.62455 279.60352 464.97546 curveto 279.98177 465.32638 280.49902 465.50183 281.15527 465.50183 curveto 281.81152 465.50183 282.32877 465.32638 282.70703 464.97546 curveto 283.08528 464.62 283.27441 464.13692 283.27441 463.52625 curveto 283.27441 462.91101 283.08528 462.42794 282.70703 462.07703 curveto 282.33333 461.72612 281.81608 461.55066 281.15527 461.55066 curveto 279.77441 460.96277 moveto 279.18196 460.81694 278.7194 460.54122 278.38672 460.13562 curveto 278.05859 459.73003 277.89453 459.23556 277.89453 458.65222 curveto 277.89453 457.83648 278.18392 457.19162 278.7627 456.71765 curveto 279.34603 456.2437 280.14355 456.00672 281.15527 456.00671 curveto 282.17154 456.00672 282.96907 456.2437 283.54785 456.71765 curveto 284.12662 457.19162 284.41601 457.83648 284.41602 458.65222 curveto 284.41601 459.23556 284.24967 459.73003 283.91699 460.13562 curveto 283.58886 460.54122 283.13085 460.81694 282.54297 460.96277 curveto 283.20833 461.11772 283.72558 461.42078 284.09473 461.87195 curveto 284.46842 462.32312 284.65527 462.87456 284.65527 463.52625 curveto 284.65527 464.51518 284.35221 465.27397 283.74609 465.80261 curveto 283.14452 466.33126 282.28092 466.59558 281.15527 466.59558 curveto 280.02962 466.59558 279.16373 466.33126 278.55762 465.80261 curveto 277.95605 465.27397 277.65527 464.51518 277.65527 463.52625 curveto 277.65527 462.87456 277.84212 462.32312 278.21582 461.87195 curveto 278.58952 461.42078 279.10905 461.11772 279.77441 460.96277 curveto 279.26855 458.7821 moveto 279.26855 459.31076 279.43261 459.72319 279.76074 460.01941 curveto 280.09342 460.31564 280.55826 460.46375 281.15527 460.46375 curveto 281.74772 460.46375 282.21028 460.31564 282.54297 460.01941 curveto 282.8802 459.72319 283.04882 459.31076 283.04883 458.7821 curveto 283.04882 458.25347 282.8802 457.84103 282.54297 457.5448 curveto 282.21028 457.24858 281.74772 457.10047 281.15527 457.10046 curveto 280.55826 457.10047 280.09342 457.24858 279.76074 457.5448 curveto 279.43261 457.84103 279.26855 458.25347 279.26855 458.7821 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 287.25977 464.66101 moveto 288.70215 464.66101 lineto 288.70215 465.83679 lineto 287.58105 468.02429 lineto 286.69922 468.02429 lineto 287.25977 465.83679 lineto 287.25977 464.66101 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 291.58691 456.19128 moveto 297.00781 456.19128 lineto 297.00781 457.35339 lineto 292.85156 457.35339 lineto 292.85156 459.85535 lineto 293.05208 459.78699 293.2526 459.73686 293.45312 459.70496 curveto 293.65364 459.6685 293.85416 459.65028 294.05469 459.65027 curveto 295.19401 459.65028 296.09635 459.96245 296.76172 460.58679 curveto 297.42708 461.21115 297.75976 462.05652 297.75977 463.12292 curveto 297.75976 464.22123 297.41796 465.07573 296.73438 465.6864 curveto 296.05078 466.29252 295.08691 466.59558 293.84277 466.59558 curveto 293.41438 466.59558 292.97689 466.55912 292.53027 466.48621 curveto 292.08821 466.41329 291.63021 466.30391 291.15625 466.15808 curveto 291.15625 464.77039 lineto 291.5664 464.99369 291.99023 465.16004 292.42773 465.26941 curveto 292.86523 465.37879 293.3278 465.43347 293.81543 465.43347 curveto 294.60384 465.43347 295.22818 465.22612 295.68848 464.8114 curveto 296.14876 464.39669 296.3789 463.83386 296.37891 463.12292 curveto 296.3789 462.41199 296.14876 461.84917 295.68848 461.43445 curveto 295.22818 461.01974 294.60384 460.81238 293.81543 460.81238 curveto 293.44629 460.81238 293.07715 460.8534 292.70801 460.93542 curveto 292.34342 461.01746 291.96972 461.14507 291.58691 461.31824 curveto 291.58691 456.19128 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 300.63086 464.66101 moveto 302.07324 464.66101 lineto 302.07324 465.83679 lineto 300.95215 468.02429 lineto 300.07031 468.02429 lineto 300.63086 465.83679 lineto 300.63086 464.66101 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 309.80469 462.48035 moveto 309.80468 461.56889 309.61555 460.86251 309.2373 460.36121 curveto 308.8636 459.85991 308.33723 459.60926 307.6582 459.60925 curveto 306.98372 459.60926 306.45735 459.85991 306.0791 460.36121 curveto 305.7054 460.86251 305.51855 461.56889 305.51855 462.48035 curveto 305.51855 463.38725 305.7054 464.09135 306.0791 464.59265 curveto 306.45735 465.09395 306.98372 465.34461 307.6582 465.3446 curveto 308.33723 465.34461 308.8636 465.09395 309.2373 464.59265 curveto 309.61555 464.09135 309.80468 463.38725 309.80469 462.48035 curveto 311.0625 465.44714 moveto 311.06249 466.75053 310.7731 467.71895 310.19434 468.35242 curveto 309.61555 468.99044 308.72916 469.30945 307.53516 469.30945 curveto 307.0931 469.30945 306.6761 469.27527 306.28418 469.20691 curveto 305.89225 469.1431 305.51172 469.04284 305.14258 468.90613 curveto 305.14258 467.6825 lineto 305.51172 467.88301 305.8763 468.03113 306.23633 468.12683 curveto 306.59635 468.22253 306.96321 468.27038 307.33691 468.27039 curveto 308.16178 468.27038 308.77929 468.05391 309.18945 467.62097 curveto 309.5996 467.19259 309.80468 466.54317 309.80469 465.67273 curveto 309.80469 465.05066 lineto 309.54492 465.50183 309.21223 465.83907 308.80664 466.06238 curveto 308.40104 466.28569 307.91569 466.39734 307.35059 466.39734 curveto 306.41178 466.39734 305.65527 466.03959 305.08105 465.3241 curveto 304.50683 464.6086 304.21973 463.66069 304.21973 462.48035 curveto 304.21973 461.29546 304.50683 460.34526 305.08105 459.62976 curveto 305.65527 458.91427 306.41178 458.55653 307.35059 458.55652 curveto 307.91569 458.55653 308.40104 458.66818 308.80664 458.89148 curveto 309.21223 459.11479 309.54492 459.45203 309.80469 459.9032 curveto 309.80469 458.74109 lineto 311.0625 458.74109 lineto 311.0625 465.44714 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 313.45508 455.77429 moveto 314.54883 455.77429 lineto 315.23242 456.84982 315.74284 457.90256 316.08008 458.9325 curveto 316.42187 459.96245 316.59277 460.98556 316.59277 462.00183 curveto 316.59277 463.02267 316.42187 464.05034 316.08008 465.08484 curveto 315.74284 466.11934 315.23242 467.17208 314.54883 468.24304 curveto 313.45508 468.24304 lineto 314.0612 467.19942 314.51237 466.16264 314.80859 465.13269 curveto 315.10937 464.09819 315.25976 463.05457 315.25977 462.00183 curveto 315.25976 460.9491 315.10937 459.91004 314.80859 458.88464 curveto 314.51237 457.85926 314.0612 456.82248 313.45508 455.77429 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 174.3125 475.84265 moveto 173.70182 476.89084 173.24837 477.92762 172.95215 478.953 curveto 172.65592 479.9784 172.50781 481.01746 172.50781 482.07019 curveto 172.50781 483.12293 172.65592 484.16655 172.95215 485.20105 curveto 173.25293 486.231 173.70638 487.26778 174.3125 488.3114 curveto 173.21875 488.3114 lineto 172.53515 487.24044 172.02246 486.1877 171.68066 485.1532 curveto 171.34342 484.1187 171.1748 483.09103 171.1748 482.07019 curveto 171.1748 481.05392 171.34342 480.03081 171.68066 479.00085 curveto 172.0179 477.97092 172.5306 476.91818 173.21875 475.84265 curveto 174.3125 475.84265 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 176.97852 486.25378 moveto 176.97852 484.99597 lineto 177.32487 485.16004 177.67578 485.28536 178.03125 485.37195 curveto 178.38672 485.45854 178.73535 485.50183 179.07715 485.50183 curveto 179.9886 485.50183 180.68359 485.19649 181.16211 484.58582 curveto 181.64518 483.97058 181.92089 483.03862 181.98926 481.78992 curveto 181.72493 482.18185 181.38997 482.48263 180.98438 482.69226 curveto 180.57877 482.9019 180.12988 483.00672 179.6377 483.00671 curveto 178.61686 483.00672 177.80794 482.6991 177.21094 482.08386 curveto 176.61849 481.46408 176.32226 480.6187 176.32227 479.54773 curveto 176.32226 478.49956 176.63216 477.65874 177.25195 477.02527 curveto 177.87174 476.39182 178.69661 476.07508 179.72656 476.07507 curveto 180.9069 476.07508 181.80696 476.52853 182.42676 477.43542 curveto 183.0511 478.33778 183.36327 479.65028 183.36328 481.37292 curveto 183.36327 482.98165 182.98046 484.26681 182.21484 485.22839 curveto 181.45377 486.18543 180.42838 486.66394 179.13867 486.66394 curveto 178.79231 486.66394 178.4414 486.62976 178.08594 486.5614 curveto 177.73047 486.49304 177.36133 486.3905 176.97852 486.25378 curveto 179.72656 481.92664 moveto 180.34635 481.92664 180.83626 481.71473 181.19629 481.29089 curveto 181.56087 480.86707 181.74316 480.28602 181.74316 479.54773 curveto 181.74316 478.81401 181.56087 478.23524 181.19629 477.8114 curveto 180.83626 477.38303 180.34635 477.16883 179.72656 477.16882 curveto 179.10677 477.16883 178.61458 477.38303 178.25 477.8114 curveto 177.88997 478.23524 177.70996 478.81401 177.70996 479.54773 curveto 177.70996 480.28602 177.88997 480.86707 178.25 481.29089 curveto 178.61458 481.71473 179.10677 481.92664 179.72656 481.92664 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 185.99512 484.72937 moveto 187.4375 484.72937 lineto 187.4375 485.90515 lineto 186.31641 488.09265 lineto 185.43457 488.09265 lineto 185.99512 485.90515 lineto 185.99512 484.72937 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 193.43262 480.81238 moveto 192.81282 480.81238 192.32063 481.0243 191.95605 481.44812 curveto 191.59603 481.87195 191.41601 482.45301 191.41602 483.19128 curveto 191.41601 483.92501 191.59603 484.50606 191.95605 484.93445 curveto 192.32063 485.35828 192.81282 485.57019 193.43262 485.57019 curveto 194.0524 485.57019 194.54231 485.35828 194.90234 484.93445 curveto 195.26692 484.50606 195.44921 483.92501 195.44922 483.19128 curveto 195.44921 482.45301 195.26692 481.87195 194.90234 481.44812 curveto 194.54231 481.0243 194.0524 480.81238 193.43262 480.81238 curveto 196.17383 476.48523 moveto 196.17383 477.74304 lineto 195.82747 477.57899 195.47656 477.45366 195.12109 477.36707 curveto 194.77018 477.28049 194.42154 477.23719 194.0752 477.23718 curveto 193.16373 477.23719 192.46647 477.54481 191.9834 478.16003 curveto 191.50488 478.77528 191.23144 479.70496 191.16309 480.9491 curveto 191.43196 480.55262 191.7692 480.24956 192.1748 480.03992 curveto 192.5804 479.82573 193.02701 479.71863 193.51465 479.71863 curveto 194.54003 479.71863 195.34895 480.03081 195.94141 480.65515 curveto 196.5384 481.27495 196.83691 482.12032 196.83691 483.19128 curveto 196.83691 484.23946 196.52701 485.08028 195.90723 485.71375 curveto 195.28743 486.34721 194.46256 486.66394 193.43262 486.66394 curveto 192.25228 486.66394 191.34993 486.21277 190.72559 485.31042 curveto 190.10124 484.40353 189.78906 483.09103 189.78906 481.37292 curveto 189.78906 479.75965 190.17187 478.4745 190.9375 477.51746 curveto 191.70312 476.55588 192.73079 476.07508 194.02051 476.07507 curveto 194.36686 476.07508 194.71549 476.10926 195.06641 476.17761 curveto 195.42187 476.24598 195.79101 476.34852 196.17383 476.48523 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 199.36621 484.72937 moveto 200.80859 484.72937 lineto 200.80859 485.90515 lineto 199.6875 488.09265 lineto 198.80566 488.09265 lineto 199.36621 485.90515 lineto 199.36621 484.72937 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 206.46875 479.69128 moveto 205.79427 479.69129 205.26106 479.95561 204.86914 480.48425 curveto 204.47721 481.00835 204.28125 481.7284 204.28125 482.64441 curveto 204.28125 483.56043 204.47493 484.28276 204.8623 484.8114 curveto 205.25423 485.33549 205.78971 485.59754 206.46875 485.59753 curveto 207.13867 485.59754 207.66959 485.33321 208.06152 484.80457 curveto 208.45344 484.27592 208.64941 483.55587 208.64941 482.64441 curveto 208.64941 481.73751 208.45344 481.01974 208.06152 480.49109 curveto 207.66959 479.95789 207.13867 479.69129 206.46875 479.69128 curveto 206.46875 478.62488 moveto 207.56249 478.62489 208.42154 478.98035 209.0459 479.69128 curveto 209.67024 480.40223 209.98241 481.3866 209.98242 482.64441 curveto 209.98241 483.89767 209.67024 484.88204 209.0459 485.59753 curveto 208.42154 486.30847 207.56249 486.66394 206.46875 486.66394 curveto 205.37044 486.66394 204.50911 486.30847 203.88477 485.59753 curveto 203.26497 484.88204 202.95508 483.89767 202.95508 482.64441 curveto 202.95508 481.3866 203.26497 480.40223 203.88477 479.69128 curveto 204.50911 478.98035 205.37044 478.62489 206.46875 478.62488 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 211.8623 475.84265 moveto 212.95605 475.84265 lineto 213.63965 476.91818 214.15006 477.97092 214.4873 479.00085 curveto 214.8291 480.03081 215 481.05392 215 482.07019 curveto 215 483.09103 214.8291 484.1187 214.4873 485.1532 curveto 214.15006 486.1877 213.63965 487.24044 212.95605 488.3114 curveto 211.8623 488.3114 lineto 212.46842 487.26778 212.91959 486.231 213.21582 485.20105 curveto 213.5166 484.16655 213.66699 483.12293 213.66699 482.07019 curveto 213.66699 481.01746 213.5166 479.9784 213.21582 478.953 curveto 212.91959 477.92762 212.46842 476.89084 211.8623 475.84265 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 222.12305 476.34265 moveto 221.51237 477.39084 221.05892 478.42762 220.7627 479.453 curveto 220.46647 480.4784 220.31836 481.51746 220.31836 482.57019 curveto 220.31836 483.62293 220.46647 484.66655 220.7627 485.70105 curveto 221.06347 486.731 221.51692 487.76778 222.12305 488.8114 curveto 221.0293 488.8114 lineto 220.3457 487.74044 219.83301 486.6877 219.49121 485.6532 curveto 219.15397 484.6187 218.98535 483.59103 218.98535 482.57019 curveto 218.98535 481.55392 219.15397 480.53081 219.49121 479.50085 curveto 219.82845 478.47092 220.34114 477.41818 221.0293 476.34265 curveto 222.12305 476.34265 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 224.9873 485.80359 moveto 227.24316 485.80359 lineto 227.24316 478.01746 lineto 224.78906 478.50964 lineto 224.78906 477.25183 lineto 227.22949 476.75964 lineto 228.61035 476.75964 lineto 228.61035 485.80359 lineto 230.86621 485.80359 lineto 230.86621 486.9657 lineto 224.9873 486.9657 lineto 224.9873 485.80359 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 236.61523 477.66882 moveto 235.90429 477.66883 235.36881 478.01974 235.00879 478.72156 curveto 234.65332 479.41883 234.47558 480.46929 234.47559 481.87292 curveto 234.47558 483.27202 234.65332 484.32247 235.00879 485.02429 curveto 235.36881 485.72156 235.90429 486.07019 236.61523 486.07019 curveto 237.33072 486.07019 237.86621 485.72156 238.22168 485.02429 curveto 238.5817 484.32247 238.76171 483.27202 238.76172 481.87292 curveto 238.76171 480.46929 238.5817 479.41883 238.22168 478.72156 curveto 237.86621 478.01974 237.33072 477.66883 236.61523 477.66882 curveto 236.61523 476.57507 moveto 237.75911 476.57508 238.63183 477.02853 239.2334 477.93542 curveto 239.83951 478.83778 240.14257 480.15028 240.14258 481.87292 curveto 240.14257 483.59103 239.83951 484.90353 239.2334 485.81042 curveto 238.63183 486.71277 237.75911 487.16394 236.61523 487.16394 curveto 235.47135 487.16394 234.59635 486.71277 233.99023 485.81042 curveto 233.38867 484.90353 233.08789 483.59103 233.08789 481.87292 curveto 233.08789 480.15028 233.38867 478.83778 233.99023 477.93542 curveto 234.59635 477.02853 235.47135 476.57508 236.61523 476.57507 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 242.71973 485.22937 moveto 244.16211 485.22937 lineto 244.16211 486.40515 lineto 243.04102 488.59265 lineto 242.15918 488.59265 lineto 242.71973 486.40515 lineto 242.71973 485.22937 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 246.68457 476.75964 moveto 253.24707 476.75964 lineto 253.24707 477.34753 lineto 249.54199 486.9657 lineto 248.09961 486.9657 lineto 251.58594 477.92175 lineto 246.68457 477.92175 lineto 246.68457 476.75964 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 256.09082 485.22937 moveto 257.5332 485.22937 lineto 257.5332 486.40515 lineto 256.41211 488.59265 lineto 255.53027 488.59265 lineto 256.09082 486.40515 lineto 256.09082 485.22937 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 263.19336 480.19128 moveto 262.51888 480.19129 261.98567 480.45561 261.59375 480.98425 curveto 261.20182 481.50835 261.00586 482.2284 261.00586 483.14441 curveto 261.00586 484.06043 261.19954 484.78276 261.58691 485.3114 curveto 261.97884 485.83549 262.51432 486.09754 263.19336 486.09753 curveto 263.86328 486.09754 264.3942 485.83321 264.78613 485.30457 curveto 265.17805 484.77592 265.37402 484.05587 265.37402 483.14441 curveto 265.37402 482.23751 265.17805 481.51974 264.78613 480.99109 curveto 264.3942 480.45789 263.86328 480.19129 263.19336 480.19128 curveto 263.19336 479.12488 moveto 264.2871 479.12489 265.14615 479.48035 265.77051 480.19128 curveto 266.39485 480.90223 266.70702 481.8866 266.70703 483.14441 curveto 266.70702 484.39767 266.39485 485.38204 265.77051 486.09753 curveto 265.14615 486.80847 264.2871 487.16394 263.19336 487.16394 curveto 262.09505 487.16394 261.23372 486.80847 260.60938 486.09753 curveto 259.98958 485.38204 259.67969 484.39767 259.67969 483.14441 curveto 259.67969 481.8866 259.98958 480.90223 260.60938 480.19128 curveto 261.23372 479.48035 262.09505 479.12489 263.19336 479.12488 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 268.58691 476.34265 moveto 269.68066 476.34265 lineto 270.36425 477.41818 270.87467 478.47092 271.21191 479.50085 curveto 271.55371 480.53081 271.72461 481.55392 271.72461 482.57019 curveto 271.72461 483.59103 271.55371 484.6187 271.21191 485.6532 curveto 270.87467 486.6877 270.36425 487.74044 269.68066 488.8114 curveto 268.58691 488.8114 lineto 269.19303 487.76778 269.6442 486.731 269.94043 485.70105 curveto 270.24121 484.66655 270.3916 483.62293 270.3916 482.57019 curveto 270.3916 481.51746 270.24121 480.4784 269.94043 479.453 curveto 269.6442 478.42762 269.19303 477.39084 268.58691 476.34265 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 276.49121 476.34265 moveto 275.88053 477.39084 275.42708 478.42762 275.13086 479.453 curveto 274.83463 480.4784 274.68652 481.51746 274.68652 482.57019 curveto 274.68652 483.62293 274.83463 484.66655 275.13086 485.70105 curveto 275.43164 486.731 275.88509 487.76778 276.49121 488.8114 curveto 275.39746 488.8114 lineto 274.71386 487.74044 274.20117 486.6877 273.85938 485.6532 curveto 273.52213 484.6187 273.35351 483.59103 273.35352 482.57019 curveto 273.35351 481.55392 273.52213 480.53081 273.85938 479.50085 curveto 274.19661 478.47092 274.70931 477.41818 275.39746 476.34265 curveto 276.49121 476.34265 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 279.35547 485.80359 moveto 281.61133 485.80359 lineto 281.61133 478.01746 lineto 279.15723 478.50964 lineto 279.15723 477.25183 lineto 281.59766 476.75964 lineto 282.97852 476.75964 lineto 282.97852 485.80359 lineto 285.23438 485.80359 lineto 285.23438 486.9657 lineto 279.35547 486.9657 lineto 279.35547 485.80359 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 288.26953 485.80359 moveto 290.52539 485.80359 lineto 290.52539 478.01746 lineto 288.07129 478.50964 lineto 288.07129 477.25183 lineto 290.51172 476.75964 lineto 291.89258 476.75964 lineto 291.89258 485.80359 lineto 294.14844 485.80359 lineto 294.14844 486.9657 lineto 288.26953 486.9657 lineto 288.26953 485.80359 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 297.08789 485.22937 moveto 298.53027 485.22937 lineto 298.53027 486.40515 lineto 297.40918 488.59265 lineto 296.52734 488.59265 lineto 297.08789 486.40515 lineto 297.08789 485.22937 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 304.35449 482.11902 moveto 303.69824 482.11902 303.18099 482.29448 302.80273 482.64539 curveto 302.42903 482.9963 302.24219 483.47937 302.24219 484.0946 curveto 302.24219 484.70984 302.42903 485.19291 302.80273 485.54382 curveto 303.18099 485.89474 303.69824 486.07019 304.35449 486.07019 curveto 305.01074 486.07019 305.52799 485.89474 305.90625 485.54382 curveto 306.2845 485.18836 306.47363 484.70528 306.47363 484.0946 curveto 306.47363 483.47937 306.2845 482.9963 305.90625 482.64539 curveto 305.53255 482.29448 305.01529 482.11902 304.35449 482.11902 curveto 302.97363 481.53113 moveto 302.38118 481.3853 301.91862 481.10958 301.58594 480.70398 curveto 301.25781 480.29839 301.09375 479.80392 301.09375 479.22058 curveto 301.09375 478.40483 301.38314 477.75998 301.96191 477.28601 curveto 302.54524 476.81206 303.34277 476.57508 304.35449 476.57507 curveto 305.37076 476.57508 306.16829 476.81206 306.74707 477.28601 curveto 307.32584 477.75998 307.61523 478.40483 307.61523 479.22058 curveto 307.61523 479.80392 307.44889 480.29839 307.11621 480.70398 curveto 306.78808 481.10958 306.33007 481.3853 305.74219 481.53113 curveto 306.40755 481.68608 306.9248 481.98914 307.29395 482.44031 curveto 307.66764 482.89148 307.85448 483.44292 307.85449 484.0946 curveto 307.85448 485.08354 307.55142 485.84233 306.94531 486.37097 curveto 306.34374 486.89962 305.48014 487.16394 304.35449 487.16394 curveto 303.22884 487.16394 302.36295 486.89962 301.75684 486.37097 curveto 301.15527 485.84233 300.85449 485.08354 300.85449 484.0946 curveto 300.85449 483.44292 301.04134 482.89148 301.41504 482.44031 curveto 301.78874 481.98914 302.30827 481.68608 302.97363 481.53113 curveto 302.46777 479.35046 moveto 302.46777 479.87912 302.63183 480.29155 302.95996 480.58777 curveto 303.29264 480.884 303.75748 481.03211 304.35449 481.0321 curveto 304.94694 481.03211 305.4095 480.884 305.74219 480.58777 curveto 306.07942 480.29155 306.24804 479.87912 306.24805 479.35046 curveto 306.24804 478.82183 306.07942 478.40939 305.74219 478.11316 curveto 305.4095 477.81694 304.94694 477.66883 304.35449 477.66882 curveto 303.75748 477.66883 303.29264 477.81694 302.95996 478.11316 curveto 302.63183 478.40939 302.46777 478.82183 302.46777 479.35046 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 310.45898 485.22937 moveto 311.90137 485.22937 lineto 311.90137 486.40515 lineto 310.78027 488.59265 lineto 309.89844 488.59265 lineto 310.45898 486.40515 lineto 310.45898 485.22937 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 317.56152 480.19128 moveto 316.88704 480.19129 316.35384 480.45561 315.96191 480.98425 curveto 315.56998 481.50835 315.37402 482.2284 315.37402 483.14441 curveto 315.37402 484.06043 315.56771 484.78276 315.95508 485.3114 curveto 316.347 485.83549 316.88248 486.09754 317.56152 486.09753 curveto 318.23144 486.09754 318.76236 485.83321 319.1543 485.30457 curveto 319.54622 484.77592 319.74218 484.05587 319.74219 483.14441 curveto 319.74218 482.23751 319.54622 481.51974 319.1543 480.99109 curveto 318.76236 480.45789 318.23144 480.19129 317.56152 480.19128 curveto 317.56152 479.12488 moveto 318.65527 479.12489 319.51432 479.48035 320.13867 480.19128 curveto 320.76301 480.90223 321.07519 481.8866 321.0752 483.14441 curveto 321.07519 484.39767 320.76301 485.38204 320.13867 486.09753 curveto 319.51432 486.80847 318.65527 487.16394 317.56152 487.16394 curveto 316.46321 487.16394 315.60189 486.80847 314.97754 486.09753 curveto 314.35775 485.38204 314.04785 484.39767 314.04785 483.14441 curveto 314.04785 481.8866 314.35775 480.90223 314.97754 480.19128 curveto 315.60189 479.48035 316.46321 479.12489 317.56152 479.12488 curveto fill grestore gsave 0 0 0 setrgbcolor newpath 322.95508 476.34265 moveto 324.04883 476.34265 lineto 324.73242 477.41818 325.24284 478.47092 325.58008 479.50085 curveto 325.92187 480.53081 326.09277 481.55392 326.09277 482.57019 curveto 326.09277 483.59103 325.92187 484.6187 325.58008 485.6532 curveto 325.24284 486.6877 324.73242 487.74044 324.04883 488.8114 curveto 322.95508 488.8114 lineto 323.5612 487.76778 324.01237 486.731 324.30859 485.70105 curveto 324.60937 484.66655 324.75976 483.62293 324.75977 482.57019 curveto 324.75976 481.51746 324.60937 480.4784 324.30859 479.453 curveto 324.01237 478.42762 323.5612 477.39084 322.95508 476.34265 curveto fill grestore gsave [1.436848 0 0 0.806571 118.9493 72.56034] concat 0 0 0 setrgbcolor [] 0 setdash 1.5 setlinewidth 0 setlinejoin 0 setlinecap newpath 154.5 482.61218 moveto 154.5 515.59418 125.716 542.36218 90.25 542.36218 curveto 54.784 542.36218 26 515.59418 26 482.61218 curveto 26 449.63018 54.784 422.86218 90.25 422.86218 curveto 125.716 422.86218 154.5 449.63018 154.5 482.61218 curveto closepath stroke grestore gsave 0 0 0 setrgbcolor newpath 244.37402 420.15613 moveto 245.75488 420.15613 lineto 245.75488 430.36218 lineto 244.37402 430.36218 lineto 244.37402 420.15613 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 249.69238 420.5321 moveto 249.69238 422.70593 lineto 252.2832 422.70593 lineto 252.2832 423.68347 lineto 249.69238 423.68347 lineto 249.69238 427.83972 lineto 249.69238 428.46407 249.77669 428.86511 249.94531 429.04285 curveto 250.11849 429.22058 250.46712 429.30945 250.99121 429.30945 curveto 252.2832 429.30945 lineto 252.2832 430.36218 lineto 250.99121 430.36218 lineto 250.0205 430.36218 249.35058 430.18217 248.98145 429.82214 curveto 248.6123 429.45756 248.42773 428.79675 248.42773 427.83972 curveto 248.42773 423.68347 lineto 247.50488 423.68347 lineto 247.50488 422.70593 lineto 248.42773 422.70593 lineto 248.42773 420.5321 lineto 249.69238 420.5321 lineto fill grestore grestore gsave 0 0 0 setrgbcolor newpath 250.25488 525.79089 moveto 250.25488 529.62585 lineto 251.99121 529.62585 lineto 252.63378 529.62586 253.13053 529.45952 253.48145 529.12683 curveto 253.83235 528.79415 254.00781 528.3202 254.00781 527.70496 curveto 254.00781 527.09429 253.83235 526.62261 253.48145 526.28992 curveto 253.13053 525.95724 252.63378 525.7909 251.99121 525.79089 curveto 250.25488 525.79089 lineto 248.87402 524.65613 moveto 251.99121 524.65613 lineto 253.13509 524.65614 253.99869 524.9159 254.58203 525.43542 curveto 255.16991 525.95041 255.46386 526.70692 255.46387 527.70496 curveto 255.46386 528.71212 255.16991 529.47319 254.58203 529.98816 curveto 253.99869 530.50314 253.13509 530.76062 251.99121 530.76062 curveto 250.25488 530.76062 lineto 250.25488 534.86218 lineto 248.87402 534.86218 lineto 248.87402 524.65613 lineto fill grestore gsave 0 0 0 setrgbcolor newpath 257.68555 533.70007 moveto 259.94141 533.70007 lineto 259.94141 525.91394 lineto 257.4873 526.40613 lineto 257.4873 525.14832 lineto 259.92773 524.65613 lineto 261.30859 524.65613 lineto 261.30859 533.70007 lineto 263.56445 533.70007 lineto 263.56445 534.86218 lineto 257.68555 534.86218 lineto 257.68555 533.70007 lineto fill grestore 0 0 0 setrgbcolor [] 0 setdash 1 setlinewidth 0 setlinejoin 0 setlinecap newpath 155 302.36218 moveto 154.5 534.36218 lineto stroke grestore showpage %%EOF dune-common-2.8.0/doc/comm/indexset.cc000066400000000000000000000022711411343567400176060ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include "buildindexset.hh" #include "reverse.hh" int main(int argc, char **argv) { // This is a parallel programm so we need to // initialize mpi first. Dune::MPIHelper& helper = Dune::MPIHelper::instance(argc, argv); // The rank of our process int rank = helper.rank(); // The type used as the global index typedef int GlobalIndex; // The index set we use to identify the local indices with the globally // unique ones typedef Dune::ParallelIndexSet ParallelIndexSet; // The index set ParallelIndexSet indexSet; build(helper, indexSet); // Print the index set std::cout< #include // We use exceptions #include // An initializer of MPI #include #include enum Flags { owner, ghost }; struct Bla { /** @brief The local index. */ size_t localIndex_; /** @brief An attribute for the index. */ char attribute_; /** @brief True if the index is also known to other processors. */ bool public_; /** * @brief The state of the index. * * Has to be one of LocalIndexState! * @see LocalIndexState. */ char state_; }; template void buildBlockedIndexSet(T1& indexset, int N, const T2& comm) { int rank=comm.rank(); int size=comm.size(); int localsize=N/size; int bigger=N%size; int start, end; if(rank0) indexset.add(gindex-1,LocalIndex(index++,ghost)); for(int i=start; i > IndexSet; IndexSet blockedSet; buildBlockedIndexSet(blockedSet, n, helper.getCommunication()); } return 0; } catch (Dune::Exception &e) { std::cerr << "Dune reported error: " << e << std::endl; } catch (...) { std::cerr << "Unknown exception thrown!" << std::endl; } } dune-common-2.8.0/doc/comm/poosc08_test.cc000066400000000000000000000076631411343567400203270ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include // We use exceptions #include // An initializer of MPI #include #include #include #include #include #include enum Flags { owner, ghost }; template struct AddData { typedef typename T::value_type IndexedType; static const IndexedType& gather(const T& v, int i){ return v[i]; } static void scatter(T& v, const IndexedType& item, int i){ v[i]+=item; } }; template struct CopyData { typedef typename T::value_type IndexedType; static const IndexedType& gather(const T& v, int i){ return v[i]; } static void scatter(T& v, const IndexedType& item, int i){ v[i]=item; } }; template void doCalculations(T&){} #if HAVE_MPI void test() { int rank; MPI_Comm comm=(MPI_COMM_WORLD); MPI_Comm_rank(MPI_COMM_WORLD, &rank); using namespace Dune; // shortcut for index set type typedef ParallelLocalIndex LocalIndex; typedef ParallelIndexSet PIndexSet; PIndexSet sis; sis.beginResize(); if(rank==0) { sis.add(11, LocalIndex(0, ghost)); for(int i=1; i<=6; i++) sis.add(i-1, LocalIndex(i, owner, i<=1||i>5)); sis.add(6, LocalIndex(7, ghost)); }else{ sis.add(5, LocalIndex(0, ghost)); for(int i=1; i<=6; i++) sis.add(5+i, LocalIndex(i, owner, i<=1||i>5)); sis.add(0,LocalIndex(7, ghost)); } sis.endResize(); PIndexSet tis; tis.beginResize(); int l=0; for(int i=0; i<2; ++i) for(int j=0; j<5; ++j) { int g=rank*3-1+i*6+j; if(g<0||g>11) continue; Flags flag=(j>0&&j<4) ? owner : ghost; tis.add(g, LocalIndex(l++, flag)); } tis.endResize(); std::cout< riRedist(sis, tis, comm); riRedist.rebuild(); std::vector v; RemoteIndices riS(sis,sis, comm, v, true); riS.rebuild(); std::cout<,EnumItem,Flags> ghostFlags; EnumItem ownerFlags; Combine, EnumItem > allFlags; Interface infRedist; Interface infS; infRedist.build(riRedist, ownerFlags, allFlags); infS.build(riS, ownerFlags, ghostFlags); std::cout<<"inf "< Container; Container s(sis.size(),3), t(tis.size()); s[sis.size()-1]=-1; BufferedCommunicator bComm; BufferedCommunicator bCommRedist; bComm.build(s, s, infS); //bCommRedist.build(s, t, infRedist); for(std::size_t i=0; i >(s,s); for(std::size_t i=0; i >(s,t); // calculate on the redistributed array doCalculations(t); bCommRedist.backward >(s,t); } #endif // HAVE_MPI int main(int argc, char** argv) { try{ using namespace Dune; #if HAVE_MPI //Maybe initialize Mpi MPIHelper& helper = MPIHelper::instance(argc, argv); std::cout << "Hello World! This is poosc08. rank=" < void reverseLocalIndex(Dune::ParallelIndexSet& indexSet) { // reverse the local indices typedef typename Dune::ParallelIndexSet::iterator iterator; iterator end = indexSet.end(); size_t maxLocal = 0; // find the maximal local index for(iterator index = indexSet.begin(); index != end; ++index) { // Get the local index LocalIndex& local = index->local(); maxLocal = std::max(maxLocal, local.local()); } for(iterator index = indexSet.begin(); index != end; ++index) { // Get the local index LocalIndex& local = index->local(); local = maxLocal--; } } #endif dune-common-2.8.0/doc/doxygen/000077500000000000000000000000001411343567400161745ustar00rootroot00000000000000dune-common-2.8.0/doc/doxygen/CMakeLists.txt000066400000000000000000000002651411343567400207370ustar00rootroot00000000000000# create Doxyfile.in and Doxyfile add_doxygen_target() install( FILES Doxystyle doxygen-macros DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/dune-common/doc/doxygen ) dune-common-2.8.0/doc/doxygen/Doxylocal000066400000000000000000000005721411343567400200610ustar00rootroot00000000000000# Where to search and which files to use INPUT += @srcdir@/mainpage.txt \ @srcdir@/modules.txt \ @top_srcdir@/dune/common/modules.txt \ @top_srcdir@/dune/common EXCLUDE += @top_srcdir@/dune/common/test \ @top_srcdir@/dune/common/debugallocator.cc dune-common-2.8.0/doc/doxygen/Doxystyle000066400000000000000000000155651411343567400201370ustar00rootroot00000000000000#----------- Doxystyle ----------- ################################################################################## # Project Details: PROJECT_NAME = @DUNE_MOD_NAME@ PROJECT_NUMBER = @DUNE_MOD_VERSION@ ################################################################################## # What to parse RECURSIVE = YES FILE_PATTERNS = *.hh \ *.cc INPUT = EXCLUDE = EXCLUDE_PATTERNS = */test/* EXCLUDE_SYMBOLS = Impl detail Imp Internal # 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 = NO # don't warn about missing stl-headers etc. # 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 = @abs_top_srcdir@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_LOGFILE = doxyerr.log ################################################################################# # Styling # 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 = YES # 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 = NO # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful if your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = YES # 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 = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # 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 = YES # 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 = YES # 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 = 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. REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 3 HTML_OUTPUT = html SEARCHENGINE = YES GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES GENERATE_HTML = YES GENERATE_DOCSET = NO GENERATE_HTMLHELP = NO GENERATE_CHI = NO GENERATE_QHP = NO GENERATE_TREEVIEW = NO GENERATE_LATEX = NO GENERATE_RTF = NO GENERATE_MAN = NO GENERATE_XML = NO GENERATE_AUTOGEN_DEF = NO GENERATE_PERLMOD = NO GENERATE_TAGFILE = @DUNE_MOD_NAME@.tag GENERATE_LEGEND = NO MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES @DOT_TRUE@HAVE_DOT = YES # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES CLASS_GRAPH = YES COLLABORATION_GRAPH = NO GROUP_GRAPHS = YES INCLUDE_GRAPH = NO INCLUDED_BY_GRAPH = NO GRAPHICAL_HIERARCHY = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = NO DOT_CLEANUP = NO ##################################################################### # Header Footer and Stylesheet in use is controlled by the Makefile # # (christi 16. Jan 2006) # ##################################################################### # 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 = ########################## DOXYGEN DOXYSTYLE EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = YES EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = YES HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = dune-common-2.8.0/doc/doxygen/doxygen-macros000066400000000000000000000015251411343567400210610ustar00rootroot00000000000000# This file contains the list of predefined preprocessor macros required for running # Doxygen. It should be included automatically by the build system after # Doxystyle. # # The reason to have this separate is for building the website, where we # would otherwise have to maintain these definitions a second time. PREDEFINED = DOXYGEN \ HAVE_MPI:=1 \ _DEBUG_ALLOCATOR_H:=1 \ "DUNE_DEPRECATED:=/** \deprecated */" \ "DUNE_DEPRECATED_MSG(A):=/** \deprecated A */" \ "DUNE_INLINE_VARIABLE:= " \ __cpp_inline_variables:=201606 \ __cpp_constexpr:=201603 \ __cpp_variable_templates:=201304 \ # marker - here to allow the last line continuation dune-common-2.8.0/doc/doxygen/mainpage.txt000066400000000000000000000006361411343567400205230ustar00rootroot00000000000000/** \mainpage dune-common Automatic Documentation \section intro Introduction Welcome to the %Dune documentation pages. This documentation has been generated using Doxygen, a free source code documentation system for documenting C/C++ code. \section mods Modules The best way to start is from the page \subpage modules which gives you access to the documentation by category. */ /** \page modules Modules */ dune-common-2.8.0/doc/doxygen/modules.txt000066400000000000000000000032311411343567400204040ustar00rootroot00000000000000/** @defgroup Common Common @brief foundation classes */ /** @defgroup Allocators Allocators @brief Implementations of the STL allocator concept @ingroup Common */ /** @defgroup Utilities Utilities @brief Collection of helper classes, type traits, etc. @ingroup Common */ /** @defgroup Path Filesystem Paths @brief Utilities for filesystem path management @ingroup Utilities */ /** @defgroup RangeUtilities Range Utilities @brief Utilities for reduction like operations on ranges All these reduction operations work for appropriate ranges and scalar values @ingroup Utilities */ /** @defgroup StringUtilities String Utilities @brief Utility functions for std::string @ingroup Utilities */ /** @defgroup TupleUtilities Tuple Utilities @brief Utility classes which can be used with std::tuple @ingroup Utilities */ /** @defgroup TypeUtilities Type Utilities @brief Type traits, overload helpers, and other utilities for type computations @ingroup Utilities */ /** @defgroup HybridUtilities Hybrid Utilities @brief Hybrid utility functions that work on homogeneous as well as heterogeneous containers @ingroup Utilities */ /** @defgroup CxxUtilities C++ utilities and backports @brief Standard library features backported from newer C++ versions or technical specifications and DUNE-specific utilities. @ingroup Utilities */ /** @defgroup CxxConcepts C++ concepts @brief Concepts built on top of C++14. @ingroup Utilities */ /** @defgroup Numbers Numbers @brief Class implementing different number representations and helper functions @ingroup Common */ /** @defgroup FloatCmp FloatCmp @ingroup Numbers */ dune-common-2.8.0/doc/dunecontrol.1000066400000000000000000000106321411343567400171370ustar00rootroot00000000000000.\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH DUNECONTROL 1 "November 8, 2016" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME dunecontrol \- Control program for the Dune build system .SH SYNOPSIS .B dunecontrol [\fIOPTIONS\fP] \fICOMMANDS\fP [\fICOMMAND-OPTIONS\fP] .SH DESCRIPTION .B dunecontrol is the control program for the build system of the Dune libraries. The Dune libraries form a set of modules. Each can be built independently using CMake. Additionally, though, there are dependencies between modules, which are expected to form a directed acyclic graph. These dependencies are set in a file called .B dune.module contained in the main directory of each Dune module. The .B dunecontrol program helps to build sets of inter-dependent modules. It allows to construct the entire dependency graph and obtain information about it. Then it allows to run various build-related commands for all modules. These are executed in the order mandated by the dependency graph. .SH COMMANDS Colon-separated list of commands. Available commands are: .HP .B help .IP Show a help message and exit .HP .B print .IP Print the list of modules sorted according to their dependency relations .HP .B info .IP Same as `print', but including whether it is a dependency or suggestion .HP .B printdeps .IP Print recursive dependencies of a module .HP .B vcsetup .IP Setup version control repository (Git etc.) or working copy (SVN) .HP .B update .IP Update all modules from the repository from their respective version control systems .HP .B configure .IP Run cmake for each module .HP .B make .IP Run make for each module .HP .B all .IP Run the 'configure' and 'make' commands for each module .HP .B exec .IP Execute an arbitrary command in each module source directory .HP .B bexec .IP Execute an arbitrary command in each module build directory .HP .B status .IP Show version control status for each module .HP .B svn .IP Run svn command for each svn-managed module .HP .B git .IP Run git command for each git-managed module .HP .B export .IP Run eval `dunecontrol export` to save the list of dune.module files to the DUNE_CONTROL_PATH variable .SH OPTIONS .HP \fB\-h\fP, \fB\-\-help\fP .IP Show this help .HP \fB--debug\fP .IP Run with debugging output enabled .HP \fB--module=\fP\fImod\fP .IP Apply the actions on module .I mod and all modules it depends on .HP \fB--only=\fP\fImod\fP .IP Only apply the actions on module .I mod , but not on the modules it depends on .HP \fB--current\fP .IP Only apply the actions on the current module, the one whose source tree we are in .HP \fB--current-dep\fP .IP Apply the actions on the current module, and all modules it depends on .HP \fB--resume\fP .IP Resume a previous run (only consider the modules not built successfully on the previous run) .HP \fB--skipfirst\fP .IP Skip the first module (use with --resume) .HP \fB--skipversioncheck\fP .IP When looking for Dune modules, do not check whether they have the required versions .HP \fB--opts=\fP\fIfile\fP .IP Load default options from \fIfile\fP .HP \fB--builddir=\fP\fIname\fP .IP Make out-of-source builds in a subdir \fIname\fP. This directory is created inside each module. .HP \fB--[COMMAND]-opts=\fP\fIopts\fP .IP Set options for COMMAND (this is mainly useful for the 'all' COMMAND) .SH ENVIRONMENT VARIABLES .B dunecontrol looks for Dune modules in all directories given in the .B DUNE_CONTROL_PATH variable, and additionally recursively in all subdirectories of those directories. The default for the case that DUNE_CONTROL_PATH is empty is the current directory, plus a system-wide installation in /usr. .SH AUTHOR Dune was written by the Dune team (https://www.dune-project.org/community/people). .PP This manual page was written by Oliver Sander. .SH COPYRIGHT Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without any warranty. dune-common-2.8.0/dune-common.pc.in000066400000000000000000000004341411343567400171250ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ CXX=@CXX@ CC=@CC@ DEPENDENCIES=@REQUIRES@ Name: @PACKAGE_NAME@ Version: @VERSION@ Description: @DESCRIPTION@ URL: @URL@ Requires: ${DEPENDENCIES} Libs: -L${libdir} -ldunecommon Cflags: -I${includedir} dune-common-2.8.0/dune.module000066400000000000000000000004441411343567400161160ustar00rootroot00000000000000Module: dune-common Version: 2.8.0 Author: The Dune Core developers Maintainer: dune-devel@lists.dune-project.org Description: Basis infrastructure for all Dune modules URL: https://gitlab.dune-project.org/core/dune-common Python-Requires: portalocker numpy wheel mpi4py Whitespace-Hook: Yes dune-common-2.8.0/dune/000077500000000000000000000000001411343567400147055ustar00rootroot00000000000000dune-common-2.8.0/dune/CMakeLists.txt000066400000000000000000000003221411343567400174420ustar00rootroot00000000000000add_subdirectory(common) # if Python bindings are enabled, include necessary sub directories. if(DUNE_ENABLE_PYTHONBINDINGS) add_subdirectory(python) else() exclude_subdir_from_headercheck(python) endif() dune-common-2.8.0/dune/common/000077500000000000000000000000001411343567400161755ustar00rootroot00000000000000dune-common-2.8.0/dune/common/CMakeLists.txt000066400000000000000000000052151411343567400207400ustar00rootroot00000000000000add_subdirectory("parallel") add_subdirectory("simd") add_subdirectory("std") add_subdirectory("test") #build the library dunecommon dune_add_library("dunecommon" debugalign.cc debugallocator.cc exceptions.cc fmatrixev.cc ios_state.cc parametertree.cc parametertreeparser.cc path.cc simd/test.cc stdstreams.cc stdthread.cc) add_dune_blas_lapack_flags(dunecommon) add_dune_tbb_flags(dunecommon) #install headers install(FILES alignedallocator.hh arraylist.hh assertandreturn.hh bartonnackmanifcheck.hh bigunsignedint.hh binaryfunctions.hh bitsetvector.hh boundschecking.hh classname.hh concept.hh conditional.hh debugalign.hh debugallocator.hh debugstream.hh deprecated.hh densematrix.hh densevector.hh diagonalmatrix.hh documentation.hh dotproduct.hh dynmatrix.hh dynmatrixev.hh dynvector.hh enumset.hh exceptions.hh filledarray.hh float_cmp.cc float_cmp.hh fmatrix.hh fmatrixev.hh ftraits.hh function.hh fvector.hh gcd.hh genericiterator.hh gmpfield.hh hash.hh hybridutilities.hh indent.hh indices.hh interfaces.hh ios_state.hh iteratorfacades.hh iteratorrange.hh keywords.hh lcm.hh lru.hh mallocallocator.hh math.hh matvectraits.hh overloadset.hh parameterizedobject.hh parametertree.hh parametertreeparser.hh path.hh poolallocator.hh power.hh precision.hh propertymap.hh promotiontraits.hh proxymemberaccess.hh quadmath.hh rangeutilities.hh reservedvector.hh scalarvectorview.hh scalarmatrixview.hh shared_ptr.hh simd.hh singleton.hh sllist.hh stdstreams.hh stdthread.hh streamoperators.hh stringutility.hh to_unique_ptr.hh timer.hh transpose.hh tupleutility.hh tuplevector.hh typelist.hh typetraits.hh typeutilities.hh unused.hh vc.hh version.hh visibility.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/common) # Install some test headers, because they get used by tests in other modules # We do this here as test will not be considered for make install install(FILES test/iteratortest.hh test/checkmatrixinterface.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/common/test) dune-common-2.8.0/dune/common/alignedallocator.hh000066400000000000000000000031121411343567400220170ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_ALIGNED_ALLOCATOR_HH #define DUNE_ALIGNED_ALLOCATOR_HH #include "mallocallocator.hh" #include namespace Dune { /** @ingroup Allocators @brief Allocators which guarantee alignment of the memory @tparam T type of the object one wants to allocate @tparam Alignment explicitly specify the alignment, by default it is std::alignment_of::value */ template class AlignedAllocator : public MallocAllocator { /* * Check whether an explicit alignment was * restricted or fall back to the default alignment of T. */ static constexpr int fixAlignment(int align) { return (Alignment==-1) ? std::alignment_of::value : Alignment; } public: using pointer = typename MallocAllocator::pointer; using size_type = typename MallocAllocator::size_type; template struct rebind { typedef AlignedAllocator other; }; static constexpr int alignment = fixAlignment(sizeof(void*)); //! allocate n objects of type T pointer allocate(size_type n, [[maybe_unused]] const void* hint = 0) { if (n > this->max_size()) throw std::bad_alloc(); /* * Everybody else gets the standard treatment. */ pointer ret = static_cast(std::aligned_alloc(alignment, n * sizeof(T))); if (!ret) throw std::bad_alloc(); return ret; } }; } #endif // DUNE_ALIGNED_ALLOCATOR_HH dune-common-2.8.0/dune/common/arraylist.hh000066400000000000000000000475141411343567400205430ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_ARRAYLIST_HH #define DUNE_COMMON_ARRAYLIST_HH #include #include #include #include #include "iteratorfacades.hh" namespace Dune { // forward declaration template class ArrayListIterator; template class ConstArrayListIterator; /** * @file * \brief Implements a random-access container that can efficiently change size (similar to std::deque) * * This file implements the class ArrayList which behaves like * dynamically growing array together with * the class ArrayListIterator which is random access iterator as needed * by the stl for sorting and other algorithms. * @author Markus Blatt */ /** * @addtogroup Common * * @{ */ /** * @brief A dynamically growing random access list. * * Internally the data is organised in a list of arrays of fixed size. * Whenever the capacity of the array list is not sufficient a new * std::array is allocated. In contrast to * std::vector this approach prevents data copying. On the outside * we provide the same interface as the stl random access containers. * * While the concept sounds quite similar to std::deque there are slight * but crucial differences: * - In contrast to std:deque the actual implementation (a list of arrays) * is known. While * for std::deque there are at least two possible implementations * (dynamic array or using a double linked list. * - In contrast to std:deque there is not insert which invalidates iterators * but our push_back method leaves all iterators valid. * - Additional functionality lets one delete entries before and at an * iterator while moving the iterator to the next valid position. */ template > class ArrayList { public: /** * @brief The member type that is stored. * * Has to be assignable and has to have an empty constructor. */ typedef T MemberType; /** * @brief Value type for stl compliance. */ typedef T value_type; /** * @brief The type of a reference to the type we store. */ typedef T& reference; /** * @brief The type of a const reference to the type we store. */ typedef const T& const_reference; /** * @brief The type of a pointer to the type we store. */ typedef T* pointer; /** * @brief The type of a const pointer to the type we store. */ typedef const T* const_pointer; enum { /** * @brief The number of elements in one chunk of the list. * This has to be at least one. The default is 100. */ chunkSize_ = (N > 0) ? N : 1 }; /** * @brief A random access iterator. */ typedef ArrayListIterator iterator; /** * @brief A constant random access iterator. */ typedef ConstArrayListIterator const_iterator; /** * @brief The size type. */ typedef std::size_t size_type; /** * @brief The difference type. */ typedef std::ptrdiff_t difference_type; /** * @brief Get an iterator that is positioned at the first element. * @return The iterator. */ iterator begin(); /** * @brief Get a random access iterator that is positioned at the * first element. * @return The iterator. */ const_iterator begin() const; /** * @brief Get a random access iterator positioned after the last * element */ iterator end(); /** * @brief Get a random access iterator positioned after the last * element */ const_iterator end() const; /** * @brief Append an entry to the list. * @param entry The new entry. */ inline void push_back(const_reference entry); /** * @brief Get the element at specific position. * @param i The index of the position. * @return The element at that position. */ inline reference operator[](size_type i); /** * @brief Get the element at specific position. * @param i The index of the position. * @return The element at that position. */ inline const_reference operator[](size_type i) const; /** * @brief Get the number of elements in the list. * @return The number of elements. */ inline size_type size() const; /** * @brief Purge the list. * * If there are empty chunks at the front all nonempty * chunks will be moved towards the front and the capacity * increases. */ inline void purge(); /** * @brief Delete all entries from the list. */ inline void clear(); /** * @brief Constructs an Array list with one chunk. */ ArrayList(); private: /** * @brief The allocators for the smart pointer. */ using SmartPointerAllocator = typename std::allocator_traits::template rebind_alloc< std::shared_ptr< std::array > >; /** * @brief The allocator for the fixed array. */ using ArrayAllocator = typename std::allocator_traits::template rebind_alloc< std::array >; /** * @brief The iterator needs access to the private variables. */ friend class ArrayListIterator; friend class ConstArrayListIterator; /** @brief the data chunks of our list. */ std::vector >, SmartPointerAllocator> chunks_; /** @brief The current data capacity. * This is the capacity that the list could have theoretically * with this number of chunks. That is chunks * chunkSize. * In practice some of the chunks at the beginning might be empty * (i.e. null pointers in the first start_/chunkSize chunks) * because of previous calls to eraseToHere. * start_+size_<=capacity_ holds. */ size_type capacity_; /** @brief The current number of elements in our data structure. */ size_type size_; /** @brief The index of the first entry. */ size_type start_; /** * @brief Get the element at specific position. * * Index 0 always refers to the first entry in the list * whether it is erased or not! * @param i The index of the position. * @return The element at that position. */ inline reference elementAt(size_type i); /** * @brief Get the element at specific position. * * Index 0 always refers to the first entry in the list * whether it is erased or not! * @param i The index of the position. * @return The element at that position. */ inline const_reference elementAt(size_type i) const; }; /** * @brief A random access iterator for the Dune::ArrayList class. */ template class ArrayListIterator : public RandomAccessIteratorFacade, typename A::value_type, typename A::value_type &, typename A::difference_type> { friend class ArrayList; friend class ConstArrayListIterator; public: /** * @brief The member type. */ typedef typename A::value_type MemberType; typedef typename A::difference_type difference_type; typedef typename A::size_type size_type; using reference = typename A::value_type &; using const_reference = typename A::value_type const&; enum { /** * @brief The number of elements in one chunk of the list. * * This has to be at least one. The default is 100. */ chunkSize_ = (N > 0) ? N : 1 }; /** * @brief Comares two iterators. * @return True if the iterators are for the same list and * at the position. */ inline bool equals(const ArrayListIterator& other) const; /** * @brief Comares two iterators. * @return True if the iterators are for the same list and * at the position. */ inline bool equals(const ConstArrayListIterator& other) const; /** * @brief Increment the iterator. */ inline void increment(); /** * @brief decrement the iterator. */ inline void decrement(); /** * @brief Get the value of the list at an arbitrary position. * @return The value at that position. */ inline reference elementAt(size_type i) const; /** * @brief Access the element at the current position. * @return The element at the current position. */ inline reference dereference() const; /** * @brief Erase all entries before the current position * and the one at the current position. * * Afterwards the iterator will be positioned at the next * unerased entry or the end if the list is empty. * This does not invalidate any iterators positioned after * the current position but those positioned at previous ones. * @return An iterator to the first position after the deleted * ones or to the end if the list is empty. */ inline void eraseToHere(); /** \todo Please doc me! */ inline size_type position(){return position_;} /** \todo Please doc me! */ inline void advance(difference_type n); /** \todo Please doc me! */ inline difference_type distanceTo(const ArrayListIterator& other) const; /** \todo Please doc me! */ inline ArrayListIterator& operator=(const ArrayListIterator& other); //! Standard constructor inline ArrayListIterator() : position_(0), list_(nullptr) {} private: /** * @brief Constructor. * @param list The list we are an iterator for. * @param position The initial position of the iterator. */ inline ArrayListIterator(ArrayList& arrayList, size_type position); /** * @brief The current position. */ size_type position_; /** * @brief The list we are an iterator for. */ ArrayList* list_; }; /** * @brief A constant random access iterator for the Dune::ArrayList class. */ template class ConstArrayListIterator : public RandomAccessIteratorFacade, const typename A::value_type, typename A::value_type const&, typename A::difference_type> { friend class ArrayList; friend class ArrayListIterator; public: /** * @brief The member type. */ typedef typename A::value_type MemberType; typedef typename A::difference_type difference_type; typedef typename A::size_type size_type; using reference = typename A::value_type &; using const_reference = typename A::value_type const&; enum { /** * @brief The number of elements in one chunk of the list. * * This has to be at least one. The default is 100. */ chunkSize_ = (N > 0) ? N : 1 }; /** * @brief Comares to iterators. * @return true if the iterators are for the same list and * at the position. */ inline bool equals(const ConstArrayListIterator& other) const; /** * @brief Increment the iterator. */ inline void increment(); /** * @brief decrement the iterator. */ inline void decrement(); /** \todo Please doc me! */ inline void advance(difference_type n); /** \todo Please doc me! */ inline difference_type distanceTo(const ConstArrayListIterator& other) const; /** * @brief Get the value of the list at an arbitrary position. * @return The value at that position. */ inline const_reference elementAt(size_type i) const; /** * @brief Access the element at the current position. * @return The element at the current position. */ inline const_reference dereference() const; inline const ConstArrayListIterator& operator=(const ConstArrayListIterator& other); inline ConstArrayListIterator() : position_(0), list_(nullptr) {} inline ConstArrayListIterator(const ArrayListIterator& other); private: /** * @brief Constructor. * @param list The list we are an iterator for. * @param position The initial position of the iterator. */ inline ConstArrayListIterator(const ArrayList& arrayList, size_type position); /** * @brief The current position. */ size_type position_; /** * @brief The list we are an iterator for. */ const ArrayList* list_; }; template ArrayList::ArrayList() : capacity_(0), size_(0), start_(0) { chunks_.reserve(100); } template void ArrayList::clear(){ capacity_=0; size_=0; start_=0; chunks_.clear(); } template size_t ArrayList::size() const { return size_; } template void ArrayList::push_back(const_reference entry) { size_t index=start_+size_; if(index==capacity_) { chunks_.push_back(std::make_shared >()); capacity_ += chunkSize_; } elementAt(index)=entry; ++size_; } template typename ArrayList::reference ArrayList::operator[](size_type i) { return elementAt(start_+i); } template typename ArrayList::const_reference ArrayList::operator[](size_type i) const { return elementAt(start_+i); } template typename ArrayList::reference ArrayList::elementAt(size_type i) { return chunks_[i/chunkSize_]->operator[](i%chunkSize_); } template typename ArrayList::const_reference ArrayList::elementAt(size_type i) const { return chunks_[i/chunkSize_]->operator[](i%chunkSize_); } template ArrayListIterator ArrayList::begin() { return ArrayListIterator(*this, start_); } template ConstArrayListIterator ArrayList::begin() const { return ConstArrayListIterator(*this, start_); } template ArrayListIterator ArrayList::end() { return ArrayListIterator(*this, start_+size_); } template ConstArrayListIterator ArrayList::end() const { return ConstArrayListIterator(*this, start_+size_); } template void ArrayList::purge() { // Distance to copy to the left. size_t distance = start_/chunkSize_; if(distance>0) { // Number of chunks with entries in it; size_t chunks = ((start_%chunkSize_ + size_)/chunkSize_ ); // Copy chunks to the left. std::copy(chunks_.begin()+distance, chunks_.begin()+(distance+chunks), chunks_.begin()); // Calculate new parameters start_ = start_ % chunkSize_; //capacity += distance * chunkSize_; } } template void ArrayListIterator::advance(difference_type i) { position_+=i; } template void ConstArrayListIterator::advance(difference_type i) { position_+=i; } template bool ArrayListIterator::equals(const ArrayListIterator& other) const { // Makes only sense if we reference a common list assert(list_==(other.list_)); return position_==other.position_ ; } template bool ArrayListIterator::equals(const ConstArrayListIterator& other) const { // Makes only sense if we reference a common list assert(list_==(other.list_)); return position_==other.position_ ; } template bool ConstArrayListIterator::equals(const ConstArrayListIterator& other) const { // Makes only sense if we reference a common list assert(list_==(other.list_)); return position_==other.position_ ; } template void ArrayListIterator::increment() { ++position_; } template void ConstArrayListIterator::increment() { ++position_; } template void ArrayListIterator::decrement() { --position_; } template void ConstArrayListIterator::decrement() { --position_; } template typename ArrayListIterator::reference ArrayListIterator::elementAt(size_type i) const { return list_->elementAt(i+position_); } template typename ConstArrayListIterator::const_reference ConstArrayListIterator::elementAt(size_type i) const { return list_->elementAt(i+position_); } template typename ArrayListIterator::reference ArrayListIterator::dereference() const { return list_->elementAt(position_); } template typename ConstArrayListIterator::const_reference ConstArrayListIterator::dereference() const { return list_->elementAt(position_); } template typename ArrayListIterator::difference_type ArrayListIterator::distanceTo(const ArrayListIterator& other) const { // Makes only sense if we reference a common list assert(list_==(other.list_)); return other.position_ - position_; } template typename ConstArrayListIterator::difference_type ConstArrayListIterator::distanceTo(const ConstArrayListIterator& other) const { // Makes only sense if we reference a common list assert(list_==(other.list_)); return other.position_ - position_; } template ArrayListIterator& ArrayListIterator::operator=(const ArrayListIterator& other) { position_=other.position_; list_=other.list_; return *this; } template const ConstArrayListIterator& ConstArrayListIterator::operator=(const ConstArrayListIterator& other) { position_=other.position_; list_=other.list_; return *this; } template void ArrayListIterator::eraseToHere() { list_->size_ -= ++position_ - list_->start_; // chunk number of the new position. size_t posChunkStart = position_ / chunkSize_; // number of chunks to deallocate size_t chunks = (position_ - list_->start_ + list_->start_ % chunkSize_) / chunkSize_; list_->start_ = position_; // Deallocate memory not needed any more. for(size_t chunk=0; chunkchunks_[posChunkStart].reset(); } // Capacity stays the same as the chunks before us // are still there. They null pointers. assert(list_->start_+list_->size_<=list_->capacity_); } template ArrayListIterator::ArrayListIterator(ArrayList& arrayList, size_type position) : position_(position), list_(&arrayList) {} template ConstArrayListIterator::ConstArrayListIterator(const ArrayList& arrayList, size_type position) : position_(position), list_(&arrayList) {} template ConstArrayListIterator::ConstArrayListIterator(const ArrayListIterator& other) : position_(other.position_), list_(other.list_) {} /** @} */ } #endif dune-common-2.8.0/dune/common/assertandreturn.hh000066400000000000000000000014241411343567400217430ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_ASSERTANDRETURN_HH #define DUNE_COMMON_ASSERTANDRETURN_HH #include //! Asserts a condition and return on success in constexpr context. /** * The macro DUNE_ASSERT_AND_RETURN can be used as expression in the return * statement of a constexpr function to have assert() and constexpr at the * same time. It first uses assert for the condition given by the first argument * and then returns the value of the second argument. * * \ingroup CxxUtilities */ #ifdef NDEBUG #define DUNE_ASSERT_AND_RETURN(C,X) X #else #define DUNE_ASSERT_AND_RETURN(C,X) (!(C) ? throw [&](){assert(!#C);return 0;}() : 0), X #endif #endif // DUNE_COMMON_ASSERTANDRETURN_HH dune-common-2.8.0/dune/common/bartonnackmanifcheck.hh000066400000000000000000000044021411343567400226510ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /** @file @author Robert Kloefkorn @brief Provides check for implementation of interface methods when using static polymorphism, i.e. the Barton-Nackman trick. This is purely for debugging purposes. To check the correct implementation of interface methods (and pick up possible infinite loops) NDEBUG must be undefined and DUNE_INTERFACECHECK has to be defined. Use by invoking CHECK_INTERFACE_IMPLEMENTATION(asImp().methodToCheck()) and for template methods double (CHECK_INTERFACE_IMPLEMENTATION((asImp().template methodToCheck ())). If either NDEBUG is defined or DUNE_INTERFACECHECK is undefined the CHECK_INTERFACE_IMPLEMENTATION macro is empty. Note: adding the interface check to a method will cause the implementation of the method to be called twice, so before use make sure that this will not cause problems e.g. if internal counters are updated. **/ //- Dune includes #include #ifdef CHECK_INTERFACE_IMPLEMENTATION #undef CHECK_INTERFACE_IMPLEMENTATION #endif #ifdef CHECK_AND_CALL_INTERFACE_IMPLEMENTATION #undef CHECK_AND_CALL_INTERFACE_IMPLEMENTATION #endif #if defined NDEBUG || !defined DUNE_INTERFACECHECK #define CHECK_INTERFACE_IMPLEMENTATION(dummy) #else #define CHECK_INTERFACE_IMPLEMENTATION(__interface_method_to_call__) \ {\ static bool call = false; \ if( call == true ) \ DUNE_THROW(NotImplemented,"Interface method not implemented!");\ call = true; \ try { \ (__interface_method_to_call__); \ call = false; \ } \ catch ( ... ) \ { \ call = false; \ throw; \ } \ } #endif /** The macro CHECK_AND_CALL_INTERFACE_IMPLEMENTATION throws an exception, if the interface method ist not implemented and just calls the method otherwise. If NDEBUG is defined no checking is done and the method is just called. */ #if defined NDEBUG || !defined DUNE_INTERFACECHECK #define CHECK_AND_CALL_INTERFACE_IMPLEMENTATION(__interface_method_to_call__) \ (__interface_method_to_call__) #else #define CHECK_AND_CALL_INTERFACE_IMPLEMENTATION(__interface_method_to_call__) \ CHECK_INTERFACE_IMPLEMENTATION(__interface_method_to_call__) #endif dune-common-2.8.0/dune/common/bigunsignedint.hh000066400000000000000000000432061411343567400215340ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_BIGUNSIGNEDINT_HH #define DUNE_BIGUNSIGNEDINT_HH #include #include #include #include #include #include #include #include /** * @file * @brief Portable very large unsigned integers * @author Peter Bastian */ namespace Dune { #if HAVE_MPI template struct MPITraits; #endif /** @addtogroup Numbers * * @{ */ namespace Impl { // numeric_limits_helper provides std::numeric_limits access to the internals // of bigunsignedint. Previously, the correct specialization of std::numeric_limits // was a friend of bigunsignedint, but that creates problems on recent versions // of clang with the alternative libc++ library, because that library declares the // base template of std::numeric_limits as a class and clang subsequently complains // if the friend declaration uses 'struct'. Unfortunately, libstdc++ uses a struct, // making it impossible to keep clang happy for both standard libraries. // So we move the access helper functionality into a custom struct and simply let // the numeric_limits specialization inherit from the helper. template struct numeric_limits_helper { protected: static std::uint16_t& digit(T& big_unsigned_int, std::size_t i) { return big_unsigned_int.digit[i]; } }; } /** * @brief Portable very large unsigned integers * * Implements (arbitrarily) large unsigned integers to be used as global * ids in some grid managers. Size is a template parameter. * * \tparam k Number of bits of the integer type */ template class bigunsignedint { public: // unsigned short is 16 bits wide, n is the number of digits needed enum { bits=std::numeric_limits::digits, n=k/bits+(k%bits!=0), hexdigits=4, bitmask=0xFFFF, compbitmask=0xFFFF0000, overflowmask=0x1 }; //! Construct uninitialized bigunsignedint (); //! Construct from signed int template bigunsignedint (Signed x, typename std::enable_if::value && std::is_signed::value>::type* = 0); //! Construct from unsigned int bigunsignedint (std::uintmax_t x); //! Print number in hex notation void print (std::ostream& s) const ; //! add bigunsignedint operator+ (const bigunsignedint& x) const; bigunsignedint& operator+= (const bigunsignedint& x); //! subtract bigunsignedint operator- (const bigunsignedint& x) const; bigunsignedint& operator-= (const bigunsignedint& x); //! multiply bigunsignedint operator* (const bigunsignedint& x) const; bigunsignedint& operator*= (const bigunsignedint& x); //! prefix increment bigunsignedint& operator++ (); //! divide //! \warning This function is very slow and its usage should be //! prevented if possible bigunsignedint operator/ (const bigunsignedint& x) const; bigunsignedint& operator/= (const bigunsignedint& x); //! modulo //! \warning This function is very slow and its usage should be //! prevented if possible bigunsignedint operator% (const bigunsignedint& x) const; bigunsignedint& operator%= (const bigunsignedint& x); //! bitwise and bigunsignedint operator& (const bigunsignedint& x) const; bigunsignedint& operator&= (const bigunsignedint& x); //! bitwise exor bigunsignedint operator^ (const bigunsignedint& x) const; bigunsignedint& operator^= (const bigunsignedint& x); //! bitwise or bigunsignedint operator| (const bigunsignedint& x) const; bigunsignedint& operator|= (const bigunsignedint& x); //! bitwise complement bigunsignedint operator~ () const; //! left shift bigunsignedint operator<< (int i) const; //! right shift bigunsignedint operator>> (int i) const; //! less than bool operator< (const bigunsignedint& x) const; //! less than or equal bool operator<= (const bigunsignedint& x) const; //! greater than bool operator> (const bigunsignedint& x) const; //! greater or equal bool operator>= (const bigunsignedint& x) const; //! equal bool operator== (const bigunsignedint& x) const; //! not equal bool operator!= (const bigunsignedint& x) const; //! export to other types // operator unsigned int () const; std::uint_least32_t touint() const; /** * @brief Convert to a double. * * @warning Subject to rounding errors! */ double todouble() const; friend class bigunsignedint; friend struct Impl::numeric_limits_helper< bigunsignedint >; inline friend std::size_t hash_value(const bigunsignedint& arg) { return hash_range(arg.digit,arg.digit + arg.n); } private: std::uint16_t digit[n]; #if HAVE_MPI friend struct MPITraits >; #endif inline void assign(std::uintmax_t x); } ; // Constructors template bigunsignedint::bigunsignedint () { assign(0u); } template template bigunsignedint::bigunsignedint (Signed y, typename std::enable_if::value && std::is_signed::value>::type*) { if (y < 0) DUNE_THROW(Dune::Exception, "Trying to construct a Dune::bigunsignedint from a negative integer: " << y); assign(y); } template bigunsignedint::bigunsignedint (std::uintmax_t x) { assign(x); } template void bigunsignedint::assign(std::uintmax_t x) { static const int no=std::min(static_cast(n), static_cast(std::numeric_limits::digits/bits)); for(int i=0; i>bits; } for (unsigned int i=no; i inline std::uint_least32_t bigunsignedint::touint () const { return (digit[1]< inline double bigunsignedint::todouble() const { int firstInZeroRange=n; for(int i=n-1; i>=0; --i) if(digit[i]!=0) break; else --firstInZeroRange; int representableDigits=std::numeric_limits::digits/bits; int lastInRepresentableRange=0; if(representableDigits=lastInRepresentableRange; --i) val =val*(1< inline void bigunsignedint::print (std::ostream& s) const { bool leading=false; // print from left to right for (int i=n-1; i>=0; i--) for (int d=hexdigits-1; d>=0; d--) { // extract one hex digit int current = (digit[i]>>(d*4))&0xF; if (current!=0) { // s.setf(std::ios::noshowbase); s << std::hex << current; leading = false; } else if (!leading) s << std::hex << current; } if (leading) s << "0"; s << std::dec; } template inline std::ostream& operator<< (std::ostream& s, const bigunsignedint& x) { x.print(s); return s; } #define DUNE_BINOP(OP) \ template \ inline bigunsignedint bigunsignedint::operator OP (const bigunsignedint &x) const \ { \ auto temp = *this; \ temp OP##= x; \ return temp; \ } DUNE_BINOP(+) DUNE_BINOP(-) DUNE_BINOP(*) DUNE_BINOP(/) DUNE_BINOP(%) DUNE_BINOP(&) DUNE_BINOP(^) DUNE_BINOP(|) #undef DUNE_BINOP template inline bigunsignedint& bigunsignedint::operator+= (const bigunsignedint& x) { std::uint_fast32_t overflow=0; for (unsigned int i=0; i(digit[i]) + static_cast(x.digit[i]) + overflow; digit[i] = sum&bitmask; overflow = (sum>>bits)&overflowmask; } return *this; } template inline bigunsignedint& bigunsignedint::operator-= (const bigunsignedint& x) { std::int_fast32_t overflow=0; for (unsigned int i=0; i(digit[i]) - static_cast(x.digit[i]) - overflow; if (diff>=0) { digit[i] = static_cast(diff); overflow = 0; } else { digit[i] = static_cast(diff+bitmask+1); overflow = 1; } } return *this; } template inline bigunsignedint& bigunsignedint::operator*= (const bigunsignedint& x) { bigunsignedint<2*k> finalproduct(0); for (unsigned int m=0; m singleproduct(0); std::uint_fast32_t overflow(0); for (unsigned int i=0; i(digit[i])*static_cast(x.digit[m])+overflow; singleproduct.digit[i+m] = static_cast(digitproduct&bitmask); overflow = (digitproduct>>bits)&bitmask; } finalproduct = finalproduct+singleproduct; } for (unsigned int i=0; i inline bigunsignedint& bigunsignedint::operator++ () { std::uint_fast32_t overflow=1; for (unsigned int i=0; i(digit[i]) + overflow; digit[i] = sum&bitmask; overflow = (sum>>bits)&overflowmask; } return *this; } template inline bigunsignedint& bigunsignedint::operator/= (const bigunsignedint& x) { if(x==0) DUNE_THROW(Dune::MathError, "division by zero!"); // better slow than nothing bigunsignedint result(0); while (*this>=x) { ++result; *this -= x; } *this = result; return *this; } template inline bigunsignedint& bigunsignedint::operator%= (const bigunsignedint& x) { // better slow than nothing while (*this>=x) { *this -= x; } return *this; } template inline bigunsignedint& bigunsignedint::operator&= (const bigunsignedint& x) { for (unsigned int i=0; i inline bigunsignedint& bigunsignedint::operator^= (const bigunsignedint& x) { for (unsigned int i=0; i inline bigunsignedint& bigunsignedint::operator|= (const bigunsignedint& x) { for (unsigned int i=0; i inline bigunsignedint bigunsignedint::operator~ () const { bigunsignedint result; for (unsigned int i=0; i inline bigunsignedint bigunsignedint::operator<< (int shift) const { bigunsignedint result(0); // multiples of bits int j=shift/bits; for (int i=n-1-j; i>=0; i--) result.digit[i+j] = digit[i]; // remainder j=shift%bits; for (int i=n-1; i>=0; i--) { unsigned int temp = result.digit[i]; temp = temp<(temp&bitmask); temp = temp>>bits; if (i+1<(int)n) result.digit[i+1] = result.digit[i+1]|temp; } return result; } template inline bigunsignedint bigunsignedint::operator>> (int shift) const { bigunsignedint result(0); // multiples of bits int j=shift/bits; for (unsigned int i=0; i((temp&compbitmask)>>bits); if (i>0) result.digit[i-1] = result.digit[i-1] | (temp&bitmask); } return result; } template inline bool bigunsignedint::operator!= (const bigunsignedint& x) const { for (unsigned int i=0; i inline bool bigunsignedint::operator== (const bigunsignedint& x) const { return !((*this)!=x); } template inline bool bigunsignedint::operator< (const bigunsignedint& x) const { for (int i=n-1; i>=0; i--) if (digit[i]x.digit[i]) return false; return false; } template inline bool bigunsignedint::operator<= (const bigunsignedint& x) const { for (int i=n-1; i>=0; i--) if (digit[i]x.digit[i]) return false; return true; } template inline bool bigunsignedint::operator> (const bigunsignedint& x) const { return !((*this)<=x); } template inline bool bigunsignedint::operator>= (const bigunsignedint& x) const { return !((*this) inline bigunsignedint operator+ (const bigunsignedint& x, std::uintmax_t y) { bigunsignedint temp(y); return x+temp; } template inline bigunsignedint operator- (const bigunsignedint& x, std::uintmax_t y) { bigunsignedint temp(y); return x-temp; } template inline bigunsignedint operator* (const bigunsignedint& x, std::uintmax_t y) { bigunsignedint temp(y); return x*temp; } template inline bigunsignedint operator/ (const bigunsignedint& x, std::uintmax_t y) { bigunsignedint temp(y); return x/temp; } template inline bigunsignedint operator% (const bigunsignedint& x, std::uintmax_t y) { bigunsignedint temp(y); return x%temp; } template inline bigunsignedint operator+ (std::uintmax_t x, const bigunsignedint& y) { bigunsignedint temp(x); return temp+y; } template inline bigunsignedint operator- (std::uintmax_t x, const bigunsignedint& y) { bigunsignedint temp(x); return temp-y; } template inline bigunsignedint operator* (std::uintmax_t x, const bigunsignedint& y) { bigunsignedint temp(x); return temp*y; } template inline bigunsignedint operator/ (std::uintmax_t x, const bigunsignedint& y) { bigunsignedint temp(x); return temp/y; } template inline bigunsignedint operator% (std::uintmax_t x, const bigunsignedint& y) { bigunsignedint temp(x); return temp%y; } /** @} */ } namespace std { template struct numeric_limits > : private Dune::Impl::numeric_limits_helper > // for access to internal state of bigunsignedint { public: static const bool is_specialized = true; static Dune::bigunsignedint min() { return static_cast >(0); } static Dune::bigunsignedint max() { Dune::bigunsignedint max_; for(std::size_t i=0; i < Dune::bigunsignedint::n; ++i) // access internal state via the helper base class Dune::Impl::numeric_limits_helper >:: digit(max_,i)=std::numeric_limits::max(); return max_; } static const int digits = Dune::bigunsignedint::bits * Dune::bigunsignedint::n; static const bool is_signed = false; static const bool is_integer = true; static const bool is_exact = true; static const int radix = 2; static Dune::bigunsignedint epsilon() { return static_cast >(0); } static Dune::bigunsignedint round_error() { return static_cast >(0); } static const int min_exponent = 0; static const int min_exponent10 = 0; static const int max_exponent = 0; static const int max_exponent10 = 0; static const bool has_infinity = false; static const bool has_quiet_NaN = false; static const bool has_signaling_NaN = false; static const float_denorm_style has_denorm = denorm_absent; static const bool has_denorm_loss = false; static Dune::bigunsignedint infinity() noexcept { return static_cast >(0); } static Dune::bigunsignedint quiet_NaN() noexcept { return static_cast >(0); } static Dune::bigunsignedint signaling_NaN() noexcept { return static_cast >(0); } static Dune::bigunsignedint denorm_min() noexcept { return static_cast >(0); } static const bool is_iec559 = false; static const bool is_bounded = true; static const bool is_modulo = true; static const bool traps = false; static const bool tinyness_before = false; static const float_round_style round_style = round_toward_zero; }; } DUNE_DEFINE_HASH(DUNE_HASH_TEMPLATE_ARGS(int k),DUNE_HASH_TYPE(Dune::bigunsignedint)) #endif dune-common-2.8.0/dune/common/binaryfunctions.hh000066400000000000000000000025411411343567400217350ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_BINARYFUNCTIONS_HH #define DUNE_BINARYFUNCTIONS_HH /** \file * \brief helper classes to provide unique types for standard functions */ #include namespace Dune { template struct Min { using first_argument_type [[deprecated("This type alias is deprecated following similar deprecations in C++17")]] = Type; using second_argument_type [[deprecated("This type alias is deprecated following similar deprecations in C++17")]] = Type; using result_type [[deprecated("This type alias is deprecated following similar deprecations in C++17")]] = Type; Type operator()(const Type& t1, const Type& t2) const { using std::min; return min(t1,t2); } }; template struct Max { using first_argument_type [[deprecated("This type alias is deprecated following similar deprecations in C++17")]] = Type; using second_argument_type [[deprecated("This type alias is deprecated following similar deprecations in C++17")]] = Type; using result_type [[deprecated("This type alias is deprecated following similar deprecations in C++17")]] = Type; Type operator()(const Type& t1, const Type& t2) const { using std::max; return max(t1,t2); } }; } #endif dune-common-2.8.0/dune/common/bitsetvector.hh000066400000000000000000000423461411343567400212440ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_BLOCK_BITFIELD_HH #define DUNE_BLOCK_BITFIELD_HH /** \file \brief Efficient implementation of a dynamic array of static arrays of booleans */ #include #include #include #include #include #include #include namespace Dune { template class BitSetVector; template class BitSetVectorReference; /** \brief A proxy class that acts as a const reference to a single bitset in a BitSetVector. It contains a conversion to std::bitset and most of the interface of const std::bitset. \warning As this is only a proxy class, you can not get the address of the bitset. */ template class BitSetVectorConstReference { protected: typedef Dune::BitSetVector BitSetVector; friend class Dune::BitSetVector; BitSetVectorConstReference(const BitSetVector& blockBitField_, int block_number_) : blockBitField(blockBitField_), block_number(block_number_) { DUNE_ASSERT_BOUNDS(blockBitField_.size() > static_cast(block_number_)); } //! hide assignment operator BitSetVectorConstReference& operator=(const BitSetVectorConstReference & b); public: typedef std::bitset bitset; // bitset interface typedefs typedef typename std::vector::const_reference reference; typedef typename std::vector::const_reference const_reference; typedef size_t size_type; //! Returns a copy of *this shifted left by n bits. bitset operator<<(size_type n) const { bitset b = *this; b <<= n; return b; } //! Returns a copy of *this shifted right by n bits. bitset operator>>(size_type n) const { bitset b = *this; b >>= n; return b; } //! Returns a copy of *this with all of its bits flipped. bitset operator~() const { bitset b = *this; b.flip(); return b; } //! Returns block_size. size_type size() const { return block_size; } //! Returns the number of bits that are set. size_type count() const { size_type n = 0; for(size_type i=0; i bool equals(const BS & bs) const { bool eq = true; for(int i=0; i; }; /** \brief A proxy class that acts as a mutable reference to a single bitset in a BitSetVector. It contains an assignment operator from std::bitset. It inherits the const std::bitset interface provided by BitSetVectorConstReference and adds most of the non-const methods of std::bitset. \warning As this is only a proxy class, you can not get the address of the bitset. */ template class BitSetVectorReference : public BitSetVectorConstReference { protected: typedef Dune::BitSetVector BitSetVector; friend class Dune::BitSetVector; typedef Dune::BitSetVectorConstReference BitSetVectorConstReference; BitSetVectorReference(BitSetVector& blockBitField_, int block_number_) : BitSetVectorConstReference(blockBitField_, block_number_), blockBitField(blockBitField_) {} public: typedef std::bitset bitset; //! bitset interface typedefs //! \{ //! A proxy class that acts as a reference to a single bit. typedef typename std::vector::reference reference; //! A proxy class that acts as a const reference to a single bit. typedef typename std::vector::const_reference const_reference; //! \} //! size_type typedef (an unsigned integral type) typedef size_t size_type; //! Assignment from bool, sets each bit in the bitset to b BitSetVectorReference& operator=(bool b) { for(int i=0; i>=(size_type n) { for (size_type i=0; iblock_number,i); } }; // implementation of helper - I put it into the template to avoid having // to compile it in a dedicated compilation unit template bool BitSetVectorReference::xor_helper(bool a, bool b) { return a ^ b; } /** typetraits for BitSetVectorReference */ template struct const_reference< BitSetVectorReference > { typedef BitSetVectorConstReference type; }; template struct const_reference< BitSetVectorConstReference > { typedef BitSetVectorConstReference type; }; template struct mutable_reference< BitSetVectorReference > { typedef BitSetVectorReference type; }; template struct mutable_reference< BitSetVectorConstReference > { typedef BitSetVectorReference type; }; /** \brief A dynamic %array of blocks of booleans */ template > class BitSetVector : private std::vector { /** \brief The implementation class: an unblocked bitfield */ typedef std::vector BlocklessBaseClass; public: //! container interface typedefs //! \{ /** \brief Type of the values stored by the container */ typedef std::bitset value_type; /** \brief Reference to a small block of bits */ typedef BitSetVectorReference reference; /** \brief Const reference to a small block of bits */ typedef BitSetVectorConstReference const_reference; /** \brief Pointer to a small block of bits */ typedef BitSetVectorReference* pointer; /** \brief Const pointer to a small block of bits */ typedef BitSetVectorConstReference* const_pointer; /** \brief size type */ typedef typename std::vector::size_type size_type; /** \brief The type of the allocator */ typedef Allocator allocator_type; //! \} //! iterators //! \{ typedef Dune::GenericIterator, value_type, reference, std::ptrdiff_t, ForwardIteratorFacade> iterator; typedef Dune::GenericIterator, const value_type, const_reference, std::ptrdiff_t, ForwardIteratorFacade> const_iterator; //! \} //! Returns a iterator pointing to the beginning of the vector. iterator begin(){ return iterator(*this, 0); } //! Returns a const_iterator pointing to the beginning of the vector. const_iterator begin() const { return const_iterator(*this, 0); } //! Returns an iterator pointing to the end of the vector. iterator end(){ return iterator(*this, size()); } //! Returns a const_iterator pointing to the end of the vector. const_iterator end() const { return const_iterator(*this, size()); } //! Default constructor BitSetVector() : BlocklessBaseClass() {} //! Construction from an unblocked bitfield BitSetVector(const BlocklessBaseClass& blocklessBitField) : BlocklessBaseClass(blocklessBitField) { if (blocklessBitField.size()%block_size != 0) DUNE_THROW(RangeError, "Vector size is not a multiple of the block size!"); } /** Constructor with a given length \param n Number of blocks */ explicit BitSetVector(int n) : BlocklessBaseClass(n*block_size) {} //! Constructor which initializes the field with true or false BitSetVector(int n, bool v) : BlocklessBaseClass(n*block_size,v) {} //! Erases all of the elements. void clear() { BlocklessBaseClass::clear(); } //! Resize field void resize(int n, bool v = bool()) { BlocklessBaseClass::resize(n*block_size, v); } /** \brief Return the number of blocks */ size_type size() const { return BlocklessBaseClass::size()/block_size; } //! Sets all entries to true void setAll() { this->assign(BlocklessBaseClass::size(), true); } //! Sets all entries to false void unsetAll() { this->assign(BlocklessBaseClass::size(), false); } /** \brief Return reference to i-th block */ reference operator[](int i) { return reference(*this, i); } /** \brief Return const reference to i-th block */ const_reference operator[](int i) const { return const_reference(*this, i); } /** \brief Return reference to last block */ reference back() { return reference(*this, size()-1); } /** \brief Return const reference to last block */ const_reference back() const { return const_reference(*this, size()-1); } //! Returns the number of bits that are set. size_type count() const { return std::count(BlocklessBaseClass::begin(), BlocklessBaseClass::end(), true); } //! Returns the number of set bits, while each block is masked with 1<::reference getBit(size_type i, size_type j) { DUNE_ASSERT_BOUNDS(j < block_size); DUNE_ASSERT_BOUNDS(i < size()); return BlocklessBaseClass::operator[](i*block_size+j); } typename std::vector::const_reference getBit(size_type i, size_type j) const { DUNE_ASSERT_BOUNDS(j < block_size); DUNE_ASSERT_BOUNDS(i < size()); return BlocklessBaseClass::operator[](i*block_size+j); } friend class BitSetVectorReference; friend class BitSetVectorConstReference; }; } // namespace Dune #endif dune-common-2.8.0/dune/common/boundschecking.hh000066400000000000000000000016271411343567400215120ustar00rootroot00000000000000#ifndef DUNE_BOUNDSCHECKING_HH #define DUNE_BOUNDSCHECKING_HH #include /** * \file * \brief Macro for wrapping boundary checks */ /** * @addtogroup Common * * @{ */ #ifndef DUNE_ASSERT_BOUNDS #if defined(DUNE_CHECK_BOUNDS) || defined(DOXYGEN) /** * \brief If `DUNE_CHECK_BOUNDS` is defined: check if condition * \a cond holds; otherwise, do nothing. * * Meant to be used for conditions that assure writes and reads * do not occur outside of memory limits or pre-defined patterns * and related conditions. */ #define DUNE_ASSERT_BOUNDS(cond) \ do { \ if (!(cond)) \ DUNE_THROW(Dune::RangeError, "Index out of bounds."); \ } while (false) #else #define DUNE_ASSERT_BOUNDS(cond) #endif #endif /* @} */ #endif // DUNE_BOUNDSCHECKING_HH dune-common-2.8.0/dune/common/classname.hh000066400000000000000000000037401411343567400204700ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_CLASSNAME_HH #define DUNE_CLASSNAME_HH /** \file * \brief A free function to provide the demangled class name * of a given object or type as a string */ #include #include #include #include #include #if __has_include() && !DISABLE_CXA_DEMANGLE #define HAVE_CXA_DEMANGLE 1 #include #endif // #if HAVE_CXA_DEMANGLE namespace Dune { namespace Impl { inline std::string demangle(std::string name) { #if HAVE_CXA_DEMANGLE int status; std::unique_ptr demangled(abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status), std::free); if( demangled ) name = demangled.get(); #endif // #if HAVE_CXA_DEMANGLE return name; } } /** \brief Provide the demangled class name of a type T as a string */ /* * \ingroup CxxUtilities */ template std::string className () { typedef typename std::remove_reference::type TR; std::string className = Impl::demangle( typeid( TR ).name() ); if (std::is_const::value) className += " const"; if (std::is_volatile::value) className += " volatile"; if (std::is_lvalue_reference::value) className += "&"; else if (std::is_rvalue_reference::value) className += "&&"; return className; } /** \brief Provide the demangled class name of a given object as a string */ /* * \ingroup CxxUtilities */ template std::string className ( T&& v) { typedef typename std::remove_reference::type TR; std::string className = Impl::demangle( typeid(v).name() ); if (std::is_const::value) className += " const"; if (std::is_volatile::value) className += " volatile"; return className; } } // namespace Dune #endif // DUNE_CLASSNAME_HH dune-common-2.8.0/dune/common/concept.hh000066400000000000000000000242331411343567400201550ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_CONCEPT_HH #define DUNE_COMMON_CONCEPT_HH #include #include #include #include #include #include #include /** * \file * * \brief Infrastructure for concepts. */ namespace Dune { /** * \brief Namespace for concepts * * This namespace contains helper functions for * concept definitions and the concept definitions * themselves. * * \ingroup CxxConcepts */ namespace Concept { /** * \brief Base class for refined concepts. * * If a new concept should refine one or more existing concepts, * this can be achieved by deriving the new concept from * Refines where C1, ..., CN are the concepts * to be refined. If you want to refine several concepts * they should all be put in a single Refines<...> base * class. * * \tparam BaseConcepts The list of concepts to be refined. * * \ingroup CxxConcepts */ template struct Refines { typedef TypeList BaseConceptList; }; #ifndef DOXYGEN namespace Impl { // ############################################################################# // # All functions following here are implementation details // # for the models() function below. // ############################################################################# // Forward declaration template constexpr bool models(); // Here is the implementation of the concept checking. // The first two overloads do the magic for checking // if the requirements of a concept are satisfied. // The rest is just for checking base concepts in case // of refinement. // This overload is present if type substitution for // C::require(T...) is successful, i.e., if the T... // matches the requirement of C. In this case this // overload is selected because PriorityTag<1> // is a better match for PrioriryTag<42> than // PriorityTag<0> in the default overload. template().require(std::declval()...), 0) =0> constexpr std::true_type matchesRequirement(PriorityTag<1>) { return {}; } // If the above overload is ruled out by SFINAE because // the T... does not match the requirements of C, then // this default overload drops in. template constexpr std::false_type matchesRequirement(PriorityTag<0>) { return {}; } // An empty list C of concepts is always matched by T... template constexpr bool modelsConceptList(TypeList<>) { return true; } // A nonempty list C0,..,CN of concepts is modeled // by T... if it models the concept C0 // and all concepts in the list C1,..,CN. template constexpr bool modelsConceptList(TypeList) { return models() and modelsConceptList(TypeList()); } // If C is an unrefined concept, then T... models C // if it matches the requirement of C. template constexpr bool modelsConcept(PriorityTag<0>) { return matchesRequirement(PriorityTag<42>()); } // If C is a refined concept, then T... models C // if it matches the requirement of C and of // all base concepts. // // This overload is used if C::BaseConceptList exists // due to its higher priority. template constexpr bool modelsConcept(PriorityTag<1>) { return matchesRequirement(PriorityTag<42>()) and modelsConceptList(typename C::BaseConceptList()); } // This is the full concept check. It's defined here in the // implementation namespace with 'constexpr bool' return type // because we need a forward declaration in order to use it // internally above. // // The actual interface function can then call this one and // return the result as std::integral_constant which // does not allow for a forward declaration because the return // type is deduced. template constexpr bool models() { return modelsConcept(PriorityTag<42>()); } } // namespace Dune::Concept::Impl #endif // DOXYGEN } // namespace Dune::Concept /** * \brief Check if concept is modeled by given types * * This will check if the given concept is modeled by the given * list of types. This is true if the list of types models all * the base concepts that are refined by the given concept * and if it satisfies all additional requirements of the latter. * * Notice that a concept may be defined for a list of interacting types. * The function will check if the given list of types matches the requirements * on the whole list. It does not check if each individual type in the list * satisfies the concept. * * This concept check mechanism is inspired by the concept checking * facility in Eric Nieblers range-v3. For more information please * refer to the libraries project page https://github.com/ericniebler/range-v3 * or this blog entry: http://ericniebler.com/2013/11/23/concept-checking-in-c11. * In fact the interface provided here is almost exactly the same as in range-v3. * However the implementation differs, because range-v3 uses its own meta-programming * library whereas our implementation is more straight forward. * * The result is returned as std::integral_constant which * allows to nicely use this method with Hybrid::ifElse. * * \tparam C The concept to check * \tparam T The list of type to check against the concept * * \ingroup CxxConcepts */ template constexpr auto models() { return Std::bool_constant()>(); } namespace Concept { #ifndef DOXYGEN namespace Impl { // ############################################################################# // # All functions following here are implementation details for the // # for the tupleEntriesModel() function below. // ############################################################################# template struct TupleEntriesModelHelper { template struct AccumulateFunctor { using type = typename std::integral_constant()>; }; using Result = typename ReduceTuple::type; }; } // namespace Dune::Concept::Impl #endif // DOXYGEN // ############################################################################# // # The method tupleEntriesModel() does the actual check if the types in a tuple // # model a concept using the implementation details above. // ############################################################################# template constexpr auto tupleEntriesModel() -> typename Impl::TupleEntriesModelHelper::Result { return {}; } // ############################################################################# // # The following require*() functions are just helpers that allow to // # propagate a failed check as substitution failure. This is useful // # inside of a concept definition. // ############################################################################# // Helper function for use in concept definitions. // If the passed value b is not true, the concept will to be satisfied. template::type = 0> constexpr bool requireTrue() { return true; } // Helper function for use in concept definitions. template(), int>::type = 0> constexpr bool requireConcept() { return true; } // Helper function for use in concept definitions. // This allows to avoid using decltype template(), int>::type = 0> constexpr bool requireConcept(T&&... /*t*/) { return true; } // Helper function for use in concept definitions. // This checks if the concept given as first type is modelled by all types in the tuple passed as argument template(), int>::type = 0> constexpr bool requireConceptForTupleEntries() { return true; } // Helper function for use in concept definitions. // If the first passed type is not convertible to the second, the concept will not be satisfied. template::value, int>::type = 0> constexpr bool requireConvertible() { return true; } // Helper function for use in concept definitions. // If passed argument is not convertible to the first passed type, the concept will not be satisfied. template::value, int>::type = 0> constexpr bool requireConvertible(const From&) { return true; } // Helper function for use in concept definitions. // This will always evaluate to true. If just allow // to turn a type into an expression. The failure happens // already during substitution for the type argument. template constexpr bool requireType() { return true; } // Helper function for use in concept definitions. // If first passed type is not a base class of second type, the concept will not be satisfied. template::value, int>::type = 0> constexpr bool requireBaseOf() { return true; } // Helper function for use in concept definitions. // If first passed type is not a base class of first arguments type, the concept will not be satisfied. template::value, int>::type = 0> constexpr bool requireBaseOf(const Derived&) { return true; } // Helper function for use in concept definitions. // If the passed types are not the same, the concept will not be satisfied. template::value, int>::type = 0> constexpr bool requireSameType() { return true; } } // namespace Dune::Concept /** @} */ } // namespace Dune #endif // DUNE_COMMON_CONCEPT_HH dune-common-2.8.0/dune/common/conditional.hh000066400000000000000000000013231411343567400210200ustar00rootroot00000000000000#ifndef DUNE_COMMON_CONDITIONAL_HH #define DUNE_COMMON_CONDITIONAL_HH namespace Dune { /** \brief conditional evaluate sometimes call immediate if, evaluates to \code if (b) return v1; else return v2; \endcode In contrast to if-then-else the cond function can also be evaluated for vector valued SIMD data types, see simd.hh. \param b boolean value \param v1 value of b==true \param v2 value of b==false */ template const T1 cond(bool b, const T1 & v1, const T2 & v2) { return (b ? v1 : v2); } } // end namespace Dune #endif // DUNE_COMMON_CONDITIONAL_HH dune-common-2.8.0/dune/common/debugalign.cc000066400000000000000000000023421411343567400206060ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include #include namespace Dune { //! default alignment violation handler /** * Prints it's arguments on `stderr` and aborts. */ static void defaultViolatedAlignment(const char *className, std::size_t expectedAlignment, const void *address) { std::cerr << "Error: Detected invalid alignment for type " << className << ": Address " << address << " not aligned to 0x" << std::hex << expectedAlignment << std::endl; std::abort(); } ViolatedAlignmentHandler &violatedAlignmentHandler() { static ViolatedAlignmentHandler handler = defaultViolatedAlignment; return handler; } void violatedAlignment(const char *className, std::size_t expectedAlignment, const void *address) { const auto &handler = violatedAlignmentHandler(); if(handler) handler(className, expectedAlignment, address); } } // namespace Dune dune-common-2.8.0/dune/common/debugalign.hh000066400000000000000000000447151411343567400206320ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_DEBUGALIGN_HH #define DUNE_DEBUGALIGN_HH #include #include #include #include #include #include #include // abs #include #include #include #include #include #include #include #include #include #include namespace Dune { //! type of the handler called by `violatedAlignment()` using ViolatedAlignmentHandler = std::function; //! access the handler called by `violatedAlignment()` /** * This may be used to obtain the handler for the purpose of calling, or for * saving it somewhere to restore it later. It may also be used to set the * handler simply by assigning a new handler. Setting the handler races * with other accesses. */ ViolatedAlignmentHandler &violatedAlignmentHandler(); //! called when an alignment violation is detected /** * \p className Name of the class whose alignment was violated * \p expectedAlignment The (over-)alignment that the class expected * \p address The address the class actually found itself at. * * The main purpose of the function is to serve as a convenient breakpoint * for debugging -- which is why we put it in an external compilation unit * so it isn't inlined. */ void violatedAlignment(const char *className, std::size_t expectedAlignment, const void *address); //! check whether an address conforms to the given alignment inline bool isAligned(const void *p, std::size_t align) { // a more portable way to do this would be to abuse std::align(), but that // isn't supported by g++-4.9 yet return std::uintptr_t(p) % align == 0; } //! CRTP base mixin class to check alignment template class alignas(align) AlignedBase { void checkAlignment() const { auto pimpl = static_cast(this); if(!isAligned(pimpl, align)) violatedAlignment(className().c_str(), align, pimpl); } public: AlignedBase() { checkAlignment(); } AlignedBase(const AlignedBase &) { checkAlignment(); } AlignedBase(AlignedBase &&) { checkAlignment(); } ~AlignedBase() { checkAlignment(); } AlignedBase& operator=(const AlignedBase &) = default; AlignedBase& operator=(AlignedBase &&) = default; }; //! an alignment large enough to trigger alignment errors static constexpr auto debugAlignment = 2*alignof(std::max_align_t); namespace AlignedNumberImpl { template class AlignedNumber; } // namespace AlignedNumberImpl using AlignedNumberImpl::AlignedNumber; //! align a value to a certain alignment template AlignedNumber aligned(T value) { return { std::move(value) }; } // The purpose of this namespace is to move the `` function overloads // out of namespace `Dune`. This avoids problems where people called // e.g. `sqrt(1.0)` inside the `Dune` namespace, without first doing `using // std::sqrt;`. Without any `Dune::sqrt()`, such a use will find // `::sqrt()`, but with `Dune::sqrt()` it will find only `Dune::sqrt()`, // which does not have an overload for `double`. namespace AlignedNumberImpl { //! aligned wrappers for arithmetic types template class AlignedNumber : public AlignedBase > { T value_; public: AlignedNumber() = default; AlignedNumber(T value) : value_(std::move(value)) {} template= uAlign) && std::is_convertible::value> > AlignedNumber(const AlignedNumber &o) : value_(U(o)) {} // accessors template::value> > explicit operator U() const { return value_; } const T &value() const { return value_; } T &value() { return value_; } // I/O template friend std::basic_istream& operator>>(std::basic_istream& str, AlignedNumber &u) { return str >> u.value_; } template friend std::basic_ostream& operator<<(std::basic_ostream& str, const AlignedNumber &u) { return str << u.value_; } // The trick with `template >` is // needed because at least g++-4.9 seems to evaluates a default argument // in `template >` as soon as possible and will // error out if `expr(T)` is invalid. E.g. for `expr(T)` = // `decltype(--std::declval())`, instantiating `AlignedNumber` // will result in an unrecoverable error (`--` cannot be applied to a // `bool`). // Increment, decrement template())> > AlignedNumber &operator++() { ++value_; return *this; } template())> > AlignedNumber &operator--() { --value_; return *this; } template()++)> > decltype(auto) operator++(int) { return aligned(value_++); } template()--)> > decltype(auto) operator--(int) { return aligned(value_--); } // unary operators template())> > decltype(auto) operator+() const { return aligned(+value_); } template())> > decltype(auto) operator-() const { return aligned(-value_); } /* * silence warnings from GCC about using `~` on a bool * (when instantiated for T=bool) */ #if __GNUC__ >= 7 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wbool-operation" #endif template())> > decltype(auto) operator~() const { return aligned(~value_); } #if __GNUC__ >= 7 # pragma GCC diagnostic pop #endif template())> > decltype(auto) operator!() const { return aligned(!value_); } // assignment operators #define DUNE_ASSIGN_OP(OP) \ template() OP std::declval()) ) \ > > \ AlignedNumber &operator OP(const AlignedNumber &u) \ { \ value_ OP U(u); \ return *this; \ } \ \ template() OP \ std::declval())> > \ AlignedNumber &operator OP(const U &u) \ { \ value_ OP u; \ return *this; \ } \ \ static_assert(true, "Require semicolon to unconfuse editors") DUNE_ASSIGN_OP(+=); DUNE_ASSIGN_OP(-=); DUNE_ASSIGN_OP(*=); DUNE_ASSIGN_OP(/=); DUNE_ASSIGN_OP(%=); DUNE_ASSIGN_OP(^=); DUNE_ASSIGN_OP(&=); DUNE_ASSIGN_OP(|=); DUNE_ASSIGN_OP(<<=); DUNE_ASSIGN_OP(>>=); #undef DUNE_ASSIGN_OP }; // binary operators #define DUNE_BINARY_OP(OP) \ template() \ OP std::declval())> > \ decltype(auto) \ operator OP(const AlignedNumber &t, \ const AlignedNumber &u) \ { \ /* can't use std::max(); not constexpr */ \ return aligned<(tAlign > uAlign ? tAlign : uAlign)>(T(t) OP U(u)); \ } \ \ template() \ OP std::declval())> > \ decltype(auto) \ operator OP(const T &t, const AlignedNumber &u) \ { \ return aligned(t OP U(u)); \ } \ \ template() \ OP std::declval())> > \ decltype(auto) \ operator OP(const AlignedNumber &t, const U &u) \ { \ return aligned(T(t) OP u); \ } \ \ static_assert(true, "Require semicolon to unconfuse editors") DUNE_BINARY_OP(+); DUNE_BINARY_OP(-); DUNE_BINARY_OP(*); DUNE_BINARY_OP(/); DUNE_BINARY_OP(%); DUNE_BINARY_OP(^); DUNE_BINARY_OP(&); DUNE_BINARY_OP(|); DUNE_BINARY_OP(<<); DUNE_BINARY_OP(>>); DUNE_BINARY_OP(==); DUNE_BINARY_OP(!=); DUNE_BINARY_OP(<); DUNE_BINARY_OP(>); DUNE_BINARY_OP(<=); DUNE_BINARY_OP(>=); DUNE_BINARY_OP(&&); DUNE_BINARY_OP(||); #undef DUNE_BINARY_OP ////////////////////////////////////////////////////////////////////// // // Overloads for the functions provided by the standard library // #define DUNE_UNARY_FUNC(name) \ template \ decltype(auto) name(const AlignedNumber &u) \ { \ using std::name; \ return aligned(name(T(u))); \ } \ static_assert(true, "Require semicolon to unconfuse editors") // // functions // // note: only unary functions are provided at the moment. Getting all the // overloads right for functions with more than one argument is tricky. // All functions appear in the list below in the order they are // listed in in the standard, but the unimplemented ones are commented // out. // note: abs is provided by both (for integer) and (for // floating point). This overload works for both. DUNE_UNARY_FUNC(abs); DUNE_UNARY_FUNC(acos); DUNE_UNARY_FUNC(acosh); DUNE_UNARY_FUNC(asin); DUNE_UNARY_FUNC(asinh); DUNE_UNARY_FUNC(atan); // atan2 DUNE_UNARY_FUNC(atanh); DUNE_UNARY_FUNC(cbrt); DUNE_UNARY_FUNC(ceil); // copysign DUNE_UNARY_FUNC(cos); DUNE_UNARY_FUNC(cosh); DUNE_UNARY_FUNC(erf); DUNE_UNARY_FUNC(erfc); DUNE_UNARY_FUNC(exp); DUNE_UNARY_FUNC(exp2); DUNE_UNARY_FUNC(expm1); DUNE_UNARY_FUNC(fabs); // fdim DUNE_UNARY_FUNC(floor); // fma // fmax // fmin // fmod // frexp // hypos DUNE_UNARY_FUNC(ilogb); // ldexp DUNE_UNARY_FUNC(lgamma); DUNE_UNARY_FUNC(llrint); DUNE_UNARY_FUNC(llround); DUNE_UNARY_FUNC(log); DUNE_UNARY_FUNC(log10); DUNE_UNARY_FUNC(log1p); DUNE_UNARY_FUNC(log2); DUNE_UNARY_FUNC(logb); DUNE_UNARY_FUNC(lrint); DUNE_UNARY_FUNC(lround); // modf DUNE_UNARY_FUNC(nearbyint); // nextafter // nexttoward // pow // remainder // remquo DUNE_UNARY_FUNC(rint); DUNE_UNARY_FUNC(round); // scalbln // scalbn DUNE_UNARY_FUNC(sin); DUNE_UNARY_FUNC(sinh); DUNE_UNARY_FUNC(sqrt); DUNE_UNARY_FUNC(tan); DUNE_UNARY_FUNC(tanh); DUNE_UNARY_FUNC(tgamma); DUNE_UNARY_FUNC(trunc); DUNE_UNARY_FUNC(isfinite); DUNE_UNARY_FUNC(isinf); DUNE_UNARY_FUNC(isnan); DUNE_UNARY_FUNC(isnormal); DUNE_UNARY_FUNC(signbit); // isgreater // isgreaterequal // isless // islessequal // islessgreater // isunordered // // functions // // not all functions are implemented, and unlike for , no // comprehensive list is provided DUNE_UNARY_FUNC(real); #undef DUNE_UNARY_FUNC // We need to overload min() and max() since they require types to be // LessThanComparable, which requires `a in the standard (still open // as of 2018-07-06), which strives to require both "implicitly" and // "contextually" convertible -- plus a few other things. // // We do not want our debug type to automatically decay to the underlying // type, so we do not want to make the conversion non-explicit. So the // only option left is to overload min() and max(). template auto max(const AlignedNumber &a, const AlignedNumber &b) { using std::max; return aligned(max(T(a), T(b))); } template auto max(const T &a, const AlignedNumber &b) { using std::max; return aligned(max(a, T(b))); } template auto max(const AlignedNumber &a, const T &b) { using std::max; return aligned(max(T(a), b)); } template auto min(const AlignedNumber &a, const AlignedNumber &b) { using std::min; return aligned(min(T(a), T(b))); } template auto min(const T &a, const AlignedNumber &b) { using std::min; return aligned(min(a, T(b))); } template auto min(const AlignedNumber &a, const T &b) { using std::min; return aligned(min(T(a), b)); } } // namespace AlignedNumberImpl // SIMD-like functions from "conditional.hh" template AlignedNumber cond(const AlignedNumber &b, const AlignedNumber &v1, const AlignedNumber &v2) { return b ? v1 : v2; } // SIMD-like functions from "rangeutilities.hh" template T max_value(const AlignedNumber& val) { return T(val); } template T min_value(const AlignedNumber& val) { return T(val); } template bool any_true(const AlignedNumber& val) { return bool(val); } template bool all_true(const AlignedNumber& val) { return bool(val); } // SIMD-like functionality from "simd/interface.hh" namespace Simd { namespace Overloads { template struct ScalarType > { using type = T; }; template struct RebindType > { using type = AlignedNumber; }; template struct LaneCount > : index_constant<1> {}; template T& lane(ADLTag<5>, std::size_t l, AlignedNumber &v) { assert(l == 0); return v.value(); } template T lane(ADLTag<5>, std::size_t l, const AlignedNumber &v) { assert(l == 0); return v.value(); } template const AlignedNumber & cond(ADLTag<5>, AlignedNumber mask, const AlignedNumber &ifTrue, const AlignedNumber &ifFalse) { return mask ? ifTrue : ifFalse; } template bool anyTrue(ADLTag<5>, const AlignedNumber &mask) { return bool(mask); } } // namespace Overloads } // namespace Simd } // namespace Dune #endif // DUNE_DEBUGALIGN_HH dune-common-2.8.0/dune/common/debugallocator.cc000066400000000000000000000013641411343567400214770ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include "config.h" #endif #include "debugallocator.hh" #if HAVE_MPROTECT #include #include #include namespace Dune { namespace DebugMemory { // system constant for page size const std::ptrdiff_t page_size = sysconf(_SC_PAGESIZE); // implement member functions void AllocationManager::allocation_error(const char* msg) { std::cerr << "Abort - Memory Corruption: " << msg << std::endl; std::abort(); } // global instance of AllocationManager AllocationManager alloc_man; } // end namespace DebugMemory } // end namespace Dune #endif // HAVE_MPROTECT dune-common-2.8.0/dune/common/debugallocator.hh000066400000000000000000000226211411343567400215100ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_DEBUG_ALLOCATOR_HH #define DUNE_DEBUG_ALLOCATOR_HH #if __has_include() #include #define HAVE_SYS_MMAN_H 1 #define HAVE_MPROTECT 1 #include #include #include #include #include #include #include #include #include "mallocallocator.hh" namespace Dune { #ifndef DOXYGEN // hide implementation details from doxygen namespace DebugMemory { extern const std::ptrdiff_t page_size; struct AllocationManager { typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef void* pointer; protected: static void allocation_error(const char* msg); struct AllocationInfo; friend struct AllocationInfo; #define ALLOCATION_ASSERT(A) { if (!(A)) \ { allocation_error("Assertion " # A " failed");\ }\ }; struct AllocationInfo { AllocationInfo(const std::type_info & t) : type(&t) {} const std::type_info * type; pointer page_ptr; pointer ptr; size_type pages; size_type capacity; size_type size; bool not_free; }; typedef MallocAllocator Alloc; typedef std::vector AllocationList; AllocationList allocation_list; private: void memprotect([[maybe_unused]] void* from, [[maybe_unused]] difference_type len, [[maybe_unused]] int prot) { #if HAVE_SYS_MMAN_H && HAVE_MPROTECT int result = mprotect(from, len, prot); if (result == -1) { std::cerr << "ERROR: (" << result << ": " << strerror(result) << ")" << std::endl; std::cerr << " Failed to "; if (prot == PROT_NONE) std::cerr << "protect "; else std::cerr << "unprotect "; std::cerr << "memory range: " << from << ", " << static_cast( static_cast(from) + len) << std::endl; abort(); } #else std::cerr << "WARNING: memory protection not available" << std::endl; #endif } public: ~AllocationManager () { AllocationList::iterator it; bool error = false; for (it=allocation_list.begin(); it!=allocation_list.end(); it++) { if (it->not_free) { std::cerr << "ERROR: found memory chunk still in use: " << it->capacity << " bytes at " << it->ptr << std::endl; error = true; } munmap(it->page_ptr, it->pages * page_size); } if (error) allocation_error("lost allocations"); } template T* allocate(size_type n) { // setup chunk info AllocationInfo ai(typeid(T)); ai.size = n; ai.capacity = n * sizeof(T); ai.pages = (ai.capacity) / page_size + 2; ai.not_free = true; size_type overlap = ai.capacity % page_size; ai.page_ptr = mmap(NULL, ai.pages * page_size, PROT_READ | PROT_WRITE, #ifdef __APPLE__ MAP_ANON | MAP_PRIVATE, #else MAP_ANONYMOUS | MAP_PRIVATE, #endif -1, 0); if (MAP_FAILED == ai.page_ptr) { throw std::bad_alloc(); } ai.ptr = static_cast(ai.page_ptr) + page_size - overlap; // write protect memory behind the actual data memprotect(static_cast(ai.page_ptr) + (ai.pages-1) * page_size, page_size, PROT_NONE); // remember the chunk allocation_list.push_back(ai); // return the ptr return static_cast(ai.ptr); } template void deallocate(T* ptr, size_type n = 0) noexcept { // compute page address void* page_ptr = static_cast( (char*)(ptr) - ((std::uintptr_t)(ptr) % page_size)); // search list AllocationList::iterator it; unsigned int i = 0; for (it=allocation_list.begin(); it!=allocation_list.end(); it++, i++) { if (it->page_ptr == page_ptr) { // std::cout << "found memory_block in allocation " << i << std::endl; // sanity checks if (n != 0) ALLOCATION_ASSERT(n == it->size); ALLOCATION_ASSERT(ptr == it->ptr); ALLOCATION_ASSERT(true == it->not_free); ALLOCATION_ASSERT(typeid(T) == *(it->type)); // free memory it->not_free = false; #if DEBUG_ALLOCATOR_KEEP // write protect old memory memprotect(it->page_ptr, (it->pages) * page_size, PROT_NONE); #else // unprotect old memory memprotect(it->page_ptr, (it->pages) * page_size, PROT_READ | PROT_WRITE); munmap(it->page_ptr, it->pages * page_size); // remove chunk info allocation_list.erase(it); #endif return; } } allocation_error("memory block not found"); } }; #undef ALLOCATION_ASSERT extern AllocationManager alloc_man; } // end namespace DebugMemory #endif // DOXYGEN template class DebugAllocator; // specialize for void template <> class DebugAllocator { public: typedef void* pointer; typedef const void* const_pointer; // reference to void members are impossible. typedef void value_type; template struct rebind { typedef DebugAllocator other; }; }; // actual implementation /** @ingroup Allocators @brief Allocators implementation which performs different kind of memory checks We check: - access past the end - only free memory which was allocated with this allocator - list allocated memory chunks still in use upon destruction of the allocator When defining DEBUG_ALLOCATOR_KEEP to 1, we also check - double free - access after free When defining DEBUG_NEW_DELETE >= 1, we - overload new/delte - use the Debug memory management for new/delete - DEBUG_NEW_DELETE > 2 gives extensive debug output */ template class DebugAllocator { public: typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template struct rebind { typedef DebugAllocator other; }; //! create a new DebugAllocator DebugAllocator() noexcept {} //! copy construct from an other DebugAllocator, possibly for a different result type template DebugAllocator(const DebugAllocator&) noexcept {} //! cleanup this allocator ~DebugAllocator() noexcept {} pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } //! allocate n objects of type T pointer allocate(size_type n, [[maybe_unused]] DebugAllocator::const_pointer hint = 0) { return DebugMemory::alloc_man.allocate(n); } //! deallocate n objects of type T at address p void deallocate(pointer p, size_type n) { DebugMemory::alloc_man.deallocate(p,n); } //! max size for allocate size_type max_size() const noexcept { return size_type(-1) / sizeof(T); } //! copy-construct an object of type T (i.e. make a placement new on p) void construct(pointer p, const T& val) { ::new((void*)p)T(val); } //! construct an object of type T from variadic parameters template void construct(pointer p, Args&&... args) { ::new((void *)p)T(std::forward(args) ...); } //! destroy an object of type T (i.e. call the destructor) void destroy(pointer p) { p->~T(); } }; //! check whether allocators are equivalent template constexpr bool operator==(const DebugAllocator &, const DebugAllocator &) { return true; } //! check whether allocators are not equivalent template constexpr bool operator!=(const DebugAllocator &, const DebugAllocator &) { return false; } } #ifdef DEBUG_NEW_DELETE void * operator new(size_t size) { // try to allocate size bytes void *p = Dune::DebugMemory::alloc_man.allocate(size); #if DEBUG_NEW_DELETE > 2 std::cout << "NEW " << size << " -> " << p << std::endl; #endif return p; } void operator delete(void * p) noexcept { #if DEBUG_NEW_DELETE > 2 std::cout << "FREE " << p << std::endl; #endif Dune::DebugMemory::alloc_man.deallocate(static_cast(p)); } void operator delete(void * p, size_t size) noexcept { #if DEBUG_NEW_DELETE > 2 std::cout << "FREE " << p << std::endl; #endif Dune::DebugMemory::alloc_man.deallocate(static_cast(p), size); } #endif // DEBUG_NEW_DELETE #endif // __has_include() #endif // DUNE_DEBUG_ALLOCATOR_HH dune-common-2.8.0/dune/common/debugstream.hh000066400000000000000000000310051411343567400210170ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_DEBUGSTREAM_HH #define DUNE_DEBUGSTREAM_HH /** \file * \brief Defines several output streams for messages of different importance */ #include #include #include namespace Dune { /*! \defgroup DebugOut Debug output \ingroup Common The debug output is implemented by instances of DebugStream which provides the following features: - output-syntax in the standard ostream-notation - output can be totally deactivated depending on template parameters - streams with active output can be deactivated during runtime - redirecting to std::ostream or other DebugStream s during runtime - stack oriented state The Dune-components should use the streams explained in \ref StdStreams for output so that applications may redirect the output globally. Changes in runtime are provided by three sets of methods: - push()/pop() sets new activation flag or restore old setting - attach()/detach() redirects output to a different std::ostream or restore old stream - tie()/untie() redirects output through another DebugStream. If the state of the master stream changes (activation or output-stream) it is changed in the tied stream as well The first methods implement a full stack whereas tie() is a bit different: though a tied stream may be (de)activated via push()/pop() you cannot attach() or detach() an output. You'll need to change the master stream instead. \section DebugAppl Applications Applications using the Dune-library should create an independent set of DebugStreams so that the debug levels can be changed separately. Example: \code static const Dune::DebugLevel APPL_MINLEVEL = 3; Dune::DebugStream<1, APPL_MINLEVEL> myverbose; Dune::DebugStream<2, APPL_MINLEVEL> myinfo; Dune::DebugStream<3, APPL_MINLEVEL> mywarn; \endcode This code creates three streams of which only the last one really creates output. The output-routines of the other streams vanish in optimized executables. You can use the common_bits-Template to switch to a policy using bitflags: \code enum { APPL_CORE = 1, APPL_IO = 2, APPL_GRAPHICS = 4}; static const Dune::DebugLevel APPL_DEBUG_MASK = APPL_CORE | APPL_GRAPHICS; static const Dune::DebugLevel APPL_ACTIVE_MASK = 0xff; Dune::DebugStream coreout; Dune::DebugStream ioout; Dune::DebugStream graphout; \endcode Applications that wish to redirect the \ref StdStreams through their private streams may use the tie()-mechanism: \code // initialize streams like above Dune::dwarn.tie(coreout); // ... Dune-output to dwarn will be directed through coreout ... Dune::dwarn.untie(); \endcode Keep in mind to untie() a stream before the tied stream is destructed. An alternative is to attach() an output stream defined by the application: \code std::ofstream mylog("application.log"); Dune::dwarn.attach(mylog); \endcode */ /** \addtogroup DebugOut \{ */ /*! \file This file implements the class DebugStream to support output in a variety of debug levels. Additionally, template parameters control if the output operation is really performed so that unused debug levels can be deactivated */ /*! \brief Type for debug levels. Only positive values allowed */ typedef unsigned int DebugLevel; /*! \brief Greater or equal template test. value is false if current is below the threshold, true otherwise This is the default struct to control the activation policy of DebugStream and deactivates output below the threshold */ template struct greater_or_equal { static const bool value = (current >= threshold); }; /*! \brief activate if current and mask have common bits switched on. This template implements an alternative strategy to activate or deactivate a DebugStream. Keep in mind to number your streams as powers of two if using this template */ template struct common_bits { enum {value = ((current & mask)!=0) }; }; //! \brief standard exception for the debugstream class DebugStreamError : public IOError {}; class StreamWrap { public: StreamWrap(std::ostream& _out) : out(_out) { } std::ostream& out; StreamWrap *next; }; //! \brief Intermediate class to implement tie-operation of DebugStream class DebugStreamState { // !!! should be protected somehow but that won't be easy public: //! \brief current output stream and link to possibly pushed old output streams StreamWrap* current; //! \brief flag to switch output during runtime bool _active; //! \brief are we tied to another DebugStream? bool _tied; //! \brief how many streams are tied to this state unsigned int _tied_streams; }; /*! \brief Generic class to implement debug output streams The main function of a DebugStream is to provide output in a standard ostream fashion that is fully deactivated if the level of the stream does not meet the current requirements. More information in \ref DebugOut \param thislevel this level \param dlevel level needed for any output to happen \param alevel level needed to switch activation flag on \param activator template describing the activation policy \todo Fix visibility of internal data */ template class activator = greater_or_equal> class DebugStream : public DebugStreamState { public: /*! \brief Create a DebugStream and set initial output stream during runtime another stream can be attach()ed, however the initial stream may not be detach()ed. */ DebugStream(std::ostream& out = std::cerr) { // start a new list of streams current = new StreamWrap(out); current->next = 0; // check if we are above the default activation level _active = activator::value; // we're not tied to another DebugStream _tied = false; // no child streams yet _tied_streams = 0; } /*! \brief Create a DebugStream and directly tie to another DebugStream The fallback is used if a DebugStream constructed via this method is untie()ed later. Otherwise the stream would be broken afterwards. */ DebugStream (DebugStreamState& master, std::ostream& fallback = std::cerr) { // start a new list of streams current = new StreamWrap(fallback); current->next = 0; // check if we are above the default activation level _active = activator::value; _tied_streams = 0; // tie to the provided stream _tied = true; tiedstate = &master; tiedstate->_tied_streams++; } /*! \brief Destroy stream. If other streams still tie() to this stream the destructor will call std::terminate() because you can hardly recover from this problem and the child streams would certainly break on the next output. */ ~DebugStream() { // untie if (_tied) tiedstate->_tied_streams--; else { // check if somebody still ties to us... if (_tied_streams != 0) { std::cerr << "DebugStream destructor is called while other streams are still tied to it. Terminating!" << std::endl; std::terminate(); } } // remove ostream-stack while (current != 0) { StreamWrap *s = current; current = current->next; delete s; } } //! \brief Generic types are passed on to current output stream template DebugStream& operator<<(const T data) { // remove the following code if stream wasn't compiled active if (activator::value) { if (! _tied) { if (_active) current->out << data; } else { if (_active && tiedstate->_active) tiedstate->current->out << data; } } return *this; } /*! \brief explicit specialization so that enums can be printed Operators for built-in types follow special rules (§11.2.3) so that enums won't fit into the generic method above. With an existing operator<< for int however the enum will be automatically casted. */ DebugStream& operator<<(const int data) { // remove the following code if stream wasn't compiled active if (activator::value) { if (! _tied) { if (_active) current->out << data; } else { if (_active && tiedstate->_active) tiedstate->current->out << data; } } return *this; } //! \brief pass on manipulators to underlying output stream DebugStream& operator<<(std::ostream& (*f)(std::ostream&)) { if (activator::value) { if (! _tied) { if (_active) f(current->out); } else { if (_active && tiedstate->_active) f(tiedstate->current->out); } } return *this; } //! \brief pass on flush to underlying output stream DebugStream& flush() { if (activator::value) { if (! _tied) { if (_active) current->out.flush(); } else { if (_active && tiedstate->_active) tiedstate->current->out.flush(); } } return *this; } //! \brief set activation flag and store old value void push(bool b) { // are we at all active? if (activator::value) { _actstack.push(_active); _active = b; } else { // stay off _actstack.push(false); } } /*! \brief restore previously set activation flag * \throws DebugStreamError */ void pop() { if (_actstack.empty()) DUNE_THROW(DebugStreamError, "No previous activation setting!"); _active = _actstack.top(); _actstack.pop(); } /*! \brief reports if this stream will produce output a DebugStream that is deactivated because of its level will always return false, otherwise the state of the internal activation is returned */ bool active() const { return activator::value && _active; } /*! \brief set output to a different stream. Old stream data is stored */ void attach(std::ostream& stream) { if (_tied) DUNE_THROW(DebugStreamError, "Cannot attach to a tied stream!"); StreamWrap* newcurr = new StreamWrap(stream); newcurr->next = current; current = newcurr; } /*! \brief detach current output stream and restore to previous stream * \throws DebugStreamError */ void detach() { if (current->next == 0) DUNE_THROW(DebugStreamError, "Cannot detach initial stream!"); if (_tied) DUNE_THROW(DebugStreamError, "Cannot detach a tied stream!"); StreamWrap* old = current; current = current->next; delete old; } /*! \brief Tie a stream to this one. * \throws DebugStreamError */ void tie(DebugStreamState& to) { if (to._tied) DUNE_THROW(DebugStreamError, "Cannot tie to an already tied stream!"); if (_tied) DUNE_THROW(DebugStreamError, "Stream already tied: untie first!"); _tied = true; tiedstate = &to; // tell master class tiedstate->_tied_streams++; } /*! \brief Untie stream * \throws DebugStreamError */ void untie() { if(! _tied) DUNE_THROW(DebugStreamError, "Cannot untie, stream is not tied!"); tiedstate->_tied_streams--; _tied = false; tiedstate = 0; } private: //! \brief pointer to data of stream we're tied to DebugStreamState* tiedstate; /*! \brief Activation state history. store old activation settings so that the outside code doesn't need to remember */ std::stack _actstack; }; /** /} */ } #endif dune-common-2.8.0/dune/common/densematrix.hh000066400000000000000000001151201411343567400210410ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_DENSEMATRIX_HH #define DUNE_DENSEMATRIX_HH #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Dune { template class DenseMatrix; template struct FieldTraits< DenseMatrix > { typedef const typename FieldTraits< typename DenseMatVecTraits::value_type >::field_type field_type; typedef const typename FieldTraits< typename DenseMatVecTraits::value_type >::real_type real_type; }; /** work around a problem of FieldMatrix/FieldVector, there is no unique way to obtain the size of a class \deprecated VectorSize is deprecated; please call the 'size()' method directly instead. This will be removed after Dune 2.8. */ template class FieldMatrix; template class FieldVector; namespace { template struct [[deprecated("VectorSize is deprecated; please call the 'size()' method directly instead")]] VectorSize { static typename V::size_type size(const V & v) { return v.size(); } }; DUNE_NO_DEPRECATED_BEGIN template struct [[deprecated("VectorSize is deprecated; please call the 'size()' method directly instead")]] VectorSize< const FieldVector > { typedef FieldVector V; static typename V::size_type size([[maybe_unused]] const V & v) { return N; } }; DUNE_NO_DEPRECATED_END } /** @addtogroup DenseMatVec @{ */ /*! \file \brief Implements a matrix constructed from a given type representing a field and a compile-time given number of rows and columns. */ /** \brief you have to specialize this structure for any type that should be assignable to a DenseMatrix \tparam DenseMatrix Some type implementing the dense matrix interface \tparam RHS Right hand side type */ template< class DenseMatrix, class RHS > struct DenseMatrixAssigner; #ifndef DOXYGEN namespace Impl { template< class DenseMatrix, class RHS, class = void > class DenseMatrixAssigner {}; template< class DenseMatrix, class RHS > class DenseMatrixAssigner< DenseMatrix, RHS, std::enable_if_t< Dune::IsNumber< RHS >::value > > { public: static void apply ( DenseMatrix &denseMatrix, const RHS &rhs ) { typedef typename DenseMatrix::field_type field_type; std::fill( denseMatrix.begin(), denseMatrix.end(), static_cast< field_type >( rhs ) ); } }; template< class DenseMatrix, class RHS > class DenseMatrixAssigner< DenseMatrix, RHS, std::enable_if_t< !std::is_same< typename RHS::const_iterator, void >::value && std::is_convertible< typename RHS::const_iterator::value_type, typename DenseMatrix::iterator::value_type >::value > > { public: static void apply ( DenseMatrix &denseMatrix, const RHS &rhs ) { DUNE_ASSERT_BOUNDS(rhs.N() == denseMatrix.N()); DUNE_ASSERT_BOUNDS(rhs.M() == denseMatrix.M()); typename DenseMatrix::iterator tIt = std::begin(denseMatrix); typename RHS::const_iterator sIt = std::begin(rhs); for(; sIt != std::end(rhs); ++tIt, ++sIt) std::copy(std::begin(*sIt), std::end(*sIt), std::begin(*tIt)); } }; } // namespace Impl template< class DenseMatrix, class RHS > struct DenseMatrixAssigner : public Impl::DenseMatrixAssigner< DenseMatrix, RHS > {}; namespace Impl { template< class DenseMatrix, class RHS > std::true_type hasDenseMatrixAssigner ( DenseMatrix &, const RHS &, decltype( Dune::DenseMatrixAssigner< DenseMatrix, RHS >::apply( std::declval< DenseMatrix & >(), std::declval< const RHS & >() ) ) * = nullptr ); std::false_type hasDenseMatrixAssigner ( ... ); } // namespace Impl template< class DenseMatrix, class RHS > struct HasDenseMatrixAssigner : public decltype( Impl::hasDenseMatrixAssigner( std::declval< DenseMatrix & >(), std::declval< const RHS & >() ) ) {}; #endif // #ifndef DOXYGEN /** @brief Error thrown if operations of a FieldMatrix fail. */ class FMatrixError : public MathError {}; /** @brief A dense n x m matrix. Matrices represent linear maps from a vector space V to a vector space W. This class represents such a linear map by storing a two-dimensional %array of numbers of a given field type K. The number of rows and columns is given at compile time. \tparam MAT type of the matrix implementation */ template class DenseMatrix { typedef DenseMatVecTraits Traits; // Curiously recurring template pattern constexpr MAT & asImp() { return static_cast(*this); } constexpr const MAT & asImp() const { return static_cast(*this); } template friend class DenseMatrix; public: //===== type definitions and constants //! type of derived matrix class typedef typename Traits::derived_type derived_type; //! export the type representing the field typedef typename Traits::value_type value_type; //! export the type representing the field typedef typename Traits::value_type field_type; //! export the type representing the components typedef typename Traits::value_type block_type; //! The type used for the index access and size operation typedef typename Traits::size_type size_type; //! The type used to represent a row (must fulfill the Dune::DenseVector interface) typedef typename Traits::row_type row_type; //! The type used to represent a reference to a row (usually row_type &) typedef typename Traits::row_reference row_reference; //! The type used to represent a reference to a constant row (usually const row_type &) typedef typename Traits::const_row_reference const_row_reference; //! We are at the leaf of the block recursion enum { //! The number of block levels we contain. This is 1. blocklevel = 1 }; private: //! \brief if value_type is a simd vector, then this is a simd vector of //! the same length that can be used for indices. using simd_index_type = Simd::Rebind; public: //===== access to components //! random access row_reference operator[] ( size_type i ) { return asImp().mat_access(i); } const_row_reference operator[] ( size_type i ) const { return asImp().mat_access(i); } //! size method (number of rows) size_type size() const { return rows(); } //===== iterator interface to rows of the matrix //! Iterator class for sequential access typedef DenseIterator Iterator; //! typedef for stl compliant access typedef Iterator iterator; //! rename the iterators for easier access typedef Iterator RowIterator; //! rename the iterators for easier access typedef typename std::remove_reference::type::Iterator ColIterator; //! begin iterator Iterator begin () { return Iterator(*this,0); } //! end iterator Iterator end () { return Iterator(*this,rows()); } //! @returns an iterator that is positioned before //! the end iterator of the vector, i.e. at the last entry. Iterator beforeEnd () { return Iterator(*this,rows()-1); } //! @returns an iterator that is positioned before //! the first entry of the vector. Iterator beforeBegin () { return Iterator(*this,-1); } //! Iterator class for sequential access typedef DenseIterator ConstIterator; //! typedef for stl compliant access typedef ConstIterator const_iterator; //! rename the iterators for easier access typedef ConstIterator ConstRowIterator; //! rename the iterators for easier access typedef typename std::remove_reference::type::ConstIterator ConstColIterator; //! begin iterator ConstIterator begin () const { return ConstIterator(*this,0); } //! end iterator ConstIterator end () const { return ConstIterator(*this,rows()); } //! @returns an iterator that is positioned before //! the end iterator of the vector. i.e. at the last element ConstIterator beforeEnd () const { return ConstIterator(*this,rows()-1); } //! @returns an iterator that is positioned before //! the first entry of the vector. ConstIterator beforeBegin () const { return ConstIterator(*this,-1); } //===== assignment template< class RHS, class = std::enable_if_t< HasDenseMatrixAssigner< MAT, RHS >::value > > derived_type &operator= ( const RHS &rhs ) { DenseMatrixAssigner< MAT, RHS >::apply( asImp(), rhs ); return asImp(); } //===== vector space arithmetic //! vector space addition template derived_type &operator+= (const DenseMatrix& x) { DUNE_ASSERT_BOUNDS(rows() == x.rows()); for (size_type i=0; i derived_type &operator-= (const DenseMatrix& x) { DUNE_ASSERT_BOUNDS(rows() == x.rows()); for (size_type i=0; i derived_type &axpy (const field_type &a, const DenseMatrix &x ) { DUNE_ASSERT_BOUNDS(rows() == x.rows()); for( size_type i = 0; i < rows(); ++i ) (*this)[ i ].axpy( a, x[ i ] ); return asImp(); } //! Binary matrix comparison template bool operator== (const DenseMatrix& x) const { DUNE_ASSERT_BOUNDS(rows() == x.rows()); for (size_type i=0; i bool operator!= (const DenseMatrix& x) const { return !operator==(x); } //===== linear maps //! y = A x template void mv (const X& x, Y& y) const { auto&& xx = Impl::asVector(x); auto&& yy = Impl::asVector(y); DUNE_ASSERT_BOUNDS((void*)(&x) != (void*)(&y)); DUNE_ASSERT_BOUNDS(xx.N() == M()); DUNE_ASSERT_BOUNDS(yy.N() == N()); using y_field_type = typename FieldTraits::field_type; for (size_type i=0; i void mtv ( const X &x, Y &y ) const { auto&& xx = Impl::asVector(x); auto&& yy = Impl::asVector(y); DUNE_ASSERT_BOUNDS((void*)(&x) != (void*)(&y)); DUNE_ASSERT_BOUNDS(xx.N() == N()); DUNE_ASSERT_BOUNDS(yy.N() == M()); using y_field_type = typename FieldTraits::field_type; for(size_type i = 0; i < cols(); ++i) { yy[i] = y_field_type(0); for(size_type j = 0; j < rows(); ++j) yy[i] += (*this)[j][i] * xx[j]; } } //! y += A x template void umv (const X& x, Y& y) const { auto&& xx = Impl::asVector(x); auto&& yy = Impl::asVector(y); DUNE_ASSERT_BOUNDS(xx.N() == M()); DUNE_ASSERT_BOUNDS(yy.N() == N()); for (size_type i=0; i void umtv (const X& x, Y& y) const { auto&& xx = Impl::asVector(x); auto&& yy = Impl::asVector(y); DUNE_ASSERT_BOUNDS(xx.N() == N()); DUNE_ASSERT_BOUNDS(yy.N() == M()); for(size_type i = 0; i void umhv (const X& x, Y& y) const { auto&& xx = Impl::asVector(x); auto&& yy = Impl::asVector(y); DUNE_ASSERT_BOUNDS(xx.N() == N()); DUNE_ASSERT_BOUNDS(yy.N() == M()); for (size_type i=0; i void mmv (const X& x, Y& y) const { auto&& xx = Impl::asVector(x); auto&& yy = Impl::asVector(y); DUNE_ASSERT_BOUNDS(xx.N() == M()); DUNE_ASSERT_BOUNDS(yy.N() == N()); for (size_type i=0; i void mmtv (const X& x, Y& y) const { auto&& xx = Impl::asVector(x); auto&& yy = Impl::asVector(y); DUNE_ASSERT_BOUNDS(xx.N() == N()); DUNE_ASSERT_BOUNDS(yy.N() == M()); for (size_type i=0; i void mmhv (const X& x, Y& y) const { auto&& xx = Impl::asVector(x); auto&& yy = Impl::asVector(y); DUNE_ASSERT_BOUNDS(xx.N() == N()); DUNE_ASSERT_BOUNDS(yy.N() == M()); for (size_type i=0; i void usmv (const typename FieldTraits::field_type & alpha, const X& x, Y& y) const { auto&& xx = Impl::asVector(x); auto&& yy = Impl::asVector(y); DUNE_ASSERT_BOUNDS(xx.N() == M()); DUNE_ASSERT_BOUNDS(yy.N() == N()); for (size_type i=0; i void usmtv (const typename FieldTraits::field_type & alpha, const X& x, Y& y) const { auto&& xx = Impl::asVector(x); auto&& yy = Impl::asVector(y); DUNE_ASSERT_BOUNDS(xx.N() == N()); DUNE_ASSERT_BOUNDS(yy.N() == M()); for (size_type i=0; i void usmhv (const typename FieldTraits::field_type & alpha, const X& x, Y& y) const { auto&& xx = Impl::asVector(x); auto&& yy = Impl::asVector(y); DUNE_ASSERT_BOUNDS(xx.N() == N()); DUNE_ASSERT_BOUNDS(yy.N() == M()); for (size_type i=0; i::real_type frobenius_norm () const { typename FieldTraits::real_type sum=(0.0); for (size_type i=0; i::real_type frobenius_norm2 () const { typename FieldTraits::real_type sum=(0.0); for (size_type i=0; i::value, int>::type = 0> typename FieldTraits::real_type infinity_norm() const { using real_type = typename FieldTraits::real_type; using std::max; real_type norm = 0; for (auto const &x : *this) { real_type const a = x.one_norm(); norm = max(a, norm); } return norm; } //! simplified infinity norm (uses Manhattan norm for complex values) template ::value, int>::type = 0> typename FieldTraits::real_type infinity_norm_real() const { using real_type = typename FieldTraits::real_type; using std::max; real_type norm = 0; for (auto const &x : *this) { real_type const a = x.one_norm_real(); norm = max(a, norm); } return norm; } //! infinity norm (row sum norm, how to generalize for blocks?) template ::value, int>::type = 0> typename FieldTraits::real_type infinity_norm() const { using real_type = typename FieldTraits::real_type; using std::max; real_type norm = 0; real_type isNaN = 1; for (auto const &x : *this) { real_type const a = x.one_norm(); norm = max(a, norm); isNaN += a; } return norm * (isNaN / isNaN); } //! simplified infinity norm (uses Manhattan norm for complex values) template ::value, int>::type = 0> typename FieldTraits::real_type infinity_norm_real() const { using real_type = typename FieldTraits::real_type; using std::max; real_type norm = 0; real_type isNaN = 1; for (auto const &x : *this) { real_type const a = x.one_norm_real(); norm = max(a, norm); isNaN += a; } return norm * (isNaN / isNaN); } //===== solve /** \brief Solve system A x = b * * \exception FMatrixError if the matrix is singular */ template void solve (V1& x, const V2& b, bool doPivoting = true) const; /** \brief Compute inverse * * \exception FMatrixError if the matrix is singular */ void invert(bool doPivoting = true); //! calculates the determinant of this matrix field_type determinant (bool doPivoting = true) const; //! Multiplies M from the left to this matrix template MAT& leftmultiply (const DenseMatrix& M) { DUNE_ASSERT_BOUNDS(M.rows() == M.cols()); DUNE_ASSERT_BOUNDS(M.rows() == rows()); AutonomousValue C(asImp()); for (size_type i=0; i MAT& rightmultiply (const DenseMatrix& M) { DUNE_ASSERT_BOUNDS(M.rows() == M.cols()); DUNE_ASSERT_BOUNDS(M.cols() == cols()); AutonomousValue C(asImp()); for (size_type i=0; i DenseMatrix leftmultiplyany (const FieldMatrix& M) const { FieldMatrix C; for (size_type i=0; i FieldMatrix rightmultiplyany (const FieldMatrix& M) const { FieldMatrix C; for (size_type i=0; i= 0 && i < rows()); DUNE_ASSERT_BOUNDS(j >= 0 && j < cols()); return true; } protected: #ifndef DOXYGEN struct ElimPivot { ElimPivot(std::vector & pivot); void swap(std::size_t i, simd_index_type j); template void operator()(const T&, int, int) {} std::vector & pivot_; }; template struct Elim { Elim(V& rhs); void swap(std::size_t i, simd_index_type j); void operator()(const typename V::field_type& factor, int k, int i); V* rhs_; }; struct ElimDet { ElimDet(field_type& sign) : sign_(sign) { sign_ = 1; } void swap(std::size_t i, simd_index_type j) { sign_ *= Simd::cond(simd_index_type(i) == j, field_type(1), field_type(-1)); } void operator()(const field_type&, int, int) {} field_type& sign_; }; #endif // DOXYGEN //! do an LU-Decomposition on matrix A /** * \param A The matrix to decompose, and to store the * result in. * \param func Functor used for swapping lanes and to conduct * the elimination. Depending on the functor, \c * luDecomposition() can be used for solving, for * inverting, or to compute the determinant. * \param nonsingularLanes SimdMask of lanes that are nonsingular. * \param throwEarly Whether to throw an \c FMatrixError immediately * as soon as one lane is discovered to be * singular. If \c false, do not throw, instead * continue until finished or all lanes are * singular, and exit via return in both cases. * \param doPivoting Enable pivoting. * * There are two modes of operation: *
    *
  • Terminate as soon as one lane is discovered to be singular. Early * termination is done by throwing an \c FMatrixError. On entry, \c * Simd::allTrue(nonsingularLanes) and \c throwEarly==true should hold. * After early termination, the contents of \c A should be considered * bogus, and \c nonsingularLanes has the lane(s) that triggered the * early termination unset. There may be more singular lanes than the * one reported in \c nonsingularLanes, which just havent been * discovered yet; so the value of \c nonsingularLanes is mostly * useful for diagnostics.
  • *
  • Terminate only when all lanes are discovered to be singular. Use * this when you want to apply special postprocessing in singular * lines (e.g. setting the determinant of singular lanes to 0 in \c * determinant()). On entry, \c nonsingularLanes may have any value * and \c throwEarly==false should hold. The function will not throw * an exception if some lanes are discovered to be singular, instead * it will continue running until all lanes are singular or until * finished, and terminate only via normal return. On exit, \c * nonsingularLanes contains the map of lanes that are valid in \c * A.
  • *
*/ template static void luDecomposition(DenseMatrix& A, Func func, Mask &nonsingularLanes, bool throwEarly, bool doPivoting); }; #ifndef DOXYGEN template DenseMatrix::ElimPivot::ElimPivot(std::vector & pivot) : pivot_(pivot) { typedef typename std::vector::size_type size_type; for(size_type i=0; i < pivot_.size(); ++i) pivot_[i]=i; } template void DenseMatrix::ElimPivot::swap(std::size_t i, simd_index_type j) { pivot_[i] = Simd::cond(Simd::Scalar(i) == j, pivot_[i], j); } template template DenseMatrix::Elim::Elim(V& rhs) : rhs_(&rhs) {} template template void DenseMatrix::Elim::swap(std::size_t i, simd_index_type j) { using std::swap; // see the comment in luDecomposition() for(std::size_t l = 0; l < Simd::lanes(j); ++l) swap(Simd::lane(l, (*rhs_)[ i ]), Simd::lane(l, (*rhs_)[Simd::lane(l, j)])); } template template void DenseMatrix:: Elim::operator()(const typename V::field_type& factor, int k, int i) { (*rhs_)[k] -= factor*(*rhs_)[i]; } template template inline void DenseMatrix:: luDecomposition(DenseMatrix& A, Func func, Mask &nonsingularLanes, bool throwEarly, bool doPivoting) { using std::max; using std::swap; typedef typename FieldTraits::real_type real_type; // LU decomposition of A in A for (size_type i=0; i pivmax; pivmax = Simd::cond(mask, abs, pivmax); imax = Simd::cond(mask, simd_index_type(k), imax); } // swap rows for (size_type j=0; j template inline void DenseMatrix::solve(V1& x, const V2& b, bool doPivoting) const { using real_type = typename FieldTraits::real_type; // never mind those ifs, because they get optimized away if (rows()!=cols()) DUNE_THROW(FMatrixError, "Can't solve for a " << rows() << "x" << cols() << " matrix!"); if (rows()==1) { #ifdef DUNE_FMatrix_WITH_CHECKING if (Simd::anyTrue(fvmeta::absreal((*this)[0][0]) < FMatrixPrecision<>::absolute_limit())) DUNE_THROW(FMatrixError,"matrix is singular"); #endif x[0] = b[0]/(*this)[0][0]; } else if (rows()==2) { field_type detinv = (*this)[0][0]*(*this)[1][1]-(*this)[0][1]*(*this)[1][0]; #ifdef DUNE_FMatrix_WITH_CHECKING if (Simd::anyTrue(fvmeta::absreal(detinv) < FMatrixPrecision<>::absolute_limit())) DUNE_THROW(FMatrixError,"matrix is singular"); #endif detinv = real_type(1.0)/detinv; x[0] = detinv*((*this)[1][1]*b[0]-(*this)[0][1]*b[1]); x[1] = detinv*((*this)[0][0]*b[1]-(*this)[1][0]*b[0]); } else if (rows()==3) { field_type d = determinant(doPivoting); #ifdef DUNE_FMatrix_WITH_CHECKING if (Simd::anyTrue(fvmeta::absreal(d) < FMatrixPrecision<>::absolute_limit())) DUNE_THROW(FMatrixError,"matrix is singular"); #endif x[0] = (b[0]*(*this)[1][1]*(*this)[2][2] - b[0]*(*this)[2][1]*(*this)[1][2] - b[1] *(*this)[0][1]*(*this)[2][2] + b[1]*(*this)[2][1]*(*this)[0][2] + b[2] *(*this)[0][1]*(*this)[1][2] - b[2]*(*this)[1][1]*(*this)[0][2]) / d; x[1] = ((*this)[0][0]*b[1]*(*this)[2][2] - (*this)[0][0]*b[2]*(*this)[1][2] - (*this)[1][0] *b[0]*(*this)[2][2] + (*this)[1][0]*b[2]*(*this)[0][2] + (*this)[2][0] *b[0]*(*this)[1][2] - (*this)[2][0]*b[1]*(*this)[0][2]) / d; x[2] = ((*this)[0][0]*(*this)[1][1]*b[2] - (*this)[0][0]*(*this)[2][1]*b[1] - (*this)[1][0] *(*this)[0][1]*b[2] + (*this)[1][0]*(*this)[2][1]*b[0] + (*this)[2][0] *(*this)[0][1]*b[1] - (*this)[2][0]*(*this)[1][1]*b[0]) / d; } else { V1& rhs = x; // use x to store rhs rhs = b; // copy data Elim elim(rhs); AutonomousValue A(asImp()); Simd::Mask::real_type> nonsingularLanes(true); AutonomousValue::luDecomposition(A, elim, nonsingularLanes, true, doPivoting); // backsolve for(int i=rows()-1; i>=0; i--) { for (size_type j=i+1; j inline void DenseMatrix::invert(bool doPivoting) { using real_type = typename FieldTraits::real_type; using std::swap; // never mind those ifs, because they get optimized away if (rows()!=cols()) DUNE_THROW(FMatrixError, "Can't invert a " << rows() << "x" << cols() << " matrix!"); if (rows()==1) { #ifdef DUNE_FMatrix_WITH_CHECKING if (Simd::anyTrue(fvmeta::absreal((*this)[0][0]) < FMatrixPrecision<>::absolute_limit())) DUNE_THROW(FMatrixError,"matrix is singular"); #endif (*this)[0][0] = real_type( 1 ) / (*this)[0][0]; } else if (rows()==2) { field_type detinv = (*this)[0][0]*(*this)[1][1]-(*this)[0][1]*(*this)[1][0]; #ifdef DUNE_FMatrix_WITH_CHECKING if (Simd::anyTrue(fvmeta::absreal(detinv) < FMatrixPrecision<>::absolute_limit())) DUNE_THROW(FMatrixError,"matrix is singular"); #endif detinv = real_type( 1 ) / detinv; field_type temp=(*this)[0][0]; (*this)[0][0] = (*this)[1][1]*detinv; (*this)[0][1] = -(*this)[0][1]*detinv; (*this)[1][0] = -(*this)[1][0]*detinv; (*this)[1][1] = temp*detinv; } else if (rows()==3) { using K = field_type; // code generated by maple K t4 = (*this)[0][0] * (*this)[1][1]; K t6 = (*this)[0][0] * (*this)[1][2]; K t8 = (*this)[0][1] * (*this)[1][0]; K t10 = (*this)[0][2] * (*this)[1][0]; K t12 = (*this)[0][1] * (*this)[2][0]; K t14 = (*this)[0][2] * (*this)[2][0]; K det = (t4*(*this)[2][2]-t6*(*this)[2][1]-t8*(*this)[2][2]+ t10*(*this)[2][1]+t12*(*this)[1][2]-t14*(*this)[1][1]); K t17 = K(1.0)/det; K matrix01 = (*this)[0][1]; K matrix00 = (*this)[0][0]; K matrix10 = (*this)[1][0]; K matrix11 = (*this)[1][1]; (*this)[0][0] = ((*this)[1][1] * (*this)[2][2] - (*this)[1][2] * (*this)[2][1])*t17; (*this)[0][1] = -((*this)[0][1] * (*this)[2][2] - (*this)[0][2] * (*this)[2][1])*t17; (*this)[0][2] = (matrix01 * (*this)[1][2] - (*this)[0][2] * (*this)[1][1])*t17; (*this)[1][0] = -((*this)[1][0] * (*this)[2][2] - (*this)[1][2] * (*this)[2][0])*t17; (*this)[1][1] = (matrix00 * (*this)[2][2] - t14) * t17; (*this)[1][2] = -(t6-t10) * t17; (*this)[2][0] = (matrix10 * (*this)[2][1] - matrix11 * (*this)[2][0]) * t17; (*this)[2][1] = -(matrix00 * (*this)[2][1] - t12) * t17; (*this)[2][2] = (t4-t8) * t17; } else { using std::swap; AutonomousValue A(asImp()); std::vector pivot(rows()); Simd::Mask::real_type> nonsingularLanes(true); AutonomousValue::luDecomposition(A, ElimPivot(pivot), nonsingularLanes, true, doPivoting); auto& L=A; auto& U=A; // initialize inverse *this=field_type(); for(size_type i=0; i0;) { --i; for (size_type k=0; k0; ) { --i; for(std::size_t l = 0; l < Simd::lanes((*this)[0][0]); ++l) { std::size_t pi = Simd::lane(l, pivot[i]); if(i!=pi) for(size_type j=0; j inline typename DenseMatrix::field_type DenseMatrix::determinant(bool doPivoting) const { // never mind those ifs, because they get optimized away if (rows()!=cols()) DUNE_THROW(FMatrixError, "There is no determinant for a " << rows() << "x" << cols() << " matrix!"); if (rows()==1) return (*this)[0][0]; if (rows()==2) return (*this)[0][0]*(*this)[1][1] - (*this)[0][1]*(*this)[1][0]; if (rows()==3) { // code generated by maple field_type t4 = (*this)[0][0] * (*this)[1][1]; field_type t6 = (*this)[0][0] * (*this)[1][2]; field_type t8 = (*this)[0][1] * (*this)[1][0]; field_type t10 = (*this)[0][2] * (*this)[1][0]; field_type t12 = (*this)[0][1] * (*this)[2][0]; field_type t14 = (*this)[0][2] * (*this)[2][0]; return (t4*(*this)[2][2]-t6*(*this)[2][1]-t8*(*this)[2][2]+ t10*(*this)[2][1]+t12*(*this)[1][2]-t14*(*this)[1][1]); } AutonomousValue A(asImp()); field_type det; Simd::Mask::real_type> nonsingularLanes(true); AutonomousValue::luDecomposition(A, ElimDet(det), nonsingularLanes, false, doPivoting); det = Simd::cond(nonsingularLanes, det, field_type(0)); for (size_type i = 0; i < rows(); ++i) det *= A[i][i]; return det; } #endif // DOXYGEN namespace DenseMatrixHelp { //! calculates ret = matrix * x template static inline void multAssign(const DenseMatrix &matrix, const DenseVector & x, DenseVector & ret) { DUNE_ASSERT_BOUNDS(x.size() == matrix.cols()); DUNE_ASSERT_BOUNDS(ret.size() == matrix.rows()); typedef typename DenseMatrix::size_type size_type; for(size_type i=0; i static inline void multAssignTransposed( const FieldMatrix &matrix, const FieldVector & x, FieldVector & ret) { typedef typename FieldMatrix::size_type size_type; for(size_type i=0; i static inline FieldVector mult(const FieldMatrix &matrix, const FieldVector & x) { FieldVector ret; multAssign(matrix,x,ret); return ret; } //! calculates ret = matrix^T * x template static inline FieldVector multTransposed(const FieldMatrix &matrix, const FieldVector & x) { FieldVector ret; multAssignTransposed( matrix, x, ret ); return ret; } #endif } // end namespace DenseMatrixHelp /** \brief Sends the matrix to an output stream */ template std::ostream& operator<< (std::ostream& s, const DenseMatrix& a) { for (typename DenseMatrix::size_type i=0; i #include #include #include "genericiterator.hh" #include "ftraits.hh" #include "matvectraits.hh" #include "promotiontraits.hh" #include "dotproduct.hh" #include "boundschecking.hh" namespace Dune { // forward declaration of template template class DenseVector; template struct FieldTraits< DenseVector > { typedef typename FieldTraits< typename DenseMatVecTraits::value_type >::field_type field_type; typedef typename FieldTraits< typename DenseMatVecTraits::value_type >::real_type real_type; }; /** @defgroup DenseMatVec Dense Matrix and Vector Template Library @ingroup Common @{ */ /*! \file * \brief Implements the dense vector interface, with an exchangeable storage class */ namespace fvmeta { /** \private \memberof Dune::DenseVector */ template inline typename FieldTraits::real_type absreal (const K& k) { using std::abs; return abs(k); } /** \private \memberof Dune::DenseVector */ template inline typename FieldTraits::real_type absreal (const std::complex& c) { using std::abs; return abs(c.real()) + abs(c.imag()); } /** \private \memberof Dune::DenseVector */ template inline typename FieldTraits::real_type abs2 (const K& k) { return k*k; } /** \private \memberof Dune::DenseVector */ template inline typename FieldTraits::real_type abs2 (const std::complex& c) { return c.real()*c.real() + c.imag()*c.imag(); } /** \private \memberof Dune::DenseVector */ template::is_integer> struct Sqrt { static inline typename FieldTraits::real_type sqrt (const K& k) { using std::sqrt; return sqrt(k); } }; /** \private \memberof Dune::DenseVector */ template struct Sqrt { static inline typename FieldTraits::real_type sqrt (const K& k) { using std::sqrt; return typename FieldTraits::real_type(sqrt(double(k))); } }; /** \private \memberof Dune::DenseVector */ template inline typename FieldTraits::real_type sqrt (const K& k) { return Sqrt::sqrt(k); } } /*! \brief Generic iterator class for dense vector and matrix implementations provides sequential access to DenseVector, FieldVector and FieldMatrix */ template class DenseIterator : public Dune::RandomAccessIteratorFacade,T, R, std::ptrdiff_t> { friend class DenseIterator::type, typename std::remove_const::type, typename mutable_reference::type >; friend class DenseIterator::type, const typename std::remove_const::type, typename const_reference::type >; typedef DenseIterator::type, typename std::remove_const::type, typename mutable_reference::type > MutableIterator; typedef DenseIterator::type, const typename std::remove_const::type, typename const_reference::type > ConstIterator; public: /** * @brief The type of the difference between two positions. */ typedef std::ptrdiff_t DifferenceType; /** * @brief The type to index the underlying container. */ typedef typename C::size_type SizeType; // Constructors needed by the base iterators. DenseIterator() : container_(0), position_() {} DenseIterator(C& cont, SizeType pos) : container_(&cont), position_(pos) {} DenseIterator(const MutableIterator & other) : container_(other.container_), position_(other.position_) {} DenseIterator(const ConstIterator & other) : container_(other.container_), position_(other.position_) {} // Methods needed by the forward iterator bool equals(const MutableIterator &other) const { return position_ == other.position_ && container_ == other.container_; } bool equals(const ConstIterator & other) const { return position_ == other.position_ && container_ == other.container_; } R dereference() const { return container_->operator[](position_); } void increment(){ ++position_; } // Additional function needed by BidirectionalIterator void decrement(){ --position_; } // Additional function needed by RandomAccessIterator R elementAt(DifferenceType i) const { return container_->operator[](position_+i); } void advance(DifferenceType n){ position_=position_+n; } DifferenceType distanceTo(DenseIterator::type,const typename std::remove_const::type> other) const { assert(other.container_==container_); return static_cast< DifferenceType >( other.position_ ) - static_cast< DifferenceType >( position_ ); } DifferenceType distanceTo(DenseIterator::type, typename std::remove_const::type> other) const { assert(other.container_==container_); return static_cast< DifferenceType >( other.position_ ) - static_cast< DifferenceType >( position_ ); } //! return index SizeType index () const { return this->position_; } private: C *container_; SizeType position_; }; /** \brief Interface for a class of dense vectors over a given field. * * \tparam V implementation class of the vector */ template class DenseVector { typedef DenseMatVecTraits Traits; // typedef typename Traits::value_type K; // Curiously recurring template pattern V & asImp() { return static_cast(*this); } const V & asImp() const { return static_cast(*this); } protected: // construction allowed to derived classes only constexpr DenseVector() = default; // copying only allowed by derived classes DenseVector(const DenseVector&) = default; public: //===== type definitions and constants //! type of derived vector class typedef typename Traits::derived_type derived_type; //! export the type representing the field typedef typename Traits::value_type value_type; //! export the type representing the field typedef typename FieldTraits< value_type >::field_type field_type; //! export the type representing the components typedef typename Traits::value_type block_type; //! The type used for the index access and size operation typedef typename Traits::size_type size_type; //! We are at the leaf of the block recursion enum { //! The number of block levels we contain blocklevel = 1 }; //===== assignment from scalar //! Assignment operator for scalar inline derived_type& operator= (const value_type& k) { for (size_type i=0; i::value_type>::value, int> = 0> derived_type& operator= (const DenseVector& other) { assert(other.size() == size()); for (size_type i=0; i Iterator; //! typedef for stl compliant access typedef Iterator iterator; //! begin iterator Iterator begin () { return Iterator(*this,0); } //! end iterator Iterator end () { return Iterator(*this,size()); } //! @returns an iterator that is positioned before //! the end iterator of the vector, i.e. at the last entry. Iterator beforeEnd () { return Iterator(*this,size()-1); } //! @returns an iterator that is positioned before //! the first entry of the vector. Iterator beforeBegin () { return Iterator(*this,-1); } //! return iterator to given element or end() Iterator find (size_type i) { return Iterator(*this,std::min(i,size())); } //! ConstIterator class for sequential access typedef DenseIterator ConstIterator; //! typedef for stl compliant access typedef ConstIterator const_iterator; //! begin ConstIterator ConstIterator begin () const { return ConstIterator(*this,0); } //! end ConstIterator ConstIterator end () const { return ConstIterator(*this,size()); } //! @returns an iterator that is positioned before //! the end iterator of the vector. i.e. at the last element ConstIterator beforeEnd () const { return ConstIterator(*this,size()-1); } //! @returns an iterator that is positioned before //! the first entry of the vector. ConstIterator beforeBegin () const { return ConstIterator(*this,-1); } //! return iterator to given element or end() ConstIterator find (size_type i) const { return ConstIterator(*this,std::min(i,size())); } //===== vector space arithmetic //! vector space addition template derived_type& operator+= (const DenseVector& x) { DUNE_ASSERT_BOUNDS(x.size() == size()); for (size_type i=0; i derived_type& operator-= (const DenseVector& x) { DUNE_ASSERT_BOUNDS(x.size() == size()); for (size_type i=0; i derived_type operator+ (const DenseVector& b) const { derived_type z = asImp(); return (z+=b); } //! Binary vector subtraction template derived_type operator- (const DenseVector& b) const { derived_type z = asImp(); return (z-=b); } //! Vector negation derived_type operator- () const { V result; using idx_type = typename decltype(result)::size_type; for (idx_type i = 0; i < size(); ++i) result[i] = -asImp()[i]; return result; } //! \brief vector space add scalar to all comps /** we use enable_if to avoid an ambiguity, if the function parameter can be converted to value_type implicitly. (see FS#1457) The function is only enabled, if the parameter is directly convertible to value_type. */ template typename std::enable_if< std::is_convertible::value, derived_type >::type& operator+= (const ValueType& kk) { const value_type& k = kk; for (size_type i=0; i typename std::enable_if< std::is_convertible::value, derived_type >::type& operator-= (const ValueType& kk) { const value_type& k = kk; for (size_type i=0; i typename std::enable_if< std::is_convertible::value, derived_type >::type& operator*= (const FieldType& kk) { const field_type& k = kk; for (size_type i=0; i typename std::enable_if< std::is_convertible::value, derived_type >::type& operator/= (const FieldType& kk) { const field_type& k = kk; for (size_type i=0; i bool operator== (const DenseVector& x) const { DUNE_ASSERT_BOUNDS(x.size() == size()); for (size_type i=0; i bool operator!= (const DenseVector& x) const { return !operator==(x); } //! vector space axpy operation ( *this += a x ) template derived_type& axpy (const field_type& a, const DenseVector& x) { DUNE_ASSERT_BOUNDS(x.size() == size()); for (size_type i=0; i typename PromotionTraits::field_type>::PromotedType operator* (const DenseVector& x) const { typedef typename PromotionTraits::field_type>::PromotedType PromotedType; PromotedType result(0); assert(x.size() == size()); for (size_type i=0; i typename PromotionTraits::field_type>::PromotedType dot(const DenseVector& x) const { typedef typename PromotionTraits::field_type>::PromotedType PromotedType; PromotedType result(0); assert(x.size() == size()); for (size_type i=0; i::real_type one_norm() const { using std::abs; typename FieldTraits::real_type result( 0 ); for (size_type i=0; i::real_type one_norm_real () const { typename FieldTraits::real_type result( 0 ); for (size_type i=0; i::real_type two_norm () const { typename FieldTraits::real_type result( 0 ); for (size_type i=0; i::real_type two_norm2 () const { typename FieldTraits::real_type result( 0 ); for (size_type i=0; i::value, int>::type = 0> typename FieldTraits::real_type infinity_norm() const { using real_type = typename FieldTraits::real_type; using std::abs; using std::max; real_type norm = 0; for (auto const &x : *this) { real_type const a = abs(x); norm = max(a, norm); } return norm; } //! simplified infinity norm (uses Manhattan norm for complex values) template ::value, int>::type = 0> typename FieldTraits::real_type infinity_norm_real() const { using real_type = typename FieldTraits::real_type; using std::max; real_type norm = 0; for (auto const &x : *this) { real_type const a = fvmeta::absreal(x); norm = max(a, norm); } return norm; } //! infinity norm (maximum of absolute values of entries) template ::value, int>::type = 0> typename FieldTraits::real_type infinity_norm() const { using real_type = typename FieldTraits::real_type; using std::abs; using std::max; real_type norm = 0; real_type isNaN = 1; for (auto const &x : *this) { real_type const a = abs(x); norm = max(a, norm); isNaN += a; } return norm * (isNaN / isNaN); } //! simplified infinity norm (uses Manhattan norm for complex values) template ::value, int>::type = 0> typename FieldTraits::real_type infinity_norm_real() const { using real_type = typename FieldTraits::real_type; using std::max; real_type norm = 0; real_type isNaN = 1; for (auto const &x : *this) { real_type const a = fvmeta::absreal(x); norm = max(a, norm); isNaN += a; } return norm * (isNaN / isNaN); } //===== sizes //! number of blocks in the vector (are of size 1 here) size_type N () const { return size(); } //! dimension of the vector space size_type dim () const { return size(); } }; /** \brief Write a DenseVector to an output stream * \relates DenseVector * * \param[in] s std :: ostream to write to * \param[in] v DenseVector to write * * \returns the output stream (s) */ template std::ostream& operator<< (std::ostream& s, const DenseVector& v) { for (typename DenseVector::size_type i=0; i0) ? " " : "") << v[i]; return s; } /** @} end documentation */ } // end namespace #endif // DUNE_DENSEVECTOR_HH dune-common-2.8.0/dune/common/deprecated.hh000066400000000000000000000054731411343567400206270ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_DEPRECATED_HH #define DUNE_DEPRECATED_HH /** \file * \brief Definition of the DUNE_DEPRECATED macro for the case that config.h * is not available */ //! @addtogroup CxxUtilities //! @{ #if defined(DOXYGEN) || !defined(HAS_ATTRIBUTE_DEPRECATED) //! Mark some entity as deprecated /** * \deprecated Use C++14's \code[[deprecated]]\endcode instead. It will be * removed after Dune 2.8. Be aware that it must be sometimes placed at * different position in the code. */ #define DUNE_DEPRECATED #else // defined(HAS_ATTRIBUTE_DEPRECATED) #define DUNE_DEPRECATED __attribute__((deprecated)) #endif #if defined(DOXYGEN) || !defined(HAS_ATTRIBUTE_DEPRECATED_MSG) //! Mark some entity as deprecated /** * \deprecated Use C++14's \code[[deprecated(msg)]]\endcode instead. It * will be removed after Dune 2.8. Be aware that it must be sometimes * placed at different position in the code. */ #define DUNE_DEPRECATED_MSG(text) DUNE_DEPRECATED #else // defined(HAS_ATTRIBUTE_DEPRECATED_MSG) #define DUNE_DEPRECATED_MSG(text) __attribute__((deprecated(# text))) #endif #ifdef DOXYGEN /** * \brief Ignore deprecation warnings (start) * * This macro can be used together with `DUNE_NO_DEPRECATED_END` to mark a * block in which deprecation warnings are ignored. This can be useful for * implementations of deprecated methods that call other deprecated methods * or for testing deprecated methods in the testsuite. * * \code DUNE_NO_DEPRECATED_BEGIN some_deprecated_function(); another_deprecated_function(); DUNE_NO_DEPRECATED_END * \endcode * * \warning This macro must always be used together with `DUNE_NO_DEPRECATED_END` */ #define DUNE_NO_DEPRECATED_BEGIN ... /** * \brief Ignore deprecation warnings (end) * * \warning This macro must always be used together with `DUNE_NO_DEPRECATED_BEGIN` */ #define DUNE_NO_DEPRECATED_END ... #else # if defined __clang__ # define DUNE_NO_DEPRECATED_BEGIN \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") # define DUNE_NO_DEPRECATED_END _Pragma("clang diagnostic pop") # elif defined __INTEL_COMPILER # define DUNE_NO_DEPRECATED_BEGIN \ _Pragma("warning push") \ _Pragma("warning(disable:1478)") \ _Pragma("warning(disable:1786)") # define DUNE_NO_DEPRECATED_END _Pragma("warning pop") # elif defined __GNUC__ # define DUNE_NO_DEPRECATED_BEGIN \ _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") # define DUNE_NO_DEPRECATED_END _Pragma("GCC diagnostic pop") # else # define DUNE_NO_DEPRECATED_BEGIN /* Noop. */ # define DUNE_NO_DEPRECATED_END /* Noop. */ # endif #endif //! @} #endif dune-common-2.8.0/dune/common/diagonalmatrix.hh000066400000000000000000000673741411343567400215420ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_DIAGONAL_MATRIX_HH #define DUNE_DIAGONAL_MATRIX_HH /*! \file \brief This file implements a quadratic diagonal matrix of fixed size. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Dune { template< class K, int n > class DiagonalRowVectorConst; template< class K, int n > class DiagonalRowVector; template< class DiagonalMatrixType > class DiagonalMatrixWrapper; template< class C, class T, class R> class ContainerWrapperIterator; /** @addtogroup DenseMatVec @{ */ /** *@brief A diagonal matrix of static size. * * This is meant to be a replacement of FieldMatrix for the case that * it is a diagonal matrix. * * \tparam K Type used for scalars * \tparam n Matrix size */ template class DiagonalMatrix { typedef DiagonalMatrixWrapper< DiagonalMatrix > WrapperType; public: //===== type definitions and constants //! export the type representing the field typedef K value_type; typedef value_type field_type; //! export the type representing the components typedef K block_type; //! The type used for the index access and size operations. typedef std::size_t size_type; //! We are at the leaf of the block recursion enum { //! The number of block levels we contain. This is 1. blocklevel = 1 }; //! Each row is implemented by a field vector typedef DiagonalRowVector row_type; typedef row_type reference; typedef row_type row_reference; typedef DiagonalRowVectorConst const_row_type; typedef const_row_type const_reference; typedef const_row_type const_row_reference; //! export size enum { //! The number of rows rows = n, //! The number of columns cols = n }; //==== size static constexpr size_type size () { return rows; } //===== constructors //! Default constructor constexpr DiagonalMatrix() = default; //! Constructor initializing the whole matrix with a scalar DiagonalMatrix (const K& k) : diag_(k) {} //! Constructor initializing the diagonal with a vector DiagonalMatrix (const FieldVector& diag) : diag_(diag) {} /** \brief Construct diagonal matrix from an initializer list * * The elements of the list are copied into the diagonal elements of the matrix. * If the initializer list is shorter than the matrix diagonal (which has n elements), * the remaining matrix diagonal elements are left uninitialized. If the initializer * list is longer, than only the first n elements will be copied into the matrix * diagonal. */ DiagonalMatrix (std::initializer_list const &l) { std::copy_n(l.begin(), std::min(static_cast(rows), l.size()), diag_.begin()); } /** \brief Assignment from a scalar */ DiagonalMatrix& operator= (const K& k) { diag_ = k; return *this; } /** \brief Check if matrix is the same object as the other matrix */ bool identical(const DiagonalMatrix& other) const { return (this==&other); } //===== iterator interface to rows of the matrix //! Iterator class for sequential access typedef ContainerWrapperIterator Iterator; //! typedef for stl compliant access typedef Iterator iterator; //! rename the iterators for easier access typedef Iterator RowIterator; //! rename the iterators for easier access typedef typename row_type::Iterator ColIterator; //! begin iterator Iterator begin () { return Iterator(WrapperType(this),0); } //! end iterator Iterator end () { return Iterator(WrapperType(this),n); } //! @returns an iterator that is positioned before //! the end iterator of the rows, i.e. at the last row. Iterator beforeEnd () { return Iterator(WrapperType(this),n-1); } //! @returns an iterator that is positioned before //! the first row of the matrix. Iterator beforeBegin () { return Iterator(WrapperType(this),-1); } //! Iterator class for sequential access typedef ContainerWrapperIterator ConstIterator; //! typedef for stl compliant access typedef ConstIterator const_iterator; //! rename the iterators for easier access typedef ConstIterator ConstRowIterator; //! rename the iterators for easier access typedef typename const_row_type::ConstIterator ConstColIterator; //! begin iterator ConstIterator begin () const { return ConstIterator(WrapperType(this),0); } //! end iterator ConstIterator end () const { return ConstIterator(WrapperType(this),n); } //! @returns an iterator that is positioned before //! the end iterator of the rows. i.e. at the last row. ConstIterator beforeEnd() const { return ConstIterator(WrapperType(this),n-1); } //! @returns an iterator that is positioned before //! the first row of the matrix. ConstIterator beforeBegin () const { return ConstIterator(WrapperType(this),-1); } //===== vector space arithmetic //! vector space addition DiagonalMatrix& operator+= (const DiagonalMatrix& y) { diag_ += y.diag_; return *this; } //! vector space subtraction DiagonalMatrix& operator-= (const DiagonalMatrix& y) { diag_ -= y.diag_; return *this; } //! vector space multiplication with scalar DiagonalMatrix& operator+= (const K& k) { diag_ += k; return *this; } //! vector space division by scalar DiagonalMatrix& operator-= (const K& k) { diag_ -= k; return *this; } //! vector space multiplication with scalar DiagonalMatrix& operator*= (const K& k) { diag_ *= k; return *this; } //! vector space division by scalar DiagonalMatrix& operator/= (const K& k) { diag_ /= k; return *this; } //===== comparison ops //! comparison operator bool operator==(const DiagonalMatrix& other) const { return diag_==other.diagonal(); } //! incomparison operator bool operator!=(const DiagonalMatrix& other) const { return diag_!=other.diagonal(); } //===== linear maps //! y = A x template void mv (const X& x, Y& y) const { #ifdef DUNE_FMatrix_WITH_CHECKING if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range"); if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range"); #endif for (size_type i=0; i void mtv (const X& x, Y& y) const { mv(x, y); } //! y += A x template void umv (const X& x, Y& y) const { #ifdef DUNE_FMatrix_WITH_CHECKING if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range"); if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range"); #endif for (size_type i=0; i void umtv (const X& x, Y& y) const { #ifdef DUNE_FMatrix_WITH_CHECKING if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range"); if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range"); #endif for (size_type i=0; i void umhv (const X& x, Y& y) const { #ifdef DUNE_FMatrix_WITH_CHECKING if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range"); if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range"); #endif for (size_type i=0; i void mmv (const X& x, Y& y) const { #ifdef DUNE_FMatrix_WITH_CHECKING if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range"); if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range"); #endif for (size_type i=0; i void mmtv (const X& x, Y& y) const { #ifdef DUNE_FMatrix_WITH_CHECKING if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range"); if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range"); #endif for (size_type i=0; i void mmhv (const X& x, Y& y) const { #ifdef DUNE_FMatrix_WITH_CHECKING if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range"); if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range"); #endif for (size_type i=0; i void usmv (const typename FieldTraits::field_type & alpha, const X& x, Y& y) const { #ifdef DUNE_FMatrix_WITH_CHECKING if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range"); if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range"); #endif for (size_type i=0; i void usmtv (const typename FieldTraits::field_type & alpha, const X& x, Y& y) const { #ifdef DUNE_FMatrix_WITH_CHECKING if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range"); if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range"); #endif for (size_type i=0; i void usmhv (const typename FieldTraits::field_type & alpha, const X& x, Y& y) const { #ifdef DUNE_FMatrix_WITH_CHECKING if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range"); if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range"); #endif for (size_type i=0; i void solve (V& x, const V& b) const { for (int i=0; i::real_type; for (int i=0; i= 0 && i < n); DUNE_ASSERT_BOUNDS(j >= 0 && j < n); return i==j; } //! Sends the matrix to an output stream friend std::ostream& operator<< (std::ostream& s, const DiagonalMatrix& a) { for (size_type i=0; i(&diag_[i]), i); } //! Return const_reference object as row replacement const_reference operator[](size_type i) const { return const_reference(const_cast(&diag_[i]), i); } //! Get const reference to diagonal entry const K& diagonal(size_type i) const { return diag_[i]; } //! Get reference to diagonal entry K& diagonal(size_type i) { return diag_[i]; } //! Get const reference to diagonal vector const FieldVector& diagonal() const { return diag_; } //! Get reference to diagonal vector FieldVector& diagonal() { return diag_; } private: // the data, a FieldVector storing the diagonal FieldVector diag_; }; template< class K, int n > struct FieldTraits< DiagonalMatrix > { typedef typename FieldTraits::field_type field_type; typedef typename FieldTraits::real_type real_type; }; #ifndef DOXYGEN // hide specialization /** \brief Special type for 1x1 matrices */ template< class K > class DiagonalMatrix : public FieldMatrix { typedef FieldMatrix Base; public: //! The type used for index access and size operations typedef typename Base::size_type size_type; //! We are at the leaf of the block recursion enum { //! The number of block levels we contain. //! This is always one for this type. blocklevel = 1 }; typedef typename Base::row_type row_type; typedef typename Base::row_reference row_reference; typedef typename Base::const_row_reference const_row_reference; //! export size enum { //! \brief The number of rows. //! This is always one for this type. rows = 1, //! \brief The number of columns. //! This is always one for this type. cols = 1 }; //! Default Constructor constexpr DiagonalMatrix() = default; //! Constructor initializing the whole matrix with a scalar DiagonalMatrix(const K& scalar) { (*this)[0][0] = scalar; } //! Get const reference to diagonal entry const K& diagonal(size_type) const { return (*this)[0][0]; } //! Get reference to diagonal entry K& diagonal(size_type) { return (*this)[0][0]; } //! Get const reference to diagonal vector const FieldVector& diagonal() const { return (*this)[0]; } //! Get reference to diagonal vector FieldVector& diagonal() { return (*this)[0]; } }; #endif template class DiagonalMatrixWrapper { typedef typename DiagonalMatrixType::reference reference; typedef typename DiagonalMatrixType::const_reference const_reference; typedef typename DiagonalMatrixType::field_type K; typedef DiagonalRowVector row_type; typedef std::size_t size_type; typedef DiagonalMatrixWrapper< DiagonalMatrixType> MyType; friend class ContainerWrapperIterator; friend class ContainerWrapperIterator; public: DiagonalMatrixWrapper() : mat_(0) {} DiagonalMatrixWrapper(const DiagonalMatrixType* mat) : mat_(const_cast(mat)) {} size_type realIndex(int i) const { return i; } row_type* pointer(int i) const { row_ = row_type(&(mat_->diagonal(i)), i); return &row_; } bool identical(const DiagonalMatrixWrapper& other) const { return mat_==other.mat_; } private: mutable DiagonalMatrixType* mat_; mutable row_type row_; }; /** \brief * */ template< class K, int n > class DiagonalRowVectorConst { template friend class DiagonalMatrixWrapper; friend class ContainerWrapperIterator, const K, const K&>; public: // remember size of vector enum { dimension = n }; // standard constructor and everything is sufficient ... //===== type definitions and constants //! export the type representing the field typedef K field_type; //! export the type representing the components typedef K block_type; //! The type used for the index access and size operation typedef std::size_t size_type; //! We are at the leaf of the block recursion enum { //! The number of block levels we contain blocklevel = 1 }; //! export size enum { //! The size of this vector. size = n }; //! Constructor making uninitialized vector DiagonalRowVectorConst() : p_(0), row_(0) {} //! Constructor making vector with identical coordinates explicit DiagonalRowVectorConst (K* p, int col) : p_(p), row_(col) {} //===== access to components //! same for read only access const K& operator[] ([[maybe_unused]] size_type i) const { DUNE_ASSERT_BOUNDS(i == row_); return *p_; } // check if row is identical to other row (not only identical values) // since this is a proxy class we need to check equality of the stored pointer bool identical(const DiagonalRowVectorConst& other) const { return ((p_ == other.p_)and (row_ == other.row_)); } //! ConstIterator class for sequential access typedef ContainerWrapperIterator, const K, const K&> ConstIterator; //! typedef for stl compliant access typedef ConstIterator const_iterator; //! begin ConstIterator ConstIterator begin () const { return ConstIterator(*this,0); } //! end ConstIterator ConstIterator end () const { return ConstIterator(*this,1); } //! @returns an iterator that is positioned before //! the end iterator of the rows. i.e. at the row. ConstIterator beforeEnd() const { return ConstIterator(*this,0); } //! @returns an iterator that is positioned before //! the first row of the matrix. ConstIterator beforeBegin () const { return ConstIterator(*this,-1); } //! Binary vector comparison bool operator== (const DiagonalRowVectorConst& y) const { return ((p_==y.p_)and (row_==y.row_)); } //===== sizes //! number of blocks in the vector (are of size 1 here) size_type N () const { return n; } //! dimension of the vector space size_type dim () const { return n; } //! index of this row in surrounding matrix size_type rowIndex() const { return row_; } //! the diagonal value const K& diagonal() const { return *p_; } protected: size_type realIndex([[maybe_unused]] int i) const { return rowIndex(); } K* pointer([[maybe_unused]] size_type i) const { return const_cast(p_); } DiagonalRowVectorConst* operator&() { return this; } // the data, very simply a pointer to the diagonal value and the row number K* p_; size_type row_; }; template< class K, int n > class DiagonalRowVector : public DiagonalRowVectorConst { template friend class DiagonalMatrixWrapper; friend class ContainerWrapperIterator, K, K&>; public: // standard constructor and everything is sufficient ... //===== type definitions and constants //! export the type representing the field typedef K field_type; //! export the type representing the components typedef K block_type; //! The type used for the index access and size operation typedef std::size_t size_type; //! Constructor making uninitialized vector DiagonalRowVector() : DiagonalRowVectorConst() {} //! Constructor making vector with identical coordinates explicit DiagonalRowVector (K* p, int col) : DiagonalRowVectorConst(p, col) {} //===== assignment from scalar //! Assignment operator for scalar DiagonalRowVector& operator= (const K& k) { *p_ = k; return *this; } //===== access to components //! random access K& operator[] ([[maybe_unused]] size_type i) { DUNE_ASSERT_BOUNDS(i == row_); return *p_; } //! Iterator class for sequential access typedef ContainerWrapperIterator, K, K&> Iterator; //! typedef for stl compliant access typedef Iterator iterator; //! begin iterator Iterator begin () { return Iterator(*this, 0); } //! end iterator Iterator end () { return Iterator(*this, 1); } //! @returns an iterator that is positioned before //! the end iterator of the rows, i.e. at the last row. Iterator beforeEnd () { return Iterator(*this, 0); } //! @returns an iterator that is positioned before //! the first row of the matrix. Iterator beforeBegin () { return Iterator(*this, -1); } //! ConstIterator class for sequential access typedef ContainerWrapperIterator, const K, const K&> ConstIterator; //! typedef for stl compliant access typedef ConstIterator const_iterator; using DiagonalRowVectorConst::identical; using DiagonalRowVectorConst::operator[]; using DiagonalRowVectorConst::operator==; using DiagonalRowVectorConst::begin; using DiagonalRowVectorConst::end; using DiagonalRowVectorConst::beforeEnd; using DiagonalRowVectorConst::beforeBegin; using DiagonalRowVectorConst::N; using DiagonalRowVectorConst::dim; using DiagonalRowVectorConst::rowIndex; using DiagonalRowVectorConst::diagonal; protected: DiagonalRowVector* operator&() { return this; } private: using DiagonalRowVectorConst::p_; using DiagonalRowVectorConst::row_; }; // implement type traits template struct const_reference< DiagonalRowVector > { typedef DiagonalRowVectorConst type; }; template struct const_reference< DiagonalRowVectorConst > { typedef DiagonalRowVectorConst type; }; template struct mutable_reference< DiagonalRowVector > { typedef DiagonalRowVector type; }; template struct mutable_reference< DiagonalRowVectorConst > { typedef DiagonalRowVector type; }; /** \brief Iterator class for sparse vector-like containers * * This class provides an iterator for sparse vector like containers. * It contains a ContainerWrapper that must provide the translation * from the position in the underlying container to the index * in the sparse container. * * The ContainerWrapper must be default and copy-constructable. * Furthermore it must provide the methods: * * bool identical(other) - check if this is identical to other (same container, not only equal) * T* pointer(position) - get pointer to data at position in underlying container * size_t realIndex(position) - get index in sparse container for position in underlying container * * Notice that the iterator stores a ContainerWrapper. * This allows one to use proxy classes as underlying container * and as returned reference type. * * \tparam CW The container wrapper class * \tparam T The contained type * \tparam R The reference type returned by dereference */ template class ContainerWrapperIterator : public BidirectionalIteratorFacade,T, R, int> { typedef typename std::remove_const::type NonConstCW; friend class ContainerWrapperIterator::type, typename mutable_reference::type>; friend class ContainerWrapperIterator::type, typename const_reference::type>; typedef ContainerWrapperIterator::type, typename mutable_reference::type> MyType; typedef ContainerWrapperIterator::type, typename const_reference::type> MyConstType; public: // Constructors needed by the facade iterators. ContainerWrapperIterator() : containerWrapper_(), position_(0) {} ContainerWrapperIterator(CW containerWrapper, int position) : containerWrapper_(containerWrapper), position_(position) {} template ContainerWrapperIterator(OtherContainerWrapperIteratorType& other) : containerWrapper_(other.containerWrapper_), position_(other.position_) {} ContainerWrapperIterator(const MyType& other) : containerWrapper_(other.containerWrapper_), position_(other.position_) {} ContainerWrapperIterator(const MyConstType& other) : containerWrapper_(other.containerWrapper_), position_(other.position_) {} template ContainerWrapperIterator& operator=(OtherContainerWrapperIteratorType& other) { containerWrapper_ = other.containerWrapper_; position_ = other.position_; return *this; } // This operator is needed since we can not get the address of the // temporary object returned by dereference T* operator->() const { return containerWrapper_.pointer(position_); } // Methods needed by the forward iterator bool equals(const MyType& other) const { return position_ == other.position_ && containerWrapper_.identical(other.containerWrapper_); } bool equals(const MyConstType& other) const { return position_ == other.position_ && containerWrapper_.identical(other.containerWrapper_); } R dereference() const { return *containerWrapper_.pointer(position_); } void increment() { ++position_; } // Additional function needed by BidirectionalIterator void decrement() { --position_; } // Additional function needed by RandomAccessIterator R elementAt(int i) const { return *containerWrapper_.pointer(position_+i); } void advance(int n) { position_=position_+n; } template std::ptrdiff_t distanceTo(OtherContainerWrapperIteratorType& other) const { assert(containerWrapper_.identical(other)); return other.position_ - position_; } std::ptrdiff_t index() const { return containerWrapper_.realIndex(position_); } private: NonConstCW containerWrapper_; size_t position_; }; template struct DenseMatrixAssigner> { static void apply(DenseMatrix& denseMatrix, DiagonalMatrix const& rhs) { DUNE_ASSERT_BOUNDS(denseMatrix.M() == N); DUNE_ASSERT_BOUNDS(denseMatrix.N() == N); denseMatrix = field(0); for (int i = 0; i < N; ++i) denseMatrix[i][i] = rhs.diagonal()[i]; } }; /* @} */ } // end namespace #endif dune-common-2.8.0/dune/common/documentation.hh000066400000000000000000000024641411343567400213750ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_DOCUMENTATION_HH #define DUNE_COMMON_DOCUMENTATION_HH /** \file \brief Documentation related stuff */ namespace Dune { /** * \brief Dummy struct used for documentation purposes * * This struct can be used for documenting interfaces. One example would * be: * \code * // Traits class that determines some property for some other type T * template * class SomeTraits { * static_assert(Dune::AlwaysFalse::value, * "Sorry, SomeTraits must be specialized for all types"); * public: * // The type of some property of T * typedef ImplementationDefined type; * }; * #ifndef DOXYGEN * template<> * struct SomeTraits * typedef ... type; * }; * // ... * #endif // DOXYGEN * \endcode * * \sa implementationDefined * \ingroup Common */ struct ImplementationDefined {}; /** * \brief Dummy integral value used for documentation purposes * * \var Dune::implementationDefined * \code * #include * \endcode * * \sa ImplementationDefined * \ingroup Common */ enum { implementationDefined }; } #endif // DUNE_COMMON_DOCUMENTATION_HH dune-common-2.8.0/dune/common/dotproduct.hh000066400000000000000000000062461411343567400207150ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_DOTPRODUCT_HH #define DUNE_DOTPRODUCT_HH #include "ftraits.hh" #include "typetraits.hh" namespace Dune { /** * @file * @brief Provides the functions dot(a,b) := \f$a^H \cdot b \f$ and dotT(a,b) := \f$a^T \cdot b \f$ * * The provided dot products dot,dotT are used to compute (indefinite) dot products for fundamental types as well as DUNE vector types, such as DenseVector, FieldVector, ISTLVector. * Note that the definition of dot(a,b) conjugates the first argument. This agrees with the behaviour of Matlab and Petsc, but not with BLAS. * @author Jö Fahlke, Matthias Wohlmuth */ /** @addtogroup Common * * @{ */ template struct IsVector : std::false_type {}; template struct IsVector > : std::true_type {}; /** @brief computes the dot product for fundamental data types according to Petsc's VectDot function: dot(a,b) := std::conj(a)*b * * @see http://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecDot.html#VecDot * @param a * @param b * @return conj(a)*b */ template auto dot(const A & a, const B & b) -> typename std::enable_if::value && !std::is_same::field_type,typename FieldTraits
::real_type> ::value, decltype(conj(a)*b)>::type { return conj(a)*b; } /** * @brief computes the dot product for fundamental data types according to Petsc's VectDot function: dot(a,b) := std::conj(a)*b * * Specialization for real first arguments which replaces conj(a) by a. * @see http://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecTDot.html#VecTDot * @param a * @param b * @return a*b (which is the same as conj(a)*b in this case) */ // fundamental type with A being a real type template auto dot(const A & a, const B & b) -> typename std::enable_if::value && std::is_same::field_type,typename FieldTraits::real_type>::value, decltype(a*b)>::type { return a*b; } /** * @brief computes the dot product for various dune vector types according to Petsc's VectDot function: dot(a,b) := std::conj(a)*b * * Specialization for real first arguments which replaces conj(a) by a. * @see http://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecTDot.html#VecTDot * @param a * @param b * @return dot(a,b) */ template auto dot(const A & a, const B & b) -> typename std::enable_if::value, decltype(a.dot(b))>::type { return a.dot(b); } /** @} */ /** * @brief Computes an indefinite vector dot product for fundamental data types according to Petsc's VectTDot function: dotT(a,b) := a*b * @see http://www.mcs.anl.gov/petsc/petsc-current/docs/manualpages/Vec/VecTDot.html#VecTDot * @param a * @param b * @return a*b */ template auto dotT(const A & a, const B & b) -> decltype(a*b) { return a*b; } /** @} */ } // end namespace DUNE #endif // DUNE_DOTPRODUCT_HH dune-common-2.8.0/dune/common/dynmatrix.hh000066400000000000000000000077311411343567400205450ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_DYNMATRIX_HH #define DUNE_DYNMATRIX_HH #include #include #include #include #include #include #include #include #include namespace Dune { /** @addtogroup DenseMatVec @{ */ /*! \file * \brief This file implements a dense matrix with dynamic numbers of rows and columns. */ template< class K > class DynamicMatrix; template< class K > struct DenseMatVecTraits< DynamicMatrix > { typedef DynamicMatrix derived_type; typedef DynamicVector row_type; typedef row_type &row_reference; typedef const row_type &const_row_reference; typedef std::vector container_type; typedef K value_type; typedef typename container_type::size_type size_type; }; template< class K > struct FieldTraits< DynamicMatrix > { typedef typename FieldTraits::field_type field_type; typedef typename FieldTraits::real_type real_type; }; /** \brief Construct a matrix with a dynamic size. * * \tparam K is the field type (use float, double, complex, etc) */ template class DynamicMatrix : public DenseMatrix< DynamicMatrix > { std::vector< DynamicVector > _data; typedef DenseMatrix< DynamicMatrix > Base; public: typedef typename Base::size_type size_type; typedef typename Base::value_type value_type; typedef typename Base::row_type row_type; //===== constructors //! \brief Default constructor DynamicMatrix () {} //! \brief Constructor initializing the whole matrix with a scalar DynamicMatrix (size_type r, size_type c, value_type v = value_type() ) : _data(r, row_type(c, v) ) {} /** \brief Constructor initializing the matrix from a list of vector */ DynamicMatrix (std::initializer_list> const &ll) : _data(ll) {} template ::value && HasDenseMatrixAssigner::value>> DynamicMatrix(T const& rhs) { *this = rhs; } //==== resize related methods /** * \brief resize matrix to r × c * * Resize the matrix to r × c, using v * as the value of all entries. * * \warning All previous entries are lost, even when the matrix * was not actually resized. * * \param r number of rows * \param c number of columns * \param v value of matrix entries */ void resize (size_type r, size_type c, value_type v = value_type() ) { _data.resize(0); _data.resize(r, row_type(c, v) ); } //===== assignment // General assignment with resizing template ::value>> DynamicMatrix& operator=(T const& rhs) { _data.resize(rhs.N()); std::fill(_data.begin(), _data.end(), row_type(rhs.M(), K(0))); Base::operator=(rhs); return *this; } // Specialisation: scalar assignment (no resizing) template ::value>> DynamicMatrix& operator=(T scalar) { std::fill(_data.begin(), _data.end(), scalar); return *this; } // make this thing a matrix size_type mat_rows() const { return _data.size(); } size_type mat_cols() const { assert(this->rows()); return _data.front().size(); } row_type & mat_access(size_type i) { DUNE_ASSERT_BOUNDS(i < _data.size()); return _data[i]; } const row_type & mat_access(size_type i) const { DUNE_ASSERT_BOUNDS(i < _data.size()); return _data[i]; } }; /** @} end documentation */ } // end namespace #endif dune-common-2.8.0/dune/common/dynmatrixev.hh000066400000000000000000000060221411343567400210700ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_DYNMATRIXEIGENVALUES_HH #define DUNE_DYNMATRIXEIGENVALUES_HH #include #include #include "dynmatrix.hh" #include "fmatrixev.hh" /*! \file \brief utility functions to compute eigenvalues for dense matrices. \addtogroup DenseMatVec @{ */ namespace Dune { namespace DynamicMatrixHelp { #if HAVE_LAPACK using Dune::FMatrixHelp::eigenValuesNonsymLapackCall; #endif /** \brief calculates the eigenvalues of a symmetric field matrix \param[in] matrix matrix eigenvalues are calculated for \param[out] eigenValues FieldVector that contains eigenvalues in ascending order \param[out] eigenVectors (optional) list of right eigenvectors \note LAPACK::dgeev is used to calculate the eigen values */ template static void eigenValuesNonSym(const DynamicMatrix& matrix, DynamicVector& eigenValues, std::vector>* eigenVectors = nullptr ) { #if HAVE_LAPACK { const long int N = matrix.rows(); const char jobvl = 'n'; const char jobvr = eigenVectors ? 'v' : 'n'; // matrix to put into dgeev auto matrixVector = std::make_unique(N*N); // copy matrix int row = 0; for(int i=0; i(N); auto eigenI = std::make_unique(N); const long int lwork = eigenVectors ? 4*N : 3*N; auto work = std::make_unique(lwork); auto vr = eigenVectors ? std::make_unique(N*N) : std::unique_ptr{}; // return value information long int info = 0; // call LAPACK routine (see fmatrixev_ext.cc) eigenValuesNonsymLapackCall(&jobvl, &jobvr, &N, matrixVector.get(), &N, eigenR.get(), eigenI.get(), nullptr, &N, vr.get(), &N, work.get(), &lwork, &info); if( info != 0 ) { std::cerr << "For matrix " << matrix << " eigenvalue calculation failed! " << std::endl; DUNE_THROW(InvalidStateException,"eigenValues: Eigenvalue calculation failed!"); } eigenValues.resize(N); for (int i=0; i(eigenR[i], eigenI[i]); if (eigenVectors) { eigenVectors->resize(N); for (int i = 0; i < N; ++i) { auto& v = (*eigenVectors)[i]; v.resize(N); std::copy(vr.get() + N*i, vr.get() + N*(i+1), &v[0]); } } } #else // #if HAVE_LAPACK DUNE_THROW(NotImplemented,"LAPACK not found!"); #endif } } } /** @} */ #endif dune-common-2.8.0/dune/common/dynvector.hh000066400000000000000000000124761411343567400205450ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_DYNVECTOR_HH #define DUNE_DYNVECTOR_HH #include #include #include #include #include #include #include #include #include "boundschecking.hh" #include "exceptions.hh" #include "genericiterator.hh" #include #include "densevector.hh" namespace Dune { /** @addtogroup DenseMatVec @{ */ /*! \file * \brief This file implements a dense vector with a dynamic size. */ template< class K, class Allocator > class DynamicVector; template< class K, class Allocator > struct DenseMatVecTraits< DynamicVector< K, Allocator > > { typedef DynamicVector< K, Allocator > derived_type; typedef std::vector< K, Allocator > container_type; typedef K value_type; typedef typename container_type::size_type size_type; }; template< class K, class Allocator > struct FieldTraits< DynamicVector< K, Allocator > > { typedef typename FieldTraits< K >::field_type field_type; typedef typename FieldTraits< K >::real_type real_type; }; /** \brief Construct a vector with a dynamic size. * * \tparam K is the field type (use float, double, complex, etc) * \tparam Allocator type of allocator object used to define the storage allocation model, * default Allocator = std::allocator< K >. */ template< class K, class Allocator = std::allocator< K > > class DynamicVector : public DenseVector< DynamicVector< K, Allocator > > { std::vector< K, Allocator > _data; typedef DenseVector< DynamicVector< K, Allocator > > Base; public: typedef typename Base::size_type size_type; typedef typename Base::value_type value_type; typedef std::vector< K, Allocator > container_type; typedef Allocator allocator_type; //! Constructor making uninitialized vector explicit DynamicVector(const allocator_type &a = allocator_type() ) : _data( a ) {} explicit DynamicVector(size_type n, const allocator_type &a = allocator_type() ) : _data( n, value_type(), a ) {} //! Constructor making vector with identical coordinates DynamicVector( size_type n, value_type c, const allocator_type &a = allocator_type() ) : _data( n, c, a ) {} /** \brief Construct from a std::initializer_list */ DynamicVector (std::initializer_list const &l) : _data(l) {} //! Constructor making vector with identical coordinates DynamicVector(const DynamicVector & x) : Base(), _data(x._data) {} //! Move constructor DynamicVector(DynamicVector && x) : _data(std::move(x._data)) {} template< class T > DynamicVector(const DynamicVector< T, Allocator > & x) : _data(x.begin(), x.end(), x.get_allocator()) {} //! Copy constructor from another DenseVector template< class X > DynamicVector(const DenseVector< X > & x, const allocator_type &a = allocator_type() ) : _data(a) { const size_type n = x.size(); _data.reserve(n); for( size_type i =0; i inline std::istream &operator>> ( std::istream &in, DynamicVector< K, Allocator > &v ) { DynamicVector< K, Allocator > w(v); for( typename DynamicVector< K, Allocator >::size_type i = 0; i < w.size(); ++i ) in >> w[ i ]; if(in) v = std::move(w); return in; } /** @} end documentation */ } // end namespace #endif dune-common-2.8.0/dune/common/enumset.hh000066400000000000000000000067661411343567400202150ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_ENUMSET_HH #define DUNE_ENUMSET_HH #include namespace Dune { /** * @file * @brief Classes for building sets out of enumeration values. * @author Markus Blatt */ /** @addtogroup Common * * @{ */ /** * @brief An empty set. */ template class EmptySet { public: /** * @brief The POD type the set holds. */ typedef TA Type; /** * @brief Always returns false. */ static bool contains(const Type& attribute); }; /** * @brief A set containing everything. */ template class AllSet { public: /** * @brief The POD type the set holds. */ typedef TA Type; /** * @brief Always returns true. */ static bool contains(const Type& attribute); }; /** * @brief A set consisting only of one item. */ template class EnumItem { public: /** * @brief The type the set holds. */ typedef TA Type; /** * @brief Tests whether an item is in the set. * @return True if item==Type. */ static bool contains(const Type& attribute); }; /** * @brief A set representing a range including the borders. */ template class EnumRange //: public PODSet,T> { public: /** * @brief The type the set holds. */ typedef TA Type; static bool contains(const Type& item); }; /** * @brief The negation of a set. * An item is contained in the set if and only if it is not * contained in the negated set. */ template class NegateSet { public: typedef typename S::Type Type; static bool contains(const Type& item) { return !S::contains(item); } }; /** * @brief A set combining two other sets. */ template class Combine { public: static bool contains(const TA& item); }; template inline bool EmptySet::contains([[maybe_unused]] const Type& attribute) { return false; } template inline bool AllSet::contains([[maybe_unused]] const Type& attribute) { return true; } template inline bool EnumItem::contains(const Type& item) { return item==i; } template inline std::ostream& operator<<(std::ostream& os, const EnumItem&) { return os< inline bool EnumRange::contains(const Type& item) { return from<=item && item<=to; } template inline std::ostream& operator<<(std::ostream& os, const EnumRange&) { return os<<"["< inline bool Combine::contains(const TA& item) { return TI1::contains(item) || TI2::contains(item); } template inline Combine combine([[maybe_unused]] const TI1& set1, [[maybe_unused]] const TI2& set2) { return Combine(); } template inline std::ostream& operator<<(std::ostream& os, const Combine&) { return os << TI1()<<" "< namespace Dune { /* static member of Dune::Exception */ ExceptionHook * Exception::_hook = 0; /* Implementation of Dune::Exception */ Exception::Exception () { // call the hook if necessary if (_hook != 0) _hook->operator()(); } void Exception::registerHook (ExceptionHook * hook) { _hook = hook; } void Exception::clearHook () { _hook = 0; } void Exception::message(const std::string & msg) { _message = msg; } const char* Exception::what() const noexcept { return _message.data(); } } dune-common-2.8.0/dune/common/exceptions.hh000066400000000000000000000174221411343567400207050ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_EXCEPTIONS_HH #define DUNE_EXCEPTIONS_HH #include #include #include namespace Dune { /*! \defgroup Exceptions Exception handling \ingroup Common \{ The Dune-exceptions are designed to allow a simple derivation of subclasses and to accept a text written in the '<<' syntax. Example of usage: \code #include ... class FileNotFoundError : public Dune::IOError {}; ... void fileopen (std::string name) { std::ifstream file; file.open(name.c_str()); if (file == 0) DUNE_THROW(FileNotFoundError, "File " << name << " not found!"); ... file.close(); } ... int main () { try { ... } catch (Dune::IOError &e) { std::cerr << "I/O error: " << e << std::endl; return 1; } catch (Dune::Exception &e) { std::cerr << "Generic Dune error: " << e << std::endl; return 2; } } \endcode \see exceptions.hh for detailed info */ /*! \file \brief A few common exception classes This file defines a common framework for generating exception subclasses and to throw them in a simple manner */ /* forward declarations */ class Exception; struct ExceptionHook; /*! \class Exception \brief Base class for Dune-Exceptions all Dune exceptions are derived from this class via trivial subclassing: \code class MyException : public Dune::Exception {}; \endcode You should not \c throw a Dune::Exception directly but use the macro DUNE_THROW() instead which fills the message-buffer of the exception in a standard way and features a way to pass the result in the operator<<-style \see DUNE_THROW, IOError, MathError */ class Exception : public std::exception { public: Exception (); void message(const std::string &msg); //!< store string in internal message buffer const char* what() const noexcept override; //!< output internal message buffer static void registerHook (ExceptionHook * hook); //!< add a functor which is called before a Dune::Exception is emitted (see Dune::ExceptionHook) \see Dune::ExceptionHook static void clearHook (); //!< remove all hooks private: std::string _message; static ExceptionHook * _hook; }; /*! \brief Base class to add a hook to the Dune::Exception The user can add a functor which should be called before a Dune::Exception is emitted. Example: attach a debugger to the process, if an exception is thrown \code struct ExceptionHookDebugger : public Dune::ExceptionHook { char * process_; char * debugger_; ExceptionHookDebugger (int argc, char ** argv, std::string debugger) { process_ = strdup(argv[0]); debugger_ = strdup(debugger.c_str()); } virtual void operator () () { pid_t pid = getpid(); pid_t cpid; cpid = fork(); if (cpid == 0) // child { char * argv[4]; argv[0] = debugger_; argv[1] = process_; argv[2] = new char[12]; snprintf(argv[2], 12, "%i", int(pid)); argv[3] = 0; // execute debugger std::cout << process_ << "\n"; std::cout << argv[0] << " " << argv[1] << " " << argv[2] << std::endl; execv(argv[0], argv); } else // parent { // send application to sleep kill(pid, SIGSTOP); } } }; \endcode This hook is registered via a static method of Dune::Exception: \code int main(int argc, char** argv) { Dune::MPIHelper & mpihelper = Dune::MPIHelper::instance(argc,argv); ExceptionHookDebugger debugger(argc, argv, "/usr/bin/ddd"); Dune::Exception::registerHook(& debugger); try { ... } catch (std::string & s) { std::cout << mpihelper.rank() << ": ERROR: " << s << std::endl; } catch (Dune::Exception & e) { std::cout << mpihelper.rank() << ": DUNE ERROR: " << e.what() << std::endl; } } \endcode */ struct ExceptionHook { virtual ~ExceptionHook() {} virtual void operator () () = 0; }; inline std::ostream& operator<<(std::ostream &stream, const Exception &e) { return stream << e.what(); } #ifndef DOXYGEN // the "format" the exception-type gets printed. __FILE__ and // __LINE__ are standard C-defines, the GNU cpp-infofile claims that // C99 defines __func__ as well. __FUNCTION__ is a GNU-extension #define THROWSPEC(E) # E << " [" << __func__ << ":" << __FILE__ << ":" << __LINE__ << "]: " #endif // DOXYGEN /*! Macro to throw an exception \code #include \endcode \param E exception class derived from Dune::Exception \param m reason for this exception in ostream-notation Example: \code if (filehandle == 0) DUNE_THROW(FileError, "Could not open " << filename << " for reading!"); \endcode DUNE_THROW automatically adds information about the exception thrown to the text. \note you can add a hook to be called before a Dune::Exception is emitted, e.g. to add additional information to the exception, or to invoke a debugger during parallel debugging. (see Dune::ExceptionHook) */ // this is the magic: use the usual do { ... } while (0) trick, create // the full message via a string stream and throw the created object #define DUNE_THROW(E, m) do { E th__ex; std::ostringstream th__out; \ th__out << THROWSPEC(E) << m; th__ex.message(th__out.str()); throw th__ex; \ } while (0) /*! \brief Default exception class for I/O errors This is a superclass for any errors dealing with file/socket I/O problems like - file not found - could not write file - could not connect to remote socket */ class IOError : public Exception {}; /*! \brief Default exception class for mathematical errors This is the superclass for all errors which are caused by mathematical problems like - matrix not invertible - not convergent */ class MathError : public Exception {}; /*! \brief Default exception class for range errors This is the superclass for all errors which are caused because the user tries to access data that was not allocated before. These can be problems like - accessing array entries behind the last entry - adding the fourth non zero entry in a sparse matrix with only three non zero entries per row */ class RangeError : public Exception {}; /*! \brief Default exception for dummy implementations This exception can be used for functions/methods - that have to be implemented but should never be called - that are missing */ class NotImplemented : public Exception {}; /*! \brief Default exception class for OS errors This class is thrown when a system-call is used and returns an error. */ class SystemError : public Exception {}; /*! \brief Default exception if memory allocation fails */ class OutOfMemoryError : public SystemError {}; /*! \brief Default exception if a function was called while the object is not in a valid state for that function. */ class InvalidStateException : public Exception {}; /*! \brief Default exception if an error in the parallel communication of the program occurred \ingroup ParallelCommunication */ class ParallelError : public Exception {}; } // end namespace #endif dune-common-2.8.0/dune/common/filledarray.hh000066400000000000000000000020101411343567400210050ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_FILLED_ARRAY_HH #define DUNE_COMMON_FILLED_ARRAY_HH /** \file \brief Utility to generate an array with a certain value */ #include #include namespace Dune { /** @addtogroup Common @{ */ //! Return an array filled with the provided value. /** * \note This function is `constexpr` only in C++17, or, more precisely, * when `std::array::begin()` and `std::array::end()` are `constexpr`. * * \tparam n Size of the returned array. * \tparam T Value type of the returned array. This is usually deduced * from `t`. */ template constexpr std::array filledArray(const T& t) { std::array arr{}; // this is constexpr in c++17, `arr.fill(t)` is not for(auto &el : arr) el = t; return arr; } /** @} */ } // end namespace Dune #endif // DUNE_COMMON_FILLED_ARRAY_HH dune-common-2.8.0/dune/common/float_cmp.cc000066400000000000000000000456521411343567400204640ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include "float_cmp.hh" #include #include #include #include #include namespace Dune { namespace FloatCmp { // traits //! Mapping of value type to epsilon type /** * @ingroup FloatCmp * @tparam T The value type */ template struct EpsilonType { //! The epsilon type corresponding to value type T typedef T Type; }; //! Specialization of EpsilonType for std::vector /** * @ingroup FloatCmp * @tparam T The value_type of the std::vector * @tparam A The Allocator of the std::vector */ template struct EpsilonType > { //! The epsilon type corresponding to value type std::vector typedef typename EpsilonType::Type Type; }; //! Specialization of EpsilonType for Dune::FieldVector /** * @ingroup FloatCmp * @tparam T The field_type of the Dune::FieldVector * @tparam n The size of the Dune::FieldVector */ template struct EpsilonType > { //! The epsilon type corresponding to value type Dune::FieldVector typedef typename EpsilonType::Type Type; }; // default epsilon template struct DefaultEpsilon { static typename EpsilonType::Type value() { return std::numeric_limits::Type>::epsilon()*8.; } }; template struct DefaultEpsilon { static typename EpsilonType::Type value() { return std::numeric_limits::Type>::epsilon()*8.; } }; template struct DefaultEpsilon { static typename EpsilonType::Type value() { return std::max(std::numeric_limits::Type>::epsilon(), 1e-6); } }; namespace Impl { // basic comparison template struct eq_t; template struct eq_t { static bool eq(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { using std::abs; return abs(first - second) <= epsilon*std::max(abs(first), abs(second)); } }; template struct eq_t { static bool eq(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { using std::abs; return abs(first - second) <= epsilon*std::min(abs(first), abs(second)); } }; template struct eq_t { static bool eq(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { using std::abs; return abs(first-second) <= epsilon; } }; template struct eq_t_std_vec { typedef std::vector V; static bool eq(const V &first, const V &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { auto size = first.size(); if(size != second.size()) return false; for(unsigned int i = 0; i < size; ++i) if(!eq_t::eq(first[i], second[i], epsilon)) return false; return true; } }; template< class T> struct eq_t, relativeWeak> : eq_t_std_vec {}; template< class T> struct eq_t, relativeStrong> : eq_t_std_vec {}; template< class T> struct eq_t, absolute> : eq_t_std_vec {}; template struct eq_t_fvec { typedef Dune::FieldVector V; static bool eq(const V &first, const V &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { for(int i = 0; i < n; ++i) if(!eq_t::eq(first[i], second[i], epsilon)) return false; return true; } }; template< class T, int n > struct eq_t< Dune::FieldVector, relativeWeak> : eq_t_fvec {}; template< class T, int n > struct eq_t< Dune::FieldVector, relativeStrong> : eq_t_fvec {}; template< class T, int n > struct eq_t< Dune::FieldVector, absolute> : eq_t_fvec {}; } // namespace Impl // operations in functional style template bool eq(const T &first, const T &second, typename EpsilonType::Type epsilon) { return Impl::eq_t::eq(first, second, epsilon); } template bool ne(const T &first, const T &second, typename EpsilonType::Type epsilon) { return !eq(first, second, epsilon); } template bool gt(const T &first, const T &second, typename EpsilonType::Type epsilon) { return first > second && ne(first, second, epsilon); } template bool lt(const T &first, const T &second, typename EpsilonType::Type epsilon) { return first < second && ne(first, second, epsilon); } template bool ge(const T &first, const T &second, typename EpsilonType::Type epsilon) { return first > second || eq(first, second, epsilon); } template bool le(const T &first, const T &second, typename EpsilonType::Type epsilon) { return first < second || eq(first, second, epsilon); } // default template arguments template bool eq(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return eq(first, second, epsilon); } template bool ne(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return ne(first, second, epsilon); } template bool gt(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return gt(first, second, epsilon); } template bool lt(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return lt(first, second, epsilon); } template bool ge(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return ge(first, second, epsilon); } template bool le(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return le(first, second, epsilon); } // rounding operations namespace Impl { template struct round_t; template struct round_t { static I round(const T &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { // first get an approximation I lower = I(val); I upper; if(eq(T(lower), val, epsilon)) return lower; if(T(lower) > val) { upper = lower; lower--; } else upper = lower+1; if(le(val - T(lower), T(upper) - val, epsilon)) return lower; else return upper; } }; template struct round_t { static I round(const T &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { // first get an approximation I lower = I(val); I upper; if(eq(T(lower), val, epsilon)) return lower; if(T(lower) > val) { upper = lower; lower--; } else upper = lower+1; if(lt(val - T(lower), T(upper) - val, epsilon)) return lower; else return upper; } }; template struct round_t { static I round(const T &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { if(val > T(0)) return round_t::round(val, epsilon); else return round_t::round(val, epsilon); } }; template struct round_t { static I round(const T &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { if(val > T(0)) return round_t::round(val, epsilon); else return round_t::round(val, epsilon); } }; template struct round_t, std::vector, cstyle, rstyle> { static std::vector round(const T &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { unsigned int size = val.size(); std::vector res(size); for(unsigned int i = 0; i < size; ++i) res[i] = round_t::round(val[i], epsilon); return res; } }; template struct round_t, Dune::FieldVector, cstyle, rstyle> { static Dune::FieldVector round(const T &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { Dune::FieldVector res; for(int i = 0; i < n; ++i) res[i] = round_t::round(val[i], epsilon); return res; } }; } // end namespace Impl template I round(const T &val, typename EpsilonType::Type epsilon /*= DefaultEpsilon::value()*/) { return Impl::round_t::round(val, epsilon); } template I round(const T &val, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return round(val, epsilon); } template I round(const T &val, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return round(val, epsilon); } template I round(const T &val, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return round(val, epsilon); } // truncation namespace Impl { template struct trunc_t; template struct trunc_t { static I trunc(const T &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { // this should be optimized away unless needed if(!std::numeric_limits::is_signed) // make sure this works for all useful cases even if I is an unsigned type if(eq(val, T(0), epsilon)) return I(0); // first get an approximation I lower = I(val); // now |val-lower| < 1 // make sure we're really lower in case the cast truncated to an unexpected direction if(T(lower) > val) lower--; // now val-lower < 1 // check whether lower + 1 is approximately val if(eq(T(lower+1), val, epsilon)) return lower+1; else return lower; } }; template struct trunc_t { static I trunc(const T &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { I upper = trunc_t::trunc(val, epsilon); if(ne(T(upper), val, epsilon)) ++upper; return upper; } }; template struct trunc_t { static I trunc(const T &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { if(val > T(0)) return trunc_t::trunc(val, epsilon); else return trunc_t::trunc(val, epsilon); } }; template struct trunc_t { static I trunc(const T &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { if(val > T(0)) return trunc_t::trunc(val, epsilon); else return trunc_t::trunc(val, epsilon); } }; template struct trunc_t, std::vector, cstyle, rstyle> { static std::vector trunc(const std::vector &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { unsigned int size = val.size(); std::vector res(size); for(unsigned int i = 0; i < size; ++i) res[i] = trunc_t::trunc(val[i], epsilon); return res; } }; template struct trunc_t, Dune::FieldVector, cstyle, rstyle> { static Dune::FieldVector trunc(const Dune::FieldVector &val, typename EpsilonType::Type epsilon = (DefaultEpsilon::value())) { Dune::FieldVector res; for(int i = 0; i < n; ++i) res[i] = trunc_t::trunc(val[i], epsilon); return res; } }; } // namespace Impl template I trunc(const T &val, typename EpsilonType::Type epsilon /*= DefaultEpsilon::value()*/) { return Impl::trunc_t::trunc(val, epsilon); } template I trunc(const T &val, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return trunc(val, epsilon); } template I trunc(const T &val, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return trunc(val, epsilon); } template I trunc(const T &val, typename EpsilonType::Type epsilon = DefaultEpsilon::value()) { return trunc(val, epsilon); } } //namespace Dune // oo interface template FloatCmpOps:: FloatCmpOps(EpsilonType epsilon) : epsilon_(epsilon) {} template typename FloatCmpOps::EpsilonType FloatCmpOps::epsilon() const { return epsilon_; } template void FloatCmpOps::epsilon(EpsilonType epsilon__) { epsilon_ = epsilon__; } template bool FloatCmpOps:: eq(const ValueType &first, const ValueType &second) const { return Dune::FloatCmp::eq(first, second, epsilon_); } template bool FloatCmpOps:: ne(const ValueType &first, const ValueType &second) const { return Dune::FloatCmp::ne(first, second, epsilon_); } template bool FloatCmpOps:: gt(const ValueType &first, const ValueType &second) const { return Dune::FloatCmp::gt(first, second, epsilon_); } template bool FloatCmpOps:: lt(const ValueType &first, const ValueType &second) const { return Dune::FloatCmp::lt(first, second, epsilon_); } template bool FloatCmpOps:: ge(const ValueType &first, const ValueType &second) const { return Dune::FloatCmp::ge(first, second, epsilon_); } template bool FloatCmpOps:: le(const ValueType &first, const ValueType &second) const { return Dune::FloatCmp::le(first, second, epsilon_); } template template I FloatCmpOps:: round(const ValueType &val) const { return Dune::FloatCmp::round(val, epsilon_); } template template I FloatCmpOps:: trunc(const ValueType &val) const { return Dune::FloatCmp::trunc(val, epsilon_); } } //namespace Dune dune-common-2.8.0/dune/common/float_cmp.hh000066400000000000000000000355101411343567400204660ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_FLOAT_CMP_HH #define DUNE_COMMON_FLOAT_CMP_HH /** \file * \brief Various ways to compare floating-point numbers */ /** @addtogroup FloatCmp @section How_to_compare How to compare floats When comparing floating point numbers for equality, one often faces the problem that floating point operations are not always exact. For example on i386 the expression @code 0.2 + 0.2 + 0.2 + 0.2 + 0.2 + 0.2 + 0.2 + 0.2 + 0.2 + 0.2 == 2.0 @endcode evaluates to @code 1.99999999999999977796 == 2.00000000000000000000 @endcode which is false. One solution is to compare approximately, using an epsilon which says how much deviation to accept. The most straightforward way of comparing is using an @em absolute epsilon. This means comparison for equality is replaced by @code abs(first-second) <= epsilon @endcode This has a severe disadvantage: if you have an epsilon like 1e-10 but first and second are of the magnitude 1e-15 everything will compare equal which is certainly not what you want. This can be overcome by selecting an appropriate epsilon. Nevertheless this method of comparing is not recommended in general, and we will present a more robus method in the next paragraph. There is another way of comparing approximately, using a @em relative epsilon which is then scaled with first: @code abs(first-second) <= epsilon * abs(first) @endcode Of cource the comparison should be symmetric in first and second so we cannot arbitrarily select either first or second to scale epsilon. The are two symmetric variants, @em relative_weak @code abs(first-second) <= epsilon * max(abs(first), abs(second)) @endcode and @em relative_strong @code abs(first-second) <= epsilon * min(abs(first), abs(second)) @endcode Both variants are good, but in practice the relative_weak variant is preferred. This is also the default variant. \note Although using a relative epsilon is better than using an absolute epsilon, using a relative epsilon leads to problems if either first or second equals 0. In principle the relative method can be combined with an absolute method using an epsilon near the minimum representable positive value, but this is not implemented here. There is a completely different way of comparing floats. Instead of giving an epsilon, the programmer states how many representable value are allowed between first and second. See the "Comparing using integers" section in http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm for more about that. @section Interface Interface To do the comparison, you can use the free functions @link Dune::FloatCmp::eq eq()@endlink, @link Dune::FloatCmp::ne ne()@endlink, @link Dune::FloatCmp::gt gt()@endlink, @link Dune::FloatCmp::lt lt()@endlink, @link Dune::FloatCmp::ge ge()@endlink and @link Dune::FloatCmp::le le()@endlink from the namespace Dune::FloatCmp. They take the values to compare and optionally an epsilon, which defaults to 8 times the machine epsilon (the difference between 1.0 and the smallest representable value > 1.0) for relative comparisons, or simply 1e-6 for absolute comparisons. The compare style can be given as an optional second template parameter and defaults to relative_weak. You can also use the class Dune::FloatCmpOps which has @link Dune::FloatCmpOps::eq eq()@endlink, @link Dune::FloatCmpOps::ne ne()@endlink, @link Dune::FloatCmpOps::gt gt()@endlink, @link Dune::FloatCmpOps::lt lt()@endlink, @link Dune::FloatCmpOps::ge ge()@endlink and @link Dune::FloatCmpOps::le le()@endlink as member functions. In this case the class encapsulates the epsilon and the comparison style (again the defaults from the previous paragraph apply). This may be more convenient if you write your own class utilizing floating point comparisons, and you want the user of you class to specify epsilon and compare style. */ //! Dune namespace namespace Dune { //! FloatCmp namespace //! @ingroup FloatCmp namespace FloatCmp { // basic constants //! How to compare //! @ingroup FloatCmp enum CmpStyle { //! |a-b|/|a| <= epsilon || |a-b|/|b| <= epsilon relativeWeak, //! |a-b|/|a| <= epsilon && |a-b|/|b| <= epsilon relativeStrong, //! |a-b| <= epsilon absolute, //! the global default compare style (relative_weak) defaultCmpStyle = relativeWeak }; //! How to round or truncate //! @ingroup FloatCmp enum RoundingStyle { //! always round toward 0 towardZero, //! always round away from 0 towardInf, //! round toward \f$-\infty\f$ downward, //! round toward \f$+\infty\f$ upward, //! the global default rounding style (toward_zero) defaultRoundingStyle = towardZero }; template struct EpsilonType; //! mapping from a value type and a compare style to a default epsilon /** * @ingroup FloatCmp * @tparam T The value type to map from * @tparam style The compare style to map from */ template struct DefaultEpsilon { //! Returns the default epsilon for the given value type and compare style static typename EpsilonType::Type value(); }; // operations in functional style //! @addtogroup FloatCmp //! @{ //! test for equality using epsilon /** * @tparam T Type of the values to compare * @tparam style How to compare. This defaults to defaultCmpStyle. * @param first left operand of equals operation * @param second right operand of equals operation * @param epsilon The epsilon to use in the comparison */ template bool eq(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()); //! test for inequality using epsilon /** * @tparam T Type of the values to compare * @tparam style How to compare. This defaults to defaultCmpStyle. * @param first left operand of not-equal operation * @param second right operand of not-equal operation * @param epsilon The epsilon to use in the comparison * @return !eq(first, second, epsilon) */ template bool ne(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()); //! test if first greater than second /** * @tparam T Type of the values to compare * @tparam style How to compare. This defaults to defaultCmpStyle. * @param first left operand of greater-than operation * @param second right operand of greater-than operation * @param epsilon The epsilon to use in the comparison * @return ne(first, second, epsilon) && first > second * * this is like first > second but the region that compares equal with an * epsilon is excluded */ template bool gt(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()); //! test if first lesser than second /** * @tparam T Type of the values to compare * @tparam style How to compare. This defaults to defaultCmpStyle. * @param first left operand of less-than operation * @param second right operand of less-than operation * @param epsilon The epsilon to use in the comparison * @return ne(first, second, epsilon) && first < second * * this is like first < second, but the region that compares equal with an * epsilon is excluded */ template bool lt(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()); //! test if first greater or equal second /** * @tparam T Type of the values to compare * @tparam style How to compare. This defaults to defaultCmpStyle. * @param first left operand of greater-or-equals operation * @param second right operand of greater-or-equals operation * @param epsilon The epsilon to use in the comparison * @return eq(first, second, epsilon) || first > second * * this is like first > second, but the region that compares equal with an * epsilon is also included */ template bool ge(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()); //! test if first lesser or equal second /** * @tparam T Type of the values to compare * @tparam style How to compare. This defaults to defaultCmpStyle. * @param first left operand of less-or-equals operation * @param second right operand of less-or-equals operation * @param epsilon The epsilon to use in the comparison * @return eq(first, second) || first < second * * this is like first < second, but the region that compares equal with an * epsilon is also included */ template bool le(const T &first, const T &second, typename EpsilonType::Type epsilon = DefaultEpsilon::value()); // rounding operations //! round using epsilon /** * @tparam I The integral type to round to * @tparam T Type of the value to round * @tparam cstyle How to compare. This defaults to defaultCmpStyle. * @tparam rstyle How to round. This defaults to defaultRoundingStyle. * @param val The value to round * @param epsilon The epsilon to use in comparisons * @return The rounded value * * Round according to rstyle. If val is already near the mean of two * adjacent integers in terms of epsilon, the result will be the rounded * mean. */ template I round(const T &val, typename EpsilonType::Type epsilon = DefaultEpsilon::value()); // truncation //! truncate using epsilon /** * @tparam I The integral type to truncate to * @tparam T Type of the value to truncate * @tparam cstyle How to compare. This defaults to defaultCmpStyle. * @tparam rstyle How to truncate. This defaults to defaultRoundingStyle. * @param val The value to truncate * @param epsilon The epsilon to use in comparisons * @return The truncated value * * Truncate according to rstyle. If val is already near an integer in * terms of epsilon, the result will be that integer instead of the real * truncated value. */ template I trunc(const T &val, typename EpsilonType::Type epsilon = DefaultEpsilon::value()); //! @} // group FloatCmp } //namespace FloatCmp // oo interface //! Class encapsulating a default epsilon /** * @ingroup FloatCmp * @tparam T Type of the values to compare * @tparam cstyle_ How to compare * @tparam rstyle_ How to round */ template class FloatCmpOps { typedef FloatCmp::CmpStyle CmpStyle; typedef FloatCmp::RoundingStyle RoundingStyle; public: // record template parameters //! How comparisons are done static const CmpStyle cstyle = cstyle_; //! How rounding is done static const RoundingStyle rstyle = rstyle_; //! Type of the values to compare typedef T ValueType; //! Type of the epsilon. /** * May be different from the value type, for example for complex */ typedef typename FloatCmp::EpsilonType::Type EpsilonType; private: EpsilonType epsilon_; typedef FloatCmp::DefaultEpsilon DefaultEpsilon; public: //! construct an operations object /** * @param epsilon Use the specified epsilon for comparing */ FloatCmpOps(EpsilonType epsilon = DefaultEpsilon::value()); //! return the current epsilon EpsilonType epsilon() const; //! set new epsilon void epsilon(EpsilonType epsilon__); //! test for equality using epsilon bool eq(const ValueType &first, const ValueType &second) const; //! test for inequality using epsilon /** * this is exactly !eq(first, second) */ bool ne(const ValueType &first, const ValueType &second) const; //! test if first greater than second /** * this is exactly ne(first, second) && first > second, i.e. greater but * the region that compares equal with an epsilon is excluded */ bool gt(const ValueType &first, const ValueType &second) const; //! test if first lesser than second /** * this is exactly ne(first, second) && first < second, i.e. lesser but * the region that compares equal with an epsilon is excluded */ bool lt(const ValueType &first, const ValueType &second) const; //! test if first greater or equal second /** * this is exactly eq(first, second) || first > second, i.e. greater but * the region that compares equal with an epsilon is also included */ bool ge(const ValueType &first, const ValueType &second) const; //! test if first lesser or equal second /** * this is exactly eq(first, second) || first > second, i.e. lesser but * the region that compares equal with an epsilon is also included */ bool le(const ValueType &first, const ValueType &second) const; //! round using epsilon /** * @tparam I The integral type to round to * * @param val The value to round * * Round according to rstyle. If val is already near the mean of two * adjacent integers in terms of epsilon, the result will be the rounded * mean. */ template I round(const ValueType &val) const; //! truncate using epsilon /** * @tparam I The integral type to truncate to * * @param val The value to truncate * * Truncate according to rstyle. If val is already near an integer in * terms of epsilon, the result will be that integer instead of the real * truncated value. */ template I trunc(const ValueType &val) const; }; } //namespace Dune #include "float_cmp.cc" #endif //DUNE_COMMON_FLOAT_CMP_HH dune-common-2.8.0/dune/common/fmatrix.hh000066400000000000000000000544721411343567400202040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FMATRIX_HH #define DUNE_FMATRIX_HH #include #include #include #include #include #include #include #include #include #include #include #include namespace Dune { /** @addtogroup DenseMatVec @{ */ /*! \file \brief Implements a matrix constructed from a given type representing a field and compile-time given number of rows and columns. */ template< class K, int ROWS, int COLS = ROWS > class FieldMatrix; template< class K, int ROWS, int COLS > struct DenseMatVecTraits< FieldMatrix > { typedef FieldMatrix derived_type; // each row is implemented by a field vector typedef FieldVector row_type; typedef row_type &row_reference; typedef const row_type &const_row_reference; typedef std::array container_type; typedef K value_type; typedef typename container_type::size_type size_type; }; template< class K, int ROWS, int COLS > struct FieldTraits< FieldMatrix > { typedef typename FieldTraits::field_type field_type; typedef typename FieldTraits::real_type real_type; }; /** @brief A dense n x m matrix. Matrices represent linear maps from a vector space V to a vector space W. This class represents such a linear map by storing a two-dimensional %array of numbers of a given field type K. The number of rows and columns is given at compile time. */ template class FieldMatrix : public DenseMatrix< FieldMatrix > { std::array< FieldVector, ROWS > _data; typedef DenseMatrix< FieldMatrix > Base; public: //! export size enum { //! The number of rows. rows = ROWS, //! The number of columns. cols = COLS }; typedef typename Base::size_type size_type; typedef typename Base::row_type row_type; typedef typename Base::row_reference row_reference; typedef typename Base::const_row_reference const_row_reference; //===== constructors /** \brief Default constructor */ constexpr FieldMatrix() = default; /** \brief Constructor initializing the matrix from a list of vector */ FieldMatrix(std::initializer_list > const &l) { assert(l.size() == rows); // Actually, this is not needed any more! std::copy_n(l.begin(), std::min(static_cast(ROWS), l.size()), _data.begin()); } template ::value>> FieldMatrix(T const& rhs) { *this = rhs; } using Base::operator=; //! copy assignment operator FieldMatrix& operator=(const FieldMatrix&) = default; //! copy assignment from FieldMatrix over a different field template FieldMatrix& operator=(const FieldMatrix& x) { _data = x._data; return *this; } //! no copy assignment from FieldMatrix of different size template FieldMatrix& operator=(FieldMatrix const&) = delete; //! vector space addition -- two-argument version template friend auto operator+ ( const FieldMatrix& matrixA, const FieldMatrix& matrixB) { FieldMatrix::PromotedType,ROWS,COLS> result; for (size_type i = 0; i < ROWS; ++i) for (size_type j = 0; j < COLS; ++j) result[i][j] = matrixA[i][j] + matrixB[i][j]; return result; } //! vector space subtraction -- two-argument version template friend auto operator- ( const FieldMatrix& matrixA, const FieldMatrix& matrixB) { FieldMatrix::PromotedType,ROWS,COLS> result; for (size_type i = 0; i < ROWS; ++i) for (size_type j = 0; j < COLS; ++j) result[i][j] = matrixA[i][j] - matrixB[i][j]; return result; } //! vector space multiplication with scalar template ::value, int> = 0> friend auto operator* ( const FieldMatrix& matrix, Scalar scalar) { FieldMatrix::PromotedType,ROWS,COLS> result; for (size_type i = 0; i < ROWS; ++i) for (size_type j = 0; j < COLS; ++j) result[i][j] = matrix[i][j] * scalar; return result; } //! vector space multiplication with scalar template ::value, int> = 0> friend auto operator* ( Scalar scalar, const FieldMatrix& matrix) { FieldMatrix::PromotedType,ROWS,COLS> result; for (size_type i = 0; i < ROWS; ++i) for (size_type j = 0; j < COLS; ++j) result[i][j] = scalar * matrix[i][j]; return result; } //! vector space division by scalar template ::value, int> = 0> friend auto operator/ ( const FieldMatrix& matrix, Scalar scalar) { FieldMatrix::PromotedType,ROWS,COLS> result; for (size_type i = 0; i < ROWS; ++i) for (size_type j = 0; j < COLS; ++j) result[i][j] = matrix[i][j] / scalar; return result; } /** \brief Matrix-matrix multiplication */ template friend auto operator* ( const FieldMatrix& matrixA, const FieldMatrix& matrixB) { FieldMatrix::PromotedType,ROWS,otherCols> result; for (size_type i = 0; i < matrixA.mat_rows(); ++i) for (size_type j = 0; j < matrixB.mat_cols(); ++j) { result[i][j] = 0; for (size_type k = 0; k < matrixA.mat_cols(); ++k) result[i][j] += matrixA[i][k] * matrixB[k][j]; } return result; } //! Multiplies M from the left to this matrix, this matrix is not modified template FieldMatrix leftmultiplyany (const FieldMatrix& M) const { FieldMatrix C; for (size_type i=0; i FieldMatrix& rightmultiply (const FieldMatrix& M) { static_assert(r == c, "Cannot rightmultiply with non-square matrix"); static_assert(r == cols, "Size mismatch"); FieldMatrix C(*this); for (size_type i=0; i FieldMatrix rightmultiplyany (const FieldMatrix& M) const { FieldMatrix C; for (size_type i=0; i class FieldMatrix : public DenseMatrix< FieldMatrix > { FieldVector _data; typedef DenseMatrix< FieldMatrix > Base; public: // standard constructor and everything is sufficient ... //===== type definitions and constants //! The type used for index access and size operations typedef typename Base::size_type size_type; //! We are at the leaf of the block recursion enum { //! The number of block levels we contain. //! This is always one for this type. blocklevel = 1 }; typedef typename Base::row_type row_type; typedef typename Base::row_reference row_reference; typedef typename Base::const_row_reference const_row_reference; //! export size enum { //! \brief The number of rows. //! This is always one for this type. rows = 1, //! \brief The number of columns. //! This is always one for this type. cols = 1 }; //===== constructors /** \brief Default constructor */ constexpr FieldMatrix() = default; /** \brief Constructor initializing the matrix from a list of vector */ FieldMatrix(std::initializer_list> const &l) { std::copy_n(l.begin(), std::min(static_cast< std::size_t >( 1 ), l.size()), &_data); } template ::value>> FieldMatrix(T const& rhs) { *this = rhs; } using Base::operator=; //! vector space addition -- two-argument version template friend auto operator+ ( const FieldMatrix& matrixA, const FieldMatrix& matrixB) { return FieldMatrix::PromotedType,1,1>{matrixA[0][0] + matrixB[0][0]}; } //! Binary addition when treating FieldMatrix like K template ::value, int> = 0> friend auto operator+ ( const FieldMatrix& matrix, const Scalar& scalar) { return FieldMatrix::PromotedType,1,1>{matrix[0][0] + scalar}; } //! Binary addition when treating FieldMatrix like K template ::value, int> = 0> friend auto operator+ ( const Scalar& scalar, const FieldMatrix& matrix) { return FieldMatrix::PromotedType,1,1>{scalar + matrix[0][0]}; } //! vector space subtraction -- two-argument version template friend auto operator- ( const FieldMatrix& matrixA, const FieldMatrix& matrixB) { return FieldMatrix::PromotedType,1,1>{matrixA[0][0] - matrixB[0][0]}; } //! Binary subtraction when treating FieldMatrix like K template ::value, int> = 0> friend auto operator- ( const FieldMatrix& matrix, const Scalar& scalar) { return FieldMatrix::PromotedType,1,1>{matrix[0][0] - scalar}; } //! Binary subtraction when treating FieldMatrix like K template ::value, int> = 0> friend auto operator- ( const Scalar& scalar, const FieldMatrix& matrix) { return FieldMatrix::PromotedType,1,1>{scalar - matrix[0][0]}; } //! vector space multiplication with scalar template ::value, int> = 0> friend auto operator* ( const FieldMatrix& matrix, Scalar scalar) { return FieldMatrix::PromotedType,1,1> {matrix[0][0] * scalar}; } //! vector space multiplication with scalar template ::value, int> = 0> friend auto operator* ( Scalar scalar, const FieldMatrix& matrix) { return FieldMatrix::PromotedType,1,1> {scalar * matrix[0][0]}; } //! vector space division by scalar template ::value, int> = 0> friend auto operator/ ( const FieldMatrix& matrix, Scalar scalar) { return FieldMatrix::PromotedType,1,1> {matrix[0][0] / scalar}; } //===== solve /** \brief Matrix-matrix multiplication */ template friend auto operator* ( const FieldMatrix& matrixA, const FieldMatrix& matrixB) { FieldMatrix::PromotedType,1,otherCols> result; for (size_type j = 0; j < matrixB.mat_cols(); ++j) result[0][j] = matrixA[0][0] * matrixB[0][j]; return result; } //! Multiplies M from the left to this matrix, this matrix is not modified template FieldMatrix leftmultiplyany (const FieldMatrix& M) const { FieldMatrix C; for (size_type j=0; j FieldMatrix rightmultiplyany (const FieldMatrix& M) const { FieldMatrix C; for (size_type j=0; j std::ostream& operator<< (std::ostream& s, const FieldMatrix& a) { s << a[0][0]; return s; } #endif // DOXYGEN namespace FMatrixHelp { //! invert scalar without changing the original matrix template static inline K invertMatrix (const FieldMatrix &matrix, FieldMatrix &inverse) { using real_type = typename FieldTraits::real_type; inverse[0][0] = real_type(1.0)/matrix[0][0]; return matrix[0][0]; } //! invert scalar without changing the original matrix template static inline K invertMatrix_retTransposed (const FieldMatrix &matrix, FieldMatrix &inverse) { return invertMatrix(matrix,inverse); } //! invert 2x2 Matrix without changing the original matrix template static inline K invertMatrix (const FieldMatrix &matrix, FieldMatrix &inverse) { using real_type = typename FieldTraits::real_type; // code generated by maple K det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]); K det_1 = real_type(1.0)/det; inverse[0][0] = matrix[1][1] * det_1; inverse[0][1] = - matrix[0][1] * det_1; inverse[1][0] = - matrix[1][0] * det_1; inverse[1][1] = matrix[0][0] * det_1; return det; } //! invert 2x2 Matrix without changing the original matrix //! return transposed matrix template static inline K invertMatrix_retTransposed (const FieldMatrix &matrix, FieldMatrix &inverse) { using real_type = typename FieldTraits::real_type; // code generated by maple K det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]); K det_1 = real_type(1.0)/det; inverse[0][0] = matrix[1][1] * det_1; inverse[1][0] = - matrix[0][1] * det_1; inverse[0][1] = - matrix[1][0] * det_1; inverse[1][1] = matrix[0][0] * det_1; return det; } //! invert 3x3 Matrix without changing the original matrix template static inline K invertMatrix (const FieldMatrix &matrix, FieldMatrix &inverse) { using real_type = typename FieldTraits::real_type; // code generated by maple K t4 = matrix[0][0] * matrix[1][1]; K t6 = matrix[0][0] * matrix[1][2]; K t8 = matrix[0][1] * matrix[1][0]; K t10 = matrix[0][2] * matrix[1][0]; K t12 = matrix[0][1] * matrix[2][0]; K t14 = matrix[0][2] * matrix[2][0]; K det = (t4*matrix[2][2]-t6*matrix[2][1]-t8*matrix[2][2]+ t10*matrix[2][1]+t12*matrix[1][2]-t14*matrix[1][1]); K t17 = real_type(1.0)/det; inverse[0][0] = (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17; inverse[0][1] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17; inverse[0][2] = (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17; inverse[1][0] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17; inverse[1][1] = (matrix[0][0] * matrix[2][2] - t14) * t17; inverse[1][2] = -(t6-t10) * t17; inverse[2][0] = (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17; inverse[2][1] = -(matrix[0][0] * matrix[2][1] - t12) * t17; inverse[2][2] = (t4-t8) * t17; return det; } //! invert 3x3 Matrix without changing the original matrix template static inline K invertMatrix_retTransposed (const FieldMatrix &matrix, FieldMatrix &inverse) { using real_type = typename FieldTraits::real_type; // code generated by maple K t4 = matrix[0][0] * matrix[1][1]; K t6 = matrix[0][0] * matrix[1][2]; K t8 = matrix[0][1] * matrix[1][0]; K t10 = matrix[0][2] * matrix[1][0]; K t12 = matrix[0][1] * matrix[2][0]; K t14 = matrix[0][2] * matrix[2][0]; K det = (t4*matrix[2][2]-t6*matrix[2][1]-t8*matrix[2][2]+ t10*matrix[2][1]+t12*matrix[1][2]-t14*matrix[1][1]); K t17 = real_type(1.0)/det; inverse[0][0] = (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17; inverse[1][0] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17; inverse[2][0] = (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17; inverse[0][1] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17; inverse[1][1] = (matrix[0][0] * matrix[2][2] - t14) * t17; inverse[2][1] = -(t6-t10) * t17; inverse[0][2] = (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17; inverse[1][2] = -(matrix[0][0] * matrix[2][1] - t12) * t17; inverse[2][2] = (t4-t8) * t17; return det; } //! calculates ret = A * B template< class K, int m, int n, int p > static inline void multMatrix ( const FieldMatrix< K, m, n > &A, const FieldMatrix< K, n, p > &B, FieldMatrix< K, m, p > &ret ) { typedef typename FieldMatrix< K, m, p > :: size_type size_type; for( size_type i = 0; i < m; ++i ) { for( size_type j = 0; j < p; ++j ) { ret[ i ][ j ] = K( 0 ); for( size_type k = 0; k < n; ++k ) ret[ i ][ j ] += A[ i ][ k ] * B[ k ][ j ]; } } } //! calculates ret= A_t*A template static inline void multTransposedMatrix(const FieldMatrix &matrix, FieldMatrix& ret) { typedef typename FieldMatrix::size_type size_type; for(size_type i=0; i static inline void multAssignTransposed( const FieldMatrix &matrix, const FieldVector & x, FieldVector & ret) { typedef typename FieldMatrix::size_type size_type; for(size_type i=0; i static inline FieldVector mult(const FieldMatrix &matrix, const FieldVector & x) { FieldVector ret; multAssign(matrix,x,ret); return ret; } //! calculates ret = matrix^T * x template static inline FieldVector multTransposed(const FieldMatrix &matrix, const FieldVector & x) { FieldVector ret; multAssignTransposed( matrix, x, ret ); return ret; } } // end namespace FMatrixHelp /** @} end documentation */ } // end namespace #include "fmatrixev.hh" #endif dune-common-2.8.0/dune/common/fmatrixev.cc000066400000000000000000000245361411343567400205230ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FMATRIXEIGENVALUES_CC #define DUNE_FMATRIXEIGENVALUES_CC #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #if HAVE_LAPACK #ifdef LAPACK_NEEDS_UNDERLINE #define LAPACK_MANGLE(name,NAME) name##_ #else #define LAPACK_MANGLE(name,NAME) name #endif #define FC_FUNC LAPACK_MANGLE // symmetric matrices #define DSYEV_FORTRAN FC_FUNC (dsyev, DSYEV) #define SSYEV_FORTRAN FC_FUNC (ssyev, SSYEV) // nonsymmetric matrices #define DGEEV_FORTRAN FC_FUNC (dgeev, DGEEV) #define SGEEV_FORTRAN FC_FUNC (sgeev, SGEEV) // dsyev declaration (in liblapack) extern "C" { /* * ** purpose ** ======= ** ** xsyev computes all eigenvalues and, optionally, eigenvectors of a ** BASE DATA TYPE symmetric matrix a. ** ** arguments ** ========= ** ** jobz (input) char ** = 'n': compute eigenvalues only; ** = 'v': compute eigenvalues and eigenvectors. ** ** uplo (input) char ** = 'u': upper triangle of a is stored; ** = 'l': lower triangle of a is stored. ** ** n (input) long int ** the order of the matrix a. n >= 0. ** ** a (input/output) BASE DATA TYPE array, dimension (lda, n) ** on entry, the symmetric matrix a. if uplo = 'u', the ** leading n-by-n upper triangular part of a contains the ** upper triangular part of the matrix a. if uplo = 'l', ** the leading n-by-n lower triangular part of a contains ** the lower triangular part of the matrix a. ** on exit, if jobz = 'v', then if info = 0, a contains the ** orthonormal eigenvectors of the matrix a. ** if jobz = 'n', then on exit the lower triangle (if uplo='l') ** or the upper triangle (if uplo='u') of a, including the ** diagonal, is destroyed. ** ** lda (input) long int ** the leading dimension of the array a. lda >= max(1,n). ** ** w (output) BASE DATA TYPE array, dimension (n) ** if info = 0, the eigenvalues in ascending order. ** ** work (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK)) ** On exit, if INFO = 0, WORK(1) returns the optimal LWORK. ** ** lwork (input) INTEGER ** The length of the array WORK. LWORK >= max(1,3*N-1). ** For optimal efficiency, LWORK >= (NB+2)*N, ** where NB is the blocksize for DSYTRD returned by ILAENV. ** ** If LWORK = -1, then a workspace query is assumed; the routine ** only calculates the optimal size of the WORK array, returns ** this value as the first entry of the WORK array, and no error ** message related to LWORK is issued by XERBLA. ** ** ** info (output) long int ** = 0: successful exit ** < 0: if info = -i, the i-th argument had an illegal value ** > 0: if info = i, the algorithm failed to converge; i ** off-diagonal elements of an intermediate tridiagonal ** form did not converge to zero. ** **/ extern void DSYEV_FORTRAN(const char* jobz, const char* uplo, const long int* n, double* a, const long int* lda, double* w, double* work, const long int* lwork, long int* info); extern void SSYEV_FORTRAN(const char* jobz, const char* uplo, const long int* n, float* a, const long int* lda, float* w, float* work, const long int* lwork, long int* info); /* * ** purpose ** ======= ** ** xgeev computes for an N-by-N BASE DATA TYPE nonsymmetric matrix A, the ** eigenvalues and, optionally, the left and/or right eigenvectors. ** ** The right eigenvector v(j) of A satisfies ** A * v(j) = lambda(j) * v(j) ** where lambda(j) is its eigenvalue. ** The left eigenvector u(j) of A satisfies ** u(j)**T * A = lambda(j) * u(j)**T ** where u(j)**T denotes the transpose of u(j). ** ** The computed eigenvectors are normalized to have Euclidean norm ** equal to 1 and largest component real. ** ** arguments ** ========= ** ** jobvl (input) char ** = 'n': left eigenvectors of a are not computed; ** = 'v': left eigenvectors of a are computed. ** ** jobvr (input) char ** = 'n': right eigenvectors of a are not computed; ** = 'v': right eigenvectors of a are computed. ** ** n (input) long int ** the order of the matrix v. v >= 0. ** ** a (input/output) BASE DATA TYPE array, dimension (lda,n) ** on entry, the n-by-n matrix a. ** on exit, a has been overwritten. ** ** lda (input) long int ** the leading dimension of the array a. lda >= max(1,n). ** ** wr (output) BASE DATA TYPE array, dimension (n) ** wi (output) BASE DATA TYPE array, dimension (n) ** wr and wi contain the real and imaginary parts, ** respectively, of the computed eigenvalues. complex ** conjugate pairs of eigenvalues appear consecutively ** with the eigenvalue having the positive imaginary part ** first. ** ** vl (output) COMPLEX DATA TYPE array, dimension (ldvl,n) ** if jobvl = 'v', the left eigenvectors u(j) are stored one ** after another in the columns of vl, in the same order ** as their eigenvalues. ** if jobvl = 'n', vl is not referenced. ** if the j-th eigenvalue is real, then u(j) = vl(:,j), ** the j-th column of vl. ** if the j-th and (j+1)-st eigenvalues form a complex ** conjugate pair, then u(j) = vl(:,j) + i*vl(:,j+1) and ** u(j+1) = vl(:,j) - i*vl(:,j+1). ** ** ldvl (input) long int ** the leading dimension of the array vl. ldvl >= 1; if ** jobvl = 'v', ldvl >= n. ** ** vr (output) COMPLEX DATA TYPE array, dimension (ldvr,n) ** if jobvr = 'v', the right eigenvectors v(j) are stored one ** after another in the columns of vr, in the same order ** as their eigenvalues. ** if jobvr = 'n', vr is not referenced. ** if the j-th eigenvalue is real, then v(j) = vr(:,j), ** the j-th column of vr. ** if the j-th and (j+1)-st eigenvalues form a complex ** conjugate pair, then v(j) = vr(:,j) + i*vr(:,j+1) and ** v(j+1) = vr(:,j) - i*vr(:,j+1). ** ** ldvr (input) long int ** the leading dimension of the array vr. ldvr >= 1; if ** jobvr = 'v', ldvr >= n. ** ** work (workspace/output) BASE DATA TYPE array, dimension (max(1,lwork)) ** on exit, if info = 0, work(1) returns the optimal lwork. ** ** lwork (input) long int ** the dimension of the array work. lwork >= max(1,3*n), and ** if jobvl = 'v' or jobvr = 'v', lwork >= 4*n. for good ** performance, lwork must generally be larger. ** ** if lwork = -1, then a workspace query is assumed; the routine ** only calculates the optimal size of the work array, returns ** this value as the first entry of the work array, and no error ** message related to lwork is issued by xerbla. ** ** info (output) long int ** = 0: successful exit ** < 0: if info = -i, the i-th argument had an illegal value. ** > 0: if info = i, the qr algorithm failed to compute all the ** eigenvalues, and no eigenvectors have been computed; ** elements i+1:n of wr and wi contain eigenvalues which ** have converged. ** **/ extern void DGEEV_FORTRAN(const char* jobvl, const char* jobvr, const long int* n, double* a, const long int* lda, double* wr, double* wi, double* vl, const long int* ldvl, double* vr, const long int* ldvr, double* work, const long int* lwork, long int* info); extern void SGEEV_FORTRAN(const char* jobvl, const char* jobvr, const long int* n, float* a, const long int* lda, float* wr, float* wi, float* vl, const long int* ldvl, float* vr, const long int* ldvr, float* work, const long int* lwork, long int* info); } // end extern C namespace Dune { namespace FMatrixHelp { void eigenValuesLapackCall( const char* jobz, const char* uplo, const long int* n, double* a, const long int* lda, double* w, double* work, const long int* lwork, long int* info) { // call LAPACK dsyev DSYEV_FORTRAN(jobz, uplo, n, a, lda, w, work, lwork, info); } void eigenValuesLapackCall( const char* jobz, const char* uplo, const long int* n, float* a, const long int* lda, float* w, float* work, const long int* lwork, long int* info) { // call LAPACK dsyev SSYEV_FORTRAN(jobz, uplo, n, a, lda, w, work, lwork, info); } void eigenValuesNonsymLapackCall( const char* jobvl, const char* jobvr, const long int* n, double* a, const long int* lda, double* wr, double* wi, double* vl, const long int* ldvl, double* vr, const long int* ldvr, double* work, const long int* lwork, long int* info) { // call LAPACK dgeev DGEEV_FORTRAN(jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork, info); } void eigenValuesNonsymLapackCall( const char* jobvl, const char* jobvr, const long int* n, float* a, const long int* lda, float* wr, float* wi, float* vl, const long int* ldvl, float* vr, const long int* ldvr, float* work, const long int* lwork, long int* info) { // call LAPACK dgeev SGEEV_FORTRAN(jobvl, jobvr, n, a, lda, wr, wi, vl, ldvl, vr, ldvr, work, lwork, info); } } // end namespace FMatrixHelp } // end namespace Dune #endif // #if HAVE_LAPACK #endif // #ifndef DUNE_FMATRIXEIGENVALUES_CC dune-common-2.8.0/dune/common/fmatrixev.hh000066400000000000000000000610151411343567400205260ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FMATRIXEIGENVALUES_HH #define DUNE_FMATRIXEIGENVALUES_HH /** \file * \brief Eigenvalue computations for the FieldMatrix class */ #include #include #include #include #include #include #include #include namespace Dune { /** @addtogroup DenseMatVec @{ */ namespace FMatrixHelp { #if HAVE_LAPACK // defined in fmatrixev.cc extern void eigenValuesLapackCall( const char* jobz, const char* uplo, const long int* n, double* a, const long int* lda, double* w, double* work, const long int* lwork, long int* info); extern void eigenValuesNonsymLapackCall( const char* jobvl, const char* jobvr, const long int* n, double* a, const long int* lda, double* wr, double* wi, double* vl, const long int* ldvl, double* vr, const long int* ldvr, double* work, const long int* lwork, long int* info); extern void eigenValuesLapackCall( const char* jobz, const char* uplo, const long int* n, float* a, const long int* lda, float* w, float* work, const long int* lwork, long int* info); extern void eigenValuesNonsymLapackCall( const char* jobvl, const char* jobvr, const long int* n, float* a, const long int* lda, float* wr, float* wi, float* vl, const long int* ldvl, float* vr, const long int* ldvr, float* work, const long int* lwork, long int* info); #endif namespace Impl { //internal tag to activate/disable code for eigenvector calculation at compile time enum Jobs { OnlyEigenvalues=0, EigenvaluesEigenvectors=1 }; //internal dummy used if only eigenvalues are to be calculated template using EVDummy = FieldMatrix; //compute the cross-product of two vectors template inline FieldVector crossProduct(const FieldVector& vec0, const FieldVector& vec1) { return {vec0[1]*vec1[2] - vec0[2]*vec1[1], vec0[2]*vec1[0] - vec0[0]*vec1[2], vec0[0]*vec1[1] - vec0[1]*vec1[0]}; } template static void eigenValues2dImpl(const FieldMatrix& matrix, FieldVector& eigenvalues) { using std::sqrt; const K p = 0.5 * (matrix[0][0] + matrix [1][1]); const K p2 = p - matrix[1][1]; K q = p2 * p2 + matrix[1][0] * matrix[0][1]; if( q < 0 && q > -1e-14 ) q = 0; if (q < 0) { std::cout << matrix << std::endl; // Complex eigenvalues are either caused by non-symmetric matrices or by round-off errors DUNE_THROW(MathError, "Complex eigenvalue detected (which this implementation cannot handle)."); } // get square root q = sqrt(q); // store eigenvalues in ascending order eigenvalues[0] = p - q; eigenvalues[1] = p + q; } /* This implementation was adapted from the pseudo-code (Python?) implementation found on http://en.wikipedia.org/wiki/Eigenvalue_algorithm (retrieved late August 2014). Wikipedia claims to have taken it from Smith, Oliver K. (April 1961), Eigenvalues of a symmetric 3 × 3 matrix., Communications of the ACM 4 (4): 168, doi:10.1145/355578.366316 */ template static K eigenValues3dImpl(const FieldMatrix& matrix, FieldVector& eigenvalues) { using std::sqrt; using std::acos; using real_type = typename FieldTraits::real_type; const K pi = MathematicalConstants::pi(); K p1 = matrix[0][1]*matrix[0][1] + matrix[0][2]*matrix[0][2] + matrix[1][2]*matrix[1][2]; if (p1 <= std::numeric_limits::epsilon()) { // A is diagonal. eigenvalues[0] = matrix[0][0]; eigenvalues[1] = matrix[1][1]; eigenvalues[2] = matrix[2][2]; std::sort(eigenvalues.begin(), eigenvalues.end()); return 0.0; } else { // q = trace(A)/3 K q = 0; for (int i=0; i<3; i++) q += matrix[i][i] / 3.0; K p2 = (matrix[0][0] - q)*(matrix[0][0] - q) + (matrix[1][1] - q)*(matrix[1][1] - q) + (matrix[2][2] - q)*(matrix[2][2] - q) + 2.0 * p1; K p = sqrt(p2 / 6); // B = (1 / p) * (A - q * I); // I is the identity matrix FieldMatrix B; for (int i=0; i<3; i++) for (int j=0; j<3; j++) B[i][j] = (real_type(1.0)/p) * (matrix[i][j] - q*(i==j)); K r = B.determinant() / 2.0; /*In exact arithmetic for a symmetric matrix -1 <= r <= 1 but computation error can leave it slightly outside this range. acos(z) function requires |z| <= 1, but will fail silently and return NaN if the input is larger than 1 in magnitude. Thus r is clamped to [-1,1].*/ r = std::min(std::max(r, -1.0), 1.0); K phi = acos(r) / 3.0; // the eigenvalues satisfy eig[2] <= eig[1] <= eig[0] eigenvalues[2] = q + 2 * p * cos(phi); eigenvalues[0] = q + 2 * p * cos(phi + (2*pi/3)); eigenvalues[1] = 3 * q - eigenvalues[0] - eigenvalues[2]; // since trace(matrix) = eig1 + eig2 + eig3 return r; } } //see https://www.geometrictools.com/Documentation/RobustEigenSymmetric3x3.pdf //Robustly compute a right-handed orthonormal set {u, v, evec0}. template void orthoComp(const FieldVector& evec0, FieldVector& u, FieldVector& v) { if(std::abs(evec0[0]) > std::abs(evec0[1])) { //The component of maximum absolute value is either evec0[0] or evec0[2]. FieldVector temp = {evec0[0], evec0[2]}; auto L = 1.0 / temp.two_norm(); u = L * FieldVector({-evec0[2], 0.0, evec0[0]}); } else { //The component of maximum absolute value is either evec0[1] or evec0[2]. FieldVector temp = {evec0[1], evec0[2]}; auto L = 1.0 / temp.two_norm(); u = L * FieldVector({0.0, evec0[2], -evec0[1]}); } v = crossProduct(evec0, u); } //see https://www.geometrictools.com/Documentation/RobustEigenSymmetric3x3.pdf template void eig0(const FieldMatrix& matrix, K eval0, FieldVector& evec0) { /* Compute a unit-length eigenvector for eigenvalue[i0]. The matrix is rank 2, so two of the rows are linearly independent. For a robust computation of the eigenvector, select the two rows whose cross product has largest length of all pairs of rows. */ using Vector = FieldVector; Vector row0 = {matrix[0][0]-eval0, matrix[0][1], matrix[0][2]}; Vector row1 = {matrix[1][0], matrix[1][1]-eval0, matrix[1][2]}; Vector row2 = {matrix[2][0], matrix[2][1], matrix[2][2]-eval0}; Vector r0xr1 = crossProduct(row0, row1); Vector r0xr2 = crossProduct(row0, row2); Vector r1xr2 = crossProduct(row1, row2); auto d0 = r0xr1.two_norm(); auto d1 = r0xr2.two_norm(); auto d2 = r1xr2.two_norm(); auto dmax = d0 ; int imax = 0; if(d1>dmax) { dmax = d1; imax = 1; } if(d2>dmax) imax = 2; if(imax == 0) evec0 = r0xr1 / d0; else if(imax == 1) evec0 = r0xr2 / d1; else evec0 = r1xr2 / d2; } //see https://www.geometrictools.com/Documentation/RobustEigenSymmetric3x3.pdf template void eig1(const FieldMatrix& matrix, const FieldVector& evec0, FieldVector& evec1, K eval1) { using Vector = FieldVector; //Robustly compute a right-handed orthonormal set {u, v, evec0}. Vector u,v; orthoComp(evec0, u, v); /* Let e be eval1 and let E be a corresponding eigenvector which is a solution to the linear system (A - e*I)*E = 0. The matrix (A - e*I) is 3x3, not invertible (so infinitely many solutions), and has rank 2 when eval1 and eval are different. It has rank 1 when eval1 and eval2 are equal. Numerically, it is difficult to compute robustly the rank of a matrix. Instead, the 3x3 linear system is reduced to a 2x2 system as follows. Define the 3x2 matrix J = [u,v] whose columns are the u and v computed previously. Define the 2x1 vector X = J*E. The 2x2 system is 0 = M * X = (J^T * (A - e*I) * J) * X where J^T is the transpose of J and M = J^T * (A - e*I) * J is a 2x2 matrix. The system may be written as +- -++- -+ +- -+ | U^T*A*U - e U^T*A*V || x0 | = e * | x0 | | V^T*A*U V^T*A*V - e || x1 | | x1 | +- -++ -+ +- -+ where X has row entries x0 and x1. */ Vector Au, Av; matrix.mv(u, Au); matrix.mv(v, Av); auto m00 = u.dot(Au) - eval1; auto m01 = u.dot(Av); auto m11 = v.dot(Av) - eval1; /* For robustness, choose the largest-length row of M to compute the eigenvector. The 2-tuple of coefficients of U and V in the assignments to eigenvector[1] lies on a circle, and U and V are unit length and perpendicular, so eigenvector[1] is unit length (within numerical tolerance). */ auto absM00 = std::abs(m00); auto absM01 = std::abs(m01); auto absM11 = std::abs(m11); if(absM00 >= absM11) { auto maxAbsComp = std::max(absM00, absM01); if(maxAbsComp > 0.0) { if(absM00 >= absM01) { m01 /= m00; m00 = 1.0 / std::sqrt(1.0 + m01*m01); m01 *= m00; } else { m00 /= m01; m01 = 1.0 / std::sqrt(1.0 + m00*m00); m00 *= m01; } evec1 = m01*u - m00*v; } else evec1 = u; } else { auto maxAbsComp = std::max(absM11, absM01); if(maxAbsComp > 0.0) { if(absM11 >= absM01) { m01 /= m11; m11 = 1.0 / std::sqrt(1.0 + m01*m01); m01 *= m11; } else { m11 /= m01; m01 = 1.0 / std::sqrt(1.0 + m11*m11); m11 *= m01; } evec1 = m11*u - m01*v; } else evec1 = u; } } // 1d specialization template static void eigenValuesVectorsImpl(const FieldMatrix& matrix, FieldVector& eigenValues, FieldMatrix& eigenVectors) { eigenValues[0] = matrix[0][0]; if constexpr(Tag==EigenvaluesEigenvectors) eigenVectors[0] = {1.0}; } // 2d specialization template static void eigenValuesVectorsImpl(const FieldMatrix& matrix, FieldVector& eigenValues, FieldMatrix& eigenVectors) { // Compute eigen values Impl::eigenValues2dImpl(matrix, eigenValues); // Compute eigenvectors by exploiting the Cayley–Hamilton theorem. // If λ_1, λ_2 are the eigenvalues, then (A - λ_1I )(A - λ_2I ) = (A - λ_2I )(A - λ_1I ) = 0, // so the columns of (A - λ_2I ) are annihilated by (A - λ_1I ) and vice versa. // Assuming neither matrix is zero, the columns of each must include eigenvectors // for the other eigenvalue. (If either matrix is zero, then A is a multiple of the // identity and any non-zero vector is an eigenvector.) // From: https://en.wikipedia.org/wiki/Eigenvalue_algorithm#2x2_matrices if constexpr(Tag==EigenvaluesEigenvectors) { // Special casing for multiples of the identity FieldMatrix temp = matrix; temp[0][0] -= eigenValues[0]; temp[1][1] -= eigenValues[0]; if(temp.infinity_norm() <= 1e-14) { eigenVectors[0] = {1.0, 0.0}; eigenVectors[1] = {0.0, 1.0}; } else { // The columns of A - λ_2I are eigenvectors for λ_1, or zero. // Take the column with the larger norm to avoid zero columns. FieldVector ev0 = {matrix[0][0]-eigenValues[1], matrix[1][0]}; FieldVector ev1 = {matrix[0][1], matrix[1][1]-eigenValues[1]}; eigenVectors[0] = (ev0.two_norm2() >= ev1.two_norm2()) ? ev0/ev0.two_norm() : ev1/ev1.two_norm(); // The columns of A - λ_1I are eigenvectors for λ_2, or zero. // Take the column with the larger norm to avoid zero columns. ev0 = {matrix[0][0]-eigenValues[0], matrix[1][0]}; ev1 = {matrix[0][1], matrix[1][1]-eigenValues[0]}; eigenVectors[1] = (ev0.two_norm2() >= ev1.two_norm2()) ? ev0/ev0.two_norm() : ev1/ev1.two_norm(); } } } // 3d specialization template static void eigenValuesVectorsImpl(const FieldMatrix& matrix, FieldVector& eigenValues, FieldMatrix& eigenVectors) { using Vector = FieldVector; using Matrix = FieldMatrix; //compute eigenvalues /* Precondition the matrix by factoring out the maximum absolute value of the components. This guards against floating-point overflow when computing the eigenvalues.*/ using std::isnormal; K maxAbsElement = (isnormal(matrix.infinity_norm())) ? matrix.infinity_norm() : K(1.0); Matrix scaledMatrix = matrix / maxAbsElement; K r = Impl::eigenValues3dImpl(scaledMatrix, eigenValues); if constexpr(Tag==EigenvaluesEigenvectors) { K offDiagNorm = Vector{scaledMatrix[0][1],scaledMatrix[0][2],scaledMatrix[1][2]}.two_norm2(); if (offDiagNorm <= std::numeric_limits::epsilon()) { eigenValues = {scaledMatrix[0][0], scaledMatrix[1][1], scaledMatrix[2][2]}; eigenVectors = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}}; // Use bubble sort to jointly sort eigenvalues and eigenvectors // such that eigenvalues are ascending if (eigenValues[0] > eigenValues[1]) { std::swap(eigenValues[0], eigenValues[1]); std::swap(eigenVectors[0], eigenVectors[1]); } if (eigenValues[1] > eigenValues[2]) { std::swap(eigenValues[1], eigenValues[2]); std::swap(eigenVectors[1], eigenVectors[2]); } if (eigenValues[0] > eigenValues[1]) { std::swap(eigenValues[0], eigenValues[1]); std::swap(eigenVectors[0], eigenVectors[1]); } } else { /*Compute the eigenvectors so that the set [evec[0], evec[1], evec[2]] is right handed and orthonormal. */ Matrix evec(0.0); Vector eval(eigenValues); if(r >= 0) { Impl::eig0(scaledMatrix, eval[2], evec[2]); Impl::eig1(scaledMatrix, evec[2], evec[1], eval[1]); evec[0] = Impl::crossProduct(evec[1], evec[2]); } else { Impl::eig0(scaledMatrix, eval[0], evec[0]); Impl::eig1(scaledMatrix, evec[0], evec[1], eval[1]); evec[2] = Impl::crossProduct(evec[0], evec[1]); } //sort eval/evec-pairs in ascending order using EVPair = std::pair; std::vector pairs; for(std::size_t i=0; i<=2; ++i) pairs.push_back(EVPair(eval[i], evec[i])); auto comp = [](EVPair x, EVPair y){ return x.first < y.first; }; std::sort(pairs.begin(), pairs.end(), comp); for(std::size_t i=0; i<=2; ++i){ eigenValues[i] = pairs[i].first; eigenVectors[i] = pairs[i].second; } } } //The preconditioning scaled the matrix, which scales the eigenvalues. Revert the scaling. eigenValues *= maxAbsElement; } // forwarding to LAPACK with corresponding tag template static void eigenValuesVectorsLapackImpl(const FieldMatrix& matrix, FieldVector& eigenValues, FieldMatrix& eigenVectors) { { #if HAVE_LAPACK /*Lapack uses a proprietary tag to determine whether both eigenvalues and -vectors ('v') or only eigenvalues ('n') should be calculated */ const char jobz = "nv"[Tag]; const long int N = dim ; const char uplo = 'u'; // use upper triangular matrix // length of matrix vector, LWORK >= max(1,3*N-1) const long int lwork = 3*N -1 ; constexpr bool isKLapackType = std::is_same_v || std::is_same_v; using LapackNumType = std::conditional_t; // matrix to put into dsyev LapackNumType matrixVector[dim * dim]; // copy matrix int row = 0; for(int i=0; i static void eigenValuesVectorsImpl(const FieldMatrix& matrix, FieldVector& eigenValues, FieldMatrix& eigenVectors) { eigenValuesVectorsLapackImpl(matrix,eigenValues,eigenVectors); } } //namespace Impl /** \brief calculates the eigenvalues of a symmetric field matrix \param[in] matrix matrix eigenvalues are calculated for \param[out] eigenValues FieldVector that contains eigenvalues in ascending order \note specializations for dim=1,2,3 exist, for dim>3 LAPACK::dsyev is used */ template static void eigenValues(const FieldMatrix& matrix, FieldVector& eigenValues) { Impl::EVDummy dummy; Impl::eigenValuesVectorsImpl(matrix, eigenValues, dummy); } /** \brief calculates the eigenvalues and eigenvectors of a symmetric field matrix \param[in] matrix matrix eigenvalues are calculated for \param[out] eigenValues FieldVector that contains eigenvalues in ascending order \param[out] eigenVectors FieldMatrix that contains the eigenvectors \note specializations for dim=1,2,3 exist, for dim>3 LAPACK::dsyev is used */ template static void eigenValuesVectors(const FieldMatrix& matrix, FieldVector& eigenValues, FieldMatrix& eigenVectors) { Impl::eigenValuesVectorsImpl(matrix, eigenValues, eigenVectors); } /** \brief calculates the eigenvalues of a symmetric field matrix \param[in] matrix matrix eigenvalues are calculated for \param[out] eigenValues FieldVector that contains eigenvalues in ascending order \note LAPACK::dsyev is used to calculate the eigenvalues */ template static void eigenValuesLapack(const FieldMatrix& matrix, FieldVector& eigenValues) { Impl::EVDummy dummy; Impl::eigenValuesVectorsLapackImpl(matrix, eigenValues, dummy); } /** \brief calculates the eigenvalues and -vectors of a symmetric field matrix \param[in] matrix matrix eigenvalues are calculated for \param[out] eigenValues FieldVector that contains eigenvalues in ascending order \param[out] eigenVectors FieldMatrix that contains the eigenvectors \note LAPACK::dsyev is used to calculate the eigenvalues and -vectors */ template static void eigenValuesVectorsLapack(const FieldMatrix& matrix, FieldVector& eigenValues, FieldMatrix& eigenVectors) { Impl::eigenValuesVectorsLapackImpl(matrix, eigenValues, eigenVectors); } /** \brief calculates the eigenvalues of a non-symmetric field matrix \param[in] matrix matrix eigenvalues are calculated for \param[out] eigenValues FieldVector that contains eigenvalues in ascending order \note LAPACK::dgeev is used to calculate the eigenvalues */ template static void eigenValuesNonSym(const FieldMatrix& matrix, FieldVector& eigenValues) { #if HAVE_LAPACK { const long int N = dim ; const char jobvl = 'n'; const char jobvr = 'n'; constexpr bool isKLapackType = std::is_same_v || std::is_same_v; using LapackNumType = std::conditional_t; // matrix to put into dgeev LapackNumType matrixVector[dim * dim]; // copy matrix int row = 0; for(int i=0; i #include namespace Dune { /** @addtogroup DenseMatVec \brief Type traits to retrieve the field and the real type of classes Type traits to retrieve the field and the real type of classes e.g. that of FieldVector or FieldMatrix */ template struct FieldTraits { //! export the type representing the field typedef T field_type; //! export the type representing the real type of the field typedef T real_type; }; template struct FieldTraits { typedef typename FieldTraits::field_type field_type; typedef typename FieldTraits::real_type real_type; }; template struct FieldTraits< std::complex > { typedef std::complex field_type; typedef T real_type; }; template struct FieldTraits< T[N] > { typedef typename FieldTraits::field_type field_type; typedef typename FieldTraits::real_type real_type; }; template struct FieldTraits< std::vector > { typedef typename FieldTraits::field_type field_type; typedef typename FieldTraits::real_type real_type; }; } // end namespace Dune #endif // DUNE_FTRAITS_HH dune-common-2.8.0/dune/common/function.hh000066400000000000000000000110051411343567400203400ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FUNCTION_HH_SILENCE_DEPRECATION #warning This file is deprecated after Dune 2.7! Use C++ function objects and std::function stuff instead! #else // !DUNE_FUNCTION_HH_SILENCE_DEPRECATION #undef DUNE_FUNCTION_HH_SILENCE_DEPRECATION #endif // !DUNE_FUNCTION_HH_SILENCE_DEPRECATION #ifndef DUNE_FUNCTION_HH #define DUNE_FUNCTION_HH #include #include #include "typetraits.hh" namespace Dune { /** @addtogroup Common @{ */ /*! \file \brief Simple base class templates for functions. */ /** * \brief Base class template for function classes * * \tparam Domain Type of input variable. This could be some 'const T' or 'const T&'. * * \tparam Range Type of output variable. This should be some non-const 'T&' to allow to return results. */ template class [[deprecated("Dune::Function is deprecated after Dune 2.7. Use C++ " "function objects instead!")]] Function { typedef typename std::remove_cv::type >::type RawDomainType; typedef typename std::remove_cv::type >::type RawRangeType; public: //! Raw type of input variable with removed reference and constness typedef RawRangeType RangeType; //! Raw type of output variable with removed reference and constness typedef RawDomainType DomainType; //! Traits class containing raw types struct Traits { typedef RawDomainType DomainType; typedef RawRangeType RangeType; }; /** * \brief Function evaluation. * * \param x Argument for function evaluation. * \param y Result of function evaluation. */ void evaluate(const typename Traits::DomainType& x, typename Traits::RangeType& y) const; }; // end of Function class DUNE_NO_DEPRECATED_BEGIN /** * \brief Virtual base class template for function classes. * * \see makeVirtualFunction for a helper to convert lambda functions to * `VirtualFunction` objects. * * \tparam DomainType The type of the input variable is 'const DomainType &' * * \tparam RangeType The type of the output variable is 'RangeType &' */ template class [[deprecated("Dune::VirtualFunction is deprecated after Dune 2.7. Use C++ " "function objects and std::function instead!")]] VirtualFunction : public Function { public: typedef typename Function::Traits Traits; virtual ~VirtualFunction() {} /** * \brief Function evaluation. * * \param x Argument for function evaluation. * \param y Result of function evaluation. */ virtual void evaluate(const typename Traits::DomainType& x, typename Traits::RangeType& y) const = 0; }; // end of VirtualFunction class DUNE_NO_DEPRECATED_END namespace Impl { DUNE_NO_DEPRECATED_BEGIN template class LambdaVirtualFunction final : public VirtualFunction { public: LambdaVirtualFunction(F&& f) : f_(std::move(f)) {} LambdaVirtualFunction(const F& f) : f_(f) {} void evaluate(const Domain& x, Range& y) const override { y = f_(x); } private: const F f_; }; DUNE_NO_DEPRECATED_END } /* namespace Impl */ /** * \brief make `VirtualFunction` out of a function object * * This helper function wraps a function object into a class implementing * the `VirtualFunction` interface. It allows for easy use of lambda * expressions in places that expect a `VirtualFunction`: \code void doSomething(const VirtualFunction& f); auto f = makeVirtualFunction( [](double x) { return x*x; }); doSomething(f); \endcode * * \returns object of a class derived from `VirtualFunction` * * \tparam Domain domain of the function * \tparam Range range of the function */ template [[deprecated("Dune::LambdaVirtualFunction is deprecated after Dune 2.7. " "Use std::function instead!")]] Impl::LambdaVirtualFunction< Domain, Range, std::decay_t > makeVirtualFunction(F&& f) { return {std::forward(f)}; } /** @} end documentation */ } // end namespace #endif dune-common-2.8.0/dune/common/fvector.hh000066400000000000000000000413771411343567400202020ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_FVECTOR_HH #define DUNE_FVECTOR_HH #include #include #include #include #include #include #include #include #include #include "typetraits.hh" #include "exceptions.hh" #include "ftraits.hh" #include "densevector.hh" #include "boundschecking.hh" #include #include namespace Dune { /** @addtogroup DenseMatVec @{ */ /*! \file * \brief Implements a vector constructed from a given type representing a field and a compile-time given size. */ template< class K, int SIZE > class FieldVector; template< class K, int SIZE > struct DenseMatVecTraits< FieldVector > { typedef FieldVector derived_type; typedef std::array container_type; typedef K value_type; typedef typename container_type::size_type size_type; }; template< class K, int SIZE > struct FieldTraits< FieldVector > { typedef typename FieldTraits::field_type field_type; typedef typename FieldTraits::real_type real_type; }; /** * @brief TMP to check the size of a DenseVectors statically, if possible. * * If the implementation type of C is a FieldVector, we statically check * whether its dimension is SIZE. * @tparam C The implementation of the other DenseVector * @tparam SIZE The size we need assume. */ template struct IsFieldVectorSizeCorrect { enum { /** *@param True if C is not of type FieldVector or its dimension * is not equal SIZE. */ value = true }; }; template struct IsFieldVectorSizeCorrect,SIZE> { enum {value = true}; }; template struct IsFieldVectorSizeCorrect,SIZE> { enum {value = false}; }; /** \brief vector space out of a tensor product of fields. * * \tparam K the field type (use float, double, complex, etc) * \tparam SIZE number of components. */ template< class K, int SIZE > class FieldVector : public DenseVector< FieldVector > { std::array _data; typedef DenseVector< FieldVector > Base; public: //! export size enum { //! The size of this vector. dimension = SIZE }; typedef typename Base::size_type size_type; typedef typename Base::value_type value_type; /** \brief The type used for references to the vector entry */ typedef value_type& reference; /** \brief The type used for const references to the vector entry */ typedef const value_type& const_reference; //! Constructor making default-initialized vector constexpr FieldVector() : _data{{}} {} //! Constructor making vector with identical coordinates explicit FieldVector (const K& t) { std::fill(_data.begin(),_data.end(),t); } #if __GNUC__ == 5 && !defined(__clang__) // `... = default;` causes an internal compiler error on GCC 5.4 (Ubuntu 16.04) //! copy constructor FieldVector(const FieldVector& x) : _data(x._data) {} #else //! Copy constructor FieldVector (const FieldVector&) = default; #endif /** \brief Construct from a std::initializer_list */ FieldVector (std::initializer_list const &l) { assert(l.size() == dimension);// Actually, this is not needed any more! std::copy_n(l.begin(), std::min(static_cast(dimension), l.size()), _data.begin()); } //! copy assignment operator FieldVector& operator= (const FieldVector&) = default; template FieldVector& operator= (const FieldVector& x) { std::copy_n(x.begin(), SIZE, _data.begin()); return *this; } template FieldVector& operator=(const FieldVector&) = delete; /** * \brief Copy constructor from a second vector of possibly different type * * If the DenseVector type of the this constructor's argument * is implemented by a FieldVector, it is statically checked * if it has the correct size. If this is not the case * the constructor is removed from the overload set using SFINAE. * * \param[in] x A DenseVector with correct size. * \param[in] dummy A void* dummy argument needed by SFINAE. */ template FieldVector (const DenseVector & x, [[maybe_unused]] typename std::enable_if::value>::type* dummy=0) { // do a run-time size check, for the case that x is not a FieldVector assert(x.size() == SIZE); // Actually this is not needed any more! std::copy_n(x.begin(), std::min(static_cast(SIZE),x.size()), _data.begin()); } //! Constructor making vector with identical coordinates template explicit FieldVector (const FieldVector & x) { std::copy_n(x.begin(), SIZE, _data.begin()); } template explicit FieldVector(const FieldVector&) = delete; using Base::operator=; // make this thing a vector static constexpr size_type size () { return SIZE; } K & operator[](size_type i) { DUNE_ASSERT_BOUNDS(i < SIZE); return _data[i]; } const K & operator[](size_type i) const { DUNE_ASSERT_BOUNDS(i < SIZE); return _data[i]; } //! return pointer to underlying array K* data() noexcept { return _data.data(); } //! return pointer to underlying array const K* data() const noexcept { return _data.data(); } //! vector space multiplication with scalar template ::value, int> = 0> friend auto operator* ( const FieldVector& vector, Scalar scalar) { FieldVector::PromotedType,SIZE> result; for (size_type i = 0; i < vector.size(); ++i) result[i] = vector[i] * scalar; return result; } //! vector space multiplication with scalar template ::value, int> = 0> friend auto operator* ( Scalar scalar, const FieldVector& vector) { FieldVector::PromotedType,SIZE> result; for (size_type i = 0; i < vector.size(); ++i) result[i] = scalar * vector[i]; return result; } //! vector space division by scalar template ::value, int> = 0> friend auto operator/ ( const FieldVector& vector, Scalar scalar) { FieldVector::PromotedType,SIZE> result; for (size_type i = 0; i < vector.size(); ++i) result[i] = vector[i] / scalar; return result; } }; /** \brief Read a FieldVector from an input stream * \relates FieldVector * * \note This operator is STL compliant, i.e., the content of v is only * changed if the read operation is successful. * * \param[in] in std :: istream to read from * \param[out] v FieldVector to be read * * \returns the input stream (in) */ template inline std::istream &operator>> ( std::istream &in, FieldVector &v ) { FieldVector w; for( typename FieldVector::size_type i = 0; i < SIZE; ++i ) in >> w[ i ]; if(in) v = w; return in; } #ifndef DOXYGEN template< class K > struct DenseMatVecTraits< FieldVector > { typedef FieldVector derived_type; typedef K container_type; typedef K value_type; typedef size_t size_type; }; /** \brief Vectors containing only one component */ template class FieldVector : public DenseVector< FieldVector > { K _data; typedef DenseVector< FieldVector > Base; public: //! export size enum { //! The size of this vector. dimension = 1 }; typedef typename Base::size_type size_type; /** \brief The type used for references to the vector entry */ typedef K& reference; /** \brief The type used for const references to the vector entry */ typedef const K& const_reference; //===== construction /** \brief Default constructor */ constexpr FieldVector () : _data() {} /** \brief Constructor with a given scalar */ template::value && ! std::is_base_of::field_type>, K >::value >::type > FieldVector (const T& k) : _data(k) {} //! Constructor from static vector of different type template::value_type>::value, int> = 0> FieldVector (const DenseVector & x) { static_assert(((bool)IsFieldVectorSizeCorrect::value), "FieldVectors do not match in dimension!"); assert(x.size() == 1); _data = x[0]; } //! copy constructor FieldVector(const FieldVector&) = default; //! copy assignment operator FieldVector& operator=(const FieldVector&) = default; template FieldVector& operator= (const FieldVector& other) { _data = other[0]; return *this; } template FieldVector& operator=(const FieldVector&) = delete; /** \brief Construct from a std::initializer_list */ FieldVector (std::initializer_list const &l) { assert(l.size() == 1); _data = *l.begin(); } //! Assignment operator for scalar template::value && ! std::is_base_of::field_type>, K >::value >::type > inline FieldVector& operator= (const T& k) { _data = k; return *this; } //===== forward methods to container static constexpr size_type size () { return 1; } K & operator[]([[maybe_unused]] size_type i) { DUNE_ASSERT_BOUNDS(i == 0); return _data; } const K & operator[]([[maybe_unused]] size_type i) const { DUNE_ASSERT_BOUNDS(i == 0); return _data; } //! return pointer to underlying array K* data() noexcept { return &_data; } //! return pointer to underlying array const K* data() const noexcept { return &_data; } //===== conversion operator /** \brief Conversion operator */ operator K& () { return _data; } /** \brief Const conversion operator */ operator const K& () const { return _data; } }; /* ----- FV / FV ----- */ /* mostly not necessary as these operations are already covered via the cast operator */ //! Binary compare, when using FieldVector like K template inline bool operator> (const FieldVector& a, const FieldVector& b) { return a[0]>b[0]; } //! Binary compare, when using FieldVector like K template inline bool operator>= (const FieldVector& a, const FieldVector& b) { return a[0]>=b[0]; } //! Binary compare, when using FieldVector like K template inline bool operator< (const FieldVector& a, const FieldVector& b) { return a[0] like K template inline bool operator<= (const FieldVector& a, const FieldVector& b) { return a[0]<=b[0]; } /* ----- FV / scalar ----- */ //! Binary addition, when using FieldVector like K template inline FieldVector operator+ (const FieldVector& a, const K b) { return a[0]+b; } //! Binary subtraction, when using FieldVector like K template inline FieldVector operator- (const FieldVector& a, const K b) { return a[0]-b; } //! Binary multiplication, when using FieldVector like K template inline FieldVector operator* (const FieldVector& a, const K b) { return a[0]*b; } //! Binary division, when using FieldVector like K template inline FieldVector operator/ (const FieldVector& a, const K b) { return a[0]/b; } //! Binary compare, when using FieldVector like K template inline bool operator> (const FieldVector& a, const K b) { return a[0]>b; } //! Binary compare, when using FieldVector like K template inline bool operator>= (const FieldVector& a, const K b) { return a[0]>=b; } //! Binary compare, when using FieldVector like K template inline bool operator< (const FieldVector& a, const K b) { return a[0] like K template inline bool operator<= (const FieldVector& a, const K b) { return a[0]<=b; } //! Binary compare, when using FieldVector like K template inline bool operator== (const FieldVector& a, const K b) { return a[0]==b; } //! Binary compare, when using FieldVector like K template inline bool operator!= (const FieldVector& a, const K b) { return a[0]!=b; } /* ----- scalar / FV ------ */ //! Binary addition, when using FieldVector like K template inline FieldVector operator+ (const K a, const FieldVector& b) { return a+b[0]; } //! Binary subtraction, when using FieldVector like K template inline FieldVector operator- (const K a, const FieldVector& b) { return a-b[0]; } //! Binary multiplication, when using FieldVector like K template inline FieldVector operator* (const K a, const FieldVector& b) { return a*b[0]; } //! Binary division, when using FieldVector like K template inline FieldVector operator/ (const K a, const FieldVector& b) { return a/b[0]; } //! Binary compare, when using FieldVector like K template inline bool operator> (const K a, const FieldVector& b) { return a>b[0]; } //! Binary compare, when using FieldVector like K template inline bool operator>= (const K a, const FieldVector& b) { return a>=b[0]; } //! Binary compare, when using FieldVector like K template inline bool operator< (const K a, const FieldVector& b) { return a like K template inline bool operator<= (const K a, const FieldVector& b) { return a<=b[0]; } //! Binary compare, when using FieldVector like K template inline bool operator== (const K a, const FieldVector& b) { return a==b[0]; } //! Binary compare, when using FieldVector like K template inline bool operator!= (const K a, const FieldVector& b) { return a!=b[0]; } #endif /* Overloads for common classification functions */ namespace MathOverloads { // ! Returns whether all entries are finite template auto isFinite(const FieldVector &b, PriorityTag<2>, ADLTag) { bool out = true; for(int i=0; i bool isInf(const FieldVector &b, PriorityTag<2>, ADLTag) { bool out = false; for(int i=0; i::value>> bool isNaN(const FieldVector &b, PriorityTag<2>, ADLTag) { bool out = false; for(int i=0; i::value>> bool isUnordered(const FieldVector &b, const FieldVector &c, PriorityTag<2>, ADLTag) { return Dune::isUnordered(b[0],c[0]); } } //MathOverloads /** @} end documentation */ } // end namespace #endif dune-common-2.8.0/dune/common/gcd.hh000066400000000000000000000011621411343567400172530ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_GCD_HH #define DUNE_GCD_HH #warning "This header is deprecated and will be removed after Dune release 2.8. Use std::gcd instead" #include namespace Dune { /** * @brief Calculator of the greatest common divisor. */ template struct [[deprecated("Will be removed after Dune 2.8. Use std::gcd from instead!")]] Gcd { /** * @brief The greatest common divisior of a and b. */ constexpr static long value = std::gcd(a,b); }; /** * @} */ } #endif dune-common-2.8.0/dune/common/genericiterator.hh000066400000000000000000000172261411343567400217140ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_GENERICITERATOR_HH #define DUNE_GENERICITERATOR_HH #include #include namespace Dune { /*! \defgroup GenericIterator GenericIterator \ingroup IteratorFacades \brief Generic Iterator class for writing stl conformant iterators for any container class with operator[] Using this template class you can create an iterator and a const_iterator for any container class. Imagine you have SimpleContainer and would like to have an iterator. All you have to do is provide operator[], begin() and end() (for const and for non-const). \code template class SimpleContainer{ public: typedef GenericIterator,T> iterator; typedef GenericIterator,const T> const_iterator; SimpleContainer(){ for(int i=0; i < 100; i++) values_[i]=i; } iterator begin(){ return iterator(*this, 0); } const_iterator begin() const{ return const_iterator(*this, 0); } iterator end(){ return iterator(*this, 100); } const_iterator end() const{ return const_iterator(*this, 100); } T& operator[](int i){ return values_[i]; } const T& operator[](int i) const{ return values_[i]; } private: T values_[100]; }; \endcode See dune/common/test/iteratorfacestest.hh for details or Dune::QuadratureDefault in dune/quadrature/quadrature.hh for a real example. */ /** * @file * @brief Implements a generic iterator class for writing stl conformant iterators. * * Using this generic iterator writing iterators for containers * that implement operator[] is only a matter of seconds. */ /** \brief Get the 'const' version of a reference to a mutable object Given a reference R=T& const_reference::type gives you the typedef for const T& */ template struct const_reference { typedef const R type; }; template struct const_reference { typedef const R type; }; template struct const_reference { typedef const R& type; }; template struct const_reference { typedef const R& type; }; /** \brief get the 'mutable' version of a reference to a const object given a const reference R=const T& mutable_reference::type gives you the typedef for T& */ template struct mutable_reference { typedef R type; }; template struct mutable_reference { typedef R type; }; template struct mutable_reference { typedef R& type; }; template struct mutable_reference { typedef R& type; }; /** @addtogroup GenericIterator * * @{ */ /** * @brief Generic class for stl-conforming iterators for container classes with operator[]. * * If template parameter C has a const qualifier we are a const iterator, otherwise we * are a mutable iterator. */ template class IteratorFacade=RandomAccessIteratorFacade> class GenericIterator : public IteratorFacade,T,R,D> { friend class GenericIterator::type, typename std::remove_const::type, typename mutable_reference::type, D, IteratorFacade>; friend class GenericIterator::type, const typename std::remove_const::type, typename const_reference::type, D, IteratorFacade>; typedef GenericIterator::type, typename std::remove_const::type, typename mutable_reference::type, D, IteratorFacade> MutableIterator; typedef GenericIterator::type, const typename std::remove_const::type, typename const_reference::type, D, IteratorFacade> ConstIterator; public: /** * @brief The type of container we are an iterator for. * * The container type must provide an operator[] method. * * If C has a const qualifier we are a const iterator, otherwise we * are a mutable iterator. */ typedef C Container; /** * @brief The value type of the iterator. * * This is the return type when dereferencing the iterator. */ typedef T Value; /** * @brief The type of the difference between two positions. */ typedef D DifferenceType; /** * @brief The type of the reference to the values accessed. */ typedef R Reference; // Constructors needed by the base iterators GenericIterator() : container_(0), position_(0) {} /** * @brief Constructor * @param cont Reference to the container we are an iterator for * @param pos The position the iterator will be positioned to * (e.g. 0 for an iterator returned by Container::begin() or * the size of the container for an iterator returned by Container::end() */ GenericIterator(Container& cont, DifferenceType pos) : container_(&cont), position_(pos) {} /** * @brief Copy constructor * * This is somehow hard to understand, therefore play with the cases: * 1. if we are mutable this is the only valid copy constructor, as the argument is a mutable iterator * 2. if we are a const iterator the argument is a mutable iterator => This is the needed conversion to initialize a const iterator from a mutable one. */ GenericIterator(const MutableIterator& other) : container_(other.container_), position_(other.position_) {} /** * @brief Copy constructor * * @warning Calling this method results in a compiler error, if this is a mutable iterator. * * This is somehow hard to understand, therefore play with the cases: * 1. if we are mutable the arguments is a const iterator and therefore calling this method is mistake in the user's code and results in a (probably not understandable) compiler error * 2. If we are a const iterator this is the default copy constructor as the argument is a const iterator too. */ GenericIterator(const ConstIterator& other) : container_(other.container_), position_(other.position_) {} // Methods needed by the forward iterator bool equals(const MutableIterator & other) const { return position_ == other.position_ && container_ == other.container_; } bool equals(const ConstIterator & other) const { return position_ == other.position_ && container_ == other.container_; } Reference dereference() const { return container_->operator[](position_); } void increment(){ ++position_; } // Additional function needed by BidirectionalIterator void decrement(){ --position_; } // Additional function needed by RandomAccessIterator Reference elementAt(DifferenceType i) const { return container_->operator[](position_+i); } void advance(DifferenceType n){ position_=position_+n; } DifferenceType distanceTo(const MutableIterator& other) const { assert(other.container_==container_); return other.position_ - position_; } DifferenceType distanceTo(const ConstIterator& other) const { assert(other.container_==container_); return other.position_ - position_; } private: Container *container_; DifferenceType position_; }; /** @} */ } // end namespace Dune #endif dune-common-2.8.0/dune/common/gmpfield.hh000066400000000000000000000046701411343567400203140ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_GMPFIELD_HH #define DUNE_GMPFIELD_HH /** \file * \brief Wrapper for the GNU multiprecision (GMP) library */ #include #include #include #if HAVE_GMP || DOXYGEN #include #include #include namespace Dune { /** * \ingroup Numbers * \brief Number class for high precision floating point number using the GMP library mpf_class implementation */ template< unsigned int precision > class GMPField : public mpf_class { typedef mpf_class Base; public: /** default constructor, initialize to zero */ GMPField () : Base(0,precision) {} /** \brief initialize from a string \note this is the only reliable way to initialize with higher precision values */ GMPField ( const char* str ) : Base(str,precision) {} /** \brief initialize from a string \note this is the only reliable way to initialize with higher precision values */ GMPField ( const std::string& str ) : Base(str,precision) {} /** \brief initialize from a compatible scalar type */ template< class T, typename EnableIf = typename std::enable_if< std::is_convertible::value>::type > GMPField ( const T &v ) : Base( v,precision ) {} // type conversion operators operator double () const { return this->get_d(); } }; template struct IsNumber> : public std::integral_constant { }; template< unsigned int precision1, unsigned int precision2 > struct PromotionTraits, GMPField> { typedef GMPField<(precision1 > precision2 ? precision1 : precision2)> PromotedType; }; template< unsigned int precision > struct PromotionTraits,GMPField> { typedef GMPField PromotedType; }; template< unsigned int precision, class T > struct PromotionTraits, T> { typedef GMPField PromotedType; }; template< class T, unsigned int precision > struct PromotionTraits> { typedef GMPField PromotedType; }; } #endif // HAVE_GMP #endif // #ifndef DUNE_GMPFIELD_HH dune-common-2.8.0/dune/common/hash.hh000066400000000000000000000312271411343567400174460ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_HASH_HH #define DUNE_COMMON_HASH_HH #include #include /** * \file * \brief Support for calculating hash values of objects. * * This file provides the functor Dune::hash to calculate hash values and * some infrastructure to simplify extending Dune::hash for user-defined types, * independent of the actual underlying implementation. * */ // ******************************************************************************** // Doxygen documentation // ******************************************************************************** #ifdef DOXYGEN namespace Dune { //! Functor for hashing objects of type T. /** * The interface outlined below is compatible with std::hash, std::tr1::hash and * boost::hash, so it is possible to use Dune::hash in associative containers from * those libraries. */ template struct hash { //! Calculates the hash of t. std::size_t operator()(const T& t) const { return hash(t); } }; } //! Defines the required struct specialization to make type hashable via `Dune::hash`. /** * In order to calculate the hash, operator() of the generated specialization will * return the result of an unqualified call to the global function `hash_value(const type&)`. * As the call is not qualified, the function will be found using argument-dependent lookup, * allowing implementors to conveniently place it inside the class body. * * Consider the following type: * * \code * namespace ns { * template * class Foo * { * ... * }; * } * \endcode * * In order to add support for `Dune::hash`, you need to extend the definition like this: * * \code * namespace ns { * template * class Foo * { * ... * // The keyword "friend" turns this into a global function that is a friend of Foo. * inline friend std::size_t hash_value(const Foo& arg) * { * return ...; * } * }; * } * * // Define hash struct specialization * DUNE_DEFINE_HASH(DUNE_HASH_TEMPLATE_ARGS(typename A, int i),DUNE_HASH_TYPE(Foo)) * \endcode * * \warning * As the specialization has to be placed in the original namespace of the * `hash` struct (e.g. `std`), this macro *must* be called from the global namespace! * * \param template_args The template arguments required by the hash struct specialization, * wrapped in a call to DUNE_HASH_TEMPLATE_ARGS. If this is a complete * specialization, call DUNE_HASH_TEMPLATE_ARGS without arguments. * \param type The exact type of the specialization, wrapped in a call to DUNE_HASH_TYPE. */ #define DUNE_DEFINE_HASH(template_args,type) //! Wrapper macro for the template arguments in DUNE_DEFINE_HASH. /** * This macro should always be used as a wrapper for the template arguments when calling DUNE_DEFINE_HASH. * It works around some preprocessor limitations when the template arguments contain commas or the list * is completely empty. */ #define DUNE_HASH_TEMPLATE_ARGS(...) //! Wrapper macro for the type to be hashed in DUNE_DEFINE_HASH. /** * This macro should always be used as a wrapper for the type of the specialization when calling * DUNE_DEFINE_HASH. * It works around some preprocessor limitations when the type contains commas. */ #define DUNE_HASH_TYPE(...) #else // DOXYGEN - hide all the ugly implementation // ******************************************************************************** // C++11 support // ******************************************************************************** // import std::hash into Dune namespace namespace Dune { using std::hash; } // Macro for defining a std::hash specialization for type. // This should not be called directly. Call DUNE_DEFINE_HASH // instead. #define DUNE_DEFINE_STD_HASH(template_args,type) \ namespace std { \ \ template \ struct hash \ { \ \ typedef type argument_type; \ typedef std::size_t result_type; \ \ std::size_t operator()(const type& arg) const \ { \ return hash_value(arg); \ } \ }; \ \ template \ struct hash \ { \ \ typedef type argument_type; \ typedef std::size_t result_type; \ \ std::size_t operator()(const type& arg) const \ { \ return hash_value(arg); \ } \ }; \ \ } \ // Wrapper macro for template arguments. // This is required because the template arguments can contain commas, // which will create a macro argument list of unknown length. That in itself // would not be a problem, but DUNE_DEFINE_HASH has to be called with two argument // lists of unknown length. So this macro wraps its arguments with parentheses, // turning it into a single argument. The result is used as the parameter list of // an expansion macro in the calls to the implementation-specific macros // for C++11 and TR1. Noto that technically, this trick is only legal for C++11, // but pretty much every compiler supports variadic macros in C++03 mode, as they // are part of C99. #define DUNE_HASH_TEMPLATE_ARGS(...) (__VA_ARGS__) // Wrapper macro for type to be hashed. // See above for rationale. #define DUNE_HASH_TYPE(...) (__VA_ARGS__) // Expansion macro for the parenthesed argument lists created by // DUNE_HASH_TEMPLATE_ARGS and DUNE_HASH_TYPE. #define DUNE_HASH_EXPAND_VA_ARGS(...) __VA_ARGS__ // Define specializations for all discovered hash implementations. #define DUNE_DEFINE_HASH(template_args,type) \ DUNE_DEFINE_STD_HASH(DUNE_HASH_EXPAND_VA_ARGS template_args, DUNE_HASH_EXPAND_VA_ARGS type) \ #endif // DOXYGEN // ******************************************************************************** // Some utility functions for combining hashes of member variables. // ******************************************************************************** namespace Dune { // The following functions are an implementation of the proposed hash extensions for // the C++ standard by Peter Dimov // (cf. http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf, issue 6.18). // They are also contained in the boost::functional::hash library by Daniel James, but // that implementation uses boost::hash internally, while we want to use Dune::hash. They // are also considered for inclusion in TR2 (then based on std::hash, of course). #ifndef DOXYGEN // helper struct for providing different hash combining algorithms dependent on // the size of size_t. // hash_combiner has to be specialized for the size (in bytes) of std::size_t. // Specialized versions should provide a method // // template // void operator()(typeof_size_t& seed, const T& arg) const; // // that will be called by the interface function hash_combine() described further below. // The redundant template parameter typeof_size_t is needed to avoid warnings for the // unused 64-bit specialization on 32-bit systems. // // There is no default implementation! template struct hash_combiner; // hash combining for 64-bit platforms. template<> struct hash_combiner<8> { template void operator()(typeof_size_t& seed, const T& arg) const { static_assert(sizeof(typeof_size_t)==8, "hash_combiner::operator() instantiated with nonmatching type and size"); // The following algorithm for combining two 64-bit hash values is inspired by a similar // function in CityHash (http://cityhash.googlecode.com/svn-history/r2/trunk/src/city.h), // which is in turn based on ideas from the MurmurHash library. The basic idea is easy to // grasp, though: New information is XORed into the existing hash multiple times at different // places (using shift operations), and the resulting pattern is spread over the complete // range of available bits via multiplication with a "magic" constant. The constants used // below (47 and 0x9ddfea08eb382d69ULL) are taken from the CityHash implementation. // // We opted not to use the mixing algorithm proposed in the C++ working group defect list at // http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2005/n1756.pdf, p. 57f. because it // has very bad hash distribution properties if you apply it to lists of very small numbers, // an application that is frequent in PDELab's ordering framework. Dune::hash hasher; const typeof_size_t kMul = 0x9ddfea08eb382d69ULL; typeof_size_t h = hasher(arg); typeof_size_t a = (seed ^ h) * kMul; a ^= (a >> 47); typeof_size_t b = (h ^ a) * kMul; b ^= (b >> 47); b *= kMul; seed = b; } }; // hash combining for 32-bit platforms. template<> struct hash_combiner<4> { template void operator()(typeof_size_t& seed, const T& arg) const { static_assert(sizeof(typeof_size_t)==4, "hash_combiner::operator() instantiated with nonmatching type and size"); // The default algorithm above requires a 64-bit std::size_t. The following algorithm is a // 32-bit compatible fallback, again inspired by CityHash and MurmurHash // (http://cityhash.googlecode.com/svn-history/r2/trunk/src/city.cc). // It uses 32-bit constants and relies on rotation instead of multiplication to spread the // mixed bits as that is apparently more efficient on IA-32. The constants used below are again // taken from CityHash, in particular from the file referenced above. Dune::hash hasher; const typeof_size_t c1 = 0xcc9e2d51; const typeof_size_t c2 = 0x1b873593; const typeof_size_t c3 = 0xe6546b64; typeof_size_t h = hasher(arg); typeof_size_t a = seed * c1; a = (a >> 17) | (a << (32 - 17)); a *= c2; h ^= a; h = (h >> 19) | (h << (32 - 19)); seed = h * 5 + c3; } }; #endif // DOXYGEN //! Calculates the hash value of arg and combines it in-place with seed. /** * * \param seed The hash value that will be combined with the hash of arg. * \param arg The object for which to calculate a hash value and combine it with seed. */ template inline void hash_combine(std::size_t& seed, const T& arg) { hash_combiner()(seed,arg); } //! Hashes all elements in the range [first,last) and returns the combined hash. /** * * \param first Iterator pointing to the first object to hash. * \param last Iterator pointing one past the last object to hash. * \returns The result of hashing all objects in the range and combining them * using hash_combine() in sequential fashion, starting with seed 0. */ template inline std::size_t hash_range(It first, It last) { std::size_t seed = 0; for (; first != last; ++first) { hash_combine(seed,*first); } return seed; } //! Hashes all elements in the range [first,last) and combines the hashes in-place with seed. /** * * \param seed Start value that will be combined with the hash values of all objects in * the range using hash_combine() in sequential fashion. * \param first Iterator pointing to the first ojbect to hash. * \param last Iterator pointing one past the last object to hash. */ template inline void hash_range(std::size_t& seed, It first, It last) { for (; first != last; ++first) { hash_combine(seed,*first); } } } // end namespace Dune #endif // DUNE_COMMON_HASH_HH dune-common-2.8.0/dune/common/hybridutilities.hh000066400000000000000000000333671411343567400217470ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_HYBRIDUTILITIES_HH #define DUNE_COMMON_HYBRIDUTILITIES_HH #include #include #include #include #include #include #include #include namespace Dune { namespace Hybrid { namespace Impl { // Try if tuple_size is implemented for class template constexpr auto size(const Dune::FieldVector&, const PriorityTag<5>&) -> decltype(std::integral_constant()) { return {}; } // Try if tuple_size is implemented for class template constexpr auto size(const T&, const PriorityTag<3>&) -> decltype(std::integral_constant::value>()) { return {}; } // Try if there's a static constexpr size() template constexpr auto size(const T&, const PriorityTag<1>&) -> decltype(std::integral_constant()) { return {}; } // As a last resort try if there's a static constexpr size() template constexpr auto size(const T& t, const PriorityTag<0>&) { return t.size(); } } // namespace Impl /** * \brief Size query * * \ingroup HybridUtilities * * \tparam T Type of container whose size is queried * * \param t Container whose size is queried * * \return Size of t * * If the size of t is known at compile type the size is * returned as std::integral_constant. * Otherwise the result of t.size() is returned. * * Supported types for deriving the size at compile time are: * * instances of std::integer_sequence * * all types std::tuple_size is implemented for * * all typed that have a static method ::size() * * instances of Dune::FieldVector */ template constexpr auto size(const T& t) { return Impl::size(t, PriorityTag<42>()); } namespace Impl { template>::value, int> = 0> constexpr decltype(auto) elementAt(Container&& c, Index&&, PriorityTag<2>) { return std::get::value>(c); } template constexpr decltype(auto) elementAt(std::integer_sequence c, Index, PriorityTag<1>) { return Dune::integerSequenceEntry(c, std::integral_constant()); } template constexpr decltype(auto) elementAt(Container&& c, Index&& i, PriorityTag<0>) { return c[i]; } } // namespace Impl /** * \brief Get element at given position from container * * \ingroup HybridUtilities * * \tparam Container Type of given container * \tparam Index Type of index * * \param c Given container * \param i Index of element to obtain * * \return The element at position i, i.e. c[i] * * If this returns the i-th entry of c. It supports the following * containers * * Containers providing dynamic access via operator[] * * Heterogeneous containers providing access via operator[](integral_constant<...>) * * std::tuple<...> * * std::integer_sequence */ template constexpr decltype(auto) elementAt(Container&& c, Index&& i) { return Impl::elementAt(std::forward(c), std::forward(i), PriorityTag<42>()); } namespace Impl { template::value and IsIntegralConstant::value, int> = 0> constexpr auto integralRange(const Begin& /*begin*/, const End& /*end*/, const PriorityTag<1>&) { static_assert(Begin::value <= End::value, "You cannot create an integralRange where end(); } // This should be constexpr but gcc-4.9 does not support // the relaxed constexpr requirements. Hence for being // constexpr the function body can only contain a return // statement and no assertion before this. template constexpr auto integralRange(const Begin& begin, const End& end, const PriorityTag<0>&) { return DUNE_ASSERT_AND_RETURN(begin<=end, Dune::IntegralRange(begin, end)); } } // namespace Impl /** * \brief Create an integral range * * \ingroup HybridUtilities * * \tparam Begin Type of begin entry of the range * \tparam End Type of end entry of the range * * \param begin First entry of the range * \param end One past the last entry of the range * * \returns An object encoding the given range * * If Begin and End are both instances of type * std::integral_constant, the returned range * encodes begin and end statically. */ template constexpr auto integralRange(const Begin& begin, const End& end) { return Impl::integralRange(begin, end, PriorityTag<42>()); } /** * \brief Create an integral range starting from 0 * * \ingroup HybridUtilities * * \tparam End Type of end entry of the range * * \param end One past the last entry of the range * * \returns An object encoding the given range * * This is a short cut for integralRange(_0, end). */ template constexpr auto integralRange(const End& end) { return Impl::integralRange(Dune::Indices::_0, end, PriorityTag<42>()); } namespace Impl { template constexpr void evaluateFoldExpression(std::initializer_list&&) {} template constexpr void forEachIndex(Range&& range, F&& f, std::integer_sequence) { evaluateFoldExpression({(f(Hybrid::elementAt(range, std::integral_constant())), 0)...}); } template constexpr void forEach(std::integer_sequence /*range*/, F&& f, PriorityTag<2>) { evaluateFoldExpression({(f(std::integral_constant()), 0)...}); } template()))>::value, int> = 0> constexpr void forEach(Range&& range, F&& f, PriorityTag<1>) { auto size = Hybrid::size(range); auto indices = std::make_index_sequence(); (forEachIndex)(std::forward(range), std::forward(f), indices); } template constexpr void forEach(Range&& range, F&& f, PriorityTag<0>) { for(auto&& e : range) f(e); } } // namespace Impl /** * \brief Range based for loop * * \ingroup HybridUtilities * * \tparam Range Type of given range * \tparam F Type of given predicate * * \param range The range to loop over * \param f A predicate that will be called with each entry of the range * * This supports looping over the following ranges * * ranges obtained from integralRange() * * all ranges that provide Hybrid::size() and Hybrid::elementAt() * * This especially included instances of std::integer_sequence, * std::tuple, Dune::TupleVector, and Dune::MultiTypeBlockVector. */ template constexpr void forEach(Range&& range, F&& f) { Impl::forEach(std::forward(range), std::forward(f), PriorityTag<42>()); } /** * \brief Accumulate values * * \ingroup HybridUtilities * * \tparam Range Type of given range * \tparam T Type of accumulated value * \tparam F Type of binary accumulation operator * * \param range The range of values to accumulate * \param value Initial value for accumulation * \param f Binary operator for accumulation * * This supports looping over the same ranges as Hybrid::forEach */ template constexpr T accumulate(Range&& range, T value, F&& f) { forEach(std::forward(range), [&](auto&& entry) { value = f(value, entry); }); return value; } namespace Impl { struct Id { template constexpr T operator()(T&& x) const { return std::forward(x); } }; template constexpr decltype(auto) ifElse(std::true_type, IfFunc&& ifFunc, ElseFunc&& /*elseFunc*/) { return ifFunc(Id{}); } template constexpr decltype(auto) ifElse(std::false_type, IfFunc&& /*ifFunc*/, ElseFunc&& elseFunc) { return elseFunc(Id{}); } template decltype(auto) ifElse(const bool& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc) { if (condition) return ifFunc(Id{}); else return elseFunc(Id{}); } } // namespace Impl /** * \brief A conditional expression * * \ingroup HybridUtilities * * This will call either ifFunc or elseFunc depending * on the condition. In any case a single argument * will be passed to the called function. This will always * be the identity function. Passing an expression through * this function will lead to lazy evaluation. This way both * 'branches' can contain expressions that are only valid * within this branch if the condition is a std::integral_constant. * * In order to do this, the passed functors must have a single * argument of type auto. * * Due to the lazy evaluation mechanism and support for * std::integral_constant this allows to emulate * a static if statement. */ template decltype(auto) ifElse(const Condition& condition, IfFunc&& ifFunc, ElseFunc&& elseFunc) { return Impl::ifElse(condition, std::forward(ifFunc), std::forward(elseFunc)); } /** * \brief A conditional expression * * \ingroup HybridUtilities * * This provides an ifElse conditional with empty else clause. */ template void ifElse(const Condition& condition, IfFunc&& ifFunc) { ifElse(condition, std::forward(ifFunc), [](auto&&) {}); } namespace Impl { template constexpr auto equals(const T1& /*t1*/, const T2& /*t2*/, PriorityTag<1>) -> decltype(T1::value, T2::value, std::integral_constant()) { return {}; } template constexpr auto equals(const T1& t1, const T2& t2, PriorityTag<0>) { return t1==t2; } } // namespace Impl /** * \brief Equality comparison * * \ingroup HybridUtilities * * If both types have a static member value, the result of comparing * these is returned as std::integral_constant. Otherwise * the result of a runtime comparison of t1 and t2 is directly returned. */ template constexpr auto equals(T1&& t1, T2&& t2) { return Impl::equals(std::forward(t1), std::forward(t2), PriorityTag<1>()); } namespace Impl { template constexpr Result switchCases(std::integer_sequence, const Value& /*value*/, Branches&& /*branches*/, ElseBranch&& elseBranch) { return elseBranch(); } template constexpr Result switchCases(std::integer_sequence, const Value& value, Branches&& branches, ElseBranch&& elseBranch) { return ifElse( Hybrid::equals(std::integral_constant(), value), [&](auto id) -> decltype(auto) { return id(branches)(std::integral_constant()); }, [&](auto id) -> decltype(auto) { return Impl::switchCases(id(std::integer_sequence()), value, branches, elseBranch); }); } } // namespace Impl /** * \brief Switch statement * * \ingroup HybridUtilities * * \tparam Cases Type of case range * \tparam Value Type of value to check against the cases * \tparam Branches Type of branch function * \tparam ElseBranch Type of branch function * * \param cases A range of cases to check for * \param value The value to check against the cases * \param branches A callback that will be executed with matching entry from case list * \param elseBranch A callback that will be executed if no other entry matches * * Value is checked against all entries of the given range. * If one matches, then branches is executed with the matching * value as single argument. If the range is an std::integer_sequence, * the value is passed as std::integral_constant. * If non of the entries matches, then elseBranch is executed * without any argument. * * Notice that this short circuits, e.g., if one case matches, * the others are no longer evaluated. * * The return value will be deduced from the else branch. */ template constexpr decltype(auto) switchCases(const Cases& cases, const Value& value, Branches&& branches, ElseBranch&& elseBranch) { return Impl::switchCases(cases, value, std::forward(branches), std::forward(elseBranch)); } /** * \brief Switch statement * * \ingroup HybridUtilities * * \tparam Cases Type of case range * \tparam Value Type of value to check against the cases * \tparam Branches Type of branch function * * \param cases A range of cases to check for * \param value The value to check against the cases * \param branches A callback that will be executed with matching entry from case list * * Value is checked against all entries of the given range. * If one matches, then branches is executed with the matching * value as single argument. If the range is an std::integer_sequence, * the value is passed as std::integral_constant. * If non of the entries matches, then elseBranch is executed * without any argument. */ template constexpr void switchCases(const Cases& cases, const Value& value, Branches&& branches) { Impl::switchCases(cases, value, std::forward(branches), []() {}); } } // namespace Hybrid } // namespace Dune #endif // #ifndef DUNE_COMMON_HYBRIDUTILITIES_HH dune-common-2.8.0/dune/common/indent.hh000066400000000000000000000100741411343567400200010ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_INDENT_HH #define DUNE_COMMON_INDENT_HH #include #include namespace Dune { /** @addtogroup Common * * @{ */ /** * @file * @brief Utility class for handling nested indentation in output. * @author Jö Fahlke */ //! Utility class for handling nested indentation in output. /** * An indentation object hast a string basic_indent and an indentation * level. When it is put into a std::ostream using << it will print its * basic_indent as many times as its indentation level. By default the * basic_indent will be two spaces and the indentation level will be 0. * * An Indent object may also have a reference to a parent Indent object. If * it has, that object it put into the stream with the << operator before * the indentation of this object is put into the stream. This effectively * chains Indent objects together. * * You can use the ++ operator to raise and the -- operator to lower the * indentation by one level. * * You can use the + operator with a numeric second argument morelevel to * create a copy of the Indent object with the indentation level increased * morelevel times. This is mainly useful to pass indent+1 to a function, * where indent is an indentation object. * * You can use the + operator with a string second argument newindent to * create a new Indent object with this object as parent, a basic_indent of * newindent, and an indentation level of one. This is mainly useful to * pass indent+"> " to a function, where "> " is a possibly different * indentation string then the one used by indent indentation object. * * \note The idea is for functions receive indentation objects as call by * value parameters. This way, the indentation object of the caller * will not be modified by the function and the function can simply * return at anytime without having to clean up. */ class Indent { const Indent* parent; std::string basic_indent; unsigned level; public: //! setup without parent /** * \note Initial indentation level is 0 by default for this constructor. */ inline Indent(const std::string& basic_indent_ = " ", unsigned level_ = 0) : parent(0), basic_indent(basic_indent_), level(level_) { } //! setup without parent and basic_indentation of two spaces inline Indent(unsigned level_) : parent(0), basic_indent(" "), level(level_) { } //! setup with parent /** * \note Initial indentation level is 1 by default for this constructor. */ inline Indent(const Indent* parent_, const std::string& basic_indent_ = " ", unsigned level_ = 1) : parent(parent_), basic_indent(basic_indent_), level(level_) { } //! setup with parent inline Indent(const Indent* parent_, unsigned level_) : parent(parent_), basic_indent(" "), level(level_) { } //! create new indentation object with this one as parent inline Indent operator+(const std::string& newindent) const { return Indent(this, newindent); } //! create a copy of this indentation object with raised level inline Indent operator+(unsigned morelevel) const { return Indent(parent, basic_indent, level+morelevel); } //! raise indentation level inline Indent& operator++() { ++level; return *this; } //! lower indentation level inline Indent& operator--() { if ( level > 0 ) --level; return *this; } //! write indentation to a stream friend inline std::ostream& operator<<(std::ostream& s, const Indent& indent); }; //! write indentation to a stream inline std::ostream& operator<<(std::ostream& s, const Indent& indent) { if(indent.parent) s << *indent.parent; for(unsigned i = 0; i < indent.level; ++i) s << indent.basic_indent; return s; } /** }@ group Common */ } // namespace Dune #endif // DUNE_COMMON_INDENT_HH dune-common-2.8.0/dune/common/indices.hh000066400000000000000000000102441411343567400201350ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_INDICES_HH #define DUNE_COMMON_INDICES_HH #include #include #include #include namespace Dune { /** \addtogroup Common * \{ */ /** \brief An index constant with value i * * An index constant is a simple type alias for an integral_constant. * Its main advantages are clarity (it is easier to see that code uses it * as an index) and the fact that the integral type is fixed, reducing verbosity * and avoiding the problem of maybe trying to overload / specialize using a different * integral type. */ template using index_constant = std::integral_constant; /** \brief Namespace with predefined compile time indices for the range [0,19] * * The predefined index objects in this namespace are `constexpr`, which allows them to * be used in situations where a compile time constant is needed, e.g. for a template * parameter. Apart from that, `constexpr` implies internal linkage, which helps to avoid * ODR problems. * * The constants implicitly convert to their contained value, so you can for example write * * \code{.cc} * std::array a; * // the above line is equivalent to * std::array b; * \endcode * */ namespace Indices { //! Compile time index with value 0. DUNE_INLINE_VARIABLE constexpr index_constant< 0> _0 = {}; //! Compile time index with value 1. DUNE_INLINE_VARIABLE constexpr index_constant< 1> _1 = {}; //! Compile time index with value 2. DUNE_INLINE_VARIABLE constexpr index_constant< 2> _2 = {}; //! Compile time index with value 3. DUNE_INLINE_VARIABLE constexpr index_constant< 3> _3 = {}; //! Compile time index with value 4. DUNE_INLINE_VARIABLE constexpr index_constant< 4> _4 = {}; //! Compile time index with value 5. DUNE_INLINE_VARIABLE constexpr index_constant< 5> _5 = {}; //! Compile time index with value 6. DUNE_INLINE_VARIABLE constexpr index_constant< 6> _6 = {}; //! Compile time index with value 7. DUNE_INLINE_VARIABLE constexpr index_constant< 7> _7 = {}; //! Compile time index with value 8. DUNE_INLINE_VARIABLE constexpr index_constant< 8> _8 = {}; //! Compile time index with value 9. DUNE_INLINE_VARIABLE constexpr index_constant< 9> _9 = {}; //! Compile time index with value 10. DUNE_INLINE_VARIABLE constexpr index_constant<10> _10 = {}; //! Compile time index with value 11. DUNE_INLINE_VARIABLE constexpr index_constant<11> _11 = {}; //! Compile time index with value 12. DUNE_INLINE_VARIABLE constexpr index_constant<12> _12 = {}; //! Compile time index with value 13. DUNE_INLINE_VARIABLE constexpr index_constant<13> _13 = {}; //! Compile time index with value 14. DUNE_INLINE_VARIABLE constexpr index_constant<14> _14 = {}; //! Compile time index with value 15. DUNE_INLINE_VARIABLE constexpr index_constant<15> _15 = {}; //! Compile time index with value 16. DUNE_INLINE_VARIABLE constexpr index_constant<16> _16 = {}; //! Compile time index with value 17. DUNE_INLINE_VARIABLE constexpr index_constant<17> _17 = {}; //! Compile time index with value 18. DUNE_INLINE_VARIABLE constexpr index_constant<18> _18 = {}; //! Compile time index with value 19. DUNE_INLINE_VARIABLE constexpr index_constant<19> _19 = {}; } // namespace Indices /** * \brief Unpack an std::integer_sequence to std::integral_constant... * * This forward all entries of the given std::integer_sequence * as individual std::integral_constant arguments to the given callback. * * \param f Callback which has to accept unpacked values * \param sequence Packed std::integer_sequence of values * \returns Result of calling f with unpacked integers. */ template decltype(auto) unpackIntegerSequence(F&& f, std::integer_sequence sequence) { return f(std::integral_constant()...); } } //namespace Dune #endif // DUNE_COMMON_INDICES_HH dune-common-2.8.0/dune/common/interfaces.hh000066400000000000000000000012631411343567400206430ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_INTERFACES_HH #define DUNE_INTERFACES_HH /** @file @author Robert Kloefkorn @brief Provides interfaces for detection of specific behavior */ namespace Dune { //! An interface class for cloneable objects struct Cloneable { /** \brief Clones the object * clone needs to be redefined by an implementation class, with the * return type covariantly adapted. Remember to * delete the resulting pointer. */ virtual Cloneable* clone() const = 0; /** \brief Destructor */ virtual ~Cloneable() {} }; } // end namespace Dune #endif dune-common-2.8.0/dune/common/ios_state.cc000066400000000000000000000012331411343567400204750ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include "config.h" #endif #include namespace Dune { ////////////////////////////////////////////////////////////////////// // // class ios_base_all_saver // ios_base_all_saver::ios_base_all_saver(state_type& ios_) : ios(ios_), oldflags(ios.flags()), oldprec(ios.precision()), oldwidth(ios.width()) {} ios_base_all_saver::~ios_base_all_saver() { restore(); } void ios_base_all_saver::restore() { ios.flags(oldflags); ios.precision(oldprec); ios.width(oldwidth); } } dune-common-2.8.0/dune/common/ios_state.hh000066400000000000000000000043071411343567400205140ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_IOS_STATE_HH #define DUNE_COMMON_IOS_STATE_HH #include namespace Dune { /** @addtogroup Common * * @{ */ /** * @file * @brief Utility class for storing and resetting stream attributes. * @author Markus Blatt */ /** * @brief Utility class for storing and resetting stream attributes. * * The constructor saves the attributes currently set in the ios_base * object and the destructor restores these attributes again. The * attributes can also be restores at any time by calling the method * restore(). * * The saved attributes are the format flags, precision, and width. * * @note The interface of this class is meant to be drop-in compatible the * the class of the same name from . */ class ios_base_all_saver { public: /** @brief Export type of object we save the state for */ typedef std::ios_base state_type; /** * @brief Constructor that stores the currently used flags. * @param ios_ The ios_base object whose flags are to be saved and * restored. Any stream object should work here. * * @note A reference to the ios_base object is store in this object. Thus * the ios_base object must remain valid until the destructor of * this object has been called. */ ios_base_all_saver(state_type& ios_); /** * @brief Destructor that restores the flags stored by the constructor. */ ~ios_base_all_saver(); /** * @brief Restore flags now * * The flags will also be restored at destruction time even if this method * was used. */ void restore(); private: /** @brief the ios object to restore the flags to. */ state_type& ios; /** @brief The flags used when the constructor was called. */ state_type::fmtflags oldflags; /** @brief The precision in use when the constructor was called. */ std::streamsize oldprec; /** @brief The width in use when the constructor was called. */ std::streamsize oldwidth; }; /** }@ */ } #endif // DUNE_COMMON_IOS_STATE_HH dune-common-2.8.0/dune/common/iteratorfacades.hh000066400000000000000000000523221411343567400216620ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_ITERATORFACADES_HH #define DUNE_ITERATORFACADES_HH #include #include #include "typetraits.hh" namespace Dune { /*! \defgroup IteratorFacades Iterator facades \ingroup Common \brief Iterator facades for writing stl conformant iterators. With using these facades writing iterators for arbitrary containers becomes much less cumbersome as only few functions have to be implemented. All other functions needed by the stl are provided by the facades using the Barton-Nackman trick (also known as curiously recurring template pattern). The following example illustrates how a random access iterator might be written: \code #include ... template class TestIterator : public Dune::BidirectionalIteratorFacade,T, T&, int> { friend class TestIterator::type, typename std::remove_const::type >; friend class TestIterator::type, const typename std::remove_const::type >; public: // Constructors needed by the facade iterators. TestIterator(): container_(0), position_(0) { } TestIterator(C& cont, int pos) : container_(&cont), position_(pos) {} TestIterator(const TestIterator::type, typename std::remove_const::type >& other) : container_(other.container_), position_(other.position_) {} TestIterator(const TestIterator::type, const typename std::remove_const::type >& other) : container_(other.container_), position_(other.position_) {} // Methods needed by the forward iterator bool equals(const TestIterator::type,typename std::remove_const::type>& other) const { return position_ == other.position_ && container_ == other.container_; } bool equals(const TestIterator::type,const typename std::remove_const::type>& other) const { return position_ == other.position_ && container_ == other.container_; } T& dereference() const { return container_->values_[position_]; } void increment() { ++position_; } // Additional function needed by BidirectionalIterator void decrement() { --position_; } // Additional function needed by RandomAccessIterator T& elementAt(int i)const { return container_->operator[](position_+i); } void advance(int n) { position_=position_+n; } std::ptrdiff_t distanceTo(TestIterator::type,const typename std::remove_const::type> other) const { assert(other.container_==container_); return other.position_ - position_; } std::ptrdiff_t distanceTo(TestIterator::type, typename std::remove_const::type> other) const { assert(other.container_==container_); return other.position_ - position_; } private: C *container_; size_t position_; }; \endcode See dune/common/test/iteratorbase.hh for details. */ /** * @file * @brief This file implements iterator facade classes for writing stl conformant iterators. * * With using these facades writing iterators for arbitrary containers becomes much less * cumbersome as only few functions have to be implemented. All other functions needed by * the stl are provided by the facades using the Barton-Nackman trick (also known as * curiously recurring template pattern. */ /** @addtogroup IteratorFacades * * @{ */ /** * @brief Base class for stl conformant forward iterators. * * \tparam T The derived class * \tparam V The value type * \tparam R The reference type * \tparam D The type for differences between two iterators */ template class ForwardIteratorFacade { public: /* type aliases required by C++ for iterators */ using iterator_category = std::forward_iterator_tag; using value_type = typename std::remove_const::type; using difference_type = D; using pointer = V*; using reference = R; /** * @brief The type of derived iterator. * * The iterator has to define following * functions have to be present: * * \code * * // Access the value referred to. * Reference dereference() const; * * // Compare for equality with iterator j * bool equals(j); * * // position the iterator at the next element. * void increment() * * // check for equality with other iterator * bool equals(other) * \endcode * * For an elaborate explanation see the * STL Documentation! */ typedef T DerivedType; /** * @brief The type of value accessed through the iterator. */ typedef V Value; /** * @brief The pointer to the Value. */ typedef V* Pointer; /** * @brief The type of the difference between two positions. */ typedef D DifferenceType; /** * @brief The type of the reference to the values accessed. */ typedef R Reference; /** @brief Dereferencing operator. */ Reference operator*() const { return static_cast(this)->dereference(); } Pointer operator->() const { return &(static_cast(this)->dereference()); } /** @brief Preincrement operator. */ DerivedType& operator++() { static_cast(this)->increment(); return *static_cast(this); } /** @brief Postincrement operator. */ DerivedType operator++(int) { DerivedType tmp(static_cast(*this)); this->operator++(); return tmp; } }; /** * @brief Checks for equality. * * This operation is only defined if either D2 * is convertible to D1 or vice versa. If that is * not the case the compiler will report an error * as EnableIfInterOperable::type is * not defined. * */ template inline typename EnableIfInterOperable::type operator==(const ForwardIteratorFacade& lhs, const ForwardIteratorFacade& rhs) { if(std::is_convertible::value) return static_cast(lhs).equals(static_cast(rhs)); else return static_cast(rhs).equals(static_cast(lhs)); } /** * @brief Checks for inequality. * * This operation is only defined if either D2 * is convertible to D1 or vice versa. If that is * not the case the compiler will report an error * as EnableIfInterOperable::type is * not defined. * */ template inline typename EnableIfInterOperable::type operator!=(const ForwardIteratorFacade& lhs, const ForwardIteratorFacade& rhs) { if(std::is_convertible::value) return !static_cast(lhs).equals(static_cast(rhs)); else return !static_cast(rhs).equals(static_cast(lhs)); } /** * @brief Facade class for stl conformant bidirectional iterators. * */ template class BidirectionalIteratorFacade { public: /* type aliases required by C++ for iterators */ using iterator_category = std::bidirectional_iterator_tag; using value_type = typename std::remove_const::type; using difference_type = D; using pointer = V*; using reference = R; /** * @brief The type of derived iterator. * * The iterator has to define following * functions have to be present: * * \code * * // Access the value referred to. * Reference dereference() const; * * // Compare for equality with j * bool equals(j); * * // position the iterator at the next element. * void increment() * * // position the iterator at the previous element. * void decrement() * * \endcode * * For an elaborate explanation see the * STL Documentation */ typedef T DerivedType; /** * @brief The type of value accessed through the iterator. */ typedef V Value; /** * @brief The pointer to the Value. */ typedef V* Pointer; /** * @brief The type of the difference between two positions. */ typedef D DifferenceType; /** * @brief The type of the reference to the values accessed. */ typedef R Reference; /** @brief Dereferencing operator. */ Reference operator*() const { return static_cast(this)->dereference(); } Pointer operator->() const { return &(static_cast(this)->dereference()); } /** @brief Preincrement operator. */ DerivedType& operator++() { static_cast(this)->increment(); return *static_cast(this); } /** @brief Postincrement operator. */ DerivedType operator++(int) { DerivedType tmp(static_cast(*this)); this->operator++(); return tmp; } /** @brief Preincrement operator. */ DerivedType& operator--() { static_cast(this)->decrement(); return *static_cast(this); } /** @brief Postincrement operator. */ DerivedType operator--(int) { DerivedType tmp(static_cast(*this)); this->operator--(); return tmp; } }; /** * @brief Checks for equality. * * This operation is only defined if T2 is convertible to T1, otherwise it * is removed from the overload set since the enable_if for the return type * yield an invalid type expression. */ template inline typename std::enable_if::value,bool>::type operator==(const BidirectionalIteratorFacade& lhs, const BidirectionalIteratorFacade& rhs) { return static_cast(lhs).equals(static_cast(rhs)); } /** * @brief Checks for equality. * * This operation is only defined if either T1 is convertible to T2, and T2 * is not convetible to T1. Otherwise the operator is removed from the * overload set since the enable_if for the return type yield an invalid * type expression. */ template inline typename std::enable_if::value && !std::is_convertible::value, bool>::type operator==(const BidirectionalIteratorFacade& lhs, const BidirectionalIteratorFacade& rhs) { return static_cast(rhs).equals(static_cast(lhs)); } /** * @brief Checks for inequality. * * This operation is only defined if either D2 * is convertible to D1 or vice versa. If that is * not the case the compiler will report an error * as EnableIfInterOperable::type is * not defined. * */ template inline typename EnableIfInterOperable::type operator!=(const BidirectionalIteratorFacade& lhs, const BidirectionalIteratorFacade& rhs) { return !(lhs == rhs); } /** * @brief Base class for stl conformant forward iterators. * */ template class RandomAccessIteratorFacade { public: /* type aliases required by C++ for iterators */ using iterator_category = std::random_access_iterator_tag; using value_type = typename std::remove_const::type; using difference_type = D; using pointer = V*; using reference = R; /** * @brief The type of derived iterator. * * The iterator has to define following * functions have to be present: * * \code * * // Access the value referred to. * Reference dereference() const; * // Access the value at some other location * Reference elementAt(n) const; * * // Compare for equality with j * bool equals(j); * * // position the iterator at the next element. * void increment() * * // position the iterator at the previous element. * void decrement() * * // advance the iterator by a number of positions- * void advance(DifferenceType n); * // calculate the distance to another iterator. * // One should incorporate an assertion whether * // the same containers are referenced * DifferenceType distanceTo(j) const; * \endcode * * For an elaborate explanation see the * STL Documentation */ typedef T DerivedType; /** * @brief The type of value accessed through the iterator. */ typedef V Value; /** * @brief The pointer to the Value. */ typedef V* Pointer; /** * @brief The type of the difference between two positions. */ typedef D DifferenceType; /** * @brief The type of the reference to the values accessed. */ typedef R Reference; /** @brief Dereferencing operator. */ Reference operator*() const { return static_cast(this)->dereference(); } Pointer operator->() const { return &(static_cast(this)->dereference()); } /** * @brief Get the element n positions from the current one. * @param n The distance to the element. * @return The element at that distance. */ Reference operator[](DifferenceType n) const { return static_cast(this)->elementAt(n); } /** @brief Preincrement operator. */ DerivedType& operator++() { static_cast(this)->increment(); return *static_cast(this); } /** @brief Postincrement operator. */ DerivedType operator++(int) { DerivedType tmp(static_cast(*this)); this->operator++(); return tmp; } DerivedType& operator+=(DifferenceType n) { static_cast(this)->advance(n); return *static_cast(this); } DerivedType operator+(DifferenceType n) const { DerivedType tmp(static_cast(*this)); tmp.advance(n); return tmp; } /** @brief Predecrement operator. */ DerivedType& operator--() { static_cast(this)->decrement(); return *static_cast(this); } /** @brief Postdecrement operator. */ DerivedType operator--(int) { DerivedType tmp(static_cast(*this)); this->operator--(); return tmp; } DerivedType& operator-=(DifferenceType n) { static_cast(this)->advance(-n); return *static_cast(this); } DerivedType operator-(DifferenceType n) const { DerivedType tmp(static_cast(*this)); tmp.advance(-n); return tmp; } }; /** * @brief Checks for equality. * * This operation is only defined if either D2 * is convertible to D1 or vice versa. If that is * not the case the compiler will report an error * as EnableIfInterOperable::type is * not defined. * */ template inline typename EnableIfInterOperable::type operator==(const RandomAccessIteratorFacade& lhs, const RandomAccessIteratorFacade& rhs) { if(std::is_convertible::value) return static_cast(lhs).equals(static_cast(rhs)); else return static_cast(rhs).equals(static_cast(lhs)); } /** * @brief Checks for inequality. * * This operation is only defined if either D2 * is convertible to D1 or vice versa. If that is * not the case the compiler will report an error * as EnableIfInterOperable::type is * not defined. * */ template inline typename EnableIfInterOperable::type operator!=(const RandomAccessIteratorFacade& lhs, const RandomAccessIteratorFacade& rhs) { if(std::is_convertible::value) return !static_cast(lhs).equals(static_cast(rhs)); else return !static_cast(rhs).equals(static_cast(lhs)); } /** * @brief Comparison operator. * * This operation is only defined if either D2 * is convertible to D1 or vice versa. If that is * not the case the compiler will report an error * as EnableIfInterOperable::type is * not defined. * */ template inline typename EnableIfInterOperable::type operator<(const RandomAccessIteratorFacade& lhs, const RandomAccessIteratorFacade& rhs) { if(std::is_convertible::value) return static_cast(lhs).distanceTo(static_cast(rhs))>0; else return static_cast(rhs).distanceTo(static_cast(lhs))<0; } /** * @brief Comparison operator. * * This operation is only defined if either D2 * is convertible to D1 or vice versa. If that is * not the case the compiler will report an error * as EnableIfInterOperable::type is * not defined. * */ template inline typename EnableIfInterOperable::type operator<=(const RandomAccessIteratorFacade& lhs, const RandomAccessIteratorFacade& rhs) { if(std::is_convertible::value) return static_cast(lhs).distanceTo(static_cast(rhs))>=0; else return static_cast(rhs).distanceTo(static_cast(lhs))<=0; } /** * @brief Comparison operator. * * This operation is only defined if either D2 * is convertible to D1 or vice versa. If that is * not the case the compiler will report an error * as EnableIfInterOperable::type is * not defined. * */ template inline typename EnableIfInterOperable::type operator>(const RandomAccessIteratorFacade& lhs, const RandomAccessIteratorFacade& rhs) { if(std::is_convertible::value) return static_cast(lhs).distanceTo(static_cast(rhs))<0; else return static_cast(rhs).distanceTo(static_cast(lhs))>0; } /** * @brief Comparison operator. * * This operation is only defined if either D2 * is convertible to D1 or vice versa. If that is * not the case the compiler will report an error * as EnableIfInterOperable::type is * not defined. * */ template inline typename EnableIfInterOperable::type operator>=(const RandomAccessIteratorFacade& lhs, const RandomAccessIteratorFacade& rhs) { if(std::is_convertible::value) return static_cast(lhs).distanceTo(static_cast(rhs))<=0; else return static_cast(rhs).distanceTo(static_cast(lhs))>=0; } /** * @brief Calculates the difference between two pointers. * * This operation is only defined if either D2 * is convertible to D1 or vice versa. If that is * not the case the compiler will report an error * as EnableIfInterOperable::type is * not defined. * */ template inline typename EnableIfInterOperable::type operator-(const RandomAccessIteratorFacade& lhs, const RandomAccessIteratorFacade& rhs) { if(std::is_convertible::value) return -static_cast(lhs).distanceTo(static_cast(rhs)); else return static_cast(rhs).distanceTo(static_cast(lhs)); } /** @} */ } #endif dune-common-2.8.0/dune/common/iteratorrange.hh000066400000000000000000000026771411343567400214000ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_ITERATORRANGE_HH #define DUNE_COMMON_ITERATORRANGE_HH namespace Dune { //! Simple range between a begin and an end iterator. /** * IteratorRange is mainly useful as a lightweight adaptor * class when adding support for range-based for loops to * existing containers that lack a standard begin(), end() * pair of member functions. * * \tparam Iterator The type of iterator * \ingroup CxxUtilities */ template class IteratorRange { public: //! The iterator belonging to this range. typedef Iterator iterator; //! The iterator belonging to this range. /** * This typedef is here mainly for compatibility reasons. */ typedef Iterator const_iterator; //! Constructs an iterator range on [begin,end). IteratorRange(const Iterator& begin, const Iterator& end) : _begin(begin) , _end(end) {} //! Default constructor, relies on iterators being default-constructible. IteratorRange() {} //! Returns an iterator pointing to the begin of the range. iterator begin() const { return _begin; } //! Returns an iterator pointing past the end of the range. iterator end() const { return _end; } private: Iterator _begin; Iterator _end; }; } #endif // DUNE_COMMON_ITERATORRANGE_HH dune-common-2.8.0/dune/common/keywords.hh000066400000000000000000000016651411343567400203750ustar00rootroot00000000000000#ifndef DUNE_COMMON_KEYWORDS_HH #define DUNE_COMMON_KEYWORDS_HH /** \file * \brief Definitions of several macros that conditionally make C++ syntax * available. * * This header contains several macros that enable C++ features depending on your * compiler. Most of these features are optional and provide additional functionality * like making code constexpr. * * \ingroup CxxUtilities */ #if __cpp_inline_variables >= 201606 #define DUNE_INLINE_VARIABLE inline #else //! Preprocessor macro used for marking variables inline on supported compilers. /** * \ingroup CxxUtilities */ #define DUNE_INLINE_VARIABLE #endif #if __cpp_constexpr >= 201304 #define DUNE_GENERALIZED_CONSTEXPR constexpr #else //! Preprocessor macro used for marking code as constexpr under the relaxed rules of C++14 if supported by the compiler. /** * \ingroup CxxUtilities */ #define DUNE_GENERALIZED_CONSTEXPR #endif #endif // DUNE_COMMON_KEYWORDS_HH dune-common-2.8.0/dune/common/lcm.hh000066400000000000000000000017701411343567400172760ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_LCM_HH #define DUNE_LCM_HH #warning "This header is deprecated and will be removed after release 2.8. Use std::lcm instead." /** \file * \brief Statically compute the least common multiple of two integers */ #include namespace Dune { /** * @addtogroup Common * @{ */ /** * @file * This file provides template constructs for calculation the * least common multiple. */ /** * @brief Calculate the least common multiple of two numbers */ template struct [[deprecated("Will be removed after Dune 2.8. Use std::lcm instead.")]] Lcm { static void conceptCheck() { static_assert(0 #include #include #include #include /** @file @author Christian Engwer @brief LRU Cache Container, using an STL like interface */ namespace Dune { namespace { /* hide the default traits in an empty namespace */ template > struct _lru_default_traits { typedef Key key_type; typedef Alloc allocator; typedef std::list< std::pair > list_type; typedef typename list_type::iterator iterator; typedef typename std::less cmp; typedef std::map< key_type, iterator, cmp, typename std::allocator_traits::template rebind_alloc > > map_type; }; } // end empty namespace /** @brief LRU Cache Container Implementation of an LRU (least recently used) cache container. This implementation follows the approach presented in http://aim.adc.rmit.edu.au/phd/sgreuter/papers/graphite2003.pdf */ template > class lru { typedef typename Traits::list_type list_type; typedef typename Traits::map_type map_type; typedef typename Traits::allocator allocator; typedef typename map_type::iterator map_iterator; typedef typename map_type::const_iterator const_map_iterator; public: typedef typename Traits::key_type key_type; typedef typename allocator::value_type value_type; using pointer = typename allocator::value_type*; using const_pointer = typename allocator::value_type const*; using const_reference = typename allocator::value_type const&; using reference = typename allocator::value_type&; typedef typename allocator::size_type size_type; typedef typename list_type::iterator iterator; typedef typename list_type::const_iterator const_iterator; /** * Returns a read/write reference to the data of the most * recently used entry. */ reference front() { return _data.front().second; } /** * Returns a read-only (constant) reference to the data of the * most recently used entry. */ const_reference front() const { return _data.front().second; } /** * Returns a read/write reference to the data of the least * recently used entry. */ reference back() { return _data.back().second; } /** * Returns a read-only (constant) reference to the data of the * least recently used entry. */ const_reference back ([[maybe_unused]] int i) const { return _data.back().second; } /** * @brief Removes the first element. */ void pop_front() { key_type k = _data.front().first; _data.pop_front(); _index.erase(k); } /** * @brief Removes the last element. */ void pop_back() { key_type k = _data.back().first; _data.pop_back(); _index.erase(k); } /** * @brief Finds the element whose key is k. * * @return iterator */ iterator find (const key_type & key) { const map_iterator it = _index.find(key); if (it == _index.end()) return _data.end(); return it->second; } /** * @brief Finds the element whose key is k. * * @return const_iterator */ const_iterator find (const key_type & key) const { const map_iterator it = _index.find(key); if (it == _index.end()) return _data.end(); return it->second; } /** * @brief Insert a value into the container * * Stores value under key and marks it as most recent. If this key * is already present, the associated data is replaced. * * @param key associated with data * @param data to store * * @return reference of stored data */ reference insert (const key_type & key, const_reference data) { std::pair x(key, data); /* insert item as mru */ iterator it = _data.insert(_data.begin(), x); /* store index */ _index.insert(std::make_pair(key,it)); return it->second; } /** * @copydoc touch */ reference insert (const key_type & key) { return touch (key); } /** * @brief mark data associated with key as most recent * * @return reference of stored data */ reference touch (const key_type & key) { /* query _index for iterator */ map_iterator it = _index.find(key); if (it == _index.end()) DUNE_THROW(Dune::RangeError, "Failed to touch key " << key << ", it is not in the lru container"); /* update _data move it to the front */ _data.splice(_data.begin(), _data, it->second); return it->second->second; } /** * @brief Retrieve number of entries in the container */ size_type size() const { return _data.size(); } /** * @brief ensure a maximum size of the container * * If new_size is smaller than size the oldest elements are * dropped. Otherwise nothing happens. */ void resize(size_type new_size) { assert(new_size <= size()); while (new_size < size()) pop_back(); } /** * */ void clear() { _data.clear(); _index.clear(); } private: list_type _data; map_type _index; }; } // namespace Dune #endif // DUNE_COMMON_LRU_HH dune-common-2.8.0/dune/common/mallocallocator.hh000066400000000000000000000053121411343567400216670ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_MALLOC_ALLOCATOR_HH #define DUNE_MALLOC_ALLOCATOR_HH #include #include #include #include /** * @file * @brief Allocators that use malloc/free. */ namespace Dune { /** @ingroup Allocators @brief Allocators implementation which simply calls malloc/free */ template class MallocAllocator { public: typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template struct rebind { typedef MallocAllocator other; }; //! create a new MallocAllocator MallocAllocator() noexcept {} //! copy construct from an other MallocAllocator, possibly for a different result type template MallocAllocator(const MallocAllocator&) noexcept {} //! cleanup this allocator ~MallocAllocator() noexcept {} pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } //! allocate n objects of type T pointer allocate(size_type n, [[maybe_unused]] const void* hint = 0) { if (n > this->max_size()) throw std::bad_alloc(); pointer ret = static_cast(std::malloc(n * sizeof(T))); if (!ret) throw std::bad_alloc(); return ret; } //! deallocate n objects of type T at address p void deallocate(pointer p, [[maybe_unused]] size_type n) { std::free(p); } //! max size for allocate size_type max_size() const noexcept { return size_type(-1) / sizeof(T); } //! copy-construct an object of type T (i.e. make a placement new on p) void construct(pointer p, const T& val) { ::new((void*)p)T(val); } //! construct an object of type T from variadic parameters template void construct(pointer p, Args&&... args) { ::new((void *)p)T(std::forward(args) ...); } //! destroy an object of type T (i.e. call the destructor) void destroy(pointer p) { p->~T(); } }; //! check whether allocators are equivalent template constexpr bool operator==(const MallocAllocator &, const MallocAllocator &) { return true; } //! check whether allocators are not equivalent template constexpr bool operator!=(const MallocAllocator &, const MallocAllocator &) { return false; } } #endif // DUNE_MALLOC_ALLOCATOR_HH dune-common-2.8.0/dune/common/math.hh000066400000000000000000000257471411343567400174660ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_MATH_HH #define DUNE_MATH_HH /** \file * \brief Some useful basic math stuff */ #include #include #include #include #include namespace Dune { /** \brief Standard implementation of MathematicalConstants. This implementation will work with all built-in floating point types. It provides * e as exp(1.0) * pi as acos(-1.0) */ template< class T > struct StandardMathematicalConstants { /** * \brief Euler's number */ static const T e () { using std::exp; static const T e = exp( T( 1 ) ); return e; } /** * \brief Archimedes' constant */ static const T pi () { using std::acos; static const T pi = acos( T( -1 ) ); return pi; } }; /** \brief Provides commonly used mathematical constants. a struct that is specialized for types repesenting real or complex numbers. It provides commonly used mathematical constants with the required accuary for the specified type. */ template< class Field > struct MathematicalConstants : public StandardMathematicalConstants {}; /** \brief Power method for integer exponents * * \note Make sure that Mantissa is a non-integer type when using negative exponents! */ template constexpr Mantissa power(Mantissa m, Exponent p) { static_assert(std::numeric_limits::is_integer, "Exponent must be an integer type!"); auto result = Mantissa(1); auto absp = (p<0) ? -p : p; // This is simply abs, but std::abs is not constexpr for (Exponent i = Exponent(0); i struct Factorial { //! factorial stores m! enum { factorial = m * Factorial::factorial }; }; //! end of recursion of factorial via specialization template <> struct Factorial<0> { // 0! = 1 enum { factorial = 1 }; }; //! calculate the factorial of n as a constexpr // T has to be an integral type template constexpr inline static T factorial(const T& n) noexcept { static_assert(std::numeric_limits::is_integer, "`factorial(n)` has to be called with an integer type."); T fac = 1; for(T k = 0; k < n; ++k) fac *= k+1; return fac; } //! calculate the factorial of n as a constexpr template constexpr inline static auto factorial (std::integral_constant) noexcept { return std::integral_constant{}; } //! calculate the binomial coefficient n over k as a constexpr // T has to be an integral type template constexpr inline static T binomial (const T& n, const T& k) noexcept { static_assert(std::numeric_limits::is_integer, "`binomial(n, k)` has to be called with an integer type."); if( k < 0 || k > n ) return 0; if (2*k > n) return binomial(n, n-k); T bin = 1; for(auto i = n-k; i < n; ++i) bin *= i+1; return bin / factorial(k); } //! calculate the binomial coefficient n over k as a constexpr template constexpr inline static auto binomial (std::integral_constant, std::integral_constant) noexcept { return std::integral_constant{}; } template constexpr inline static auto binomial (std::integral_constant, std::integral_constant) noexcept { return std::integral_constant= 0 ? 1 : 0)>{}; } //! compute conjugate complex of x // conjugate complex does nothing for non-complex types template inline K conjugateComplex (const K& x) { return x; } #ifndef DOXYGEN // specialization for complex template inline std::complex conjugateComplex (const std::complex& c) { return std::complex(c.real(),-c.imag()); } #endif //! Return the sign of the value template int sign(const T& val) { return (val < 0 ? -1 : 1); } namespace Impl { // Returns whether a given type behaves like std::complex<>, i.e. whether // real() and imag() are defined template struct isComplexLike { private: template static auto test(U* u) -> decltype(u->real(), u->imag(), std::true_type()); template static auto test(...) -> decltype(std::false_type()); public: static const bool value = decltype(test(0))::value; }; } // namespace Impl //! namespace for customization of math functions with Dune-Semantics /** You can add overloads for the Dune-semantics of math-functions in this namespace. These overloads will be used by functors like `Dune::isNaN` to implement these functions, and will be preferred over functions found by ADL, or the corresponding functions from the standard (whether they are found by ADL or in the namespace `std`. PriorityTag =========== There are two predefined priorities: <1> provides a default implementation, only applicable if the camelCase-Version of the function (e.g. `isNaN`) can be found via ADL for an argument of type `T`. (Otherwise the overload should not participate in overload resolution.) <0> provides a default implementation that forwards the call to the lower-case version of the function (e.g. `isnan`), found via ADL and the namespace `std`. Any higher priority up to 10 can be used by other overloads. */ namespace MathOverloads { //! Tag to make sure the functions in this namespace can be found by ADL. struct ADLTag {}; #define DUNE_COMMON_MATH_ISFUNCTION(function, stdfunction) \ template \ auto function(const T &t, PriorityTag<1>, ADLTag) \ -> decltype(function(t)) { \ return function(t); \ } \ template \ auto function(const T &t, PriorityTag<0>, ADLTag) { \ using std::stdfunction; \ return stdfunction(t); \ } \ static_assert(true, "Require semicolon to unconfuse editors") DUNE_COMMON_MATH_ISFUNCTION(isNaN,isnan); DUNE_COMMON_MATH_ISFUNCTION(isInf,isinf); DUNE_COMMON_MATH_ISFUNCTION(isFinite,isfinite); #undef DUNE_COMMON_MATH_ISFUNCTION template auto isUnordered(const T &t1, const T &t2, PriorityTag<1>, ADLTag) -> decltype(isUnordered(t1, t2)) { return isUnordered(t1, t2); } template auto isUnordered(const T &t1, const T &t2, PriorityTag<0>, ADLTag) { using std::isunordered; return isunordered(t1, t2); } } namespace MathImpl { // NOTE: it is important that these functors have names different from the // names of the functions they are forwarding to. Otherwise the // unqualified call would find the functor type, not a function, and ADL // would never be attempted. #define DUNE_COMMON_MATH_ISFUNCTION_FUNCTOR(function) \ struct function##Impl { \ template \ constexpr auto operator()(const T &t) const { \ return function(t, PriorityTag<10>{}, MathOverloads::ADLTag{}); \ } \ }; \ static_assert(true, "Require semicolon to unconfuse editors") DUNE_COMMON_MATH_ISFUNCTION_FUNCTOR(isNaN); DUNE_COMMON_MATH_ISFUNCTION_FUNCTOR(isInf); DUNE_COMMON_MATH_ISFUNCTION_FUNCTOR(isFinite); #undef DUNE_COMMON_MATH_ISFUNCTION_FUNCTOR struct isUnorderedImpl { template constexpr auto operator()(const T &t1, const T &t2) const { return isUnordered(t1, t2, PriorityTag<10>{}, MathOverloads::ADLTag{}); } }; } //MathImpl namespace Impl { /* This helper has a math functor as a static constexpr member. Doing this as a static member of a template struct means we can do this without violating the ODR or putting the definition into a seperate compilation unit, while still still ensuring the functor is the same lvalue across all compilation units. */ template struct MathDummy { static constexpr T value{}; }; template constexpr T MathDummy::value; } //namespace Impl namespace { /* Provide the math functors directly in the `Dune` namespace. This actually declares a different name in each translation unit, but they all resolve to the same lvalue. */ //! check wether the argument is NaN /** * Dune-Semantic: for multi-valued types (complex, vectors), check whether * *any* value is NaN. */ constexpr auto const &isNaN = Impl::MathDummy::value; //! check wether the argument is infinite or NaN /** * Dune-Semantic: for multi-valued types (complex, vectors), check whether * *any* value is infinite or NaN. */ constexpr auto const &isInf = Impl::MathDummy::value; //! check wether the argument is finite and non-NaN /** * Dune-Semantic: for multi-valued types (complex, vectors), check whether * *all* values are finite and non-NaN. */ constexpr auto const &isFinite = Impl::MathDummy::value; //! check wether the arguments are ordered /** * Dune-Semantic: for multi-valued types (complex, vectors), there is * never an ordering, so at the moment these types are not supported as * arguments. */ constexpr auto const &isUnordered = Impl::MathDummy::value; } namespace MathOverloads { /*Overloads for complex types*/ template::value> > auto isNaN(const T &t, PriorityTag<2>, ADLTag) { return Dune::isNaN(real(t)) || Dune::isNaN(imag(t)); } template::value> > auto isInf(const T &t, PriorityTag<2>, ADLTag) { return Dune::isInf(real(t)) || Dune::isInf(imag(t)); } template::value> > auto isFinite(const T &t, PriorityTag<2>, ADLTag) { return Dune::isFinite(real(t)) && Dune::isFinite(imag(t)); } } //MathOverloads } #endif // #ifndef DUNE_MATH_HH dune-common-2.8.0/dune/common/matvectraits.hh000066400000000000000000000016761411343567400212360ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_MATVECTRAITS_HH #define DUNE_MATVECTRAITS_HH /** \file * \brief Documentation of the traits classes you need to write for each implementation of DenseVector or DenseMatrix */ namespace Dune { /** @addtogroup DenseMatVec \brief Type Traits to retrieve types associated with an implementation of Dune::DenseVector or Dune::DenseMatrix you have to specialize this class for every implementation of DenseVector or DenseMatrix. \code //! export the type of the derived class (e.g. FieldVector) typedef ... derived_type; //! export the type of the stored values typedef ... value_type; //! export the type representing the size information typedef ... size_type; \endcode */ template struct DenseMatVecTraits {}; } // end namespace Dune #endif // DUNE_FTRAITS_HH dune-common-2.8.0/dune/common/modules.txt000066400000000000000000000005251411343567400204100ustar00rootroot00000000000000/* This file determines the order how things appear in the doxygen documentation within the dune-common module. It works like this: @defgroup commands appear only in this file here which is parsed before the other files (because it is mentioned first in the Doxyfile). Only @addtogroup is used in the code documentation. */ dune-common-2.8.0/dune/common/overloadset.hh000066400000000000000000000074311411343567400210520ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_OVERLOADSET_HH #define DUNE_COMMON_OVERLOADSET_HH #include #include #include namespace Dune { namespace Impl { template class OverloadSet : public F... { public: template OverloadSet(FF&&... ff) : F(std::forward(ff))... {} using F::operator()...; }; } // end namespace Impl /** * \brief Create an overload set * * \tparam F List of function object types * \param f List of function objects * * This returns an object that contains all * operator() implementations of the passed * functions. All those are available when * calling operator() of the returned object. * * The returned object derives from * those implementations such that it contains * all operator() implementations in its * overload set. When calling operator() * this will select the best overload. * If multiple overload are equally good this * will lead to ambiguity. * * Notice that the passed function objects are * stored by value and must be copy-constructible. * * \ingroup CxxUtilities */ template auto overload(F&&... f) { return Impl::OverloadSet...>(std::forward(f)...); } namespace Impl { template class OrderedOverloadSet: public OrderedOverloadSet, F0 { using Base = OrderedOverloadSet; public: template OrderedOverloadSet(FF0&& f0, FF&&... ff) : Base(std::forward(ff)...), F0(std::forward(f0)) {} // Forward to operator() of F0 if it can be called with the given arguments. template::value, int> = 0> decltype(auto) operator()(Args&&... args) { return F0::operator()(std::forward(args)...); } // Forward to operator() of base class if F0 cannot be called with the given // arguments. In this case the base class will successively try operator() // of all F... . template::value, int> = 0> decltype(auto) operator()(Args&&... args) { return Base::operator()(std::forward(args)...); } }; template class OrderedOverloadSet: public F0 { public: template OrderedOverloadSet(FF0&& f0) : F0(std::forward(f0)) {} // Forward to operator() of F0. If it cannot be called with // the given arguments a static assertion will fail. template decltype(auto) operator()(Args&&... args) { static_assert(IsCallable::value, "No matching overload found in OrderedOverloadSet"); return F0::operator()(std::forward(args)...); } }; } // end namespace Impl /** * \brief Create an ordered overload set * * \tparam F List of function object types * \param f List of function objects * * This returns an object that contains all * operator() implementations of the passed * functions. All those are available when * calling operator() of the returned object. * * In contrast to overload() these overloads * are ordered in the sense that the first * matching overload for the given arguments * is selected and later ones are ignored. * Hence such a call is never ambiguous. * * Notice that the passed function objects are * stored by value and must be copy-constructible. * * \ingroup CxxUtilities */ template auto orderedOverload(F&&... f) { return Impl::OrderedOverloadSet...>(std::forward(f)...); } } // end namespace Dune #endif // DUNE_COMMON_OVERLOADSET_HH dune-common-2.8.0/dune/common/parallel/000077500000000000000000000000001411343567400177715ustar00rootroot00000000000000dune-common-2.8.0/dune/common/parallel/CMakeLists.txt000066400000000000000000000011731411343567400225330ustar00rootroot00000000000000add_subdirectory(test) add_subdirectory(benchmark) #install headers install(FILES collectivecommunication.hh communication.hh communicator.hh indexset.hh indicessyncer.hh interface.hh localindex.hh mpicollectivecommunication.hh mpicommunication.hh mpiguard.hh future.hh mpifuture.hh mpidata.hh mpipack.hh mpihelper.hh mpitraits.hh plocalindex.hh remoteindices.hh selection.hh variablesizecommunicator.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/common/parallel) dune-common-2.8.0/dune/common/parallel/benchmark/000077500000000000000000000000001411343567400217235ustar00rootroot00000000000000dune-common-2.8.0/dune/common/parallel/benchmark/CMakeLists.txt000066400000000000000000000003761411343567400244710ustar00rootroot00000000000000add_executable(mpi_collective_benchmark EXCLUDE_FROM_ALL mpi_collective_benchmark.cc) dune_target_link_libraries(mpi_collective_benchmark PUBLIC "dunecommon") add_dune_mpi_flags(mpi_collective_benchmark) configure_file(options.ini options.ini COPYONLY) dune-common-2.8.0/dune/common/parallel/benchmark/mpi_collective_benchmark.cc000066400000000000000000000271401411343567400272460ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /** * @brief Benchmark for measure the possible overlap of computation * and communication at MPI collective communications. * * This benchmark is inspired by the sandia micro benchmark: * W. Lawry, C. Wilson, A. Maccabe, R. Brightwell. COMB: A Portable Benchmark * Suite for Assessing MPI Overlap. In Proceedings of the IEEE International * Conference on Cluster Computing (CLUSTER 2002), p. 472, 2002. * http://www.cs.sandia.gov/smb/overhead.html * * The following communication times are measured: * Blocking: Blocking call. E.g. MPI_Allreduce * Nonblocking_wait (NB_Wait): Nonblocking (e.g. MPI_Iallreduce) call * directly followed by MPI_Wait. * Nonblocking_sleep (NB_Sleep): Nonblocking call followed by a busy wait * until the work time has passed. Then * MPI_Wait. * Nonblocking_active (NB_active): Nonblocking call followed by a basy wait * where in every iteration MPI_Test is * called until the work time has passed. * The MPI_wait. * * The overhead is computed as the time for the Nonblocking call plus * the time for MPI_Wait. The iteration time is the time for the whole * communication. The available part of the communication * time(avail(%)) is computed as 1-(overhead/base_t), where base_t is * the time for calling the method with wait time = 0. The overhead is * determined by increasing the work time successive until it is the * dominant factor in the iteration time. Then the overhead is * computed as iter_t-work_t. * * Usage: mpirun ./mpi_collective_benchmark [options] * * options: * -method: default: allreduce. * possible methods: allreduce, barrier, * broadcast, gather, allgather, scatter * -iterations: default: 10000. Number of iterations for * measure the time for one communication * -allMethods: defaukt:0. If 1 iterates over all available methods * -startSize: default: n, where n is the size of MPI_COMM_WORLD. runs * the benchmark for different communicator sizes, starting with * startSize. After every run the size is doubled. Finally one run is * made for the whole communicator. * -verbose: default: 0. If 1 prints intermediate information while determining * the overhead. * -threshold: default: 2. The threshold when the work time is the dominant * factor in the iteration time. (Similar to the threshold in the * sandia benchmark) * -nohdr: default: 0. Suppress output of the header. * * options can be set either in the options.ini file or can be pass at * the command-line (-key value). * * To get a good 'available' value for the NB_sleep communication, some * MPI implementation need to spawn an extra thread. With MPICH you * can activate this by setting the environment variable * MPI_ASYNC_PROGRESS to 1, with IntelMPI the variable is called * I_MPI_ASYNC_PROGRESS. * (https://software.intel.com/en-us/mpi-developer-reference-linux-asynchronous-progress-control) */ #include #include #include #include #include #include #include #include Dune::ParameterTree options; std::vector all_methods = {"allreduce", "barrier", "broadcast", "gather", "allgather", "scatter"}; template void communicate(CC& cc){ auto method = options.get("method", "allreduce"); std::vector data(1, 42); if(method == "allreduce"){ cc.template allreduce>(data); return; } if(method == "barrier"){ cc.barrier(); return; } if(method == "broadcast"){ cc.broadcast(data.data(), data.size(), 0); return; } if(method == "gather"){ std::vector recv_data(cc.size(), 0); cc.gather(data.data(), recv_data.data(), 1, 0); return; } if(method == "allgather"){ std::vector recv_data(cc.size(), 0); cc.allgather(data.data(), 1, recv_data.data()); return; } if(method == "scatter"){ std::vector send_data(cc.size(), 42); cc.scatter(send_data.data(), data.data(), 1, 0); return; } DUNE_THROW(Dune::Exception, "Unknown method"); } template Dune::Future startCommunication(CC& cc){ auto method = options.get("method", "allreduce"); if(method == "allreduce"){ return cc.template iallreduce>(42); } if(method == "barrier"){ return cc.ibarrier(); } if(method == "broadcast"){ return cc.ibroadcast(42, 0); } if(method == "gather"){ return cc.igather(42, std::vector(cc.size()), 0); } if(method == "allgather"){ return cc.iallgather(42, std::vector(cc.size())); } if(method == "scatter"){ return cc.iscatter(std::vector(cc.size(), 42), 0, 0); } DUNE_THROW(Dune::Exception, "Unknown method"); } template double runBlocking(CC& cc){ std::vector answer(1, 42); int iterations = options.get("iterations", 1000); Dune::Timer watch; for(int i = 0; i < iterations; i++){ cc.barrier(); watch.start(); communicate(cc); watch.stop(); } return cc.sum(watch.elapsed())/iterations/cc.size(); } template double runNonblockingWait(CC& cc){ std::vector answer(1, 42); Dune::Timer watch; int iterations = options.get("iterations", 1000); for(int i = 0; i < iterations; i++){ cc.barrier(); watch.start(); auto f = startCommunication(cc); f.wait(); watch.stop(); } return cc.sum(watch.elapsed())/iterations/cc.size(); } std::tuple runNonblockingSleep(decltype(Dune::MPIHelper::getCommunication())& cc, std::chrono::duration wait_time){ std::vector answer(1, 42); Dune::Timer watch, watch_work; int iterations = options.get("iterations", 1000); for(int i = 0; i < iterations; i++){ cc.barrier(); watch.start(); auto f = startCommunication(cc); watch_work.start(); auto start_time = std::chrono::high_resolution_clock::now(); while(std::chrono::high_resolution_clock::now()-start_time < wait_time); watch_work.stop(); f.wait(); watch.stop(); } return std::tuple(cc.sum(watch.stop())/iterations/cc.size(), cc.sum(watch_work.stop())/iterations/cc.size()); } std::tuple runNonblockingActive(decltype(Dune::MPIHelper::getCommunication())& cc, std::chrono::duration wait_time){ std::vector answer(1, 42); int iterations = options.get("iterations", 1000); Dune::Timer watch, watch_work; for(int i = 0; i < iterations; i++){ cc.barrier(); watch.start(); auto f = startCommunication(cc); watch_work.start(); auto start_time = std::chrono::high_resolution_clock::now(); while(std::chrono::high_resolution_clock::now()-start_time < wait_time) f.ready(); watch_work.stop(); f.wait(); watch.stop(); } // return the time spend in communication methods return std::tuple(cc.sum(watch.stop())/iterations/cc.size(), cc.sum(watch_work.stop())/iterations/cc.size()); } /* Increases the work until it is the dominant factor in the iteration time. Returns the base time and how much of it is available for computations(%). It is computed with the formula 1-(overhead/base_t). */ std::tuple determineOverlap(std::function(std::chrono::duration)> fun) { double base_t = 0; std::tie(base_t, std::ignore) = fun(std::chrono::duration(0)); if(options.get("verbose", 0)) std::cout << std::endl << std::endl << std::setw(12) << "base_t:" << base_t << std::endl; double iter_t = 0; double work_t = 0; int i = 1; double iter_t_threshold = options.get("threshold", 2.0); for(double work = 0.25*base_t; iter_t < iter_t_threshold*base_t; work *= 2, i++){ std::tie(iter_t, work_t) = fun(std::chrono::duration(work)); if(options.get("verbose", 0)) std::cout << i << std::setw(12) << " iter_t:" << std::setw(12) << iter_t << std::setw(12) << " work_t:" << std::setw(12) << work_t << std::endl; } double overhead = iter_t-work_t; double avail = 1.0-overhead/base_t; if(options.get("verbose", 0)) std::cout << std::setw(12) << " ovhd:" << std::setw(12) << overhead << std::setw(12) << " available:" << std::setw(12) << avail << std::endl; return std::tuple(base_t, avail); } void printHeader(){ if(options.get("nohdr", 0) == 0){ std::cout << "Method: " << options.get("method", "allreduce") << std::endl; std::cout << std::scientific; std::cout << std::setw(10) << "commsize" << std::setw(12) << "iterations" << std::setw(16) << "Blocking" << std::setw(16) << "NB_wait" << std::setw(16) << "NB_sleep" << std::setw(12) << "avail(%)" << std::setw(16) << "NB_active" << std::setw(12) << "avail(%)" << std::endl; } } void run(int s){ auto comm_world = Dune::MPIHelper::getCommunication(); Dune::MPIHelper::MPICommunicator comm; #if HAVE_MPI MPI_Comm_split(comm_world, comm_world.rank() < s, comm_world.rank(), &comm); #endif if(comm_world.rank() < s){ Dune::Communication cc(comm); std::cout << std::setw(10) << cc.size() << std::setw(12) << options.get("iterations", 1000) << std::flush; double blocking_t = runBlocking(cc); std::cout << std::setw(16) << blocking_t << std::flush; double nb_wait_t = runNonblockingWait(cc); std::cout << std::setw(16) << nb_wait_t << std::flush; using namespace std::placeholders; auto nb_sleep = std::bind(runNonblockingSleep, std::ref(cc), _1); double nb_sleep_t, nb_sleep_avail; std::tie(nb_sleep_t, nb_sleep_avail) = determineOverlap(nb_sleep); std::cout << std::setw(16) << nb_sleep_t << std::setw(12) << std::fixed << std::setprecision(2) << 100*nb_sleep_avail << std::scientific << std::setprecision(6) << std::flush; auto nb_active = std::bind(runNonblockingActive, cc, _1); double nb_active_t, nb_active_avail; std::tie(nb_active_t, nb_active_avail) = determineOverlap(nb_active); std::cout << std::setw(16) << nb_active_t << std::setw(12) << std::fixed << std::setprecision(2) << 100*nb_active_avail << std::scientific << std::setprecision(6) << std::endl; } } int main(int argc, char** argv){ Dune::MPIHelper& mpihelper = Dune::MPIHelper::instance(argc, argv); // disable output on almost all ranks if(mpihelper.rank() != 0) std::cout.setstate(std::ios_base::failbit); // parse options Dune::ParameterTreeParser::readINITree("options.ini", options); Dune::ParameterTreeParser::readOptions(argc, argv, options); std::vector methods = {options.get("method", "allreduce")}; if(options.get("allMethods", 0) == 1) methods = std::vector(all_methods); for(std::string method : methods){ options["method"] = method; std::cout << std::left << std::scientific; printHeader(); int s = options.get("startSize", mpihelper.size()); while(s < mpihelper.size()){ run(s); s *= 2; } run(mpihelper.size()); } return 0; } dune-common-2.8.0/dune/common/parallel/benchmark/options.ini000066400000000000000000000001261411343567400241160ustar00rootroot00000000000000iterations = 10000 method = "allreduce" allMethods = 0 threshold = 2.0 # startSize = 1dune-common-2.8.0/dune/common/parallel/collectivecommunication.hh000066400000000000000000000002661411343567400252350ustar00rootroot00000000000000// Will be removed after the 2.7 release #warning "Deprecated header, use #include instead!" #include dune-common-2.8.0/dune/common/parallel/communication.hh000066400000000000000000000470241411343567400231660ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_PARALLEL_COMMUNICATION_HH #define DUNE_COMMON_PARALLEL_COMMUNICATION_HH /*! \file \brief Implements an utility class that provides collective communication methods for sequential programs. \ingroup ParallelCommunication */ #include #include #include #include #include #include #include /*! \defgroup ParallelCommunication Parallel Communication \ingroup Common \brief Abstractions for parallel computing Dune offers an abstraction to the basic methods of parallel communication. It allows one to switch parallel features on and off, without changing the code. This is done using either Communication or MPICommunication. */ /*! \file \brief An abstraction to the basic methods of parallel communication, following the message-passing paradigm. \ingroup ParallelCommunication */ namespace Dune { /* define some type that definitely differs from MPI_Comm */ struct No_Comm {}; /*! @brief Comparison operator for MPI compatibility Always returns true. */ inline bool operator==(const No_Comm&, const No_Comm&) { return true; } /*! @brief Comparison operator for MPI compatibility Always returns false. */ inline bool operator!=(const No_Comm&, const No_Comm&) { return false; } /*! @brief Collective communication interface and sequential default implementation Communication offers an abstraction to the basic methods of parallel communication, following the message-passing paradigm. It allows one to switch parallel features on and off, without changing the code. Currently only MPI and sequential code are supported. A Communication object is returned by all grids (also the sequential ones) in order to allow code to be written in a transparent way for sequential and parallel grids. This class provides a default implementation for sequential grids. The number of processes involved is 1, any sum, maximum, etc. returns just its input argument and so on. In specializations one can implement the real thing using appropriate communication functions, e.g. there exists an implementation using the Message Passing %Interface (MPI), see Dune::Communication. Moreover, the communication subsystem used by an implementation is not visible in the interface, i.e. Dune grid implementations are not restricted to MPI. \tparam Communicator The communicator type used by your message-passing implementation. For MPI this will be MPI_Comm. For sequential codes there is the dummy communicator No_Comm. It is assumed that if you want to specialize the Communication class for a message-passing system other than MPI, that message-passing system will have something equivalent to MPI communicators. \ingroup ParallelCommunication */ template class Communication { public: //! Construct default object Communication() {} /** \brief Constructor with a given communicator * * As this is implementation for the sequential setting, the communicator is a dummy and simply discarded. */ Communication (const Communicator&) {} //! Return rank, is between 0 and size()-1 int rank () const { return 0; } //! cast to the underlying Fake MPI communicator operator No_Comm() const { return {}; } //! Number of processes in set, is greater than 0 int size () const { return 1; } /** @brief Sends the data to the dest_rank @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int send([[maybe_unused]] const T& data, [[maybe_unused]] int dest_rank, [[maybe_unused]] int tag) { DUNE_THROW(ParallelError, "This method is not supported in sequential programs"); } /** @brief Sends the data to the dest_rank nonblocking @returns Future containing the send buffer, completes when data is send */ template PseudoFuture isend([[maybe_unused]] const T&& data, [[maybe_unused]] int dest_rank, [[maybe_unused]] int tag) { DUNE_THROW(ParallelError, "This method is not supported in sequential programs"); } /** @brief Receives the data from the source_rank @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template T recv([[maybe_unused]] T&& data, [[maybe_unused]] int source_rank, [[maybe_unused]] int tag, [[maybe_unused]] void* status = 0) { DUNE_THROW(ParallelError, "This method is not supported in sequential programs"); } /** @brief Receives the data from the source_rank nonblocking @returns Future containing the received data when complete */ template PseudoFuture irecv([[maybe_unused]] T&& data, [[maybe_unused]] int source_rank, [[maybe_unused]] int tag) { DUNE_THROW(ParallelError, "This method is not supported in sequential programs"); } template T rrecv([[maybe_unused]] T&& data, [[maybe_unused]] int source_rank, [[maybe_unused]] int tag, [[maybe_unused]] void* status = 0) const { DUNE_THROW(ParallelError, "This method is not supported in sequential programs"); } /** @brief Compute the sum of the argument over all processes and return the result in every process. Assumes that T has an operator+ */ template T sum (const T& in) const { return in; } /** @brief Compute the sum over all processes for each component of an array and return the result in every process. Assumes that T has an operator+ @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int sum ([[maybe_unused]] T* inout, [[maybe_unused]] int len) const { return 0; } /** @brief Compute the product of the argument over all processes and return the result in every process. Assumes that T has an operator* */ template T prod (const T& in) const { return in; } /** @brief Compute the product over all processes for each component of an array and return the result in every process. Assumes that T has an operator* @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int prod ([[maybe_unused]] T* inout, [[maybe_unused]] int len) const { return 0; } /** @brief Compute the minimum of the argument over all processes and return the result in every process. Assumes that T has an operator< */ template T min (const T& in) const { return in; } /** @brief Compute the minimum over all processes for each component of an array and return the result in every process. Assumes that T has an operator< @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int min ([[maybe_unused]] T* inout, [[maybe_unused]] int len) const { return 0; } /** @brief Compute the maximum of the argument over all processes and return the result in every process. Assumes that T has an operator< */ template T max (const T& in) const { return in; } /** @brief Compute the maximum over all processes for each component of an array and return the result in every process. Assumes that T has an operator< @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int max ([[maybe_unused]] T* inout, [[maybe_unused]] int len) const { return 0; } /** @brief Wait until all processes have arrived at this point in the program. @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ int barrier () const { return 0; } /** @brief Nonblocking barrier @returns Future which is complete when all processes have reached the barrier */ PseudoFuture ibarrier () const { return {true}; // return a valid future } /** @brief Distribute an array from the process with rank root to all other processes @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int broadcast ([[maybe_unused]] T* inout, [[maybe_unused]] int len, [[maybe_unused]] int root) const { return 0; } /** @brief Distribute an array from the process with rank root to all other processes nonblocking @returns Future containing the distributed data */ template PseudoFuture ibroadcast(T&& data, int root) const{ return {std::forward(data)}; } /** @brief Gather arrays on root task. * * Each process sends its in array of length len to the root process * (including the root itself). In the root process these arrays are stored in rank * order in the out array which must have size len * number of processes. * @param[in] in The send buffer with the data to send. * @param[out] out The buffer to store the received data in. Might have length zero on non-root * tasks. * @param[in] len The number of elements to send on each task. * @param[in] root The root task that gathers the data. * @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int gather (const T* in, T* out, int len, [[maybe_unused]] int root) const // note out must have same size as in { for (int i=0; i containing the gathered data */ template> PseudoFuture igather(TIN&& data_in, TOUT&& data_out, int root){ *(data_out.begin()) = std::forward(data_in); return {std::forward(data_out)}; } /** @brief Gather arrays of variable size on root task. * * Each process sends its in array of length sendDataLen to the root process * (including the root itself). In the root process these arrays are stored in rank * order in the out array. * @param[in] in The send buffer with the data to be sent * @param[in] sendDataLen The number of elements to send on each task * @param[out] out The buffer to store the received data in. May have length zero on non-root * tasks. * @param[in] recvDataLen An array with size equal to the number of processes containing the number * of elements to receive from process i at position i, i.e. the number that * is passed as sendDataLen argument to this function in process i. * May have length zero on non-root tasks. * @param[out] displ An array with size equal to the number of processes. Data received from * process i will be written starting at out+displ[i] on the root process. * May have length zero on non-root tasks. * @param[in] root The root task that gathers the data. * @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int gatherv (const T* in, int sendDataLen, T* out, [[maybe_unused]] int* recvDataLen, int* displ, [[maybe_unused]] int root) const { for (int i=*displ; i int scatter (const T* sendData, T* recvData, int len, [[maybe_unused]] int root) const // note out must have same size as in { for (int i=0; i containing scattered data; */ template PseudoFuture iscatter(TIN&& data_in, TOUT&& data_out, int root){ data_out = *(std::forward(data_in).begin()); return {std::forward(data_out)}; } /** @brief Scatter arrays of variable length from a root to all other tasks. * * The root process sends the elements with index from send+displ[k] to send+displ[k]-1 in * its array to task k, which stores it at index 0 to recvDataLen-1. * @param[in] sendData The array to scatter. May have length zero on non-root * tasks. * @param[in] sendDataLen An array with size equal to the number of processes containing the number * of elements to scatter to process i at position i, i.e. the number that * is passed as recvDataLen argument to this function in process i. * @param[in] displ An array with size equal to the number of processes. Data scattered to * process i will be read starting at send+displ[i] on root the process. * @param[out] recvData The buffer to store the received data in. Upon completion of the * method each task will have the same data stored there as the one in * send buffer of the root task before. * @param[in] recvDataLen The number of elements in the recvData buffer. * @param[in] root The root task that gathers the data. * @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int scatterv (const T* sendData,int* sendDataLen, int* displ, T* recvData, [[maybe_unused]] int recvDataLen, [[maybe_unused]] int root) const { for (int i=*displ; i<*sendDataLen; i++) recvData[i] = sendData[i]; return 0; } /** * @brief Gathers data from all tasks and distribute it to all. * * The block of data sent from the jth process is received by every * process and placed in the jth block of the buffer recvbuf. * * @param[in] sbuf The buffer with the data to send. Has to be the same for * each task. * @param[in] count The number of elements to send by any process. * @param[out] rbuf The receive buffer for the data. Has to be of size * notasks*count, with notasks being the number of tasks in the communicator. * @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int allgather(const T* sbuf, int count, T* rbuf) const { for(const T* end=sbuf+count; sbuf < end; ++sbuf, ++rbuf) *rbuf=*sbuf; return 0; } /** * @brief Gathers data from all tasks and distribute it to all nonblocking. @returns Future containing the distributed data */ template PseudoFuture iallgather(TIN&& data_in, TOUT&& data_out){ return {std::forward(data_out)}; } /** * @brief Gathers data of variable length from all tasks and distribute it to all. * * The block of data sent from the jth process is received by every * process and placed in the jth block of the buffer out. * * @param[in] in The send buffer with the data to send. * @param[in] sendDataLen The number of elements to send on each task. * @param[out] out The buffer to store the received data in. * @param[in] recvDataLen An array with size equal to the number of processes containing the number * of elements to receive from process i at position i, i.e. the number that * is passed as sendDataLen argument to this function in process i. * @param[in] displ An array with size equal to the number of processes. Data received from * process i will be written starting at out+displ[i]. * @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int allgatherv (const T* in, int sendDataLen, T* out, [[maybe_unused]] int* recvDataLen, int* displ) const { for (int i=*displ; i int allreduce([[maybe_unused]] Type* inout, [[maybe_unused]] int len) const { return 0; } /** * @brief Compute something over all processes nonblocking @return Future containing the computed something */ template PseudoFuture iallreduce(TIN&& data_in, TOUT&& data_out){ data_out = std::forward(data_in); return {std::forward(data_out)}; } /** * @brief Compute something over all processes nonblocking and in-place @return Future containing the computed something */ template PseudoFuture iallreduce(T&& data){ return {std::forward(data)}; } /** * @brief Compute something over all processes * for each component of an array and return the result * in every process. * * The template parameter BinaryFunction is the type of * the binary function to use for the computation * * @param in The array to compute on. * @param out The array to store the results in. * @param len The number of components in the array * @returns MPI_SUCCESS (==0) if successful, an MPI error code otherwise */ template int allreduce(const Type* in, Type* out, int len) const { std::copy(in, in+len, out); return 0; } }; template using CollectiveCommunication // Will be deprecated after the 2.7 release //[[deprecated("CollectiveCommunication is deprecated. Use Communication instead.")]] = Communication; } #endif dune-common-2.8.0/dune/common/parallel/communicator.hh000066400000000000000000001462711411343567400230250ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMUNICATOR #define DUNE_COMMUNICATOR #if HAVE_MPI #include #include #include #include #include #include #include #include #include #include #include namespace Dune { /** @defgroup Common_Parallel Parallel Computing based on Indexsets * @ingroup ParallelCommunication * @brief Provides classes for syncing distributed indexed * data structures. * * In a parallel representation a container \f$x\f$, * e.g. a plain C-array, cannot be stored with all entries on each process * because of limited memory and efficiency reasons. Therefore * it is represented by individual * pieces \f$x_p\f$, \f$p=0, \ldots, P-1\f$, where \f$x_p\f$ is the piece stored on * process \f$p\f$ of the \f$P\f$ processes participating in the calculation. * Although the global representation of the container is not * available on any process, a process \f$p\f$ needs to know how the entries * of it's local piece \f$x_p\f$ correspond to the entries of the global * container \f$x\f$, which would be used in a sequential program. In this * module we present classes describing the mapping of the local pieces * to the global * view and the communication interfaces. * * @section IndexSet Parallel Index Sets * * Form an abstract point of view a random access container \f$x: I * \rightarrow K\f$ provides a * mapping from an index set \f$I \subset N_0\f$ onto a set of objects * \f$K\f$. Note that we do not require \f$I\f$ to be consecutive. The piece * \f$x_p\f$ of the container \f$x\f$ stored on process \f$p\f$ is a mapping \f$x_p:I_p * \rightarrow K\f$, where \f$I_p \subset I\f$. Due to efficiency the entries * of \f$x_p\f$ should be stored in consecutive memory. * * This means that for the local computation the data must be addressable * by a consecutive index starting from \f$0\f$. When using adaptive * discretisation methods there might be the need to reorder the indices * after adding and/or deleting some of the discretisation * points. Therefore this index does not have to be persistent. Further * on we will call this index local index. * * For the communication phases of our algorithms these locally stored * entries must also be addressable by a global identifier to be able to * store the received values tagged with the global identifiers at the * correct local index in the consecutive local memory chunk. To ease the * addition and removal of discretisation points this global identifier has * to be persistent. Further on we will call this global identifier * global index. * * Classes to build the mapping are ParallelIndexSet and ParallelLocalIndex. * As these just provide a mapping from the global index to the local index, * the wrapper class GlobalLookupIndexSet facilitates the reverse lookup. * * @section remote Remote Index Information * * To setup communication between the processes every process needs to * know what indices are also known to other processes and what * attributes are attached to them on the remote side. This information is * calculated and encapsulated in class RemoteIndices. * * @section comm Communication * * Based on the information about the distributed index sets, data * independent interfaces between different sets of the index sets * can be setup using the class Interface. For the actual communication * data dependent communicators can be setup using BufferedCommunicator, * DatatypeCommunicator VariableSizeCommunicator based on the interface * information. In contrast to the former * the latter is independent of the class Interface can work on a map * from process number to a pair of index lists describing which local indices * are send and received from that processs, respectively. */ /** @addtogroup Common_Parallel * * @{ */ /** * @file * @brief Provides utility classes for syncing distributed data via * MPI communication. * @author Markus Blatt */ /** * @brief Flag for marking indexed data structures where data at * each index is of the same size. * @see VariableSize */ struct SizeOne {}; /** * @brief Flag for marking indexed data structures where the data at each index may * be a variable multiple of another type. * @see SizeOne */ struct VariableSize {}; /** * @brief Default policy used for communicating an indexed type. * * This */ template struct CommPolicy { /** * @brief The type the policy is for. * * It has to provide the mode * \code Type::IndexedType operator[](int i);\endcode * for * the access of the value at index i and a typedef IndexedType. * It is assumed * that only one entry is at each index (as in scalar * vector. */ typedef V Type; /** * @brief The type we get at each index with operator[]. * * The default is the value_type typedef of the container. */ typedef typename V::value_type IndexedType; /** * @brief Whether the indexed type has variable size or there * is always one value at each index. */ typedef SizeOne IndexedTypeFlag; /** * @brief Get the address of entry at an index. * * The default implementation uses operator[] to * get the address. * @param v An existing representation of the type that has more elements than index. * @param index The index of the entry. */ static const void* getAddress(const V& v, int index); /** * @brief Get the number of primitve elements at that index. * * The default always returns 1. */ static int getSize(const V&, int index); }; template class FieldVector; template class VariableBlockVector; template struct CommPolicy, A> > { typedef VariableBlockVector, A> Type; typedef typename Type::B IndexedType; typedef VariableSize IndexedTypeFlag; static const void* getAddress(const Type& v, int i); static int getSize(const Type& v, int i); }; /** * @brief Error thrown if there was a problem with the communication. */ class CommunicationError : public IOError {}; /** * @brief GatherScatter default implementation that just copies data. */ template struct CopyGatherScatter { typedef typename CommPolicy::IndexedType IndexedType; static const IndexedType& gather(const T& vec, std::size_t i); static void scatter(T& vec, const IndexedType& v, std::size_t i); }; /** * @brief An utility class for communicating distributed data structures via MPI datatypes. * * This communicator creates special MPI datatypes that address the non contiguous elements * to be send and received. The idea was to prevent the copying to an additional buffer and * the mpi implementation decide whether to allocate buffers or use buffers offered by the * interconnection network. * * Unfortunately the implementation of MPI datatypes seems to be poor. Therefore for most MPI * implementations using a BufferedCommunicator will be more efficient. */ template class DatatypeCommunicator : public InterfaceBuilder { public: /** * @brief Type of the index set. */ typedef T ParallelIndexSet; /** * @brief Type of the underlying remote indices class. */ typedef Dune::RemoteIndices RemoteIndices; /** * @brief The type of the global index. */ typedef typename RemoteIndices::GlobalIndex GlobalIndex; /** * @brief The type of the attribute. */ typedef typename RemoteIndices::Attribute Attribute; /** * @brief The type of the local index. */ typedef typename RemoteIndices::LocalIndex LocalIndex; /** * @brief Creates a new DatatypeCommunicator. */ DatatypeCommunicator(); /** * @brief Destructor. */ ~DatatypeCommunicator(); /** * @brief Builds the interface between the index sets. * * Has to be called before the actual communication by forward or backward * can be called. Nonpublic indices will be ignored! * * * The types T1 and T2 are classes representing a set of * enumeration values of type DatatypeCommunicator::Attribute. * They have to provide * a (static) method * \code * bool contains(Attribute flag) const; * \endcode * for checking whether the set contains a specific flag. * This functionality is for example provided the classes * EnumItem, EnumRange and Combine. * * @param remoteIndices The indices present on remote processes. * @param sourceFlags The set of attributes which mark indices we send to other * processes. * @param sendData The indexed data structure whose data will be send. * @param destFlags The set of attributes which mark the indices we might * receive values from. * @param receiveData The indexed data structure for which we receive data. */ template void build(const RemoteIndices& remoteIndices, const T1& sourceFlags, V& sendData, const T2& destFlags, V& receiveData); /** * @brief Sends the primitive values from the source to the destination. */ void forward(); /** * @brief Sends the primitive values from the destination to the source. */ void backward(); /** * @brief Deallocates the MPI requests and data types. */ void free(); private: enum { /** * @brief Tag for the MPI communication. */ commTag_ = 234 }; /** * @brief The indices also known at other processes. */ const RemoteIndices* remoteIndices_; typedef std::map > MessageTypeMap; /** * @brief The datatypes built according to the communication interface. */ MessageTypeMap messageTypes; /** * @brief The pointer to the data whose entries we communicate. */ void* data_; MPI_Request* requests_[2]; /** * @brief True if the request and data types were created. */ bool created_; /** * @brief Creates the MPI_Requests for the forward communication. */ template void createRequests(V& sendData, V& receiveData); /** * @brief Creates the data types needed for the unbuffered receive. */ template void createDataTypes(const T1& source, const T2& destination, V& data); /** * @brief Initiates the sending and receive. */ void sendRecv(MPI_Request* req); /** * @brief Information used for setting up the MPI Datatypes. */ struct IndexedTypeInformation { /** * @brief Allocate space for setting up the MPI datatype. * * @param i The number of values the datatype will have. */ void build(int i) { length = new int[i]; displ = new MPI_Aint[i]; size = i; } /** * @brief Free the allocated space. */ void free() { delete[] length; delete[] displ; } /** @brief The number of values at each index. */ int* length; /** @brief The displacement at each index. */ MPI_Aint* displ; /** * @brief The number of elements we send. * In case of variable sizes this will differ from * size. */ int elements; /** * @param The number of indices in the data type. */ int size; }; /** * @brief Functor for the InterfaceBuilder. * * It will record the information needed to build the MPI_Datatypes. */ template struct MPIDatatypeInformation { /** * @brief Constructor. * @param data The data we construct an MPI data type for. */ MPIDatatypeInformation(const V& data) : data_(data) {} /** * @brief Reserver space for the information about the datatype. * @param proc The rank of the process this information is for. * @param size The number of indices the datatype will contain. */ void reserve(int proc, int size) { information_[proc].build(size); } /** * @brief Add a new index to the datatype. * @param proc The rank of the process this index is send to * or received from. * @param local The index to add. */ void add(int proc, int local) { IndexedTypeInformation& info=information_[proc]; assert((info.elements)(CommPolicy::getAddress(data_, local)), info.displ+info.elements); info.length[info.elements]=CommPolicy::getSize(data_, local); info.elements++; } /** * @brief The information about the datatypes to send to or * receive from each process. */ std::map information_; /** * @brief A representative of the indexed data we send. */ const V& data_; }; }; /** * @brief A communicator that uses buffers to gather and scatter * the data to be send or received. * * Before the data is sent it is copied to a consecutive buffer and * then that buffer is sent. * The data is received in another buffer and then copied to the actual * position. */ class BufferedCommunicator { public: /** * @brief Constructor. */ BufferedCommunicator(); /** * @brief Build the buffers and information for the communication process. * * * @param interface The interface that defines what indices are to be communicated. */ template typename std::enable_if::IndexedTypeFlag>::value, void>::type build(const Interface& interface); /** * @brief Build the buffers and information for the communication process. * * @param source The source in a forward send. The values will be copied from here to the send buffers. * @param target The target in a forward send. The received values will be copied to here. * @param interface The interface that defines what indices are to be communicated. */ template void build(const Data& source, const Data& target, const Interface& interface); /** * @brief Send from source to target. * * The template parameter GatherScatter (e.g. CopyGatherScatter) has to have a static method * \code * // Gather the data at index index of data * static const typename CommPolicy::IndexedType>& gather(Data& data, int index); * * // Scatter the value at a index of data * static void scatter(Data& data, typename CommPolicy::IndexedType> value, * int index); * \endcode * in the case where CommPolicy::IndexedTypeFlag is SizeOne * and * * \code * static const typename CommPolicy::IndexedType> gather(Data& data, int index, int subindex); * * static void scatter(Data& data, typename CommPolicy::IndexedType> value, * int index, int subindex); * \endcode * in the case where CommPolicy::IndexedTypeFlag is VariableSize. Here subindex is the * subindex of the block at index. * @warning The source and target data have to have the same layout as the ones given * to the build function in case of variable size values at the indices. * @param source The values will be copied from here to the send buffers. * @param dest The received values will be copied to here. */ template void forward(const Data& source, Data& dest); /** * @brief Communicate in the reverse direction, i.e. send from target to source. * * The template parameter GatherScatter (e.g. CopyGatherScatter) has to have a static method * \code * // Gather the data at index index of data * static const typename CommPolicy::IndexedType>& gather(Data& data, int index); * * // Scatter the value at a index of data * static void scatter(Data& data, typename CommPolicy::IndexedType> value, * int index); * \endcode * in the case where CommPolicy::IndexedTypeFlag is SizeOne * and * * \code * static const typename CommPolicy::IndexedType> gather(Data& data, int index, int subindex); * * static void scatter(Data& data, typename CommPolicy::IndexedType> value, * int index, int subindex); * \endcode * in the case where CommPolicy::IndexedTypeFlag is VariableSize. Here subindex is the * subindex of the block at index. * @warning The source and target data have to have the same layout as the ones given * to the build function in case of variable size values at the indices. * @param dest The values will be copied from here to the send buffers. * @param source The received values will be copied to here. */ template void backward(Data& source, const Data& dest); /** * @brief Forward send where target and source are the same. * * The template parameter GatherScatter has to have a static method * \code * // Gather the data at index index of data * static const typename CommPolicy::IndexedType>& gather(Data& data, int index); * * // Scatter the value at a index of data * static void scatter(Data& data, typename CommPolicy::IndexedType> value, * int index); * \endcode * in the case where CommPolicy::IndexedTypeFlag is SizeOne * and * * \code * static const typename CommPolicy::IndexedType> gather(Data& data, int index, int subindex); * * static void scatter(Data& data, typename CommPolicy::IndexedType> value, * int index, int subindex); * \endcode * in the case where CommPolicy::IndexedTypeFlag is VariableSize. Here subindex is the * subindex of the block at index. * @param data Source and target of the communication. */ template void forward(Data& data); /** * @brief Backward send where target and source are the same. * * The template parameter GatherScatter has to have a static method * \code * // Gather the data at index index of data * static const typename CommPolicy::IndexedType>& gather(Data& data, int index); * * // Scatter the value at a index of data * static void scatter(Data& data, typename CommPolicy::IndexedType> value, * int index); * \endcode * in the case where CommPolicy::IndexedTypeFlag is SizeOne * and * * \code * static const typename CommPolicy::IndexedType> gather(Data& data, int index, int subindex); * * static void scatter(Data& data, typename CommPolicy::IndexedType> value, * int index, int subindex); * \endcode * in the case where CommPolicy::IndexedTypeFlag is VariableSize. Here subindex is the * subindex of the block at index. * @param data Source and target of the communication. */ template void backward(Data& data); /** * @brief Free the allocated memory (i.e. buffers and message information. */ void free(); /** * @brief Destructor. */ ~BufferedCommunicator(); private: /** * @brief The type of the map that maps interface information to processors. */ typedef std::map > InterfaceMap; /** * @brief Functors for message size caculation */ template struct MessageSizeCalculator {}; /** * @brief Functor for message size caculation for datatypes * where at each index is only one value. */ template struct MessageSizeCalculator { /** * @brief Calculate the number of values in message * @param info The information about the interface corresponding * to the message. * @return The number of values in th message. */ inline int operator()(const InterfaceInformation& info) const; /** * @brief Calculate the number of values in message * * @param info The information about the interface corresponding * to the message. * @param data ignored. * @return The number of values in th message. */ inline int operator()(const Data& data, const InterfaceInformation& info) const; }; /** * @brief Functor for message size caculation for datatypes * where at each index can be a variable number of values. */ template struct MessageSizeCalculator { /** * @brief Calculate the number of values in message * * @param info The information about the interface corresponding * to the message. * @param data A representative of the data we send. * @return The number of values in th message. */ inline int operator()(const Data& data, const InterfaceInformation& info) const; }; /** * @brief Functors for message data gathering. */ template struct MessageGatherer {}; /** * @brief Functor for message data gathering for datatypes * where at each index is only one value. */ template struct MessageGatherer { /** @brief The type of the values we send. */ typedef typename CommPolicy::IndexedType Type; /** * @brief The type of the functor that does the actual copying * during the data Scattering. */ typedef GatherScatter Gatherer; enum { /** * @brief The communication mode * * True if this was a forward communication. */ forward=send }; /** * @brief Copies the values to send into the buffer. * @param interface The interface used in the send. * @param data The data from which we copy the values. * @param buffer The send buffer to copy to. * @param bufferSize The size of the buffer in bytes. For checks. */ inline void operator()(const InterfaceMap& interface, const Data& data, Type* buffer, size_t bufferSize) const; }; /** * @brief Functor for message data scattering for datatypes * where at each index can be a variable size of values */ template struct MessageGatherer { /** @brief The type of the values we send. */ typedef typename CommPolicy::IndexedType Type; /** * @brief The type of the functor that does the actual copying * during the data Scattering. */ typedef GatherScatter Gatherer; enum { /** * @brief The communication mode * * True if this was a forward communication. */ forward=send }; /** * @brief Copies the values to send into the buffer. * @param interface The interface used in the send. * @param data The data from which we copy the values. * @param buffer The send buffer to copy to. * @param bufferSize The size of the buffer in bytes. For checks. */ inline void operator()(const InterfaceMap& interface, const Data& data, Type* buffer, size_t bufferSize) const; }; /** * @brief Functors for message data scattering. */ template struct MessageScatterer {}; /** * @brief Functor for message data gathering for datatypes * where at each index is only one value. */ template struct MessageScatterer { /** @brief The type of the values we send. */ typedef typename CommPolicy::IndexedType Type; /** * @brief The type of the functor that does the actual copying * during the data Scattering. */ typedef GatherScatter Scatterer; enum { /** * @brief The communication mode * * True if this was a forward communication. */ forward=send }; /** * @brief Copy the message data from the receive buffer to the data. * @param interface The interface used in the send. * @param data The data to which we copy the values. * @param buffer The receive buffer to copy from. * @param proc The rank of the process the message is from. */ inline void operator()(const InterfaceMap& interface, Data& data, Type* buffer, const int& proc) const; }; /** * @brief Functor for message data scattering for datatypes * where at each index can be a variable size of values */ template struct MessageScatterer { /** @brief The type of the values we send. */ typedef typename CommPolicy::IndexedType Type; /** * @brief The type of the functor that does the actual copying * during the data Scattering. */ typedef GatherScatter Scatterer; enum { /** * @brief The communication mode * * True if this was a forward communication. */ forward=send }; /** * @brief Copy the message data from the receive buffer to the data. * @param interface The interface used in the send. * @param data The data to which we copy the values. * @param buffer The receive buffer to copy from. * @param proc The rank of the process the message is from. */ inline void operator()(const InterfaceMap& interface, Data& data, Type* buffer, const int& proc) const; }; /** * @brief Information about a message to send. */ struct MessageInformation { /** @brief Constructor. */ MessageInformation() : start_(0), size_(0) {} /** * @brief Constructor. * @param start The start of the message in the global buffer. * Not in bytes but in number of values from the beginning of * the buffer * @param size The size of the message in bytes. */ MessageInformation(size_t start, size_t size) : start_(start), size_(size) {} /** * @brief Start of the message in the buffer counted in number of value. */ size_t start_; /** * @brief Number of bytes in the message. */ size_t size_; }; /** * @brief Type of the map of information about the messages to send. * * The key is the process number to communicate with and the value is * the pair of information about sending and receiving messages. */ typedef std::map > InformationMap; /** * @brief Gathered information about the messages to send. */ InformationMap messageInformation_; /** * @brief Communication buffers. */ char* buffers_[2]; /** * @brief The size of the communication buffers */ size_t bufferSize_[2]; enum { /** * @brief The tag we use for communication. */ commTag_ }; /** * @brief The interface we currently work with. */ std::map > interfaces_; MPI_Comm communicator_; /** * @brief Send and receive Data. */ template void sendRecv(const Data& source, Data& target); }; #ifndef DOXYGEN template inline const void* CommPolicy::getAddress(const V& v, int index) { return &(v[index]); } template inline int CommPolicy::getSize([[maybe_unused]] const V& v, [[maybe_unused]] int index) { return 1; } template inline const void* CommPolicy, A> >::getAddress(const Type& v, int index) { return &(v[index][0]); } template inline int CommPolicy, A> >::getSize(const Type& v, int index) { return v[index].getsize(); } template inline const typename CopyGatherScatter::IndexedType& CopyGatherScatter::gather(const T & vec, std::size_t i) { return vec[i]; } template inline void CopyGatherScatter::scatter(T& vec, const IndexedType& v, std::size_t i) { vec[i]=v; } template DatatypeCommunicator::DatatypeCommunicator() : remoteIndices_(0), created_(false) { requests_[0]=0; requests_[1]=0; } template DatatypeCommunicator::~DatatypeCommunicator() { free(); } template template inline void DatatypeCommunicator::build(const RemoteIndices& remoteIndices, const T1& source, V& sendData, const T2& destination, V& receiveData) { remoteIndices_ = &remoteIndices; free(); createDataTypes(source,destination, receiveData); createDataTypes(source,destination, sendData); createRequests(sendData, receiveData); createRequests(receiveData, sendData); created_=true; } template void DatatypeCommunicator::free() { if(created_) { delete[] requests_[0]; delete[] requests_[1]; typedef MessageTypeMap::iterator iterator; typedef MessageTypeMap::const_iterator const_iterator; const const_iterator end=messageTypes.end(); for(iterator process = messageTypes.begin(); process != end; ++process) { MPI_Datatype *type = &(process->second.first); int finalized=0; MPI_Finalized(&finalized); if(*type!=MPI_DATATYPE_NULL && !finalized) MPI_Type_free(type); type = &(process->second.second); if(*type!=MPI_DATATYPE_NULL && !finalized) MPI_Type_free(type); } messageTypes.clear(); created_=false; } } template template void DatatypeCommunicator::createDataTypes(const T1& sourceFlags, const T2& destFlags, V& data) { MPIDatatypeInformation dataInfo(data); this->template buildInterface,send>(*remoteIndices_,sourceFlags, destFlags, dataInfo); typedef typename RemoteIndices::RemoteIndexMap::const_iterator const_iterator; const const_iterator end=this->remoteIndices_->end(); // Allocate MPI_Datatypes and deallocate memory for the type construction. for(const_iterator process=this->remoteIndices_->begin(); process != end; ++process) { IndexedTypeInformation& info=dataInfo.information_[process->first]; // Shift the displacement MPI_Aint base; MPI_Get_address(const_cast(CommPolicy::getAddress(data, 0)), &base); for(int i=0; i< info.elements; i++) { info.displ[i]-=base; } // Create data type MPI_Datatype* type = &( send ? messageTypes[process->first].first : messageTypes[process->first].second); MPI_Type_create_hindexed(info.elements, info.length, info.displ, MPITraits::IndexedType>::getType(), type); MPI_Type_commit(type); // Deallocate memory info.free(); } } template template void DatatypeCommunicator::createRequests(V& sendData, V& receiveData) { typedef std::map >::const_iterator MapIterator; int rank; static int index = createForward ? 1 : 0; int noMessages = messageTypes.size(); // allocate request handles requests_[index] = new MPI_Request[2*noMessages]; const MapIterator end = messageTypes.end(); int request=0; MPI_Comm_rank(MPI_COMM_WORLD, &rank); // Set up the requests for receiving first for(MapIterator process = messageTypes.begin(); process != end; ++process, ++request) { MPI_Datatype type = createForward ? process->second.second : process->second.first; void* address = const_cast(CommPolicy::getAddress(receiveData,0)); MPI_Recv_init(address, 1, type, process->first, commTag_, this->remoteIndices_->communicator(), requests_[index]+request); } // And now the send requests for(MapIterator process = messageTypes.begin(); process != end; ++process, ++request) { MPI_Datatype type = createForward ? process->second.first : process->second.second; void* address = const_cast(CommPolicy::getAddress(sendData, 0)); MPI_Ssend_init(address, 1, type, process->first, commTag_, this->remoteIndices_->communicator(), requests_[index]+request); } } template void DatatypeCommunicator::forward() { sendRecv(requests_[1]); } template void DatatypeCommunicator::backward() { sendRecv(requests_[0]); } template void DatatypeCommunicator::sendRecv(MPI_Request* requests) { int noMessages = messageTypes.size(); // Start the receive calls first MPI_Startall(noMessages, requests); // Now the send calls MPI_Startall(noMessages, requests+noMessages); // Wait for completion of the communication send first then receive MPI_Status* status=new MPI_Status[2*noMessages]; for(int i=0; i<2*noMessages; i++) status[i].MPI_ERROR=MPI_SUCCESS; int send = MPI_Waitall(noMessages, requests+noMessages, status+noMessages); int receive = MPI_Waitall(noMessages, requests, status); // Error checks int success=1, globalSuccess=0; if(send==MPI_ERR_IN_STATUS) { int rank; MPI_Comm_rank(this->remoteIndices_->communicator(), &rank); std::cerr<remoteIndices_->communicator(), &rank); std::cerr<remoteIndices_->communicator()); delete[] status; if(!globalSuccess) DUNE_THROW(CommunicationError, "A communication error occurred!"); } inline BufferedCommunicator::BufferedCommunicator() { buffers_[0]=0; buffers_[1]=0; bufferSize_[0]=0; bufferSize_[1]=0; } template typename std::enable_if::IndexedTypeFlag>::value, void>::type BufferedCommunicator::build(const Interface& interface) { interfaces_=interface.interfaces(); communicator_=interface.communicator(); typedef typename std::map > ::const_iterator const_iterator; typedef typename CommPolicy::IndexedTypeFlag Flag; const const_iterator end = interfaces_.end(); int lrank; MPI_Comm_rank(communicator_, &lrank); bufferSize_[0]=0; bufferSize_[1]=0; for(const_iterator interfacePair = interfaces_.begin(); interfacePair != end; ++interfacePair) { int noSend = MessageSizeCalculator() (interfacePair->second.first); int noRecv = MessageSizeCalculator() (interfacePair->second.second); if (noSend + noRecv > 0) messageInformation_.insert(std::make_pair(interfacePair->first, std::make_pair(MessageInformation(bufferSize_[0], noSend*sizeof(typename CommPolicy::IndexedType)), MessageInformation(bufferSize_[1], noRecv*sizeof(typename CommPolicy::IndexedType))))); bufferSize_[0] += noSend; bufferSize_[1] += noRecv; } // allocate the buffers bufferSize_[0] *= sizeof(typename CommPolicy::IndexedType); bufferSize_[1] *= sizeof(typename CommPolicy::IndexedType); buffers_[0] = new char[bufferSize_[0]]; buffers_[1] = new char[bufferSize_[1]]; } template void BufferedCommunicator::build(const Data& source, const Data& dest, const Interface& interface) { interfaces_=interface.interfaces(); communicator_=interface.communicator(); typedef typename std::map > ::const_iterator const_iterator; typedef typename CommPolicy::IndexedTypeFlag Flag; const const_iterator end = interfaces_.end(); bufferSize_[0]=0; bufferSize_[1]=0; for(const_iterator interfacePair = interfaces_.begin(); interfacePair != end; ++interfacePair) { int noSend = MessageSizeCalculator() (source, interfacePair->second.first); int noRecv = MessageSizeCalculator() (dest, interfacePair->second.second); if (noSend + noRecv > 0) messageInformation_.insert(std::make_pair(interfacePair->first, std::make_pair(MessageInformation(bufferSize_[0], noSend*sizeof(typename CommPolicy::IndexedType)), MessageInformation(bufferSize_[1], noRecv*sizeof(typename CommPolicy::IndexedType))))); bufferSize_[0] += noSend; bufferSize_[1] += noRecv; } bufferSize_[0] *= sizeof(typename CommPolicy::IndexedType); bufferSize_[1] *= sizeof(typename CommPolicy::IndexedType); // allocate the buffers buffers_[0] = new char[bufferSize_[0]]; buffers_[1] = new char[bufferSize_[1]]; } inline void BufferedCommunicator::free() { messageInformation_.clear(); if(buffers_[0]) delete[] buffers_[0]; if(buffers_[1]) delete[] buffers_[1]; buffers_[0]=buffers_[1]=0; } inline BufferedCommunicator::~BufferedCommunicator() { free(); } template inline int BufferedCommunicator::MessageSizeCalculator::operator() (const InterfaceInformation& info) const { return info.size(); } template inline int BufferedCommunicator::MessageSizeCalculator::operator() (const Data&, const InterfaceInformation& info) const { return operator()(info); } template inline int BufferedCommunicator::MessageSizeCalculator::operator() (const Data& data, const InterfaceInformation& info) const { int entries=0; for(size_t i=0; i < info.size(); i++) entries += CommPolicy::getSize(data,info[i]); return entries; } template inline void BufferedCommunicator::MessageGatherer::operator()(const InterfaceMap& interfaces,const Data& data, Type* buffer, [[maybe_unused]] size_t bufferSize) const { typedef typename InterfaceMap::const_iterator const_iterator; int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); const const_iterator end = interfaces.end(); size_t index=0; for(const_iterator interfacePair = interfaces.begin(); interfacePair != end; ++interfacePair) { int size = forward ? interfacePair->second.first.size() : interfacePair->second.second.size(); for(int i=0; i < size; i++) { int local = forward ? interfacePair->second.first[i] : interfacePair->second.second[i]; for(std::size_t j=0; j < CommPolicy::getSize(data, local); j++, index++) { #ifdef DUNE_ISTL_WITH_CHECKING assert(bufferSize>=(index+1)*sizeof(typename CommPolicy::IndexedType)); #endif buffer[index]=GatherScatter::gather(data, local, j); } } } } template inline void BufferedCommunicator::MessageGatherer::operator()( const InterfaceMap& interfaces, const Data& data, Type* buffer, [[maybe_unused]] size_t bufferSize) const { typedef typename InterfaceMap::const_iterator const_iterator; const const_iterator end = interfaces.end(); size_t index = 0; int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); for(const_iterator interfacePair = interfaces.begin(); interfacePair != end; ++interfacePair) { size_t size = FORWARD ? interfacePair->second.first.size() : interfacePair->second.second.size(); for(size_t i=0; i < size; i++) { #ifdef DUNE_ISTL_WITH_CHECKING assert(bufferSize>=(index+1)*sizeof(typename CommPolicy::IndexedType)); #endif buffer[index++] = GatherScatter::gather(data, FORWARD ? interfacePair->second.first[i] : interfacePair->second.second[i]); } } } template inline void BufferedCommunicator::MessageScatterer::operator()(const InterfaceMap& interfaces, Data& data, Type* buffer, const int& proc) const { typedef typename InterfaceMap::value_type::second_type::first_type Information; const typename InterfaceMap::const_iterator infoPair = interfaces.find(proc); assert(infoPair!=interfaces.end()); const Information& info = FORWARD ? infoPair->second.second : infoPair->second.first; for(size_t i=0, index=0; i < info.size(); i++) { for(size_t j=0; j < CommPolicy::getSize(data, info[i]); j++) GatherScatter::scatter(data, buffer[index++], info[i], j); } } template inline void BufferedCommunicator::MessageScatterer::operator()(const InterfaceMap& interfaces, Data& data, Type* buffer, const int& proc) const { typedef typename InterfaceMap::value_type::second_type::first_type Information; const typename InterfaceMap::const_iterator infoPair = interfaces.find(proc); assert(infoPair!=interfaces.end()); const Information& info = FORWARD ? infoPair->second.second : infoPair->second.first; for(size_t i=0; i < info.size(); i++) { GatherScatter::scatter(data, buffer[i], info[i]); } } template void BufferedCommunicator::forward(Data& data) { this->template sendRecv(data, data); } template void BufferedCommunicator::backward(Data& data) { this->template sendRecv(data, data); } template void BufferedCommunicator::forward(const Data& source, Data& dest) { this->template sendRecv(source, dest); } template void BufferedCommunicator::backward(Data& source, const Data& dest) { this->template sendRecv(dest, source); } template void BufferedCommunicator::sendRecv(const Data& source, Data& dest) { int rank, lrank; MPI_Comm_rank(MPI_COMM_WORLD,&rank); MPI_Comm_rank(MPI_COMM_WORLD,&lrank); typedef typename CommPolicy::IndexedType Type; Type *sendBuffer, *recvBuffer; size_t sendBufferSize; #ifndef NDEBUG size_t recvBufferSize; #endif if(FORWARD) { sendBuffer = reinterpret_cast(buffers_[0]); sendBufferSize = bufferSize_[0]; recvBuffer = reinterpret_cast(buffers_[1]); #ifndef NDEBUG recvBufferSize = bufferSize_[1]; #endif }else{ sendBuffer = reinterpret_cast(buffers_[1]); sendBufferSize = bufferSize_[1]; recvBuffer = reinterpret_cast(buffers_[0]); #ifndef NDEBUG recvBufferSize = bufferSize_[0]; #endif } typedef typename CommPolicy::IndexedTypeFlag Flag; MessageGatherer() (interfaces_, source, sendBuffer, sendBufferSize); MPI_Request* sendRequests = new MPI_Request[messageInformation_.size()]; MPI_Request* recvRequests = new MPI_Request[messageInformation_.size()]; /* Number of recvRequests that are not MPI_REQUEST_NULL */ size_t numberOfRealRecvRequests = 0; // Setup receive first typedef typename InformationMap::const_iterator const_iterator; const const_iterator end = messageInformation_.end(); size_t i=0; int* processMap = new int[messageInformation_.size()]; for(const_iterator info = messageInformation_.begin(); info != end; ++info, ++i) { processMap[i]=info->first; if(FORWARD) { assert(info->second.second.start_*sizeof(typename CommPolicy::IndexedType)+info->second.second.size_ <= recvBufferSize ); Dune::dvverb<second.second.size_<<" from "<first<second.second.size_) { MPI_Irecv(recvBuffer+info->second.second.start_, info->second.second.size_, MPI_BYTE, info->first, commTag_, communicator_, recvRequests+i); numberOfRealRecvRequests += 1; } else { // Nothing to receive -> set request to inactive recvRequests[i]=MPI_REQUEST_NULL; } }else{ assert(info->second.first.start_*sizeof(typename CommPolicy::IndexedType)+info->second.first.size_ <= recvBufferSize ); Dune::dvverb<second.first.size_<<" to "<first<second.first.size_) { MPI_Irecv(recvBuffer+info->second.first.start_, info->second.first.size_, MPI_BYTE, info->first, commTag_, communicator_, recvRequests+i); numberOfRealRecvRequests += 1; } else { // Nothing to receive -> set request to inactive recvRequests[i]=MPI_REQUEST_NULL; } } } // now the send requests i=0; for(const_iterator info = messageInformation_.begin(); info != end; ++info, ++i) if(FORWARD) { assert(info->second.second.start_*sizeof(typename CommPolicy::IndexedType)+info->second.second.size_ <= recvBufferSize ); Dune::dvverb<second.first.size_<<" to "<first<second.first.start_*sizeof(typename CommPolicy::IndexedType)+info->second.first.size_ <= sendBufferSize ); if(info->second.first.size_) MPI_Issend(sendBuffer+info->second.first.start_, info->second.first.size_, MPI_BYTE, info->first, commTag_, communicator_, sendRequests+i); else // Nothing to send -> set request to inactive sendRequests[i]=MPI_REQUEST_NULL; }else{ assert(info->second.second.start_*sizeof(typename CommPolicy::IndexedType)+info->second.second.size_ <= sendBufferSize ); Dune::dvverb<second.second.size_<<" to "<first<second.second.size_) MPI_Issend(sendBuffer+info->second.second.start_, info->second.second.size_, MPI_BYTE, info->first, commTag_, communicator_, sendRequests+i); else // Nothing to send -> set request to inactive sendRequests[i]=MPI_REQUEST_NULL; } // Wait for completion of receive and immediately start scatter i=0; //int success = 1; int finished = MPI_UNDEFINED; MPI_Status status; //[messageInformation_.size()]; //MPI_Waitall(messageInformation_.size(), recvRequests, status); for(i=0; i< numberOfRealRecvRequests; i++) { status.MPI_ERROR=MPI_SUCCESS; MPI_Waitany(messageInformation_.size(), recvRequests, &finished, &status); assert(finished != MPI_UNDEFINED); if(status.MPI_ERROR==MPI_SUCCESS) { int& proc = processMap[finished]; typename InformationMap::const_iterator infoIter = messageInformation_.find(proc); assert(infoIter != messageInformation_.end()); MessageInformation info = (FORWARD) ? infoIter->second.second : infoIter->second.first; assert(info.start_+info.size_ <= recvBufferSize); MessageScatterer() (interfaces_, dest, recvBuffer+info.start_, proc); }else{ std::cerr<communicator()); if(!globalSuccess) DUNE_THROW(CommunicationError, "A communication error occurred!"); */ delete[] processMap; delete[] sendRequests; delete[] recvRequests; } #endif // DOXYGEN /** @} */ } #endif // HAVE_MPI #endif dune-common-2.8.0/dune/common/parallel/future.hh000066400000000000000000000102551411343567400216270ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_PARALLEL_FUTURE_HH #define DUNE_COMMON_PARALLEL_FUTURE_HH #include #include namespace Dune{ /*! \brief This exception is thrown when `ready()`, `wait()` or `get()` is called on an invalid future. A future is valid until `get()` is called and if it is not default-constructed and it was not moved from. */ class InvalidFutureException : public InvalidStateException {}; // forward declaration template class PseudoFuture; /*! \brief Type-erasure for future-like objects. A future-like object is a object satisfying the interface of FutureBase. */ template class Future{ // Future interface: class FutureBase{ public: virtual ~FutureBase() = default; virtual void wait() = 0; virtual bool ready() const = 0; virtual bool valid() const = 0; virtual T get() = 0; }; // model class template class FutureModel : public FutureBase { F _future; public: FutureModel(F&& f) : _future(std::forward(f)) {} virtual void wait() override { _future.wait(); } virtual bool ready() const override { return _future.ready(); } virtual bool valid() const override { return _future.valid(); } virtual T get() override{ return (T)_future.get(); } }; std::unique_ptr _future; public: template Future(F&& f) : _future(std::make_unique>(std::forward(f))) {} template::value && !std::is_same::value>> Future(U&& data) : _future(std::make_unique>>(PseudoFuture(std::forward(data)))) {} Future() = default; /*! \brief wait until the future is ready \throws InvalidFutureException */ void wait(){ _future->wait(); } /*! \brief Waits until the future is ready and returns the resulting value \returns The contained value \throws InvalidFutureException */ T get() { return _future->get(); } /*! \brief \returns true is the future is ready, otherwise false \throws InvalidFutureException */ bool ready() const { return _future->ready(); } /*! \brief Checks whether the future is valid. I.e. `get()' was not called on that future and when it was not default-constructed and not moved from. \returns true is the future is valid, otherwise false */ bool valid() const { if(_future) return _future->valid(); return false; } }; /*! \brief A wrapper-class for a object which is ready immediately. */ template class PseudoFuture{ bool valid_; T data_; public: PseudoFuture() : valid_(false) {} template PseudoFuture(U&& u) : valid_(true), data_(std::forward(u)) {} void wait() { if(!valid_) DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid"); } bool ready() const { if(!valid_) DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid"); return true; } T get() { if(!valid_) DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid"); valid_ = false; return std::forward(data_); } bool valid() const { return valid_; } }; template<> class PseudoFuture{ bool valid_; public: PseudoFuture(bool valid = false) : valid_(valid) {} void wait(){ if(!valid_) DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid"); } bool ready() const{ if(!valid_) DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid"); return true; } void get(){ if(!valid_) DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid"); valid_ = false; } bool valid() const{ return valid_; } }; } #endif dune-common-2.8.0/dune/common/parallel/indexset.hh000066400000000000000000000755461411343567400221560ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_INDEXSET_HH #define DUNE_INDEXSET_HH #include #include #include #include #include "localindex.hh" #include // for uint32_t namespace Dune { /** @addtogroup Common_Parallel * * @{ */ /** * @file * @brief Provides a map between global and local indices. * @author Markus Blatt */ // forward declarations template class IndexPair; /** * @brief Print an index pair. * @param os The outputstream to print to. * @param pair The index pair to print. */ template std::ostream& operator<<(std::ostream& os, const IndexPair& pair); template bool operator==(const IndexPair&, const IndexPair&); template bool operator!=(const IndexPair&, const IndexPair&); template bool operator<(const IndexPair&, const IndexPair&); template bool operator>(const IndexPair&, const IndexPair&); template bool operator<=(const IndexPair&, const IndexPair&); template bool operator >=(const IndexPair&, const IndexPair&); template bool operator==(const IndexPair&, const TG&); template bool operator!=(const IndexPair&, const TG&); template bool operator<(const IndexPair&, const TG&); template bool operator>(const IndexPair&, const TG&); template bool operator<=(const IndexPair&, const TG&); template bool operator >=(const IndexPair&, const TG&); template struct MPITraits; /** * @brief A pair consisting of a global and local index. */ template class IndexPair { friend std::ostream& operator<<<>(std::ostream&, const IndexPair&); friend bool operator==<>(const IndexPair&, const IndexPair&); friend bool operator!=<>(const IndexPair&, const IndexPair&); friend bool operator< <>(const IndexPair&, const IndexPair&); friend bool operator><>(const IndexPair&, const IndexPair&); friend bool operator<=<>(const IndexPair&, const IndexPair&); friend bool operator>=<>(const IndexPair&, const IndexPair&); friend bool operator==<>(const IndexPair&, const TG &); friend bool operator!=<>(const IndexPair&, const TG &); friend bool operator< <>(const IndexPair&, const TG &); friend bool operator> <>(const IndexPair&, const TG &); friend bool operator<=<>(const IndexPair&, const TG &); friend bool operator>=<>(const IndexPair&, const TG &); friend struct MPITraits >; public: /** * @brief the type of the global index. * * This type has to provide at least a operator< for sorting. */ typedef TG GlobalIndex; /** * @brief the type of the local index. * * This class to provide the following functions: * \code * LocalIndex operator=(int); * operator int() const; * LocalIndexState state() const; * void setState(LocalIndexState); * \endcode */ typedef TL LocalIndex; /** * @brief Constructs a new Pair. * * @param global The global index. * @param local The local index. */ IndexPair(const GlobalIndex& global, const LocalIndex& local); /** * @brief Construct a new Pair. */ IndexPair(); /** * @brief Constructs a new Pair. * * The local index will be 0. * @param global The global index. */ IndexPair(const GlobalIndex& global); /** * @brief Get the global index. * * @return The global index. */ inline const GlobalIndex& global() const; /** * @brief Get the local index. * * @return The local index. */ inline LocalIndex& local(); /** * @brief Get the local index. * * @return The local index. */ inline const LocalIndex& local() const; /** * @brief Set the local index. * * @param index The index to set it to. */ inline void setLocal(int index); private: /** @brief The global index. */ GlobalIndex global_; /** @brief The local index. */ LocalIndex local_; }; /** * @brief The states the index set can be in. * @see ParallelIndexSet::state_ */ enum ParallelIndexSetState { /** * @brief The default mode. * Indicates that the index set is ready to be used. */ GROUND, /** * @brief Indicates that the index set is currently being resized. */ RESIZE /** * @brief Indicates that all previously deleted indices are now deleted. * CLEAN, ** * @brief Indicates that the index set is currently being reordered. * REORDER */ }; /** * @brief Exception indicating that the index set is not in the expected state. */ class InvalidIndexSetState : public InvalidStateException {}; // Forward declaration template class GlobalLookupIndexSet; /** * @brief Manager class for the mapping between local indices and globally unique indices. * * The mapping is between a globally unique id and local index. The local index is consecutive * and non persistent while the global id might not be consecutive but definitely is persistent. */ template class ParallelIndexSet { friend class GlobalLookupIndexSet >; public: /** * @brief the type of the global index. * This type has to provide at least a operator< for sorting. */ typedef TG GlobalIndex; /** * @brief The type of the local index, e.g. ParallelLocalIndex. * * This class to provide the following functions: * \code * LocalIndex operator=(int); * operator int() const; * LocalIndexState state() const; * void setState(LocalIndexState); * \endcode */ typedef TL LocalIndex; /** * @brief The type of the pair stored. */ typedef Dune::IndexPair IndexPair; enum { /** * @brief The size of the individual arrays in the underlying ArrayList. * * The default value is 100. * @see ArrayList::size */ arraySize= (N>0) ? N : 1 }; /** @brief The iterator over the pairs. */ class iterator : public ArrayList::iterator { typedef typename ArrayList::iterator Father; friend class ParallelIndexSet; public: iterator(ParallelIndexSet& indexSet, const Father& father) : Father(father), indexSet_(&indexSet) {} private: /** * @brief Mark the index as deleted. * * The deleted flag will be set in the local index. * The index will be removed in the endResize method of the * index set. * * @exception InvalidIndexSetState only when NDEBUG is not defined */ inline void markAsDeleted() const { #ifndef NDEBUG if(indexSet_->state_ != RESIZE) DUNE_THROW(InvalidIndexSetState, "Indices can only be removed " <<"while in RESIZE state!"); #endif Father::operator*().local().setState(DELETED); } /** @brief The index set we are an iterator of. */ ParallelIndexSet* indexSet_; }; /** @brief The constant iterator over the pairs. */ typedef typename ArrayList::const_iterator const_iterator; /** * @brief Constructor. */ ParallelIndexSet(); /** * @brief Get the state the index set is in. * @return The state of the index set. */ inline const ParallelIndexSetState& state() { return state_; } /** * @brief Indicate that the index set is to be resized. * @exception InvalidState If index set was not in * ParallelIndexSetState::GROUND mode. */ void beginResize(); /** * @brief Add an new index to the set. * * The local index is created by the default constructor. * @param global The globally unique id of the index. * @exception InvalidState If index set is not in * ParallelIndexSetState::RESIZE mode. */ inline void add(const GlobalIndex& global); /** * @brief Add an new index to the set. * * @param global The globally unique id of the index. * @param local The local index. * @exception InvalidState If index set is not in * ParallelIndexSetState::RESIZE mode. */ inline void add(const GlobalIndex& global, const LocalIndex& local); /** * @brief Mark an index as deleted. * * The index will be deleted during endResize(). * @param position An iterator at the position we want to delete. * @exception InvalidState If index set is not in ParallelIndexSetState::RESIZE mode. */ inline void markAsDeleted(const iterator& position); /** * @brief Indicate that the resizing finishes. * * @warning Invalidates all pointers stored to the elements of this index set. * The local indices will be ordered * according to the global indices: * Let \f$(g_i,l_i)_{i=0}^N \f$ be the set of all indices then \f$l_i < l_j\f$ * if and * only if \f$g_i < g_j\f$ for arbitrary \f$i \neq j\f$. * @exception InvalidState If index set was not in * ParallelIndexSetState::RESIZE mode. */ void endResize(); /** * @brief Find the index pair with a specific global id. * * This starts a binary search for the entry and therefore has complexity * log(N). * @param global The globally unique id of the pair. * @return The pair of indices for the id. * @warning If the global index is not in the set a wrong or even a * null reference might be returned. To be save use the throwing alternative at. */ inline IndexPair& operator[](const GlobalIndex& global); /** * @brief Find the index pair with a specific global id. * * This starts a binary search for the entry and therefore has complexity * log(N). * @param global The globally unique id of the pair. * @return The pair of indices for the id. * @exception RangeError Thrown if the global id is not known. */ inline IndexPair& at(const GlobalIndex& global); /** * @brief Find the index pair with a specific global id. * * This starts a binary search for the entry and therefore has complexity * log(N). * @param global The globally unique id of the pair. * @return The pair of indices for the id. * @exception RangeError Thrown if the global id is not known. */ inline bool exists (const GlobalIndex& global) const; /** * @brief Find the index pair with a specific global id. * * This starts a binary search for the entry and therefore has complexity * log(N). * @param global The globally unique id of the pair. * @return The pair of indices for the id. * @warning If the global index is not in the set a wrong or even a * null reference might be returned. To be save use the throwing alternative at. */ inline const IndexPair& operator[](const GlobalIndex& global) const; /** * @brief Find the index pair with a specific global id. * * This starts a binary search for the entry and therefore has complexity * log(N). * @param global The globally unique id of the pair. * @return The pair of indices for the id. * @exception RangeError Thrown if the global id is not known. */ inline const IndexPair& at(const GlobalIndex& global) const; /** * @brief Get an iterator over the indices positioned at the first index. * @return Iterator over the local indices. */ inline iterator begin(); /** * @brief Get an iterator over the indices positioned after the last index. * @return Iterator over the local indices. */ inline iterator end(); /** * @brief Get an iterator over the indices positioned at the first index. * @return Iterator over the local indices. */ inline const_iterator begin() const; /** * @brief Get an iterator over the indices positioned after the last index. * @return Iterator over the local indices. */ inline const_iterator end() const; /** * @brief Renumbers the local index numbers. * * After this function returns the indices are * consecutively numbered beginning from 0. Let * $(g_i,l_i)$, $(g_j,l_j)$ be two arbitrary index * pairs with $g_i localIndices_; /** @brief The new indices for the RESIZE state. */ ArrayList newIndices_; /** @brief The state of the index set. */ ParallelIndexSetState state_; /** @brief Number to keep track of the number of resizes. */ int seqNo_; /** @brief Whether entries were deleted in resize mode. */ bool deletedEntries_; /** * @brief Merges the _localIndices and newIndices arrays and creates a new * localIndices array. */ inline void merge(); }; /** * @brief Print an index set. * @param os The outputstream to print to. * @param indexSet The index set to print. */ template std::ostream& operator<<(std::ostream& os, const ParallelIndexSet& indexSet); /** * @brief Decorates an index set with the possibility to find a global index * that is mapped to a specific local. * */ template class GlobalLookupIndexSet { public: /** * @brief The type of the index set. */ typedef I ParallelIndexSet; /** * @brief The type of the local index. */ typedef typename ParallelIndexSet::LocalIndex LocalIndex; /** * @brief The type of the global index. */ typedef typename ParallelIndexSet::GlobalIndex GlobalIndex; /** * @brief The iterator over the index pairs. */ typedef typename ParallelIndexSet::const_iterator const_iterator; typedef Dune::IndexPair IndexPair; /** * @brief Constructor. * @param indexset The index set we want to be able to lookup the corresponding * global index of a local index. * @param size The number of indices present, i.e. one more than the maximum local index. */ GlobalLookupIndexSet(const ParallelIndexSet& indexset, std::size_t size); /** * @brief Constructor. * @param indexset The index set we want to be able to lookup the corresponding * global index of a local index. */ GlobalLookupIndexSet(const ParallelIndexSet& indexset); /** * @brief Destructor. */ ~GlobalLookupIndexSet(); /** * @brief Find the index pair with a specific global id. * * This starts a binary search for the entry and therefore has complexity * log(N). This method is forwarded to the underlying index set. * @param global The globally unique id of the pair. * @return The pair of indices for the id. * @exception RangeError Thrown if the global id is not known. */ inline const IndexPair& operator[](const GlobalIndex& global) const; /** * @brief Get the index pair corresponding to a local index. */ inline const IndexPair* pair(const std::size_t& local) const; /** * @brief Get an iterator over the indices positioned at the first index. * @return Iterator over the local indices. */ inline const_iterator begin() const; /** * @brief Get an iterator over the indices positioned after the last index. * @return Iterator over the local indices. */ inline const_iterator end() const; /** * @brief Get the internal sequence number. * * Is initially 0 is incremented for each resize. * @return The sequence number. */ inline int seqNo() const; /** * @brief Get the total number (public and nonpublic) indices. * @return The total number (public and nonpublic) indices. */ inline size_t size() const; private: /** * @brief The index set we lookup in. */ const ParallelIndexSet& indexSet_; /** * @brief The number of indices. */ std::size_t size_; /** * @brief Array with the positions of the corresponding index pair of the index set. */ std::vector indices_; }; template struct LocalIndexComparator { static bool compare([[maybe_unused]] const T& t1, [[maybe_unused]] const T& t2) { return false; } }; template struct IndexSetSortFunctor { bool operator()(const IndexPair& i1, const IndexPair& i2) { return i1.global()::compare(i1.local(), i2.local())); } }; template inline std::ostream& operator<<(std::ostream& os, const IndexPair& pair) { os<<"{global="< inline std::ostream& operator<<(std::ostream& os, const ParallelIndexSet& indexSet) { typedef typename ParallelIndexSet::const_iterator Iterator; Iterator end = indexSet.end(); os<<"{"; for(Iterator index = indexSet.begin(); index != end; ++index) os<<*index<<" "; os<<"}"; return os; } template inline bool operator==(const IndexPair& a, const IndexPair& b) { return a.global_==b.global_; } template inline bool operator!=(const IndexPair& a, const IndexPair& b) { return a.global_!=b.global_; } template inline bool operator<(const IndexPair& a, const IndexPair& b) { return a.global_ inline bool operator>(const IndexPair& a, const IndexPair& b) { return a.global_>b.global_; } template inline bool operator<=(const IndexPair& a, const IndexPair& b) { return a.global_<=b.global_; } template inline bool operator >=(const IndexPair& a, const IndexPair& b) { return a.global_>=b.global_; } template inline bool operator==(const IndexPair& a, const TG& b) { return a.global_==b; } template inline bool operator!=(const IndexPair& a, const TG& b) { return a.global_!=b; } template inline bool operator<(const IndexPair& a, const TG& b) { return a.global_ inline bool operator>(const IndexPair& a, const TG& b) { return a.global_>b; } template inline bool operator<=(const IndexPair& a, const TG& b) { return a.global_<=b; } template inline bool operator >=(const IndexPair& a, const TG& b) { return a.global_>=b; } #ifndef DOXYGEN template IndexPair::IndexPair(const TG& global, const TL& local) : global_(global), local_(local){} template IndexPair::IndexPair(const TG& global) : global_(global), local_(){} template IndexPair::IndexPair() : global_(), local_(){} template inline const TG& IndexPair::global() const { return global_; } template inline TL& IndexPair::local() { return local_; } template inline const TL& IndexPair::local() const { return local_; } template inline void IndexPair::setLocal(int local){ local_=local; } template ParallelIndexSet::ParallelIndexSet() : state_(GROUND), seqNo_(0) {} template void ParallelIndexSet::beginResize() { // Checks in unproductive code #ifndef NDEBUG if(state_!=GROUND) DUNE_THROW(InvalidIndexSetState, "IndexSet has to be in GROUND state, when " << "beginResize() is called!"); #endif state_ = RESIZE; deletedEntries_ = false; } template inline void ParallelIndexSet::add(const GlobalIndex& global) { // Checks in unproductive code #ifndef NDEBUG if(state_ != RESIZE) DUNE_THROW(InvalidIndexSetState, "Indices can only be added " <<"while in RESIZE state!"); #endif newIndices_.push_back(IndexPair(global)); } template inline void ParallelIndexSet::add(const TG& global, const TL& local) { // Checks in unproductive code #ifndef NDEBUG if(state_ != RESIZE) DUNE_THROW(InvalidIndexSetState, "Indices can only be added " <<"while in RESIZE state!"); #endif newIndices_.push_back(IndexPair(global,local)); } template inline void ParallelIndexSet::markAsDeleted(const iterator& global) { // Checks in unproductive code #ifndef NDEBUG if(state_ != RESIZE) DUNE_THROW(InvalidIndexSetState, "Indices can only be removed " <<"while in RESIZE state!"); #endif deletedEntries_ = true; global.markAsDeleted(); } template void ParallelIndexSet::endResize() { // Checks in unproductive code #ifndef NDEBUG if(state_ != RESIZE) DUNE_THROW(InvalidIndexSetState, "endResize called while not " <<"in RESIZE state!"); #endif std::sort(newIndices_.begin(), newIndices_.end(), IndexSetSortFunctor()); merge(); seqNo_++; state_ = GROUND; } template inline void ParallelIndexSet::merge(){ if(localIndices_.size()==0) { localIndices_=newIndices_; newIndices_.clear(); } else if(newIndices_.size()>0 || deletedEntries_) { ArrayList tempPairs; auto old = localIndices_.begin(); auto added = newIndices_.begin(); const auto endold = localIndices_.end(); const auto endadded = newIndices_.end(); while(old != endold && added!= endadded) { if(old->local().state()==DELETED) { old.eraseToHere(); } else { if(old->global() < added->global() || (old->global() == added->global() && LocalIndexComparator::compare(old->local(),added->local()))) { tempPairs.push_back(*old); old.eraseToHere(); continue; }else { tempPairs.push_back(*added); added.eraseToHere(); } } } while(old != endold) { if(old->local().state()!=DELETED) { tempPairs.push_back(*old); } old.eraseToHere(); } while(added!= endadded) { tempPairs.push_back(*added); added.eraseToHere(); } localIndices_ = tempPairs; } } template inline const IndexPair& ParallelIndexSet::at(const TG& global) const { // perform a binary search int low=0, high=localIndices_.size()-1, probe=-1; while(low inline const IndexPair& ParallelIndexSet::operator[](const TG& global) const { // perform a binary search int low=0, high=localIndices_.size()-1, probe=-1; while(low inline IndexPair& ParallelIndexSet::at(const TG& global) { // perform a binary search int low=0, high=localIndices_.size()-1, probe=-1; while(low= global) high = probe; else low = probe+1; } if(probe==-1) DUNE_THROW(RangeError, "No entries!"); if( localIndices_[low].global() != global) DUNE_THROW(RangeError, "Could not find entry of "< inline bool ParallelIndexSet::exists (const TG& global) const { // perform a binary search int low=0, high=localIndices_.size()-1, probe=-1; while(low= global) high = probe; else low = probe+1; } if(probe==-1) return false; if( localIndices_[low].global() != global) return false; return true; } template inline IndexPair& ParallelIndexSet::operator[](const TG& global) { // perform a binary search int low=0, high=localIndices_.size()-1, probe=-1; while(low= global) high = probe; else low = probe+1; } return localIndices_[low]; } template inline typename ParallelIndexSet::iterator ParallelIndexSet::begin() { return iterator(*this, localIndices_.begin()); } template inline typename ParallelIndexSet::iterator ParallelIndexSet::end() { return iterator(*this,localIndices_.end()); } template inline typename ParallelIndexSet::const_iterator ParallelIndexSet::begin() const { return localIndices_.begin(); } template inline typename ParallelIndexSet::const_iterator ParallelIndexSet::end() const { return localIndices_.end(); } template void ParallelIndexSet::renumberLocal(){ #ifndef NDEBUG if(state_==RESIZE) DUNE_THROW(InvalidIndexSetState, "IndexSet has to be in " <<"GROUND state for renumberLocal()"); #endif const auto end_ = end(); uint32_t index=0; for(auto pair=begin(); pair!=end_; index++, ++pair) pair->local()=index; } template inline int ParallelIndexSet::seqNo() const { return seqNo_; } template inline size_t ParallelIndexSet::size() const { return localIndices_.size(); } template GlobalLookupIndexSet::GlobalLookupIndexSet(const I& indexset, std::size_t size) : indexSet_(indexset), size_(size), indices_(size_, static_cast(0)) { const_iterator end_ = indexSet_.end(); for(const_iterator pair = indexSet_.begin(); pair!=end_; ++pair) { assert(pair->local()local()] = &(*pair); } } template GlobalLookupIndexSet::GlobalLookupIndexSet(const I& indexset) : indexSet_(indexset), size_(0) { const_iterator end_ = indexSet_.end(); for(const_iterator pair = indexSet_.begin(); pair!=end_; ++pair) size_=std::max(size_,static_cast(pair->local())); indices_.resize(++size_, 0); for(const_iterator pair = indexSet_.begin(); pair!=end_; ++pair) indices_[pair->local()] = &(*pair); } template GlobalLookupIndexSet::~GlobalLookupIndexSet() {} template inline const IndexPair* GlobalLookupIndexSet::pair(const std::size_t& local) const { return indices_[local]; } template inline const IndexPair& GlobalLookupIndexSet::operator[](const GlobalIndex& global) const { return indexSet_[global]; } template typename I::const_iterator GlobalLookupIndexSet::begin() const { return indexSet_.begin(); } template typename I::const_iterator GlobalLookupIndexSet::end() const { return indexSet_.end(); } template inline size_t GlobalLookupIndexSet::size() const { return size_; } template inline int GlobalLookupIndexSet::seqNo() const { return indexSet_.seqNo(); } template bool operator==(const ParallelIndexSet& idxset, const ParallelIndexSet& idxset1) { if(idxset.size()!=idxset1.size()) return false; typedef typename ParallelIndexSet::const_iterator Iter; typedef typename ParallelIndexSet::const_iterator Iter1; Iter iter=idxset.begin(); for(Iter1 iter1=idxset1.begin(); iter1 != idxset1.end(); ++iter, ++iter1) { if(iter1->global()!=iter->global()) return false; typedef typename ParallelIndexSet::LocalIndex PI; const PI& pi=iter->local(), pi1=iter1->local(); if(pi!=pi1) return false; } return true; } template bool operator!=(const ParallelIndexSet& idxset, const ParallelIndexSet& idxset1) { return !(idxset==idxset1); } #endif // DOXYGEN } #endif dune-common-2.8.0/dune/common/parallel/indicessyncer.hh000066400000000000000000001215001411343567400231530ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_INDICESSYNCER_HH #define DUNE_INDICESSYNCER_HH #include "indexset.hh" #include "remoteindices.hh" #include #include #include #include #include #include #include #include #include #if HAVE_MPI namespace Dune { /** @addtogroup Common_Parallel * * @{ */ /** * @file * @brief Class for adding missing indices of a distributed index set in a local * communication. * @author Markus Blatt */ /** * @brief Class for recomputing missing indices of a distributed index set. * * Missing local and remote indices will be added. */ template class IndicesSyncer { public: /** @brief The type of the index set. */ typedef T ParallelIndexSet; /** @brief The type of the index pair */ typedef typename ParallelIndexSet::IndexPair IndexPair; /** @brief Type of the global index used in the index set. */ typedef typename ParallelIndexSet::GlobalIndex GlobalIndex; /** @brief Type of the attribute used in the index set. */ typedef typename ParallelIndexSet::LocalIndex::Attribute Attribute; /** * @brief Type of the remote indices. */ typedef Dune::RemoteIndices RemoteIndices; /** * @brief Constructor. * * The source as well as the target index set of the remote * indices have to be the same as the provided index set. * @param indexSet The index set with the information * of the locally present indices. * @param remoteIndices The remoteIndices. */ IndicesSyncer(ParallelIndexSet& indexSet, RemoteIndices& remoteIndices); /** * @brief Sync the index set. * * Computes the missing indices in the local and the remote index list and adds them. * No global communication is necessary! * All indices added to the index will become the local index * std::numeric_limits::max() * */ void sync(); /** * @brief Synce the index set and assign local numbers to new indices * * Computes the missing indices in the local and the remote index list and adds them. * No global communication is necessary! * @param numberer Functor providing the local indices for the added global indices. * has to provide a function size_t operator()(const TG& global) that provides the * local index to a global one. It will be called for ascending global indices. * */ template void sync(T1& numberer); private: /** @brief The set of locally present indices.*/ ParallelIndexSet& indexSet_; /** @brief The remote indices. */ RemoteIndices& remoteIndices_; /** @brief The send buffers for the neighbour processes. */ char** sendBuffers_; /** @brief The receive buffer. */ char* receiveBuffer_; /** @brief The size of the send buffers. */ std::size_t* sendBufferSizes_; /** @brief The size of the receive buffer in bytes. */ int receiveBufferSize_; // int because of MPI /** * @brief Information about the messages to send to a neighbouring process. */ struct MessageInformation { MessageInformation() : publish(), pairs() {} /** @brief The number of indices we publish for the other process. */ int publish; /** * @brief The number of pairs (attribute and process number) * we publish to the neighbour process. */ int pairs; }; /** * @brief Default numberer for sync(). */ class DefaultNumberer { public: /** * @brief Provide the lcoal index, always * std::numeric_limits::max() * @param global The global index (ignored). */ std::size_t operator()([[maybe_unused]] const GlobalIndex& global) { return std::numeric_limits::max(); } }; /** @brief The mpi datatype for the MessageInformation */ MPI_Datatype datatype_; /** @brief Our rank. */ int rank_; /** * @brief List type for temporarily storing the global indices of the * remote indices. */ typedef SLList, typename RemoteIndices::Allocator> GlobalIndexList; /** @brief The modifying iterator for the global index list. */ typedef typename GlobalIndexList::ModifyIterator GlobalIndexModifier; /** * @brief The type of the iterator of GlobalIndexList */ typedef typename SLList::iterator GlobalIndexIterator; /** @brief Type of the map of ranks onto GlobalIndexLists. */ typedef std::map GlobalIndicesMap; /** * @brief Map of global index lists onto process ranks. * * As the pointers in the remote index lists become invalid due to * resorting the index set entries one has store the corresponding * global index for each remote index. Thus the pointers can be adjusted * properly as a last step. */ GlobalIndicesMap globalMap_; /** * @brief The type of the single linked list of bools. */ typedef SLList BoolList; /** * @brief The mutable iterator of the single linked bool list. */ typedef typename BoolList::iterator BoolIterator; /** @brief The type of the modifying iterator for the list of bools. */ typedef typename BoolList::ModifyIterator BoolListModifier; /** @brief The type of the map of bool lists. */ typedef std::map BoolMap; /** * @brief Map of lists of bool indicating whether the remote index was present before * call of sync. */ BoolMap oldMap_; /** @brief Information about the messages we send. */ std::map infoSend_; /** @brief The type of the remote index list. */ typedef typename RemoteIndices::RemoteIndexList RemoteIndexList; /** @brief The tyoe of the modifying iterator of the remote index list. */ typedef typename RemoteIndexList::ModifyIterator RemoteIndexModifier; /** @brief The type of the remote inde. */ typedef Dune::RemoteIndex RemoteIndex; /** @brief The iterator of the remote index list. */ typedef typename RemoteIndexList::iterator RemoteIndexIterator; /** @brief The const iterator of the remote index list. */ typedef typename RemoteIndexList::const_iterator ConstRemoteIndexIterator; /** @brief Type of the tuple of iterators needed for the adding of indices. */ typedef std::tuple IteratorTuple; /** * @brief A tuple of iterators. * * Insertion into a single linked list is only possible at the position after the one of the iterator. * Therefore for each linked list two iterators are needed: One position before the actual entry * (for insertion) and one positioned at the actual position (for searching). */ class Iterators { friend class IndicesSyncer; public: /** * @brief Constructor. * * Initializes all iterator to first entry and the one before the first entry, respectively. * @param remoteIndices The list of the remote indices. * @param globalIndices The list of the coresponding global indices. This is needed because the * the pointers to the local index will become invalid due to the merging of the index sets. * @param booleans Whether the remote index was there before the sync process started. */ Iterators(RemoteIndexList& remoteIndices, GlobalIndexList& globalIndices, BoolList& booleans); /** * @brief Default constructor. */ Iterators(); /** * @brief Increment all iteraors. */ Iterators& operator++(); /** * @brief Insert a new remote index to the underlying remote index list. * @param index The remote index. * @param global The global index corresponding to the remote index. */ void insert(const RemoteIndex& index, const std::pair& global); /** * @brief Get the remote index at current position. * @return The current remote index. */ RemoteIndex& remoteIndex() const; /** * @brief Get the global index of the remote index at current position. * @return The current global index. */ std::pair& globalIndexPair() const; Attribute& attribute() const; /** * @brief Was this entry already in the remote index list before the sync process? * @return True if the current index wasalready in the remote index list * before the sync process. */ bool isOld() const; /** * @brief Reset all the underlying iterators. * * Position them to first list entry and the entry before the first entry respectively. * @param remoteIndices The list of the remote indices. * @param globalIndices The list of the coresponding global indices. This is needed because the * the pointers to the local index will become invalid due to the merging of the index sets. * @param booleans Whether the remote index was there before the sync process started. */ void reset(RemoteIndexList& remoteIndices, GlobalIndexList& globalIndices, BoolList& booleans); /** * @brief Are we not at the end of the list? * @return True if the iterators are not positioned at the end of the list * and the tail of the list respectively. */ bool isNotAtEnd() const; /** * @brief Are we at the end of the list? * @return True if the iterators are positioned at the end of the list * and the tail of the list respectively. */ bool isAtEnd() const; private: /** * @brief The iterator tuple. * * The tuple consists of one iterator over a single linked list of remote indices * initially positioned before the first entry, one over a sll of global indices * , one over a all of bool values both postioned at the same entry. The another three * iterators of the same type positioned at the first entry. Last an iterator over the * sll of remote indices positioned at the end. */ IteratorTuple iterators_; }; /** @brief Type of the map from ranks to iterator tuples. */ typedef std::map IteratorsMap; /** * @brief The iterator tuples mapped on the neighbours. * * The key of the map is the rank of the neighbour. * The first entry in the tuple is an iterator over the remote indices * initially positioned before the first entry. The second entry is an * iterator over the corresponding global indices also initially positioned * before the first entry. The third entry an iterator over remote indices * initially positioned at the beginning. The last entry is the iterator over * the remote indices positioned at the end. */ IteratorsMap iteratorsMap_; /** @brief Calculates the message sizes to send. */ void calculateMessageSizes(); /** * @brief Pack and send the message for another process. * @param destination The rank of the process we send to. * @param buffer The allocated buffer to use. * @param bufferSize The size of the buffer. * @param req The MPI_Request to setup the nonblocking send. */ void packAndSend(int destination, char* buffer, std::size_t bufferSize, MPI_Request& req); /** * @brief Recv and unpack the message from another process and add the indices. * @param numberer Functor providing local indices for added global indices. */ template void recvAndUnpack(T1& numberer); /** * @brief Register the MPI datatype for the MessageInformation. */ void registerMessageDatatype(); /** * @brief Insert an entry into the remote index list if not yet present. */ void insertIntoRemoteIndexList(int process, const std::pair& global, char attribute); /** * @brief Reset the iterator tuples of all neighbouring processes. */ void resetIteratorsMap(); /** * @brief Check whether the iterator tuples of all neighbouring processes * are reset. */ bool checkReset(); /** * @brief Check whether the iterator tuple is reset. * * @param iterators The iterator tuple to check. * @param rlist The SLList of the remote indices. * @param gList The SLList of the global indices. * @param bList The SLList of the bool values. */ bool checkReset(const Iterators& iterators, RemoteIndexList& rlist, GlobalIndexList& gList, BoolList& bList); }; template bool operator<(const IndexPair >& i1, const std::pair& i2) { return i1.global() < i2.first || (i1.global() == i2.first && i1.local().attribute() bool operator<(const std::pair& i1, const IndexPair >& i2) { return i1.first < i2.global() || (i1.first == i2.global() && i1.second bool operator==(const IndexPair >& i1, const std::pair& i2) { return (i1.global() == i2.first && i1.local().attribute()==i2.second); } template bool operator!=(const IndexPair >& i1, const std::pair& i2) { return (i1.global() != i2.first || i1.local().attribute()!=i2.second); } template bool operator==(const std::pair& i2, const IndexPair >& i1) { return (i1.global() == i2.first && i1.local().attribute()==i2.second); } template bool operator!=(const std::pair& i2, const IndexPair >& i1) { return (i1.global() != i2.first || i1.local().attribute()!=i2.second); } /** * @brief Stores the corresponding global indices of the remote index information. * * Whenever a ParallelIndexSet is resized all RemoteIndices that use it will be invalided * as the pointers to the index set are invalid after calling ParallelIndexSet::Resize() * One can rebuild them by storing the global indices in a map with this function and later * repairing the pointers by calling repairLocalIndexPointers. * * @warning The RemoteIndices class has to be build with the same index set for both the * sending and receiving side * @param globalMap Map to store the corresponding global indices in. * @param remoteIndices The remote index information we need to store the corresponding global * indices of. * @param indexSet The index set that is for both the sending and receiving side of the remote * index information. */ template void storeGlobalIndicesOfRemoteIndices(std::map,A> >& globalMap, const RemoteIndices& remoteIndices) { for(auto remote = remoteIndices.begin(), end =remoteIndices.end(); remote != end; ++remote) { typedef typename RemoteIndices::RemoteIndexList RemoteIndexList; typedef SLList,A> GlobalIndexList; GlobalIndexList& global = globalMap[remote->first]; RemoteIndexList& rList = *(remote->second.first); for(auto index = rList.begin(), riEnd = rList.end(); index != riEnd; ++index) { global.push_back(std::make_pair(index->localIndexPair().global(), index->localIndexPair().local().attribute())); } } } /** * @brief Repair the pointers to the local indices in the remote indices. * * @param globalMap The map of the process number to the list of global indices * corresponding to the remote index list of the process. * @param remoteIndices The known remote indices. * @param indexSet The set of local indices of the current process. */ template inline void repairLocalIndexPointers(std::map,A> >& globalMap, RemoteIndices& remoteIndices, const T& indexSet) { assert(globalMap.size()==static_cast(remoteIndices.neighbours())); // Repair pointers to index set in remote indices. auto global = globalMap.begin(); auto end = remoteIndices.remoteIndices_.end(); for(auto remote = remoteIndices.remoteIndices_.begin(); remote != end; ++remote, ++global) { assert(remote->first==global->first); assert(remote->second.first->size() == global->second.size()); auto riEnd = remote->second.first->end(); auto rIndex = remote->second.first->begin(); auto gIndex = global->second.begin(); auto index = indexSet.begin(); assert(rIndex==riEnd || gIndex != global->second.end()); while(rIndex != riEnd) { // Search for the index in the set. assert(gIndex != global->second.end()); while(!(index->global() == gIndex->first && index->local().attribute() == gIndex->second)) { ++index; // this is only needed for ALU, where there may exist // more entries with the same global index in the remote index set // than in the index set if (index->global() > gIndex->first) { index=indexSet.begin(); } } assert(index != indexSet.end() && *index == *gIndex); rIndex->localIndex_ = &(*index); ++index; ++rIndex; ++gIndex; } } remoteIndices.sourceSeqNo_ = remoteIndices.source_->seqNo(); remoteIndices.destSeqNo_ = remoteIndices.target_->seqNo(); } template IndicesSyncer::IndicesSyncer(ParallelIndexSet& indexSet, RemoteIndices& remoteIndices) : indexSet_(indexSet), remoteIndices_(remoteIndices) { // index sets must match. assert(remoteIndices.source_ == remoteIndices.target_); assert(remoteIndices.source_ == &indexSet); MPI_Comm_rank(remoteIndices_.communicator(), &rank_); } template IndicesSyncer::Iterators::Iterators(RemoteIndexList& remoteIndices, GlobalIndexList& globalIndices, BoolList& booleans) : iterators_(remoteIndices.beginModify(), globalIndices.beginModify(), booleans.beginModify(), remoteIndices.end()) { } template IndicesSyncer::Iterators::Iterators() : iterators_() {} template inline typename IndicesSyncer::Iterators& IndicesSyncer::Iterators::operator++() { ++(std::get<0>(iterators_)); ++(std::get<1>(iterators_)); ++(std::get<2>(iterators_)); return *this; } template inline void IndicesSyncer::Iterators::insert(const RemoteIndex & index, const std::pair& global) { std::get<0>(iterators_).insert(index); std::get<1>(iterators_).insert(global); std::get<2>(iterators_).insert(false); } template inline typename IndicesSyncer::RemoteIndex& IndicesSyncer::Iterators::remoteIndex() const { return *(std::get<0>(iterators_)); } template inline std::pair::GlobalIndex,typename IndicesSyncer::Attribute>& IndicesSyncer::Iterators::globalIndexPair() const { return *(std::get<1>(iterators_)); } template inline bool IndicesSyncer::Iterators::isOld() const { return *(std::get<2>(iterators_)); } template inline void IndicesSyncer::Iterators::reset(RemoteIndexList& remoteIndices, GlobalIndexList& globalIndices, BoolList& booleans) { std::get<0>(iterators_) = remoteIndices.beginModify(); std::get<1>(iterators_) = globalIndices.beginModify(); std::get<2>(iterators_) = booleans.beginModify(); } template inline bool IndicesSyncer::Iterators::isNotAtEnd() const { return std::get<0>(iterators_) != std::get<3>(iterators_); } template inline bool IndicesSyncer::Iterators::isAtEnd() const { return std::get<0>(iterators_) == std::get<3>(iterators_); } template void IndicesSyncer::registerMessageDatatype() { MPI_Datatype type[2] = {MPI_INT, MPI_INT}; int blocklength[2] = {1,1}; MPI_Aint displacement[2]; MPI_Aint base; // Compute displacement MessageInformation message; MPI_Get_address( &(message.publish), displacement); MPI_Get_address( &(message.pairs), displacement+1); // Make the displacement relative MPI_Get_address(&message, &base); displacement[0] -= base; displacement[1] -= base; MPI_Type_create_struct( 2, blocklength, displacement, type, &datatype_); MPI_Type_commit(&datatype_); } template void IndicesSyncer::calculateMessageSizes() { auto iEnd = indexSet_.end(); auto collIter = remoteIndices_.template iterator(); for(auto index = indexSet_.begin(); index != iEnd; ++index) { collIter.advance(index->global(), index->local().attribute()); if(collIter.empty()) break; int knownRemote=0; auto end = collIter.end(); // Count the remote indices we know. for(auto valid = collIter.begin(); valid != end; ++valid) { ++knownRemote; } if(knownRemote>0) { Dune::dverb<global()<< " for processes "; // Update MessageInformation for(auto valid = collIter.begin(); valid != end; ++valid) { ++(infoSend_[valid.process()].publish); (infoSend_[valid.process()].pairs) += knownRemote; Dune::dverb<first==remote->first) { // We want to send message information to that process message = const_cast(&(messageIter->second)); ++messageIter; }else // We do not want to send information but the other process might. message = &dummy; sendBufferSizes_[neighbour]=0; int tsize; // The number of indices published MPI_Pack_size(1, MPI_INT,remoteIndices_.communicator(), &tsize); sendBufferSizes_[neighbour] += tsize; for(int i=0; i < message->publish; ++i) { // The global index MPI_Pack_size(1, MPITraits::getType(), remoteIndices_.communicator(), &tsize); sendBufferSizes_[neighbour] += tsize; // The attribute in the local index MPI_Pack_size(1, MPI_CHAR, remoteIndices_.communicator(), &tsize); sendBufferSizes_[neighbour] += tsize; // The number of corresponding remote indices MPI_Pack_size(1, MPI_INT, remoteIndices_.communicator(), &tsize); sendBufferSizes_[neighbour] += tsize; } for(int i=0; i < message->pairs; ++i) { // The process of the remote index MPI_Pack_size(1, MPI_INT, remoteIndices_.communicator(), &tsize); sendBufferSizes_[neighbour] += tsize; // The attribute of the remote index MPI_Pack_size(1, MPI_CHAR, remoteIndices_.communicator(), &tsize); sendBufferSizes_[neighbour] += tsize; } Dune::dverb< void IndicesSyncer::packAndSend(int destination, char* buffer, std::size_t bufferSize, MPI_Request& request) { auto iEnd = indexSet_.end(); int bpos = 0; int published = 0; int pairs = 0; assert(checkReset()); // Pack the number of indices we publish MPI_Pack(&(infoSend_[destination].publish), 1, MPI_INT, buffer, bufferSize, &bpos, remoteIndices_.communicator()); for(auto index = indexSet_.begin(); index != iEnd; ++index) { // Search for corresponding remote indices in all iterator tuples auto iteratorsEnd = iteratorsMap_.end(); // advance all iterators to a position with global index >= index->global() for(auto iterators = iteratorsMap_.begin(); iteratorsEnd != iterators; ++iterators) { while(iterators->second.isNotAtEnd() && iterators->second.globalIndexPair().first < index->global()) ++(iterators->second); assert(!iterators->second.isNotAtEnd() || iterators->second.globalIndexPair().first >= index->global()); } // Add all remote indices positioned at global which were already present before calling sync // to the message. // Count how many remote indices we will send int indices = 0; bool knownRemote = false; // Is the remote process supposed to know this index? for(auto iterators = iteratorsMap_.begin(); iteratorsEnd != iterators; ++iterators) { std::pair p; if (iterators->second.isNotAtEnd()) { p = iterators->second.globalIndexPair(); } if(iterators->second.isNotAtEnd() && iterators->second.isOld() && iterators->second.globalIndexPair().first == index->global()) { indices++; if(destination == iterators->first) knownRemote = true; } } if(!knownRemote) // We do not need to send any indices continue; Dune::dverb<global()<<" to "<(&(index->global())), 1, MPITraits::getType(), buffer, bufferSize, &bpos, remoteIndices_.communicator()); char attr = index->local().attribute(); MPI_Pack(&attr, 1, MPI_CHAR, buffer, bufferSize, &bpos, remoteIndices_.communicator()); // Pack the number of remote indices we send. MPI_Pack(&indices, 1, MPI_INT, buffer, bufferSize, &bpos, remoteIndices_.communicator()); // Pack the information about the remote indices for(auto iterators = iteratorsMap_.begin(); iteratorsEnd != iterators; ++iterators) if(iterators->second.isNotAtEnd() && iterators->second.isOld() && iterators->second.globalIndexPair().first == index->global()) { int process = iterators->first; ++pairs; assert(pairs <= infoSend_[destination].pairs); MPI_Pack(&process, 1, MPI_INT, buffer, bufferSize, &bpos, remoteIndices_.communicator()); char attr2 = iterators->second.remoteIndex().attribute(); MPI_Pack(&attr2, 1, MPI_CHAR, buffer, bufferSize, &bpos, remoteIndices_.communicator()); --indices; } assert(indices==0); ++published; Dune::dvverb<<" (publish="< inline void IndicesSyncer::insertIntoRemoteIndexList(int process, const std::pair& globalPair, char attribute) { Dune::dverb<<"Inserting from "<second; // Search for the remote index while(iterators.isNotAtEnd() && iterators.globalIndexPair() < globalPair) { // Increment all iterators ++iterators; } if(iterators.isAtEnd() || iterators.globalIndexPair() != globalPair) { // The entry is not yet known // Insert in the list and do not change the first iterator. iterators.insert(RemoteIndex(Attribute(attribute)),globalPair); return; } // Global indices match bool indexIsThere=false; for(Iterators tmpIterators = iterators; !tmpIterators.isAtEnd() && tmpIterators.globalIndexPair() == globalPair; ++tmpIterators) //entry already exists with the same attribute if(tmpIterators.globalIndexPair().second == attribute) { indexIsThere=true; break; } if(!indexIsThere) // The entry is not yet known // Insert in the list and do not change the first iterator. iterators.insert(RemoteIndex(Attribute(attribute)),globalPair); } template template void IndicesSyncer::recvAndUnpack(T1& numberer) { const ParallelIndexSet& constIndexSet = indexSet_; auto iEnd = constIndexSet.end(); auto index = constIndexSet.begin(); int bpos = 0; int publish; assert(checkReset()); MPI_Status status; // We have to determine the message size and source before the receive MPI_Probe(MPI_ANY_SOURCE, 345, remoteIndices_.communicator(), &status); int source=status.MPI_SOURCE; int count; MPI_Get_count(&status, MPI_PACKED, &count); Dune::dvverb<receiveBufferSize_) { receiveBufferSize_=count; delete[] receiveBuffer_; receiveBuffer_ = new char[receiveBufferSize_]; } MPI_Recv(receiveBuffer_, count, MPI_PACKED, source, 345, remoteIndices_.communicator(), &status); // How many global entries were published? MPI_Unpack(receiveBuffer_, count, &bpos, &publish, 1, MPI_INT, remoteIndices_.communicator()); // Now unpack the remote indices and add them. while(publish>0) { // Unpack information about the local index on the source process GlobalIndex global; // global index of the current entry char sourceAttribute; // Attribute on the source process int pairs; MPI_Unpack(receiveBuffer_, count, &bpos, &global, 1, MPITraits::getType(), remoteIndices_.communicator()); MPI_Unpack(receiveBuffer_, count, &bpos, &sourceAttribute, 1, MPI_CHAR, remoteIndices_.communicator()); MPI_Unpack(receiveBuffer_, count, &bpos, &pairs, 1, MPI_INT, remoteIndices_.communicator()); // Insert the entry on the remote process to our // remote index list SLList > sourceAttributeList; sourceAttributeList.push_back(std::make_pair(source,Attribute(sourceAttribute))); #ifndef NDEBUG bool foundSelf = false; #endif Attribute myAttribute=Attribute(); // Unpack the remote indices for(; pairs>0; --pairs) { // Unpack the process id that knows the index int process; char attribute; MPI_Unpack(receiveBuffer_, count, &bpos, &process, 1, MPI_INT, remoteIndices_.communicator()); // Unpack the attribute MPI_Unpack(receiveBuffer_, count, &bpos, &attribute, 1, MPI_CHAR, remoteIndices_.communicator()); if(process==rank_) { #ifndef NDEBUG foundSelf=true; #endif myAttribute=Attribute(attribute); // Now we know the local attribute of the global index //Only add the index if it is unknown. // Do we know that global index already? auto pos = std::lower_bound(index, iEnd, IndexPair(global)); if(pos == iEnd || pos->global() != global) { // no entry with this global index indexSet_.add(global, ParallelLocalIndex(numberer(global), myAttribute, true)); Dune::dvverb << "Adding "<global()==global; ++pos) if(pos->local().attribute() == myAttribute) { Dune::dvverb<<"found "<(numberer(global), myAttribute, true)); Dune::dvverb << "Adding "< >::const_iterator Iter; for(Iter i=sourceAttributeList.begin(), end=sourceAttributeList.end(); i!=end; ++i) insertIntoRemoteIndexList(i->first, std::make_pair(global, myAttribute), i->second); --publish; } resetIteratorsMap(); } template void IndicesSyncer::resetIteratorsMap(){ // Reset iterators in all tuples. const auto remoteEnd = remoteIndices_.remoteIndices_.end(); auto iterators = iteratorsMap_.begin(); auto global = globalMap_.begin(); auto added = oldMap_.begin(); for(auto remote = remoteIndices_.remoteIndices_.begin(); remote != remoteEnd; ++remote, ++global, ++added, ++iterators) { iterators->second.reset(*(remote->second.first), global->second, added->second); } } template bool IndicesSyncer::checkReset(const Iterators& iterators, RemoteIndexList& rList, GlobalIndexList& gList, BoolList& bList){ if(std::get<0>(iterators.iterators_) != rList.begin()) return false; if(std::get<1>(iterators.iterators_) != gList.begin()) return false; if(std::get<2>(iterators.iterators_) != bList.begin()) return false; return true; } template bool IndicesSyncer::checkReset(){ // Reset iterators in all tuples. const auto remoteEnd = remoteIndices_.remoteIndices_.end(); auto iterators = iteratorsMap_.begin(); auto global = globalMap_.begin(); auto added = oldMap_.begin(); bool ret = true; for(auto remote = remoteIndices_.remoteIndices_.begin(); remote != remoteEnd; ++remote, ++global, ++added, ++iterators) { if(!checkReset(iterators->second, *(remote->second.first), global->second, added->second)) ret=false; } return ret; } } #endif #endif dune-common-2.8.0/dune/common/parallel/interface.hh000066400000000000000000000357541411343567400222700ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_INTERFACE_HH #define DUNE_INTERFACE_HH #if HAVE_MPI #include "remoteindices.hh" #include namespace Dune { /** @addtogroup Common_Parallel * * @{ */ /** * @file * @brief Provides classes for building the communication * interface between remote indices. * @author Markus Blatt */ /** @} */ /** * @brief Base class of all classes representing a communication * interface. * * It provides an generic utility method for building the interface * for a set of remote indices. */ class InterfaceBuilder { public: class RemoteIndicesStateError : public InvalidStateException {}; virtual ~InterfaceBuilder() {} protected: /** * @brief Not for public use. */ InterfaceBuilder() {} /** * @brief Builds the interface between remote processes. * * * The types T1 and T2 are classes representing a set of * enumeration values of type InterfaceBuilder::Attribute. They have to provide * a (static) method * \code * bool contains(Attribute flag) const; * \endcode * for checking whether the set contains a specific flag. * This functionality is for example provided the classes * EnumItem, EnumRange and Combine. * * If the template parameter send is true the sending side of * the interface will be built, otherwise the information for * receiving will be built. * * * If the template parameter send is true we create interface for sending * in a forward communication. * * @param remoteIndices The indices known to remote processes. * @param sourceFlags The set of flags marking source indices. * @param destFlags The setof flags markig destination indices. * @param functor A functor for callbacks. It should provide the * following methods: * \code * // Reserve memory for the interface to processor proc. The interface * // has to hold size entries * void reserve(int proc, int size); * * // Add an entry to the interface * // We will send/receive size entries at index local to process proc * void add(int proc, int local); * \endcode */ template void buildInterface (const R& remoteIndices, const T1& sourceFlags, const T2& destFlags, Op& functor) const; }; /** * @brief Information describing an interface. * * This class is used for temporary gathering information * about the interface needed for actually building it. It * is used be class Interface as functor for InterfaceBuilder::build. */ class InterfaceInformation { public: /** * @brief Get the number of entries in the interface. */ size_t size() const { return size_; } /** * @brief Get the local index for an entry. * @param i The index of the entry. */ std::size_t& operator[](size_t i) { assert(i > InformationMap; /** * @brief Builds the interface. * * The types T1 and T2 are classes representing a set of * enumeration values of type Interface::Attribute. They have to provide * a (static) method * \code * bool contains(Attribute flag) const; * \endcode * for checking whether the set contains a specific flag. * This functionality is for example provided the classes * EnumItem, EnumRange and Combine. * @param remoteIndices The indices known to remote processes. * @param sourceFlags The set of flags marking indices we send from. * @param destFlags The set of flags marking indices we receive for. */ template void build(const R& remoteIndices, const T1& sourceFlags, const T2& destFlags); /** * @brief Frees memory allocated during the build. */ void free(); /** * @brief Get the MPI Communicator. */ MPI_Comm communicator() const; /** * @brief Get information about the interfaces. * * @return Map of the interfaces. * The key of the map is the process number and the value * is the information pair (first the send and then the receive * information). */ const InformationMap& interfaces() const; Interface(MPI_Comm comm) : communicator_(comm), interfaces_() {} Interface() : communicator_(MPI_COMM_NULL), interfaces_() {} /** * @brief Print the interface to std::out for debugging. */ void print() const; bool operator!=(const Interface& o) const { return ! operator==(o); } bool operator==(const Interface& o) const { if(communicator_!=o.communicator_) return false; if(interfaces_.size()!=o.interfaces_.size()) return false; typedef InformationMap::const_iterator MIter; for(MIter m=interfaces_.begin(), om=o.interfaces_.begin(); m!=interfaces_.end(); ++m, ++om) { if(om->first!=m->first) return false; if(om->second.first!=om->second.first) return false; if(om->second.second!=om->second.second) return false; } return true; } /** * @brief Destructor. */ virtual ~Interface(); void strip(); protected: /** * @brief Get information about the interfaces. * * @return Map of the interfaces. * The key of the map is the process number and the value * is the information pair (first the send and then the receive * information). */ InformationMap& interfaces(); /** @brief The MPI communicator we use. */ MPI_Comm communicator_; private: /** * @brief Information about the interfaces. * * The key of the map is the process number and the value * is the information pair (first the send and then the receive * information). */ InformationMap interfaces_; template class InformationBuilder { public: InformationBuilder(InformationMap& interfaces) : interfaces_(interfaces) {} void reserve(int proc, int size) { if(send) interfaces_[proc].first.reserve(size); else interfaces_[proc].second.reserve(size); } void add(int proc, std::size_t local) { if(send) { interfaces_[proc].first.add(local); }else{ interfaces_[proc].second.add(local); } } private: InformationMap& interfaces_; }; }; template void InterfaceBuilder::buildInterface(const R& remoteIndices, const T1& sourceFlags, const T2& destFlags, Op& interfaceInformation) const { if(!remoteIndices.isSynced()) DUNE_THROW(RemoteIndicesStateError,"RemoteIndices is not in sync with the index set. Call RemoteIndices::rebuild first!"); // Allocate the memory for the data type construction. typedef R RemoteIndices; typedef typename RemoteIndices::RemoteIndexMap::const_iterator const_iterator; const const_iterator end=remoteIndices.end(); int rank; MPI_Comm_rank(remoteIndices.communicator(), &rank); // Allocate memory for the type construction. for(const_iterator process=remoteIndices.begin(); process != end; ++process) { // Messure the number of indices send to the remote process first int size=0; typedef typename RemoteIndices::RemoteIndexList::const_iterator RemoteIterator; const RemoteIterator remoteEnd = send ? process->second.first->end() : process->second.second->end(); RemoteIterator remote = send ? process->second.first->begin() : process->second.second->begin(); while(remote!=remoteEnd) { if( send ? destFlags.contains(remote->attribute()) : sourceFlags.contains(remote->attribute())) { // do we send the index? if( send ? sourceFlags.contains(remote->localIndexPair().local().attribute()) : destFlags.contains(remote->localIndexPair().local().attribute())) ++size; } ++remote; } interfaceInformation.reserve(process->first, size); } // compare the local and remote indices and set up the types for(const_iterator process=remoteIndices.begin(); process != end; ++process) { typedef typename RemoteIndices::RemoteIndexList::const_iterator RemoteIterator; const RemoteIterator remoteEnd = send ? process->second.first->end() : process->second.second->end(); RemoteIterator remote = send ? process->second.first->begin() : process->second.second->begin(); while(remote!=remoteEnd) { if( send ? destFlags.contains(remote->attribute()) : sourceFlags.contains(remote->attribute())) { // do we send the index? if( send ? sourceFlags.contains(remote->localIndexPair().local().attribute()) : destFlags.contains(remote->localIndexPair().local().attribute())) interfaceInformation.add(process->first,remote->localIndexPair().local().local()); } ++remote; } } } inline MPI_Comm Interface::communicator() const { return communicator_; } inline const std::map >& Interface::interfaces() const { return interfaces_; } inline std::map >& Interface::interfaces() { return interfaces_; } inline void Interface::print() const { typedef InformationMap::const_iterator const_iterator; const const_iterator end=interfaces_.end(); int rank; MPI_Comm_rank(communicator(), &rank); for(const_iterator infoPair=interfaces_.begin(); infoPair!=end; ++infoPair) { { std::cout<first<<": "; const InterfaceInformation& info(infoPair->second.first); for(size_t i=0; i < info.size(); i++) std::cout<first<<": "; const InterfaceInformation& info(infoPair->second.second); for(size_t i=0; i < info.size(); i++) std::cout< inline void Interface::build(const R& remoteIndices, const T1& sourceFlags, const T2& destFlags) { communicator_=remoteIndices.communicator(); assert(interfaces_.empty()); // Build the send interface InformationBuilder sendInformation(interfaces_); this->template buildInterface,true>(remoteIndices, sourceFlags, destFlags, sendInformation); // Build the receive interface InformationBuilder recvInformation(interfaces_); this->template buildInterface,false>(remoteIndices,sourceFlags, destFlags, recvInformation); strip(); } inline void Interface::strip() { typedef InformationMap::iterator const_iterator; for(const_iterator interfacePair = interfaces_.begin(); interfacePair != interfaces_.end();) if(interfacePair->second.first.size()==0 && interfacePair->second.second.size()==0) { interfacePair->second.first.free(); interfacePair->second.second.free(); const_iterator toerase=interfacePair++; interfaces_.erase(toerase); }else ++interfacePair; } inline void Interface::free() { typedef InformationMap::iterator iterator; typedef InformationMap::const_iterator const_iterator; const const_iterator end = interfaces_.end(); for(iterator interfacePair = interfaces_.begin(); interfacePair != end; ++interfacePair) { interfacePair->second.first.free(); interfacePair->second.second.free(); } interfaces_.clear(); } inline Interface::~Interface() { free(); } /** @} */ inline std::ostream& operator<<(std::ostream& os, const Interface& interface) { typedef Interface::InformationMap InfoMap; typedef InfoMap::const_iterator Iter; for(Iter i=interface.interfaces().begin(), end = interface.interfaces().end(); i!=end; ++i) { os<first<<": [ source=["; for(std::size_t j=0; j < i->second.first.size(); ++j) os<second.first[j]<<" "; os<<"] size="<second.first.size()<<", target=["; for(std::size_t j=0; j < i->second.second.size(); ++j) os<second.second[j]<<" "; os<<"] size="<second.second.size()<<"\n"; } return os; } } #endif // HAVE_MPI #endif dune-common-2.8.0/dune/common/parallel/localindex.hh000066400000000000000000000044421411343567400224400ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_LOCALINDEX_HH #define DUNE_COMMON_LOCALINDEX_HH #include namespace Dune { /** @addtogroup Common_Parallel * * @{ */ /** * @file * @brief Provides classes for use as the local index in ParallelIndexSet. * @author Markus Blatt */ /** * @brief The states avaiable for the local indices. * @see LocalIndex::state() */ enum LocalIndexState {VALID, DELETED}; /** * @brief An index present on the local process. */ class LocalIndex { public: /** * @brief Constructor. * known to other processes. */ LocalIndex() : localIndex_(0), state_(VALID){} /** * @brief Constructor. * @param index The value of the index. */ LocalIndex(std::size_t index) : localIndex_(index), state_(VALID){} /** * @brief get the local index. * @return The local index. */ inline const std::size_t& local() const; /** * @brief Convert to the local index represented by an int. */ inline operator std::size_t() const; /** * @brief Assign a new local index. * * @param index The new local index. */ inline LocalIndex& operator=(std::size_t index); /** * @brief Get the state. * @return The state. */ inline LocalIndexState state() const; /** * @brief Set the state. * @param state The state to set. */ inline void setState(LocalIndexState state); private: /** @brief The local index. */ std::size_t localIndex_; /** * @brief The state of the index. * * Has to be one of LocalIndexState! * @see LocalIndexState. */ char state_; }; inline const std::size_t& LocalIndex::local() const { return localIndex_; } inline LocalIndex::operator std::size_t() const { return localIndex_; } inline LocalIndex& LocalIndex::operator=(std::size_t index){ localIndex_ = index; return *this; } inline LocalIndexState LocalIndex::state() const { return static_cast(state_); } inline void LocalIndex::setState(LocalIndexState state){ state_ = static_cast(state); } /** @} */ } // namespace Dune #endif dune-common-2.8.0/dune/common/parallel/mpicollectivecommunication.hh000066400000000000000000000002741411343567400257420ustar00rootroot00000000000000// Will be removed after the 2.7 release #warning "Deprecated header, use #include instead!" #include dune-common-2.8.0/dune/common/parallel/mpicommunication.hh000066400000000000000000000362151411343567400236740ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_PARALLEL_MPICOMMUNICATION_HH #define DUNE_COMMON_PARALLEL_MPICOMMUNICATION_HH /*! \file \brief Implements an utility class that provides MPI's collective communication methods. \ingroup ParallelCommunication */ #if HAVE_MPI #include #include #include #include #include #include #include #include #include #include namespace Dune { //======================================================= // use singleton pattern and template specialization to // generate MPI operations //======================================================= template class Generic_MPI_Op { public: static MPI_Op get () { if (!op) { op = std::make_unique(); // The following line leaks an MPI operation object, because the corresponding //`MPI_Op_free` is never called. It is never called because there is no easy // way to call it at the right moment: right before the call to MPI_Finalize. // See https://gitlab.dune-project.org/core/dune-istl/issues/80 MPI_Op_create((void (*)(void*, void*, int*, MPI_Datatype*))&operation,true,op.get()); } return *op; } private: static void operation (Type *in, Type *inout, int *len, MPI_Datatype*) { BinaryFunction func; for (int i=0; i< *len; ++i, ++in, ++inout) { Type temp; temp = func(*in, *inout); *inout = temp; } } Generic_MPI_Op () {} Generic_MPI_Op (const Generic_MPI_Op& ) {} static std::unique_ptr op; }; template std::unique_ptr Generic_MPI_Op::op; #define ComposeMPIOp(func,op) \ template \ class Generic_MPI_Op, std::enable_if_t::is_intrinsic> >{ \ public: \ static MPI_Op get(){ \ return op; \ } \ private: \ Generic_MPI_Op () {} \ Generic_MPI_Op (const Generic_MPI_Op & ) {} \ } ComposeMPIOp(std::plus, MPI_SUM); ComposeMPIOp(std::multiplies, MPI_PROD); ComposeMPIOp(Min, MPI_MIN); ComposeMPIOp(Max, MPI_MAX); #undef ComposeMPIOp //======================================================= // use singleton pattern and template specialization to // generate MPI operations //======================================================= /*! \brief Specialization of Communication for MPI \ingroup ParallelCommunication */ template<> class Communication { public: //! Instantiation using a MPI communicator Communication (const MPI_Comm& c = MPI_COMM_WORLD) : communicator(c) { if(communicator!=MPI_COMM_NULL) { int initialized = 0; MPI_Initialized(&initialized); if (!initialized) DUNE_THROW(ParallelError,"You must call MPIHelper::instance(argc,argv) in your main() function before using the MPI Communication!"); MPI_Comm_rank(communicator,&me); MPI_Comm_size(communicator,&procs); }else{ procs=0; me=-1; } } //! @copydoc Communication::rank int rank () const { return me; } //! @copydoc Communication::size int size () const { return procs; } //! @copydoc Communication::send template int send(const T& data, int dest_rank, int tag) const { auto mpi_data = getMPIData(data); return MPI_Send(mpi_data.ptr(), mpi_data.size(), mpi_data.type(), dest_rank, tag, communicator); } //! @copydoc Communication::isend template MPIFuture isend(const T&& data, int dest_rank, int tag) const { MPIFuture future(std::forward(data)); auto mpidata = future.get_mpidata(); MPI_Isend(mpidata.ptr(), mpidata.size(), mpidata.type(), dest_rank, tag, communicator, &future.req_); return future; } //! @copydoc Communication::recv template T recv(T&& data, int source_rank, int tag, MPI_Status* status = MPI_STATUS_IGNORE) const { T lvalue_data(std::forward(data)); auto mpi_data = getMPIData(lvalue_data); MPI_Recv(mpi_data.ptr(), mpi_data.size(), mpi_data.type(), source_rank, tag, communicator, status); return lvalue_data; } //! @copydoc Communication::irecv template MPIFuture irecv(T&& data, int source_rank, int tag) const { MPIFuture future(std::forward(data)); auto mpidata = future.get_mpidata(); MPI_Irecv(mpidata.ptr(), mpidata.size(), mpidata.type(), source_rank, tag, communicator, &future.req_); return future; } template T rrecv(T&& data, int source_rank, int tag, MPI_Status* status = MPI_STATUS_IGNORE) const { MPI_Status _status; MPI_Message _message; T lvalue_data(std::forward(data)); auto mpi_data = getMPIData(lvalue_data); static_assert(!mpi_data.static_size, "rrecv work only for non-static-sized types."); if(status == MPI_STATUS_IGNORE) status = &_status; MPI_Mprobe(source_rank, tag, communicator, &_message, status); int size; MPI_Get_count(status, mpi_data.type(), &size); mpi_data.resize(size); MPI_Mrecv(mpi_data.ptr(), mpi_data.size(), mpi_data.type(), &_message, status); return lvalue_data; } //! @copydoc Communication::sum template T sum (const T& in) const { T out; allreduce >(&in,&out,1); return out; } //! @copydoc Communication::sum template int sum (T* inout, int len) const { return allreduce >(inout,len); } //! @copydoc Communication::prod template T prod (const T& in) const { T out; allreduce >(&in,&out,1); return out; } //! @copydoc Communication::prod template int prod (T* inout, int len) const { return allreduce >(inout,len); } //! @copydoc Communication::min template T min (const T& in) const { T out; allreduce >(&in,&out,1); return out; } //! @copydoc Communication::min template int min (T* inout, int len) const { return allreduce >(inout,len); } //! @copydoc Communication::max template T max (const T& in) const { T out; allreduce >(&in,&out,1); return out; } //! @copydoc Communication::max template int max (T* inout, int len) const { return allreduce >(inout,len); } //! @copydoc Communication::barrier int barrier () const { return MPI_Barrier(communicator); } //! @copydoc Communication::ibarrier MPIFuture ibarrier () const { MPIFuture future(true); // make a valid MPIFuture MPI_Ibarrier(communicator, &future.req_); return future; } //! @copydoc Communication::broadcast template int broadcast (T* inout, int len, int root) const { return MPI_Bcast(inout,len,MPITraits::getType(),root,communicator); } //! @copydoc Communication::ibroadcast template MPIFuture ibroadcast(T&& data, int root) const{ MPIFuture future(std::forward(data)); auto mpidata = future.get_mpidata(); MPI_Ibcast(mpidata.ptr(), mpidata.size(), mpidata.type(), root, communicator, &future.req_); return future; } //! @copydoc Communication::gather() //! @note out must have space for P*len elements template int gather (const T* in, T* out, int len, int root) const { return MPI_Gather(const_cast(in),len,MPITraits::getType(), out,len,MPITraits::getType(), root,communicator); } //! @copydoc Communication::igather template> MPIFuture igather(TIN&& data_in, TOUT&& data_out, int root) const{ MPIFuture future(std::forward(data_out), std::forward(data_in)); auto mpidata_in = future.get_send_mpidata(); auto mpidata_out = future.get_mpidata(); assert(root != me || mpidata_in.size()*procs <= mpidata_out.size()); int outlen = (me==root) * mpidata_in.size(); MPI_Igather(mpidata_in.ptr(), mpidata_in.size(), mpidata_in.type(), mpidata_out.ptr(), outlen, mpidata_out.type(), root, communicator, &future.req_); return future; } //! @copydoc Communication::gatherv() template int gatherv (const T* in, int sendDataLen, T* out, int* recvDataLen, int* displ, int root) const { return MPI_Gatherv(const_cast(in),sendDataLen,MPITraits::getType(), out,recvDataLen,displ,MPITraits::getType(), root,communicator); } //! @copydoc Communication::scatter() //! @note out must have space for P*len elements template int scatter (const T* sendData, T* recvData, int len, int root) const { return MPI_Scatter(const_cast(sendData),len,MPITraits::getType(), recvData,len,MPITraits::getType(), root,communicator); } //! @copydoc Communication::iscatter template MPIFuture iscatter(TIN&& data_in, TOUT&& data_out, int root) const { MPIFuture future(std::forward(data_out), std::forward(data_in)); auto mpidata_in = future.get_send_mpidata(); auto mpidata_out = future.get_mpidata(); int inlen = (me==root) * mpidata_in.size()/procs; MPI_Iscatter(mpidata_in.ptr(), inlen, mpidata_in.type(), mpidata_out.ptr(), mpidata_out.size(), mpidata_out.type(), root, communicator, &future.req_); return future; } //! @copydoc Communication::scatterv() template int scatterv (const T* sendData, int* sendDataLen, int* displ, T* recvData, int recvDataLen, int root) const { return MPI_Scatterv(const_cast(sendData),sendDataLen,displ,MPITraits::getType(), recvData,recvDataLen,MPITraits::getType(), root,communicator); } operator MPI_Comm () const { return communicator; } //! @copydoc Communication::allgather() template int allgather(const T* sbuf, int count, T1* rbuf) const { return MPI_Allgather(const_cast(sbuf), count, MPITraits::getType(), rbuf, count, MPITraits::getType(), communicator); } //! @copydoc Communication::iallgather template MPIFuture iallgather(TIN&& data_in, TOUT&& data_out) const { MPIFuture future(std::forward(data_out), std::forward(data_in)); auto mpidata_in = future.get_send_mpidata(); auto mpidata_out = future.get_mpidata(); assert(mpidata_in.size()*procs <= mpidata_out.size()); int outlen = mpidata_in.size(); MPI_Iallgather(mpidata_in.ptr(), mpidata_in.size(), mpidata_in.type(), mpidata_out.ptr(), outlen, mpidata_out.type(), communicator, &future.req_); return future; } //! @copydoc Communication::allgatherv() template int allgatherv (const T* in, int sendDataLen, T* out, int* recvDataLen, int* displ) const { return MPI_Allgatherv(const_cast(in),sendDataLen,MPITraits::getType(), out,recvDataLen,displ,MPITraits::getType(), communicator); } //! @copydoc Communication::allreduce(Type* inout,int len) const template int allreduce(Type* inout, int len) const { Type* out = new Type[len]; int ret = allreduce(inout,out,len); std::copy(out, out+len, inout); delete[] out; return ret; } template Type allreduce(Type&& in) const{ Type lvalue_data = std::forward(in); auto data = getMPIData(lvalue_data); MPI_Allreduce(MPI_IN_PLACE, data.ptr(), data.size(), data.type(), (Generic_MPI_Op::get()), communicator); return lvalue_data; } //! @copydoc Communication::iallreduce template MPIFuture iallreduce(TIN&& data_in, TOUT&& data_out) const { MPIFuture future(std::forward(data_out), std::forward(data_in)); auto mpidata_in = future.get_send_mpidata(); auto mpidata_out = future.get_mpidata(); assert(mpidata_out.size() == mpidata_in.size()); assert(mpidata_out.type() == mpidata_in.type()); MPI_Iallreduce(mpidata_in.ptr(), mpidata_out.ptr(), mpidata_out.size(), mpidata_out.type(), (Generic_MPI_Op::get()), communicator, &future.req_); return future; } //! @copydoc Communication::iallreduce template MPIFuture iallreduce(T&& data) const{ MPIFuture future(std::forward(data)); auto mpidata = future.get_mpidata(); MPI_Iallreduce(MPI_IN_PLACE, mpidata.ptr(), mpidata.size(), mpidata.type(), (Generic_MPI_Op::get()), communicator, &future.req_); return future; } //! @copydoc Communication::allreduce(Type* in,Type* out,int len) const template int allreduce(const Type* in, Type* out, int len) const { return MPI_Allreduce(const_cast(in), out, len, MPITraits::getType(), (Generic_MPI_Op::get()),communicator); } private: MPI_Comm communicator; int me; int procs; }; } // namespace dune #endif // HAVE_MPI #endif dune-common-2.8.0/dune/common/parallel/mpidata.hh000066400000000000000000000054661411343567400217440ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_PARALLEL_MPIDATA_HH #define DUNE_COMMON_PARALLEL_MPIDATA_HH #include #include #if HAVE_MPI #include #include #include /** @addtogroup ParallelCommunication * * @{ */ /** * @file * * @brief Interface class to translate objects to a MPI_Datatype, void* * and size used for MPI calls. * * Furthermore it can be used to resize the object * if possible. This makes it possible to receive a message with variable * size. See `Communication::rrecv`. * * To 'register' a new dynamic type for MPI communication specialize `MPIData` or * overload `getMPIData`. * */ namespace Dune{ template struct MPIData; template auto getMPIData(T& t){ return MPIData(t); } // Default implementation for static datatypes template struct MPIData { friend auto getMPIData(T&); protected: T& data_; MPIData(T& t) : data_(t) {} public: void* ptr() const { return (void*)&data_; } // indicates whether the datatype can be resized static constexpr bool static_size = true; int size() const{ return 1; } MPI_Datatype type() const { return MPITraits>::getType(); } }; // dummy implementation for void template<> struct MPIData{ protected: MPIData() {} public: void* ptr(){ return nullptr; } int size(){ return 0; } void get(){} MPI_Datatype type() const{ return MPI_INT; } }; // specializations: // std::vector of static sized elements or std::string template struct MPIData().data()), decltype(std::declval().size()), typename std::decay_t::value_type>>>{ private: template using hasResizeOp = decltype(std::declval().resize(0)); protected: friend auto getMPIData(T&); MPIData(T& t) : data_(t) {} public: static constexpr bool static_size = std::is_const::value || !Std::is_detected_v; void* ptr() { return (void*) data_.data(); } int size() { return data_.size(); } MPI_Datatype type() const{ return MPITraits::value_type>::getType(); } template auto /*void*/ resize(int size) -> std::enable_if_t::value || !Std::is_detected_v> { data_.resize(size); } protected: T& data_; }; } /** * @} */ #endif #endif dune-common-2.8.0/dune/common/parallel/mpifuture.hh000066400000000000000000000077041411343567400223420ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_PARALLEL_MPIFUTURE_HH #define DUNE_COMMON_PARALLEL_MPIFUTURE_HH #include #include #include #include #if HAVE_MPI namespace Dune{ namespace impl{ template struct Buffer{ Buffer(bool valid){ if(valid) value = std::make_unique(); } template Buffer(V&& t) : value(std::make_unique(std::forward(t))) {} std::unique_ptr value; T get(){ T tmp = std::move(*value); value.reset(); return tmp; } operator bool () const { return (bool)value; } T& operator *() const{ return *value; } }; template struct Buffer{ Buffer(bool valid = false) { if(valid) value = T(); } template Buffer(V&& t) : value(std::forward(t)) {} std::optional> value; T& get(){ T& tmp = *value; value.reset(); return tmp; } operator bool () const{ return (bool)value; } T& operator *() const{ return *value; } }; template<> struct Buffer{ bool valid_; Buffer(bool valid = false) : valid_(valid) {} operator bool () const{ return valid_; } void get(){} }; } /*! \brief Provides a future-like object for MPI communication. It contains the object that will be received and might contain also a sending object, which must be hold (keep alive) until the communication has been completed. */ template class MPIFuture{ mutable MPI_Request req_; mutable MPI_Status status_; impl::Buffer data_; impl::Buffer send_data_; friend class Communication; public: MPIFuture(bool valid = false) : req_(MPI_REQUEST_NULL) , data_(valid) {} // Hide this constructor if R or S is void template MPIFuture(V&& recv_data, U&& send_data, typename std::enable_if_t::value && !std::is_void::value>* = 0) : req_(MPI_REQUEST_NULL) , data_(std::forward(recv_data)) , send_data_(std::forward(send_data)) {} // hide this constructor if R is void template MPIFuture(V&& recv_data, typename std::enable_if_t::value>* = 0) : req_(MPI_REQUEST_NULL) , data_(std::forward(recv_data)) {} ~MPIFuture() { if(req_ != MPI_REQUEST_NULL){ try{ // might fail when it is a collective communication MPI_Cancel(&req_); MPI_Request_free(&req_); }catch(...){ } } } MPIFuture(MPIFuture&& f) : req_(MPI_REQUEST_NULL) , data_(std::move(f.data_)) , send_data_(std::move(f.send_data_)) { std::swap(req_, f.req_); std::swap(status_, f.status_); } MPIFuture& operator=(MPIFuture&& f){ std::swap(req_, f.req_); std::swap(status_, f.status_); std::swap(data_, f.data_); std::swap(send_data_, f.send_data_); return *this; } bool valid() const{ return (bool)data_; } void wait(){ if(!valid()) DUNE_THROW(InvalidFutureException, "The MPIFuture is not valid!"); MPI_Wait(&req_, &status_); } bool ready() const{ int flag = -1; MPI_Test(&req_, &flag, &status_); return flag; } R get() { wait(); return data_.get(); } S get_send_data(){ wait(); return send_data_.get(); } auto get_mpidata(){ return getMPIData(*data_); } auto get_send_mpidata(){ return getMPIData(*send_data_); } }; } #endif #endif dune-common-2.8.0/dune/common/parallel/mpiguard.hh000066400000000000000000000144021411343567400221230ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /** * @file * @brief Implements a MPIGuard which detects an error on a remote process * @author Christian Engwer * @ingroup ParallelCommunication */ #ifndef DUNE_COMMON_MPIGUARD_HH #define DUNE_COMMON_MPIGUARD_HH #include "mpihelper.hh" #include "communication.hh" #include "mpicommunication.hh" #include namespace Dune { #ifndef DOXYGEN /* Interface class for the communication needed by MPIGuard */ struct GuardCommunicator { // cleanup virtual ~GuardCommunicator() {}; // all the communication methods we need virtual int rank() = 0; virtual int size() = 0; virtual int sum(int i) = 0; // create a new GuardCommunicator pointer template static GuardCommunicator * create(const CollectiveCommunication & c); #if HAVE_MPI inline static GuardCommunicator * create(const MPI_Comm & c); #endif }; namespace { /* templated implementation of different communication classes */ // the default class will always fail, due to the missing implementation of "sum" template struct GenericGuardCommunicator : public GuardCommunicator {}; // specialization for Communication template struct GenericGuardCommunicator< Communication > : public GuardCommunicator { const Communication comm; GenericGuardCommunicator(const Communication & c) : comm(c) {} int rank() override { return comm.rank(); }; int size() override { return comm.size(); }; int sum(int i) override { return comm.sum(i); } }; #if HAVE_MPI // specialization for MPI_Comm template <> struct GenericGuardCommunicator : public GenericGuardCommunicator< Communication > { GenericGuardCommunicator(const MPI_Comm & c) : GenericGuardCommunicator< Communication >( Communication(c)) {} }; #endif } // anonymous namespace template GuardCommunicator * GuardCommunicator::create(const CollectiveCommunication & comm) { return new GenericGuardCommunicator< CollectiveCommunication >(comm); } #if HAVE_MPI GuardCommunicator * GuardCommunicator::create(const MPI_Comm & comm) { return new GenericGuardCommunicator< CollectiveCommunication >(comm); } #endif #endif /*! @brief This exception is thrown if the MPIGuard detects an error on a remote process @ingroup ParallelCommunication */ class MPIGuardError : public ParallelError {}; /*! @brief detects a thrown exception and communicates to all other processes @ingroup ParallelCommunication @code { MPIGuard guard(...); do_something(); // tell the guard that you successfully passed a critical operation guard.finalize(); // reactivate the guard for the next critical operation guard.reactivate(); int result = do_something_else(); // tell the guard the result of your operation guard.finalize(result == success); } @endcode You create a MPIGuard object. If an exception is risen on a process the MPIGuard detects the exception, because the finalize method was not called. When reaching the finalize call all other processes are informed that an error occurred and the MPIGuard throws an exception of type MPIGuardError. @note You can initialize the MPIGuard from different types of communication objects: - MPIHelper - Communication - MPI_Comm */ class MPIGuard { GuardCommunicator * comm_; bool active_; // we don't want to copy this class MPIGuard (const MPIGuard &); public: /*! @brief create an MPIGuard operating on the Communicator of the global Dune::MPIHelper @param active should the MPIGuard be active upon creation? */ MPIGuard (bool active=true) : comm_(GuardCommunicator::create( MPIHelper::getCommunication())), active_(active) {} /*! @brief create an MPIGuard operating on the Communicator of a special Dune::MPIHelper m @param m a reference to an MPIHelper @param active should the MPIGuard be active upon creation? */ MPIGuard (MPIHelper & m, bool active=true) : comm_(GuardCommunicator::create( m.getCommunication())), active_(active) {} /*! @brief create an MPIGuard operating on an arbitrary communicator. Supported types for the communication object are: - MPIHelper - Communication - MPI_Comm @param comm reference to a communication object @param active should the MPIGuard be active upon creation? */ template MPIGuard (const C & comm, bool active=true) : comm_(GuardCommunicator::create(comm)), active_(active) {} #if HAVE_MPI MPIGuard (const MPI_Comm & comm, bool active=true) : comm_(GuardCommunicator::create(comm)), active_(active) {} #endif /*! @brief destroy the guard and check for undetected exceptions */ ~MPIGuard() { if (active_) { active_ = false; finalize(false); } delete comm_; } /*! @brief reactivate the guard. If the guard is still active finalize(true) is called first. */ void reactivate() { if (active_ == true) finalize(); active_ = true; } /*! @brief stop the guard. If no success parameter is passed, the guard assumes that everything worked as planned. All errors are communicated and an exception of type MPIGuardError is thrown if an error (or exception) occurred on any of the processors in the communicator. @param success inform the guard about possible errors */ void finalize(bool success = true) { int result = success ? 0 : 1; bool was_active = active_; active_ = false; result = comm_->sum(result); if (result>0 && was_active) { DUNE_THROW(MPIGuardError, "Terminating process " << comm_->rank() << " due to " << result << " remote error(s)"); } } }; } #endif // DUNE_COMMON_MPIGUARD_HH dune-common-2.8.0/dune/common/parallel/mpihelper.hh000066400000000000000000000205171411343567400223040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_MPIHELPER #define DUNE_MPIHELPER #if HAVE_MPI #include #include #endif #include #include #if HAVE_MPI #include #include #endif #include namespace Dune { /** * @file * @brief Helpers for dealing with MPI. * * @ingroup ParallelCommunication * * Basically there are two helpers available: *
*
FakeMPIHelper
*
A class adhering to the interface of MPIHelper * that does not need MPI at all. This can be used * to create a sequential program even if MPI is * used to compile it. *
*
MPIHelper
*
A real MPI helper. When the singleton * gets instantiated MPI_Init will be * called and before the program exits * MPI_Finalize will be called. *
*
* * Example of who to use these classes: * * A program that is parallel if compiled with MPI * and sequential otherwise: * \code * int main(int argc, char** argv){ * typedef Dune::MPIHelper MPIHelper; * MPIHelper::instance(argc, argv); * typename MPIHelper::MPICommunicator world = * MPIHelper::getCommunicator(); * ... * \endcode * * If one wants to have sequential program even if the code is * compiled with mpi then one simply has to exchange the typedef * with \code typedef Dune::MPIHelper FakeMPIHelper; \endcode. * * For checking whether we really use MPI or just fake please use * MPIHelper::isFake (this is also possible at compile time!) */ /** * @brief A fake mpi helper. * * This helper can be used if no MPI is available * or one wants to run sequentially even if MPI is * available and used. */ class FakeMPIHelper { public: enum { /** * @brief Are we fake (i.e. pretend to have MPI support but are compiled * without.) */ isFake = true }; /** * @brief The type of the mpi communicator. */ typedef No_Comm MPICommunicator; /** \brief get the default communicator * * Return a communicator to exchange data with all processes * * \returns a fake communicator */ DUNE_EXPORT static MPICommunicator getCommunicator () { static MPICommunicator comm; return comm; } /** \brief get a local communicator * * Returns a communicator to communicate with the local process only * * \returns a fake communicator */ static MPICommunicator getLocalCommunicator () { return getCommunicator(); } // Will be deprecated after the 2.7 release //[[deprecated("getCollectionCommunication is deprecated. Use getCommunication instead.")]] static Communication getCollectiveCommunication() { return Communication(getCommunicator()); } static Communication getCommunication() { return Communication(getCommunicator()); } /** * @brief Get the singleton instance of the helper. * * This method has to be called with the same arguments * that the main method of the program was called: * \code * int main(int argc, char** argv){ * MPIHelper::instance(argc, argv); * // program code comes here * ... * } * \endcode * @param argc The number of arguments provided to main. * @param argv The arguments provided to main. */ DUNE_EXPORT static FakeMPIHelper& instance([[maybe_unused]] int argc, [[maybe_unused]] char** argv) { return instance(); } DUNE_EXPORT static FakeMPIHelper& instance() { static FakeMPIHelper singleton; return singleton; } /** * @brief return rank of process, i.e. zero */ int rank () const { return 0; } /** * @brief return rank of process, i.e. one */ int size () const { return 1; } private: FakeMPIHelper() {} FakeMPIHelper(const FakeMPIHelper&); FakeMPIHelper& operator=(const FakeMPIHelper); }; #if HAVE_MPI /** * @brief A real mpi helper. * @ingroup ParallelCommunication * * This helper should be used for parallel programs. */ class MPIHelper { public: enum { /** * @brief Are we fake (i. e. pretend to have MPI support but are compiled * without. */ isFake = false }; /** * @brief The type of the mpi communicator. */ typedef MPI_Comm MPICommunicator; /** \brief get the default communicator * * Return a communicator to exchange data with all processes * * \returns MPI_COMM_WORLD */ static MPICommunicator getCommunicator () { return MPI_COMM_WORLD; } /** \brief get a local communicator * * Returns a communicator to exchange data with the local process only * * \returns MPI_COMM_SELF */ static MPICommunicator getLocalCommunicator () { return MPI_COMM_SELF; } // Will be deprecated after the 2.7 release //[[deprecated("getCollectionCommunication is deprecated. Use getCommunication instead.")]] static Communication getCollectiveCommunication() { return Communication(getCommunicator()); } static Communication getCommunication() { return Communication(getCommunicator()); } /** * @brief Get the singleton instance of the helper. * * This method has to be called with the same arguments * that the main method of the program was called: * \code * int main(int argc, char** argv){ * MPIHelper::instance(argc, argv); * // program code comes here * ... * } * \endcode * @param argc The number of arguments provided to main. * @param argv The arguments provided to main. */ DUNE_EXPORT static MPIHelper& instance(int& argc, char**& argv) { // create singleton instance if (!instance_){ static std::mutex mutex; std::lock_guard guard(mutex); if(!instance_) instance_.reset(new MPIHelper(argc,argv)); } return *instance_; } DUNE_EXPORT static MPIHelper& instance() { if(!instance_) DUNE_THROW(InvalidStateException, "MPIHelper not initialized! Call MPIHelper::instance(argc, argv) with arguments first."); return *instance_; } /** * @brief return rank of process */ int rank () const { return rank_; } /** * @brief return number of processes */ int size () const { return size_; } //! \brief calls MPI_Finalize ~MPIHelper() { int wasFinalized = -1; MPI_Finalized( &wasFinalized ); if(!wasFinalized && initializedHere_) { MPI_Finalize(); dverb << "Called MPI_Finalize on p=" << rank_ << "!" < instance_ = {}; //! \brief calls MPI_Init with argc and argv as parameters MPIHelper(int& argc, char**& argv) : initializedHere_(false) { int wasInitialized = -1; MPI_Initialized( &wasInitialized ); if(!wasInitialized) { rank_ = -1; size_ = -1; static int is_initialized = MPI_Init(&argc, &argv); prevent_warning(is_initialized); initializedHere_ = true; } MPI_Comm_rank(MPI_COMM_WORLD,&rank_); MPI_Comm_size(MPI_COMM_WORLD,&size_); assert( rank_ >= 0 ); assert( size_ >= 1 ); dverb << "Called MPI_Init on p=" << rank_ << "!" << std::endl; } MPIHelper(const MPIHelper&); MPIHelper& operator=(const MPIHelper); }; #else // !HAVE_MPI // We do not have MPI therefore FakeMPIHelper // is the MPIHelper /** * @brief If no MPI is available FakeMPIHelper becomes the MPIHelper * @ingroup ParallelCommunication */ typedef FakeMPIHelper MPIHelper; #endif // !HAVE_MPI } // end namespace Dune #endif dune-common-2.8.0/dune/common/parallel/mpipack.hh000066400000000000000000000131241411343567400217370ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /** * @file * * @brief See MPI_Pack. * * This Wrapper class takes care of the * memory management and provides methods to pack and unpack * objects. All objects that can be used for MPI communication can * also be packed and unpacked to/from MPIPack. * * @author Nils-Arne Dreier * @ingroup ParallelCommunication */ #ifndef DUNE_COMMON_PARALLEL_MPIPACK_HH #define DUNE_COMMON_PARALLEL_MPIPACK_HH #include #if HAVE_MPI #include #include #include namespace Dune { class MPIPack { std::vector _buffer; int _position; MPI_Comm _comm; friend struct MPIData; friend struct MPIData; public: MPIPack(Communication comm, std::size_t size = 0) : _buffer(size) , _position(0) , _comm(comm) {} // Its not valid to copy a MPIPack but you can move it MPIPack(const MPIPack&) = delete; MPIPack& operator = (const MPIPack& other) = delete; MPIPack(MPIPack&&) = default; MPIPack& operator = (MPIPack&& other) = default; /** @brief Packs the data into the object. Enlarges the internal buffer if * necessary. * * @throw MPIError */ template void pack(const T& data){ auto mpidata = getMPIData(data); int size = getPackSize(mpidata.size(), _comm, mpidata.type()); constexpr bool has_static_size = decltype(getMPIData(std::declval()))::static_size; if(!has_static_size) size += getPackSize(1, _comm, MPI_INT); if (_position + size > 0 && size_t(_position + size) > _buffer.size()) // resize buffer if necessary _buffer.resize(_position + size); if(!has_static_size){ int size = mpidata.size(); MPI_Pack(&size, 1, MPI_INT, _buffer.data(), _buffer.size(), &_position, _comm); } MPI_Pack(mpidata.ptr(), mpidata.size(), mpidata.type(), _buffer.data(), _buffer.size(), &_position, _comm); } /** @brief Unpacks data from the object * * @throw MPIError */ template auto /*void*/ unpack(T& data) -> std::enable_if_t { auto mpidata = getMPIData(data); MPI_Unpack(_buffer.data(), _buffer.size(), &_position, mpidata.ptr(), mpidata.size(), mpidata.type(), _comm); } /** @brief Unpacks data from the object * * @throw MPIError */ template auto /*void*/ unpack(T& data) -> std::enable_if_t { auto mpidata = getMPIData(data); int size = 0; MPI_Unpack(_buffer.data(), _buffer.size(), &_position, &size, 1, MPI_INT, _comm); mpidata.resize(size); MPI_Unpack(_buffer.data(), _buffer.size(), &_position, mpidata.ptr(), mpidata.size(), mpidata.type(), _comm); } //! @copydoc pack template friend MPIPack& operator << (MPIPack& p, const T& t){ p.pack(t); return p; } //! @copydoc unpack template friend MPIPack& operator >> (MPIPack& p, T& t){ p.unpack(t); return p; } //! @copydoc unpack template MPIPack& read(T& t){ unpack(t); return *this; } //! @copydoc pack template MPIPack& write(const T& t){ pack(t); return *this; } /** @brief Resizes the internal buffer. \param size new size of internal buffer */ void resize(size_t size){ _buffer.resize(size); } /** @brief Enlarges the internal buffer. */ void enlarge(int s) { _buffer.resize(_buffer.size() + s); } /** @brief Returns the size of the internal buffer. */ size_t size() const { return _buffer.size(); } /** @brief Sets the position in the buffer where the next * pack/unpack operation should take place. */ void seek(int p){ _position = p; } /** @brief Gets the position in the buffer where the next * pack/unpack operation should take place. */ int tell() const{ return _position; } /** @brief Checks whether the end of the buffer is reached. */ bool eof() const{ return std::size_t(_position)==_buffer.size(); } /** @brief Returns the size of the data needed to store the data * in an MPIPack. See `MPI_Pack_size`. */ static int getPackSize(int len, const MPI_Comm& comm, const MPI_Datatype& dt){ int size; MPI_Pack_size(len, dt, comm, &size); return size; } friend bool operator==(const MPIPack& a, const MPIPack& b) { return a._buffer == b._buffer && a._comm == b._comm; } friend bool operator!=(const MPIPack& a, const MPIPack& b) { return !(a==b); } }; template struct MPIData, MPIPack>::value>> { protected: friend auto getMPIData

(P& t); MPIData(P& t) : data_(t) {} public: static constexpr bool static_size = std::is_const

::value; void* ptr() { return (void*) data_._buffer.data(); } int size() { return data_.size(); } MPI_Datatype type() const{ return MPI_PACKED; } void resize(int size){ data_.resize(size); } protected: P& data_; }; } // end namespace Dune #endif #endif dune-common-2.8.0/dune/common/parallel/mpitraits.hh000066400000000000000000000126331411343567400223330ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_MPITRAITS_HH #define DUNE_MPITRAITS_HH /** @addtogroup ParallelCommunication * * @{ */ /** * @file * @brief Traits classes for mapping types onto MPI_Datatype. * @author Markus Blatt */ #if HAVE_MPI #include #include #include #include #include #include namespace Dune { /** * @brief A traits class describing the mapping of types onto MPI_Datatypes. * * Specializations exist for the default types. * Specializations should provide a static method * \code * static MPI_Datatype getType(); * \endcode */ template struct MPITraits { private: MPITraits(){} MPITraits(const MPITraits&){} static MPI_Datatype datatype; static MPI_Datatype vectortype; public: static inline MPI_Datatype getType() { if(datatype==MPI_DATATYPE_NULL) { MPI_Type_contiguous(sizeof(T),MPI_BYTE,&datatype); MPI_Type_commit(&datatype); } return datatype; } static constexpr bool is_intrinsic = false; }; template MPI_Datatype MPITraits::datatype = MPI_DATATYPE_NULL; #ifndef DOXYGEN // A Macro for defining traits for the primitive data types #define ComposeMPITraits(p,m) \ template<> \ struct MPITraits

{ \ static inline MPI_Datatype getType(){ \ return m; \ } \ static constexpr bool is_intrinsic = true; \ } ComposeMPITraits(char, MPI_CHAR); ComposeMPITraits(unsigned char,MPI_UNSIGNED_CHAR); ComposeMPITraits(short,MPI_SHORT); ComposeMPITraits(unsigned short,MPI_UNSIGNED_SHORT); ComposeMPITraits(int,MPI_INT); ComposeMPITraits(unsigned int,MPI_UNSIGNED); ComposeMPITraits(long,MPI_LONG); ComposeMPITraits(unsigned long,MPI_UNSIGNED_LONG); ComposeMPITraits(float,MPI_FLOAT); ComposeMPITraits(double,MPI_DOUBLE); ComposeMPITraits(long double,MPI_LONG_DOUBLE); ComposeMPITraits(std::complex, MPI_CXX_DOUBLE_COMPLEX); ComposeMPITraits(std::complex, MPI_CXX_LONG_DOUBLE_COMPLEX); ComposeMPITraits(std::complex, MPI_CXX_FLOAT_COMPLEX); #undef ComposeMPITraits template class FieldVector; template struct MPITraits > { static MPI_Datatype datatype; static MPI_Datatype vectortype; static inline MPI_Datatype getType() { if(datatype==MPI_DATATYPE_NULL) { MPI_Type_contiguous(n, MPITraits::getType(), &vectortype); MPI_Type_commit(&vectortype); FieldVector fvector; MPI_Aint base; MPI_Aint displ; MPI_Get_address(&fvector, &base); MPI_Get_address(&(fvector[0]), &displ); displ -= base; int length[1]={1}; MPI_Type_create_struct(1, length, &displ, &vectortype, &datatype); MPI_Type_commit(&datatype); } return datatype; } }; template MPI_Datatype MPITraits >::datatype = MPI_DATATYPE_NULL; template MPI_Datatype MPITraits >::vectortype = {MPI_DATATYPE_NULL}; template class bigunsignedint; template struct MPITraits > { static MPI_Datatype datatype; static MPI_Datatype vectortype; static inline MPI_Datatype getType() { if(datatype==MPI_DATATYPE_NULL) { MPI_Type_contiguous(bigunsignedint::n, MPITraits::getType(), &vectortype); //MPI_Type_commit(&vectortype); bigunsignedint data; MPI_Aint base; MPI_Aint displ; MPI_Get_address(&data, &base); MPI_Get_address(&(data.digit), &displ); displ -= base; int length[1]={1}; MPI_Type_create_struct(1, length, &displ, &vectortype, &datatype); MPI_Type_commit(&datatype); } return datatype; } }; } namespace Dune { template MPI_Datatype MPITraits >::datatype = MPI_DATATYPE_NULL; template MPI_Datatype MPITraits >::vectortype = MPI_DATATYPE_NULL; template struct MPITraits > { public: inline static MPI_Datatype getType(); private: static MPI_Datatype type; }; template MPI_Datatype MPITraits >::getType() { if(type==MPI_DATATYPE_NULL) { int length[2] = {1, 1}; MPI_Aint disp[2]; MPI_Datatype types[2] = {MPITraits::getType(), MPITraits::getType()}; using Pair = std::pair; static_assert(std::is_standard_layout::value, "offsetof() is only defined for standard layout types"); disp[0] = offsetof(Pair, first); disp[1] = offsetof(Pair, second); MPI_Datatype tmp; MPI_Type_create_struct(2, length, disp, types, &tmp); MPI_Type_create_resized(tmp, 0, sizeof(Pair), &type); MPI_Type_commit(&type); MPI_Type_free(&tmp); } return type; } template MPI_Datatype MPITraits >::type=MPI_DATATYPE_NULL; #endif // !DOXYGEN } // namespace Dune #endif // HAVE_MPI /** @} group ParallelCommunication */ #endif dune-common-2.8.0/dune/common/parallel/plocalindex.hh000066400000000000000000000166701411343567400226260ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_PLOCALINDEX_HH #define DUNE_PLOCALINDEX_HH #include "localindex.hh" #include "indexset.hh" #include "mpitraits.hh" #include namespace Dune { /** @addtogroup Common_Parallel * * @{ */ /** * @file * @brief Provides classes for use as the local index in ParallelIndexSet for distributed computing. * @author Markus Blatt */ template class ParallelLocalIndex; /** * @brief Print the local index to a stream. * @param os The output stream to print to. * @param index The index to print. */ template std::ostream& operator<<(std::ostream& os, const ParallelLocalIndex& index) { os<<"{local="< class ParallelLocalIndex { #if HAVE_MPI // friend declaration needed for MPITraits friend struct MPITraits >; #endif friend std::ostream& operator<<<>(std::ostream& os, const ParallelLocalIndex& index); public: /** * @brief The type of the attributes. * Normally this will be an enumeration like *

     * enum Attributes{owner, border, overlap};
     * 
*/ typedef T Attribute; /** * @brief Constructor. * * The local index will be initialized to 0. * @param attribute The attribute of the index. * @param isPublic True if the index might also be * known to other processes. */ ParallelLocalIndex(const Attribute& attribute, bool isPublic); /** * @brief Constructor. * * @param localIndex The local index. * @param attribute The attribute of the index. * @param isPublic True if the index might also be * known to other processes. */ ParallelLocalIndex(size_t localIndex, const Attribute& attribute, bool isPublic=true); /** * @brief Parameterless constructor. * * Needed for use in container classes. */ ParallelLocalIndex(); #if 0 /** * @brief Constructor. * @param globalIndex The global index. * @param attribute The attribute of the index. * @param local The local index. * @param isPublic True if the index might also be * known to other processes. * */ ParallelLocalIndex(const Attribute& attribute, size_t local, bool isPublic); #endif /** * @brief Get the attribute of the index. * @return The associated attribute. */ inline const Attribute attribute() const; /** * @brief Set the attribute of the index. * @param attribute The associated attribute. */ inline void setAttribute(const Attribute& attribute); /** * @brief get the local index. * @return The local index. */ inline size_t local() const; /** * @brief Convert to the local index represented by an int. */ inline operator size_t() const; /** * @brief Assign a new local index. * * @param index The new local index. */ inline ParallelLocalIndex& operator=(size_t index); /** * @brief Check whether the index might also be known other processes. * @return True if the index might be known to other processors. */ inline bool isPublic() const; /** * @brief Get the state. * @return The state. */ inline LocalIndexState state() const; /** * @brief Set the state. * @param state The state to set. */ inline void setState(const LocalIndexState& state); private: /** @brief The local index. */ size_t localIndex_; /** @brief An attribute for the index. */ char attribute_; /** @brief True if the index is also known to other processors. */ char public_; /** * @brief The state of the index. * * Has to be one of LocalIndexState! * @see LocalIndexState. */ char state_; }; template bool operator==(const ParallelLocalIndex& p1, const ParallelLocalIndex& p2) { if(p1.local()!=p2.local()) return false; if(p1.attribute()!=p2.attribute()) return false; if(p1.isPublic()!=p2.isPublic()) return false; return true; } template bool operator!=(const ParallelLocalIndex& p1, const ParallelLocalIndex& p2) { return !(p1==p2); } template struct LocalIndexComparator > { static bool compare(const ParallelLocalIndex& t1, const ParallelLocalIndex& t2){ return t1.attribute() class MPITraits > { public: static MPI_Datatype getType(); private: static MPI_Datatype type; }; #endif template ParallelLocalIndex::ParallelLocalIndex(const T& attribute, bool isPublic) : localIndex_(0), attribute_(static_cast(attribute)), public_(static_cast(isPublic)), state_(static_cast(VALID)) {} template ParallelLocalIndex::ParallelLocalIndex(size_t local, const T& attribute, bool isPublic) : localIndex_(local), attribute_(static_cast(attribute)), public_(static_cast(isPublic)), state_(static_cast(VALID)) {} template ParallelLocalIndex::ParallelLocalIndex() : localIndex_(0), attribute_(), public_(static_cast(false)), state_(static_cast(VALID)) {} template inline const T ParallelLocalIndex::attribute() const { return T(attribute_); } template inline void ParallelLocalIndex::setAttribute(const Attribute& attribute) { attribute_ = attribute; } template inline size_t ParallelLocalIndex::local() const { return localIndex_; } template inline ParallelLocalIndex::operator size_t() const { return localIndex_; } template inline ParallelLocalIndex& ParallelLocalIndex::operator=(size_t index) { localIndex_=index; return *this; } template inline bool ParallelLocalIndex::isPublic() const { return static_cast(public_); } template inline LocalIndexState ParallelLocalIndex::state() const { return LocalIndexState(state_); } template inline void ParallelLocalIndex::setState(const LocalIndexState& state) { state_=static_cast(state); } #if HAVE_MPI template MPI_Datatype MPITraits >::getType() { if(type==MPI_DATATYPE_NULL) { int length = 1; MPI_Aint base, disp; MPI_Datatype types[1] = {MPITraits::getType()}; ParallelLocalIndex rep; MPI_Get_address(&rep, &base); MPI_Get_address(&(rep.attribute_), &disp); disp -= base; MPI_Datatype tmp; MPI_Type_create_struct(1, &length, &disp, types, &tmp); MPI_Type_create_resized(tmp, 0, sizeof(ParallelLocalIndex), &type); MPI_Type_commit(&type); MPI_Type_free(&tmp); } return type; } template MPI_Datatype MPITraits >::type = MPI_DATATYPE_NULL; #endif /** @} */ } // namespace Dune #endif dune-common-2.8.0/dune/common/parallel/remoteindices.hh000066400000000000000000001655641411343567400231650ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_REMOTEINDICES_HH #define DUNE_REMOTEINDICES_HH #if HAVE_MPI #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Dune { /** @addtogroup Common_Parallel * * @{ */ /** * @file * @brief Classes describing a distributed indexset * @author Markus Blatt */ //! \todo Please doc me! template class MPITraits > > { public: inline static MPI_Datatype getType(); private: static MPI_Datatype type; }; template class RemoteIndices; template class RemoteIndex; // forward declaration needed for friend declaration. template class IndicesSyncer; template std::ostream& operator<<(std::ostream& os, const RemoteIndex& index); template class RemoteIndexListModifier; /** * @brief Information about an index residing on another processor. */ template class RemoteIndex { template friend class IndicesSyncer; template friend void repairLocalIndexPointers(std::map,A> >&, RemoteIndices&, const T&); template friend class RemoteIndexListModifier; public: /** * @brief the type of the global index. * This type has to provide at least a operator< for sorting. */ typedef T1 GlobalIndex; /** * @brief The type of the attributes. * Normally this will be an enumeration like * \code * enum Attributes{owner, border, overlap} * \endcode * e.g. OwnerOverlapCopyAttributes. */ typedef T2 Attribute; /** * @brief The type of the index pair. */ typedef IndexPair > PairType; /** * @brief Get the attribute of the index on the remote process. * @return The remote attribute. */ const Attribute attribute() const; /** * @brief Get the corresponding local index pair. * @return The corresponding local index pair. */ const PairType& localIndexPair() const; /** * @brief Parameterless Constructor. */ RemoteIndex(); /** * @brief Constructor. * @param attribute The attribute of the index on the remote processor. * @param local The corresponding local index. */ RemoteIndex(const T2& attribute, const PairType* local); /** * @brief Constructor. * Private as it should only be called from within Indexset. * @param attribute The attribute of the index on the remote processor. */ RemoteIndex(const T2& attribute); bool operator==(const RemoteIndex& ri) const; bool operator!=(const RemoteIndex& ri) const; private: /** @brief The corresponding local index for this process. */ const PairType* localIndex_; /** @brief The attribute of the index on the other process. */ char attribute_; }; template std::ostream& operator<<(std::ostream& os, const RemoteIndices& indices); class InterfaceBuilder; template class CollectiveIterator; // forward declaration needed for friend declaration. template class IndicesSyncer; // forward declaration needed for friend declaration. template class OwnerOverlapCopyCommunication; /** * @brief The indices present on remote processes. * * To set up communication between the set of processes active in * the communication every process needs to know which * indices are also known to other processes and which attributes * are attached to them on the remote side. * * This information is managed by this class. The information can either * be computed automatically calling rebuild (which requires information * to be sent in a ring) or set up by hand using the * RemoteIndexListModifiers returned by function getModifier(int). * * @tparam T The type of the underlying index set. * @tparam A The type of the allocator to use. */ template > > class RemoteIndices { friend class InterfaceBuilder; friend class IndicesSyncer; template friend void repairLocalIndexPointers(std::map,A2> >&, RemoteIndices&, const T1&); template friend void fillIndexSetHoles(const G& graph, Dune::OwnerOverlapCopyCommunication& oocomm); friend std::ostream& operator<<<>(std::ostream&, const RemoteIndices&); public: /** * @brief Type of the index set we use, e.g. ParallelLocalIndexSet. */ typedef T ParallelIndexSet; /** * @brief The type of the collective iterator over all remote indices. */ typedef CollectiveIterator CollectiveIteratorT; /** * @brief The type of the global index. */ typedef typename ParallelIndexSet::GlobalIndex GlobalIndex; /** * @brief The type of the local index. */ typedef typename ParallelIndexSet::LocalIndex LocalIndex; /** * @brief The type of the attribute. */ typedef typename LocalIndex::Attribute Attribute; /** * @brief Type of the remote indices we manage. */ typedef Dune::RemoteIndex RemoteIndex; /** * @brief The type of the allocator for the remote index list. */ using Allocator = typename std::allocator_traits::template rebind_alloc; /** @brief The type of the remote index list. */ typedef Dune::SLList RemoteIndexList; /** @brief The type of the map from rank to remote index list. */ typedef std::map > RemoteIndexMap; typedef typename RemoteIndexMap::const_iterator const_iterator; /** * @brief Constructor. * @param comm The communicator to use. * @param source The indexset which represents the global to * local mapping at the source of the communication * @param destination The indexset to which the communication * which represents the global to * local mapping at the destination of the communication. * May be the same as the source indexset. * @param neighbours Optional: The neighbours the process shares indices with. * If this parameter is omitted a ring communication with all indices will take * place to calculate this information which is O(P). * @param includeSelf If true, sending from indices of the processor to other * indices on the same processor is enabled even if the same indexset is used * on both the * sending and receiving side. */ inline RemoteIndices(const ParallelIndexSet& source, const ParallelIndexSet& destination, const MPI_Comm& comm, const std::vector& neighbours=std::vector(), bool includeSelf=false); RemoteIndices(); /** * @brief Tell whether sending from indices of the processor to other * indices on the same processor is enabled even if the same indexset is * used on both the sending and receiving side. * * @param includeSelf If true it is enabled. */ void setIncludeSelf(bool includeSelf); /** * @brief Set the index sets and communicator we work with. * * @warning All remote indices already setup will be deleted! * * @param comm The communicator to use. * @param source The indexset which represents the global to * local mapping at the source of the communication * @param destination The indexset to which the communication * which represents the global to * local mapping at the destination of the communication. * May be the same as the source indexset. * @param neighbours Optional: The neighbours the process shares indices with. * If this parameter is omitted a ring communication with all indices will take * place to calculate this information which is O(P). */ void setIndexSets(const ParallelIndexSet& source, const ParallelIndexSet& destination, const MPI_Comm& comm, const std::vector& neighbours=std::vector()); template void setNeighbours(const C& neighbours) { neighbourIds.clear(); neighbourIds.insert(neighbours.begin(), neighbours.end()); } const std::set& getNeighbours() const { return neighbourIds; } /** * @brief Destructor. */ ~RemoteIndices(); /** * @brief Rebuilds the set of remote indices. * * This has to be called whenever the underlying index sets * change. * * If the template parameter ignorePublic is true all indices will be treated * as public. */ template void rebuild(); bool operator==(const RemoteIndices& ri) const; /** * @brief Checks whether the remote indices are synced with * the indexsets. * * If they are not synced the remote indices need to be rebuild. * @return True if they are synced. */ inline bool isSynced() const; /** * @brief Get the mpi communicator used. */ inline MPI_Comm communicator() const; /** * @brief Get a modifier for a remote index list. * * Sometimes the user knows in advance which indices will be present * on other processors, too. Then he can set them up using this modifier. * * @warning Use with care. If the remote index list is inconsistent * after the modification the communication might result in a dead lock! * * @tparam mode If true the index set corresponding to the remote indices might get modified. * Therefore the internal pointers to the indices need to be repaired. * @tparam send If true the remote index information at the sending side will * be modified, if false the receiving side. */ template inline RemoteIndexListModifier getModifier(int process); /** * @brief Find an iterator over the remote index lists of a specific process. * @param proc The identifier of the process. * @return The iterator the remote index lists postioned at the process. * If theres is no list for this process, the end iterator is returned. */ inline const_iterator find(int proc) const; /** * @brief Get an iterator over all remote index lists. * @return The iterator over all remote index lists postioned at the first process. */ inline const_iterator begin() const; /** * @brief Get an iterator over all remote index lists. * @return The iterator over all remote index lists postioned at the end. */ inline const_iterator end() const; /** * @brief Get an iterator for colletively iterating over the remote indices of all remote processes. */ template inline CollectiveIteratorT iterator() const; /** * @brief Free the index lists. */ inline void free(); /** * @brief Get the number of processors we share indices with. * @return The number of neighbours. */ inline int neighbours() const; /** @brief Get the index set at the source. */ inline const ParallelIndexSet& sourceIndexSet() const; /** @brief Get the index set at destination. */ inline const ParallelIndexSet& destinationIndexSet() const; private: /** copying is forbidden. */ RemoteIndices(const RemoteIndices&) = delete; /** @brief Index set used at the source of the communication. */ const ParallelIndexSet* source_; /** @brief Index set used at the destination of the communication. */ const ParallelIndexSet* target_; /** @brief The communicator to use.*/ MPI_Comm comm_; /** @brief The neighbours we share indices with. * If not empty this will speedup rebuild. */ std::set neighbourIds; /** @brief The communicator tag to use. */ const static int commTag_=333; /** * @brief The sequence number of the source index set when the remote indices * where build. */ int sourceSeqNo_; /** * @brief The sequence number of the destination index set when the remote indices * where build. */ int destSeqNo_; /** * @brief Whether the public flag was ignored during the build. */ bool publicIgnored; /** * @brief Whether the next build will be the first build ever. */ bool firstBuild; /* * @brief If true, sending from indices of the processor to other * indices on the same processor is enabled even if the same indexset is used * on both the * sending and receiving side. */ bool includeSelf; /** @brief The index pair type. */ typedef IndexPair PairType; /** * @brief The remote indices. * * The key is the process id and the values are the pair of remote * index lists, the first for receiving, the second for sending. */ RemoteIndexMap remoteIndices_; /** * @brief Build the remote mapping. * * If the template parameter ignorePublic is true all indices will be treated * as public. * @param includeSelf If true, sending from indices of the processor to other * indices on the same processor is enabled even if the same indexset is used * on both the * sending and receiving side. */ template inline void buildRemote(bool includeSelf); /** * @brief Count the number of public indices in an index set. * @param indexSet The index set whose indices we count. * @return the number of indices marked as public. */ inline int noPublic(const ParallelIndexSet& indexSet); /** * @brief Pack the indices to send if source_ and target_ are the same. * * If the template parameter ignorePublic is true all indices will be treated * as public. * @param myPairs Array to store references to the public indices in. * @param p_out The output buffer to pack the entries to. * @param type The mpi datatype for the pairs. * @param bufferSize The size of the output buffer p_out. * @param position The position to start packing. */ template inline void packEntries(PairType** myPairs, const ParallelIndexSet& indexSet, char* p_out, MPI_Datatype type, int bufferSize, int* position, int n); /** * @brief unpacks the received indices and builds the remote index list. * * @param remote The list to add the indices to. * @param remoteEntries The number of remote entries to unpack. * @param local The local indices to check whether we know the remote * indices. * @param localEntries The number of local indices. * @param type The mpi data type for unpacking. * @param p_in The input buffer to unpack from. * @param position The position in the buffer to start unpacking from. * @param bufferSize The size of the input buffer. */ inline void unpackIndices(RemoteIndexList& remote, int remoteEntries, PairType** local, int localEntries, char* p_in, MPI_Datatype type, int* position, int bufferSize, bool fromOurself); inline void unpackIndices(RemoteIndexList& send, RemoteIndexList& receive, int remoteEntries, PairType** localSource, int localSourceEntries, PairType** localDest, int localDestEntries, char* p_in, MPI_Datatype type, int* position, int bufferSize); void unpackCreateRemote(char* p_in, PairType** sourcePairs, PairType** DestPairs, int remoteProc, int sourcePublish, int destPublish, int bufferSize, bool sendTwo, bool fromOurSelf=false); }; /** @} */ /** * @brief Modifier for adding and/or deleting remote indices from * the remote index list. * * In some cases all the information about the indices also present * on remote process might already be known. In this case this * information can be provided to the RemoteIndices via this modifier. * This prevents the global communication needed by a call to * RemoteIndices::rebuild. * * In some cases it might advisable to run IndicesSyncer::sync afterwards. * * @warning Use with care. If the indices are not consistent afterwards * communication attempts might deadlock! */ template class RemoteIndexListModifier { template friend class RemoteIndices; public: class InvalidPosition : public RangeError {}; enum { /** * @brief If true the index set corresponding to the * remote indices might get modified. * * If for example new indices are added to an index set * all pointers of the remote indices to the local indices * become invalid after ParallelIndexSet::endResize() was called. */ MODIFYINDEXSET=mode }; /** * @brief Type of the index set we use. */ typedef T ParallelIndexSet; /** * @brief The type of the global index. */ typedef typename ParallelIndexSet::GlobalIndex GlobalIndex; /** * @brief The type of the local index. */ typedef typename ParallelIndexSet::LocalIndex LocalIndex; /** * @brief The type of the attribute. */ typedef typename LocalIndex::Attribute Attribute; /** * @brief Type of the remote indices we manage. */ typedef Dune::RemoteIndex RemoteIndex; /** * @brief The type of the allocator for the remote index list. */ typedef A Allocator; /** @brief The type of the remote index list. */ typedef Dune::SLList RemoteIndexList; /** * @brief The type of the modifying iterator of the remote index list. */ typedef SLListModifyIterator ModifyIterator; /** * @brief The type of the remote index list iterator. */ typedef typename RemoteIndexList::const_iterator ConstIterator; /** * @brief Insert an index to the list. * * Moves to the position where the index fits and inserts it. * After the insertion only indices with an bigger global index * than the inserted can be inserted. * * This method is only available if MODIFYINDEXSET is false. * * @param index The index to insert. * @exception InvalidPosition Thrown if the index at the current position or * the one before has bigger global index than the one to be inserted. */ void insert(const RemoteIndex& index); /** * @brief Insert an index to the list. * * Moves to the position where the index fits and inserts it. * After the insertion only indices with an bigger global index * than the inserted can be inserted. * * This method is only available if MODIFYINDEXSET is true. * * @param index The index to insert. * @param global The global index of the remote index. * @exception InvalidPosition Thrown if the index at the current position or * the one before has bigger global index than the one to be inserted. */ void insert(const RemoteIndex& index, const GlobalIndex& global); /** * @brief Remove a remote index. * @param global The global index corresponding to the remote index. * @return True If there was a corresponding remote index. * @exception InvalidPostion If there was an insertion or deletion of * a remote index corresponding to a bigger global index before. */ bool remove(const GlobalIndex& global); /** * @brief Repair the pointers to the local index pairs. * * Due to adding new indices or/and deleting indices in the * index set all pointers to the local index pair might become * invalid during ParallelIndexSet::endResize(). * This method repairs them. * * @exception InvalidIndexSetState Thrown if the underlying * index set is not in ParallelIndexSetState::GROUND mode (only when * compiled with DUNE_ISTL_WITH_CHECKING!). */ void repairLocalIndexPointers(); RemoteIndexListModifier(const RemoteIndexListModifier&); /** * @brief Default constructor. * @warning Object is not usable! */ RemoteIndexListModifier() : glist_() {} private: /** * @brief Create a modifier for a remote index list. * @param indexSet The set of indices the process knows. * @param rList The list of remote indices to modify. */ RemoteIndexListModifier(const ParallelIndexSet& indexSet, RemoteIndexList& rList); typedef SLList GlobalList; typedef typename GlobalList::ModifyIterator GlobalModifyIterator; RemoteIndexList* rList_; const ParallelIndexSet* indexSet_; GlobalList glist_; ModifyIterator iter_; GlobalModifyIterator giter_; ConstIterator end_; bool first_; GlobalIndex last_; }; /** * @brief A collective iterator for moving over the remote indices for * all processes collectively. */ template class CollectiveIterator { /** * @brief Type of the index set we use. */ typedef T ParallelIndexSet; /** * @brief The type of the global index. */ typedef typename ParallelIndexSet::GlobalIndex GlobalIndex; /** * @brief The type of the local index. */ typedef typename ParallelIndexSet::LocalIndex LocalIndex; /** * @brief The type of the attribute. */ typedef typename LocalIndex::Attribute Attribute; /** @brief The remote index type */ typedef Dune::RemoteIndex RemoteIndex; /** @brief The allocator of the remote indices. */ using Allocator = typename std::allocator_traits::template rebind_alloc; /** @brief The type of the remote index list. */ typedef Dune::SLList RemoteIndexList; /** @brief The of map for storing the iterators. */ typedef std::map > Map; public: /** @brief The type of the map from rank to remote index list. */ typedef std::map > RemoteIndexMap; /** * @brief Constructor. * @param map_ The map of the remote indices. * @param send True if we want iterate over the remote indices used for sending. */ inline CollectiveIterator(const RemoteIndexMap& map_, bool send); /** * @brief Advances all underlying iterators. * * All iterators are advanced until they point to a remote index whose * global id is bigger or equal to global. * Iterators pointing to their end are removed. * @param global The index we search for. */ inline void advance(const GlobalIndex& global); /** * @brief Advances all underlying iterators. * * All iterators are advanced until they point to a remote index whose * global id is bigger or equal to global. * Iterators pointing to their end are removed. * @param global The index we search for. * @param attribute The attribute we search for. */ inline void advance(const GlobalIndex& global, const Attribute& attribute); CollectiveIterator& operator++(); /** * @brief Checks whether there are still iterators in the map. */ inline bool empty() const; /** * @brief Iterator over the valid underlying iterators. * * An iterator is valid if it points to a remote index whose * global id is equal to the one currently examined. */ class iterator { public: typedef typename Map::iterator RealIterator; typedef typename Map::iterator ConstRealIterator; //! \todo Please doc me! iterator(const RealIterator& iter, const ConstRealIterator& end, GlobalIndex& index) : iter_(iter), end_(end), index_(index), hasAttribute(false) { // Move to the first valid entry while(iter_!=end_ && iter_->second.first->localIndexPair().global()!=index_) ++iter_; } iterator(const RealIterator& iter, const ConstRealIterator& end, GlobalIndex index, Attribute attribute) : iter_(iter), end_(end), index_(index), attribute_(attribute), hasAttribute(true) { // Move to the first valid entry or the end while(iter_!=end_ && (iter_->second.first->localIndexPair().global()!=index_ || iter_->second.first->localIndexPair().local().attribute()!=attribute)) ++iter_; } //! \todo Please doc me! iterator(const iterator& other) : iter_(other.iter_), end_(other.end_), index_(other.index_) { } //! \todo Please doc me! iterator& operator++() { ++iter_; // If entry is not valid move on while(iter_!=end_ && (iter_->second.first->localIndexPair().global()!=index_ || (hasAttribute && iter_->second.first->localIndexPair().local().attribute()!=attribute_))) ++iter_; assert(iter_==end_ || (iter_->second.first->localIndexPair().global()==index_)); assert(iter_==end_ || !hasAttribute || (iter_->second.first->localIndexPair().local().attribute()==attribute_)); return *this; } //! \todo Please doc me! const RemoteIndex& operator*() const { return *(iter_->second.first); } //! \todo Please doc me! int process() const { return iter_->first; } //! \todo Please doc me! const RemoteIndex* operator->() const { return iter_->second.first.operator->(); } //! \todo Please doc me! bool operator==(const iterator& other) const { return other.iter_==iter_; } //! \todo Please doc me! bool operator!=(const iterator& other) const { return other.iter_!=iter_; } private: iterator(); RealIterator iter_; RealIterator end_; GlobalIndex index_; Attribute attribute_; bool hasAttribute; }; iterator begin(); iterator end(); private: Map map_; GlobalIndex index_; Attribute attribute_; bool noattribute; }; template MPI_Datatype MPITraits > >::getType() { if(type==MPI_DATATYPE_NULL) { int length[2] = {1, 1}; MPI_Aint base; MPI_Aint disp[2]; MPI_Datatype types[2] = {MPITraits::getType(), MPITraits >::getType()}; IndexPair > rep; MPI_Get_address(&rep, &base); // lower bound of the datatype MPI_Get_address(&(rep.global_), &disp[0]); MPI_Get_address(&(rep.local_), &disp[1]); for (MPI_Aint& d : disp) d -= base; MPI_Datatype tmp; MPI_Type_create_struct(2, length, disp, types, &tmp); MPI_Type_create_resized(tmp, 0, sizeof(IndexPair >), &type); MPI_Type_commit(&type); MPI_Type_free(&tmp); } return type; } template MPI_Datatype MPITraits > >::type=MPI_DATATYPE_NULL; template RemoteIndex::RemoteIndex(const T2& attribute, const PairType* local) : localIndex_(local), attribute_(static_cast>(attribute)) {} template RemoteIndex::RemoteIndex(const T2& attribute) : localIndex_(0), attribute_(static_cast>(attribute)) {} template RemoteIndex::RemoteIndex() : localIndex_(0), attribute_() {} template inline bool RemoteIndex::operator==(const RemoteIndex& ri) const { return localIndex_==ri.localIndex_ && attribute_==ri.attribute; } template inline bool RemoteIndex::operator!=(const RemoteIndex& ri) const { return localIndex_!=ri.localIndex_ || attribute_!=ri.attribute_; } template inline const T2 RemoteIndex::attribute() const { return T2(attribute_); } template inline const IndexPair >& RemoteIndex::localIndexPair() const { return *localIndex_; } template inline RemoteIndices::RemoteIndices(const ParallelIndexSet& source, const ParallelIndexSet& destination, const MPI_Comm& comm, const std::vector& neighbours, bool includeSelf_) : source_(&source), target_(&destination), comm_(comm), sourceSeqNo_(-1), destSeqNo_(-1), publicIgnored(false), firstBuild(true), includeSelf(includeSelf_) { setNeighbours(neighbours); } template void RemoteIndices::setIncludeSelf(bool b) { includeSelf=b; } template RemoteIndices::RemoteIndices() : source_(0), target_(0), sourceSeqNo_(-1), destSeqNo_(-1), publicIgnored(false), firstBuild(true), includeSelf(false) {} template void RemoteIndices::setIndexSets(const ParallelIndexSet& source, const ParallelIndexSet& destination, const MPI_Comm& comm, const std::vector& neighbours) { free(); source_ = &source; target_ = &destination; comm_ = comm; firstBuild = true; setNeighbours(neighbours); } template const typename RemoteIndices::ParallelIndexSet& RemoteIndices::sourceIndexSet() const { return *source_; } template const typename RemoteIndices::ParallelIndexSet& RemoteIndices::destinationIndexSet() const { return *target_; } template RemoteIndices::~RemoteIndices() { free(); } template template inline void RemoteIndices::packEntries(IndexPair** pairs, const ParallelIndexSet& indexSet, char* p_out, MPI_Datatype type, int bufferSize, int *position, [[maybe_unused]] int n) { // fill with own indices const auto end = indexSet.end(); //Now pack the source indices int i=0; for(auto index = indexSet.begin(); index != end; ++index) if(ignorePublic || index->local().isPublic()) { MPI_Pack(const_cast(&(*index)), 1, type, p_out, bufferSize, position, comm_); pairs[i++] = const_cast(&(*index)); } assert(i==n); } template inline int RemoteIndices::noPublic(const ParallelIndexSet& indexSet) { int noPublic=0; const auto end=indexSet.end(); for(auto index=indexSet.begin(); index!=end; ++index) if(index->local().isPublic()) noPublic++; return noPublic; } template inline void RemoteIndices::unpackCreateRemote(char* p_in, PairType** sourcePairs, PairType** destPairs, int remoteProc, int sourcePublish, int destPublish, int bufferSize, bool sendTwo, bool fromOurSelf) { // unpack the number of indices we received int noRemoteSource=-1, noRemoteDest=-1; char twoIndexSets=0; int position=0; // Did we receive two index sets? MPI_Unpack(p_in, bufferSize, &position, &twoIndexSets, 1, MPI_CHAR, comm_); // The number of source indices received MPI_Unpack(p_in, bufferSize, &position, &noRemoteSource, 1, MPI_INT, comm_); // The number of destination indices received MPI_Unpack(p_in, bufferSize, &position, &noRemoteDest, 1, MPI_INT, comm_); // Indices for which we receive RemoteIndexList* receive= new RemoteIndexList(); // Indices for which we send RemoteIndexList* send=0; MPI_Datatype type= MPITraits::getType(); if(!twoIndexSets) { if(sendTwo) { send = new RemoteIndexList(); // Create both remote index sets simultaneously unpackIndices(*send, *receive, noRemoteSource, sourcePairs, sourcePublish, destPairs, destPublish, p_in, type, &position, bufferSize); }else{ // we only need one list unpackIndices(*receive, noRemoteSource, sourcePairs, sourcePublish, p_in, type, &position, bufferSize, fromOurSelf); send=receive; } }else{ int oldPos=position; // Two index sets received unpackIndices(*receive, noRemoteSource, destPairs, destPublish, p_in, type, &position, bufferSize, fromOurSelf); if(!sendTwo) //unpack source entries again as destination entries position=oldPos; send = new RemoteIndexList(); unpackIndices(*send, noRemoteDest, sourcePairs, sourcePublish, p_in, type, &position, bufferSize, fromOurSelf); } if(receive->empty() && send->empty()) { if(send==receive) { delete send; }else{ delete send; delete receive; } }else{ remoteIndices_.insert(std::make_pair(remoteProc, std::make_pair(send,receive))); } } template template inline void RemoteIndices::buildRemote(bool includeSelf_) { // Processor configuration int rank, procs; MPI_Comm_rank(comm_, &rank); MPI_Comm_size(comm_, &procs); // number of local indices to publish // The indices of the destination will be send. int sourcePublish, destPublish; // Do we need to send two index sets? char sendTwo = (source_ != target_); if(procs==1 && !(sendTwo || includeSelf_)) // Nothing to communicate return; sourcePublish = (ignorePublic) ? source_->size() : noPublic(*source_); if(sendTwo) destPublish = (ignorePublic) ? target_->size() : noPublic(*target_); else // we only need to send one set of indices destPublish = 0; int maxPublish, publish=sourcePublish+destPublish; // Calucate maximum number of indices send MPI_Allreduce(&publish, &maxPublish, 1, MPI_INT, MPI_MAX, comm_); // allocate buffers PairType** destPairs; PairType** sourcePairs = new PairType*[sourcePublish>0 ? sourcePublish : 1]; if(sendTwo) destPairs = new PairType*[destPublish>0 ? destPublish : 1]; else destPairs=sourcePairs; char** buffer = new char*[2]; int bufferSize; int position=0; int intSize; int charSize; // calculate buffer size MPI_Datatype type = MPITraits::getType(); MPI_Pack_size(maxPublish, type, comm_, &bufferSize); MPI_Pack_size(1, MPI_INT, comm_, &intSize); MPI_Pack_size(1, MPI_CHAR, comm_, &charSize); // Our message will contain the following: // a bool whether two index sets where sent // the size of the source and the dest indexset, // then the source and destination indices bufferSize += 2 * intSize + charSize; if(bufferSize<=0) bufferSize=1; buffer[0] = new char[bufferSize]; buffer[1] = new char[bufferSize]; // pack entries into buffer[0], p_out below! MPI_Pack(&sendTwo, 1, MPI_CHAR, buffer[0], bufferSize, &position, comm_); // The number of indices we send for each index set MPI_Pack(&sourcePublish, 1, MPI_INT, buffer[0], bufferSize, &position, comm_); MPI_Pack(&destPublish, 1, MPI_INT, buffer[0], bufferSize, &position, comm_); // Now pack the source indices and setup the destination pairs packEntries(sourcePairs, *source_, buffer[0], type, bufferSize, &position, sourcePublish); // If necessary send the dest indices and setup the source pairs if(sendTwo) packEntries(destPairs, *target_, buffer[0], type, bufferSize, &position, destPublish); // Update remote indices for ourself if(sendTwo|| includeSelf_) unpackCreateRemote(buffer[0], sourcePairs, destPairs, rank, sourcePublish, destPublish, bufferSize, sendTwo, includeSelf_); neighbourIds.erase(rank); if(neighbourIds.size()==0) { Dune::dvverb<::size_type size_type; size_type noNeighbours=neighbourIds.size(); // setup sends for(std::set::iterator neighbour=neighbourIds.begin(); neighbour!= neighbourIds.end(); ++neighbour) { // Only send the information to the neighbouring processors MPI_Issend(buffer[0], position , MPI_PACKED, *neighbour, commTag_, comm_, req++); } //Test for received messages for(size_type received=0; received inline void RemoteIndices::unpackIndices(RemoteIndexList& remote, int remoteEntries, PairType** local, int localEntries, char* p_in, MPI_Datatype type, int* position, int bufferSize, bool fromOurSelf) { if(remoteEntries==0) return; PairType index; MPI_Unpack(p_in, bufferSize, position, &index, 1, type, comm_); GlobalIndex oldGlobal=index.global(); int n_in=0, localIndex=0; //Check if we know the global index while(localIndexglobal()==index.global()) { int oldLocalIndex=localIndex; while(localIndexglobal()==index.global()) { if(!fromOurSelf || index.local().attribute() != local[localIndex]->local().attribute()) // if index is from us it has to have a different attribute remote.push_back(RemoteIndex(index.local().attribute(), local[localIndex])); localIndex++; } // unpack next remote index if((++n_in) < remoteEntries) { MPI_Unpack(p_in, bufferSize, position, &index, 1, type, comm_); if(index.global()==oldGlobal) // Restart comparison for the same global indices localIndex=oldLocalIndex; else oldGlobal=index.global(); }else{ // No more received indices break; } continue; } if (local[localIndex]->global() inline void RemoteIndices::unpackIndices(RemoteIndexList& send, RemoteIndexList& receive, int remoteEntries, PairType** localSource, int localSourceEntries, PairType** localDest, int localDestEntries, char* p_in, MPI_Datatype type, int* position, int bufferSize) { int n_in=0, sourceIndex=0, destIndex=0; //Check if we know the global index while(n_in= than the one in the unpacked index while(sourceIndexglobal()global()global()==index.global()) send.push_back(RemoteIndex(index.local().attribute(), localSource[sourceIndex])); if(destIndex < localDestEntries && localDest[destIndex]->global() == index.global()) receive.push_back(RemoteIndex(index.local().attribute(), localDest[sourceIndex])); } } template inline void RemoteIndices::free() { auto lend = remoteIndices_.end(); for(auto lists=remoteIndices_.begin(); lists != lend; ++lists) { if(lists->second.first==lists->second.second) { // there is only one remote index list. delete lists->second.first; }else{ delete lists->second.first; delete lists->second.second; } } remoteIndices_.clear(); firstBuild=true; } template inline int RemoteIndices::neighbours() const { return remoteIndices_.size(); } template template inline void RemoteIndices::rebuild() { // Test whether a rebuild is Needed. if(firstBuild || ignorePublic!=publicIgnored || ! isSynced()) { free(); buildRemote(includeSelf); sourceSeqNo_ = source_->seqNo(); destSeqNo_ = target_->seqNo(); firstBuild=false; publicIgnored=ignorePublic; } } template inline bool RemoteIndices::isSynced() const { return sourceSeqNo_==source_->seqNo() && destSeqNo_ ==target_->seqNo(); } template template RemoteIndexListModifier RemoteIndices::getModifier(int process) { // The user are on their own now! // We assume they know what they are doing and just set the // remote indices to synced status. sourceSeqNo_ = source_->seqNo(); destSeqNo_ = target_->seqNo(); typename RemoteIndexMap::iterator found = remoteIndices_.find(process); if(found == remoteIndices_.end()) { if(source_ != target_) found = remoteIndices_.insert(found, std::make_pair(process, std::make_pair(new RemoteIndexList(), new RemoteIndexList()))); else{ RemoteIndexList* rlist = new RemoteIndexList(); found = remoteIndices_.insert(found, std::make_pair(process, std::make_pair(rlist, rlist))); } } firstBuild = false; if(send) return RemoteIndexListModifier(*source_, *(found->second.first)); else return RemoteIndexListModifier(*target_, *(found->second.second)); } template inline typename RemoteIndices::const_iterator RemoteIndices::find(int proc) const { return remoteIndices_.find(proc); } template inline typename RemoteIndices::const_iterator RemoteIndices::begin() const { return remoteIndices_.begin(); } template inline typename RemoteIndices::const_iterator RemoteIndices::end() const { return remoteIndices_.end(); } template bool RemoteIndices::operator==(const RemoteIndices& ri) const { if(neighbours()!=ri.neighbours()) return false; const auto rend = remoteIndices_.end(); for(auto rindex = remoteIndices_.begin(), rindex1=ri.remoteIndices_.begin(); rindex!=rend; ++rindex, ++rindex1) { if(rindex->first != rindex1->first) return false; if(*(rindex->second.first) != *(rindex1->second.first)) return false; if(*(rindex->second.second) != *(rindex1->second.second)) return false; } return true; } template RemoteIndexListModifier::RemoteIndexListModifier(const ParallelIndexSet& indexSet, RemoteIndexList& rList) : rList_(&rList), indexSet_(&indexSet), iter_(rList.beginModify()), end_(rList.end()), first_(true) { if(MODIFYINDEXSET) { assert(indexSet_); for(ConstIterator iter=iter_; iter != end_; ++iter) glist_.push_back(iter->localIndexPair().global()); giter_ = glist_.beginModify(); } } template RemoteIndexListModifier::RemoteIndexListModifier(const RemoteIndexListModifier& other) : rList_(other.rList_), indexSet_(other.indexSet_), glist_(other.glist_), iter_(other.iter_), giter_(other.giter_), end_(other.end_), first_(other.first_), last_(other.last_) {} template inline void RemoteIndexListModifier::repairLocalIndexPointers() { if(MODIFYINDEXSET) { // repair pointers to local index set. #ifdef DUNE_ISTL_WITH_CHECKING if(indexSet_->state()!=GROUND) DUNE_THROW(InvalidIndexSetState, "Index has to be in ground mode for repairing pointers to indices"); #endif auto giter = glist_.begin(); auto index = indexSet_->begin(); for(auto iter=rList_->begin(); iter != end_; ++iter) { while(index->global()<*giter) { ++index; #ifdef DUNE_ISTL_WITH_CHECKING if(index == indexSet_->end()) DUNE_THROW(InvalidPosition, "No such global index in set!"); #endif } #ifdef DUNE_ISTL_WITH_CHECKING if(index->global() != *giter) DUNE_THROW(InvalidPosition, "No such global index in set!"); #endif iter->localIndex_ = &(*index); } } } template inline void RemoteIndexListModifier::insert(const RemoteIndex& index) { static_assert(!mode,"Not allowed if the mode indicates that new indices" "might be added to the underlying index set. Use " "insert(const RemoteIndex&, const GlobalIndex&) instead"); #ifdef DUNE_ISTL_WITH_CHECKING if(!first_ && index.localIndexPair().global()localIndexPair().global() < index.localIndexPair().global()) { ++iter_; } // No duplicate entries allowed assert(iter_==end_ || iter_->localIndexPair().global() != index.localIndexPair().global()); iter_.insert(index); last_ = index.localIndexPair().global(); first_ = false; } template inline void RemoteIndexListModifier::insert(const RemoteIndex& index, const GlobalIndex& global) { static_assert(mode,"Not allowed if the mode indicates that no new indices" "might be added to the underlying index set. Use " "insert(const RemoteIndex&) instead"); #ifdef DUNE_ISTL_WITH_CHECKING if(!first_ && globallocalIndexPair().global() != global); iter_.insert(index); giter_.insert(global); last_ = global; first_ = false; } template bool RemoteIndexListModifier::remove(const GlobalIndex& global) { #ifdef DUNE_ISTL_WITH_CHECKING if(!first_ && globallocalIndexPair().global() < global) ++iter_; if(iter_->localIndexPair().global()==global) { iter_.remove(); found = true; } } last_ = global; first_ = false; return found; } template template inline typename RemoteIndices::CollectiveIteratorT RemoteIndices::iterator() const { return CollectiveIterator(remoteIndices_, send); } template inline MPI_Comm RemoteIndices::communicator() const { return comm_; } template CollectiveIterator::CollectiveIterator(const RemoteIndexMap& pmap, bool send) { const auto end = pmap.end(); for(auto process = pmap.begin(); process != end; ++process) { const RemoteIndexList* list = send ? process->second.first : process->second.second; using ri_iterator = typename RemoteIndexList::const_iterator; map_.insert(std::make_pair(process->first, std::pair(list->begin(), list->end()))); } } template inline void CollectiveIterator::advance(const GlobalIndex& index) { const auto end = map_.end(); for(auto iter = map_.begin(); iter != end;) { // Step the iterator until we are >= index typename RemoteIndexList::const_iterator current = iter->second.first; typename RemoteIndexList::const_iterator rend = iter->second.second; RemoteIndex remoteIndex; if(current != rend) remoteIndex = *current; while(iter->second.first!=iter->second.second && iter->second.first->localIndexPair().global()second.first); // erase from the map if there are no more entries. if(iter->second.first == iter->second.second) map_.erase(iter++); else{ ++iter; } } index_=index; noattribute=true; } template inline void CollectiveIterator::advance(const GlobalIndex& index, const Attribute& attribute) { const auto end = map_.end(); for(auto iter = map_.begin(); iter != end;) { // Step the iterator until we are >= index typename RemoteIndexList::const_iterator current = iter->second.first; typename RemoteIndexList::const_iterator rend = iter->second.second; RemoteIndex remoteIndex; if(current != rend) remoteIndex = *current; // Move to global index or bigger while(iter->second.first!=iter->second.second && iter->second.first->localIndexPair().global()second.first); // move to attribute or bigger while(iter->second.first!=iter->second.second && iter->second.first->localIndexPair().global()==index && iter->second.first->localIndexPair().local().attribute()second.first); // erase from the map if there are no more entries. if(iter->second.first == iter->second.second) map_.erase(iter++); else{ ++iter; } } index_=index; attribute_=attribute; noattribute=false; } template inline CollectiveIterator& CollectiveIterator::operator++() { const auto end = map_.end(); for(auto iter = map_.begin(); iter != end;) { // Step the iterator until we are >= index auto current = iter->second.first; auto rend = iter->second.second; // move all iterators pointing to the current global index to next value if(iter->second.first->localIndexPair().global()==index_ && (noattribute || iter->second.first->localIndexPair().local().attribute() == attribute_)) ++(iter->second.first); // erase from the map if there are no more entries. if(iter->second.first == iter->second.second) map_.erase(iter++); else{ ++iter; } } return *this; } template inline bool CollectiveIterator::empty() const { return map_.empty(); } template inline typename CollectiveIterator::iterator CollectiveIterator::begin() { if(noattribute) return iterator(map_.begin(), map_.end(), index_); else return iterator(map_.begin(), map_.end(), index_, attribute_); } template inline typename CollectiveIterator::iterator CollectiveIterator::end() { return iterator(map_.end(), map_.end(), index_); } template inline std::ostream& operator<<(std::ostream& os, const RemoteIndex& index) { os<<"[global="< inline std::ostream& operator<<(std::ostream& os, const RemoteIndices& indices) { int rank; MPI_Comm_rank(indices.comm_, &rank); const auto rend = indices.remoteIndices_.end(); for(auto rindex = indices.remoteIndices_.begin(); rindex!=rend; ++rindex) { os<first<<":"; if(!rindex->second.first->empty()) { os<<" send:"; const auto send= rindex->second.first->end(); for(auto index = rindex->second.first->begin(); index != send; ++index) os<<*index<<" "; os<second.second->empty()) { os<first<<": "<<"receive: "; for(const auto& index : *(rindex->second.second)) os << index << " "; } os< namespace Dune { /** @addtogroup Common_Parallel * * @{ */ /** * @file * @brief Provides classes for selecting * indices based on attribute flags. * @author Markus Blatt */ /** * @brief A const iterator over an uncached selection. */ template class SelectionIterator { public: /** * @brief The type of the Set of attributes. * * It has to provide a static method * \code bool contains(AttributeType a); \endcode * that returns true if a is in the set. * Such types are EnumItem, EnumRange, Combine. */ typedef TS AttributeSet; /** * @brief The type of the underlying index set. */ typedef Dune::ParallelIndexSet ParallelIndexSet; //typedef typename ParallelIndexSet::const_iterator ParallelIndexSetIterator; typedef ConstArrayListIterator, N, std::allocator > > ParallelIndexSetIterator; /** * @brief Constructor. * @param iter The iterator over the index set. * @param end The iterator over the index set positioned at the end. */ SelectionIterator(const ParallelIndexSetIterator& iter, const ParallelIndexSetIterator& end) : iter_(iter), end_(end) { // Step to the first valid entry while(iter_!=end_ && !AttributeSet::contains(iter_->local().attribute())) ++iter_; } void operator++() { assert(iter_!=end_); for(++iter_; iter_!=end_; ++iter_) if(AttributeSet::contains(iter_->local().attribute())) break; } uint32_t operator*() const { return iter_->local().local(); } bool operator==(const SelectionIterator& other) const { return iter_ == other.iter_; } bool operator!=(const SelectionIterator& other) const { return iter_ != other.iter_; } private: ParallelIndexSetIterator iter_; const ParallelIndexSetIterator end_; }; /** * @brief An uncached selection of indices. */ template class UncachedSelection { public: /** * @brief The type of the Set of attributes. * * It has to provide a static method * \code bool contains(AttributeType a); \endcode * that returns true if a is in the set. * Such types are EnumItem, EnumRange, Combine. */ typedef TS AttributeSet; /** * @brief The type of the global index of the underlying index set. */ typedef TG GlobalIndex; /** * @brief The type of the local index of the underlying index set. * * It has to provide a function * \code AttributeType attribute(); \endcode */ typedef TL LocalIndex; /** * @brief The type of the underlying index set. */ typedef Dune::ParallelIndexSet ParallelIndexSet; /** * @brief The type of the iterator of the selected indices. */ typedef SelectionIterator iterator; /** * @brief The type of the iterator of the selected indices. */ typedef iterator const_iterator; UncachedSelection() : indexSet_() {} UncachedSelection(const ParallelIndexSet& indexset) : indexSet_(&indexset) {} /** * @brief Set the index set of the selection. * @param indexset The index set to use. */ void setIndexSet(const ParallelIndexSet& indexset); /** * @brief Get the index set we are a selection for. */ //const ParallelIndexSet& indexSet() const; /** * @brief Get an iterator over the selected indices. * @return An iterator positioned at the first selected index. */ const_iterator begin() const; /** * @brief Get an iterator over the selected indices. * @return An iterator positioned at the first selected index. */ const_iterator end() const; private: const ParallelIndexSet* indexSet_; }; /** * @brief A cached selection of indices. */ template class Selection { public: /** * @brief The type of the set of attributes. * * It has to provide a static method * \code bool contains(AttributeType a); \endcode * that returns true if a is in the set. * Such types are EnumItem, EnumRange, Combine. */ typedef TS AttributeSet; /** * @brief The type of the global index of the underlying index set. */ typedef TG GlobalIndex; /** * @brief The type of the local index of the underlying index set. * * It has to provide a function * \code AttributeType attribute(); \endcode */ typedef TL LocalIndex; /** * @brief The type of the underlying index set. */ typedef Dune::ParallelIndexSet ParallelIndexSet; /** * @brief The type of the iterator of the selected indices. */ typedef uint32_t* iterator; /** * @brief The type of the iterator of the selected indices. */ typedef uint32_t* const_iterator; Selection() : selected_() {} Selection(const ParallelIndexSet& indexset) : selected_(), size_(0), built_(false) { setIndexSet(indexset); } ~Selection(); /** * @brief Set the index set of the selection. * @param indexset The index set to use. */ void setIndexSet(const ParallelIndexSet& indexset); /** * @brief Free allocated memory. */ void free(); /** * @brief Get the index set we are a selection for. */ //IndexSet indexSet() const; /** * @brief Get an iterator over the selected indices. * @return An iterator positioned at the first selected index. */ const_iterator begin() const; /** * @brief Get an iterator over the selected indices. * @return An iterator positioned at the first selected index. */ const_iterator end() const; private: uint32_t* selected_; size_t size_; bool built_; }; template inline void Selection::setIndexSet(const ParallelIndexSet& indexset) { if(built_) free(); // Count the number of entries the selection has to hold typedef typename ParallelIndexSet::const_iterator const_iterator; const const_iterator end = indexset.end(); int entries = 0; for(const_iterator index = indexset.begin(); index != end; ++index) if(AttributeSet::contains(index->local().attribute())) ++entries; selected_ = new uint32_t[entries]; built_ = true; entries = 0; for(const_iterator index = indexset.begin(); index != end; ++index) if(AttributeSet::contains(index->local().attribute())) selected_[entries++]= index->local().local(); size_=entries; built_=true; } template uint32_t* Selection::begin() const { return selected_; } template uint32_t* Selection::end() const { return selected_+size_; } template inline void Selection::free() { delete[] selected_; size_=0; built_=false; } template inline Selection::~Selection() { if(built_) free(); } template SelectionIterator UncachedSelection::begin() const { return SelectionIterator(indexSet_->begin(), indexSet_->end()); } template SelectionIterator UncachedSelection::end() const { return SelectionIterator(indexSet_->end(), indexSet_->end()); } template void UncachedSelection::setIndexSet(const ParallelIndexSet& indexset) { indexSet_ = &indexset; } /** @} */ } #endif dune-common-2.8.0/dune/common/parallel/test/000077500000000000000000000000001411343567400207505ustar00rootroot00000000000000dune-common-2.8.0/dune/common/parallel/test/CMakeLists.txt000066400000000000000000000032611411343567400235120ustar00rootroot00000000000000dune_add_test(SOURCES communicationtest.cc LINK_LIBRARIES dunecommon MPI_RANKS 1 2 4 TIMEOUT 300 CMAKE_GUARD MPI_FOUND LABELS quick) dune_add_test(SOURCES indexsettest.cc LINK_LIBRARIES dunecommon LABELS quick) dune_add_test(SOURCES remoteindicestest.cc LINK_LIBRARIES dunecommon MPI_RANKS 1 2 4 TIMEOUT 300 CMAKE_GUARD MPI_FOUND LABELS quick) dune_add_test(SOURCES selectiontest.cc LINK_LIBRARIES dunecommon LABELS quick) dune_add_test(SOURCES syncertest.cc LINK_LIBRARIES dunecommon MPI_RANKS 1 2 4 TIMEOUT 300 CMAKE_GUARD MPI_FOUND LABELS quick) dune_add_test(SOURCES variablesizecommunicatortest.cc MPI_RANKS 1 2 4 TIMEOUT 300 CMAKE_GUARD MPI_FOUND LABELS quick) dune_add_test(SOURCES mpidatatest.cc LINK_LIBRARIES dunecommon MPI_RANKS 2 TIMEOUT 300 LABELS quick) dune_add_test(SOURCES mpifuturetest.cc LINK_LIBRARIES dunecommon MPI_RANKS 1 2 4 TIMEOUT 300 LABELS quick) dune_add_test(SOURCES mpipacktest.cc LINK_LIBRARIES dunecommon MPI_RANKS 2 TIMEOUT 300 CMAKE_GUARD MPI_FOUND LABELS quick) dune_add_test(SOURCES mpigatherscattertest.cc LINK_LIBRARIES dunecommon MPI_RANKS 2 TIMEOUT 300 CMAKE_GUARD MPI_FOUND LABELS quick) dune-common-2.8.0/dune/common/parallel/test/communicationtest.cc000066400000000000000000000023711411343567400250270ustar00rootroot00000000000000#if HAVE_CONFIG_H #include #endif #include int main(int argc, char** argv) { Dune::MPIHelper::instance(argc, argv); int ret = 0; Dune::No_Comm nc1, nc2; if ( !(nc1 == nc2)) { std::cerr << "operator==: No_Comms need to compare equal"< #include #include #include #include int testDeleteIndices() { Dune::ParallelIndexSet indexSet; Dune::ParallelIndexSet indexSet1; indexSet.beginResize(); indexSet1.beginResize(); for(int i=0; i< 10; i++) { indexSet.add(i, Dune::LocalIndex (i)); indexSet1.add(i, Dune::LocalIndex (i)); } indexSet.endResize(); indexSet1.endResize(); typedef Dune::ParallelIndexSet::iterator Iterator; Iterator entry = indexSet.begin(); indexSet.beginResize(); for(int i=0; i < 5; i++) ++entry; indexSet.markAsDeleted(entry); indexSet.endResize(); std::cout<<"Unchanged: "<global()==5) { std::cerr<<"Entry was not deleted!"<9) { std::cerr<<"Number of entries not correct!"<::iterator iter=indexSet1.begin(); // Test whether the local indices changed for(entry = indexSet.begin(); entry != end; ++entry) { while(iter->global() < entry->global()) iter++; if(iter->global() != entry->global()) { std::cerr <<" Global indices do not match!"<local() != entry->local()) { std::cerr <<" Local indices do not match!"< #include #include #include #include using namespace Dune; int main(int argc, char** argv){ Dune::MPIHelper & mpihelper = Dune::MPIHelper::instance(argc, argv); auto cc = mpihelper.getCommunication(); if(mpihelper.rank() == 0) std::cout << "Test 1: static data (int)" << std::endl; if(mpihelper.rank() == 0){ cc.send(42, 1, 0); int i = 42; const int& j = i; cc.send(j, 1, 0); } else if(mpihelper.rank() == 1){ std::cout << "receive: " << cc.recv(0, 0, 0) << std::endl; int i = 0; cc.recv(i, 0, 0); std::cout << i << std::endl; } if(mpihelper.rank() == 0) std::cout << "Test 2: dynamic data (std::vector)" << std::endl; if(mpihelper.rank() == 0){ cc.send(std::vector{ 42.0, 43.0, 4711}, 1, 0); std::vector vec{ 42.0, 43.0, 4711}; const std::vector& vec_ref = vec; cc.send(vec_ref, 1, 0); cc.send(std::move(vec), 1, 0); } else if(mpihelper.rank() == 1){ auto vec = cc.recv(std::vector{0,0,0}, 0, 0); std::cout << "receive: "; for(double d : vec) std::cout << d << ","; std::cout << "\b" << std::endl; std::vector vec2(3); cc.recv(vec2, 0, 0); for(double d : vec2) std::cout << d << ","; std::cout << "\b" << std::endl; std::vector vec3(3); auto d = vec3.data(); std::vector vec4 = cc.recv(std::move(vec3), 0, 0); for(double d : vec4) std::cout << d << ","; std::cout << "\b" << std::endl; if(d != vec4.data()) DUNE_THROW(Exception, "The vector has not the same memory"); } if(mpihelper.rank() == 0) std::cout << "Test 3: DynamicVector" << std::endl; if(mpihelper.rank() == 0){ cc.send(DynamicVector{ 42.0, 43.0, 4711}, 1, 0); DynamicVector vec{ 42.0, 43.0, 4711}; const DynamicVector& vec_ref = vec; cc.send(vec_ref, 1, 0); cc.send(std::move(vec), 1, 0); } else if(mpihelper.rank() == 1){ auto vec = cc.recv(DynamicVector{0,0,0}, 0, 0); std::cout << "receive: "; for(double d : vec) std::cout << d << ","; std::cout << "\b" << std::endl; DynamicVector vec2(3); cc.recv(vec2, 0, 0); for(double d : vec2) std::cout << d << ","; std::cout << "\b" << std::endl; DynamicVector vec3(3); auto d = vec3.container().data(); DynamicVector vec4 = cc.recv(std::move(vec3), 0, 0); for(double d : vec4) std::cout << d << ","; std::cout << "\b" << std::endl; if(d != vec4.container().data()) DUNE_THROW(Exception, "The vector has not the same memory"); } if(mpihelper.rank() == 0) std::cout << "Test 3: DynamicVector (resize receive)" << std::endl; if(mpihelper.rank() == 0){ cc.send(DynamicVector{ 42.0, 43.0, 4711}, 1, 0); DynamicVector vec{ 42.0, 43.0, 4711}; const DynamicVector& vec_ref = vec; cc.send(vec_ref, 1, 0); cc.send(std::move(vec), 1, 0); } else if(mpihelper.rank() == 1){ auto vec = cc.rrecv(DynamicVector{}, 0, 0); std::cout << "receive: "; for(double d : vec) std::cout << d << ","; std::cout << "\b" << std::endl; DynamicVector vec2(3); cc.recv(vec2, 0, 0); for(double d : vec2) std::cout << d << ","; std::cout << "\b" << std::endl; DynamicVector vec3(3); auto d = vec3.container().data(); DynamicVector vec4 = cc.recv(std::move(vec3), 0, 0); for(double d : vec4) std::cout << d << ","; std::cout << "\b" << std::endl; if(d != vec4.container().data()) DUNE_THROW(Exception, "The vector has not the same memory"); } return 0; } dune-common-2.8.0/dune/common/parallel/test/mpifuturetest.cc000066400000000000000000000101631411343567400242000ustar00rootroot00000000000000#include #include #include #include #include namespace Dune { template struct MPIData { static_assert(Dune::AlwaysFalse::value, "MPIData of reference type should not be used!"); // MPIData of reference type should not be used! // This struct should never be used it just // exists to generate a compiler error }; } int main(int argc, char** argv){ auto& mpihelper = Dune::MPIHelper::instance(argc, argv); auto cc = mpihelper.getCommunication(); // p2p if(mpihelper.size() > 1){ if(mpihelper.rank() == 0){ Dune::Future f = cc.isend(42, 1, 0); f.wait(); int i = 42; Dune::Future f2 = cc.isend(i, 1, 0); f2.wait(); }else if(mpihelper.rank() == 1){ Dune::Future f = cc.irecv(41, 0, 0); std::cout << "Rank 1 received " << f.get() << std::endl; int j = 41; Dune::Future f2 = cc.irecv(j, 0, 0); std::cout << "Rank 1 received " << f2.get() << std::endl; } } int answer; if(mpihelper.rank() == 0){ std::cout << "Broadcast lvalue-reference" << std::endl; answer = 42; } Dune::Future f = cc.template ibroadcast(answer, 0); f.wait(); std::cout << "Rank " << mpihelper.rank() << " knows: The answer is " << answer << std::endl; if(mpihelper.rank() == 0) std::cout << "Broadcast value" << std::endl; Dune::Future f2 = cc.template ibroadcast(int(answer), 0); std::cout << "Rank " << mpihelper.rank() << " knows: The answer is " << f2.get() << std::endl; Dune::DynamicVector vec(3); if(mpihelper.rank() == 0){ std::cout << "Broadcast vector" << std::endl; std::iota(vec.begin(), vec.end(), 41); } Dune::Future> f3 = cc.ibroadcast(vec, 0); f3.wait(); std::cout << "Rank " << mpihelper.rank() << " received vector: " << vec << std::endl; if(mpihelper.rank() == 0) std::cout << "nonb Barrier ==========================" << std::endl; Dune::Future f4 = cc.ibarrier(); f4.wait(); if(mpihelper.rank() == 0){ std::cout << "nonb gather ===========================" << std::endl; Dune::Future> f = cc.igather(mpihelper.rank() + 42, Dune::DynamicVector(mpihelper.size()), 0); std::cout << "Gather result: " << f.get() << std::endl; }else{ cc.igather(mpihelper.rank(), {}, 0).wait(); } if(mpihelper.rank() == 0){ std::cout << "nonb scatter ===========================" << std::endl; std::vector my_buddies(mpihelper.size()); std::iota(my_buddies.begin(), my_buddies.end(), 42); Dune::Future f = cc.iscatter(my_buddies, 0, 0); std::cout << "Scatter result (Rank " << mpihelper.rank() << "): " << f.get() << std::endl; }else{ Dune::Future f = cc.iscatter(std::vector(0), 0, 0); std::cout << "Scatter result (Rank " << mpihelper.rank() << "): " << f.get() << std::endl; } { if(mpihelper.rank() == 0) std::cout << "nonb allreduce ===========================" << std::endl; Dune::Future f = cc.iallreduce>(mpihelper.rank()+4, 0); std::cout << "Allreduce result on rank " << mpihelper.rank() <<": " << f.get() << std::endl; } { if(mpihelper.rank() == 0) std::cout << "nonb allreduce inplace ===========================" << std::endl; Dune::Future> f = cc.iallreduce>(Dune::DynamicVector{42, 3+mpihelper.rank()}); std::cout << "Allreduce result on rank " << mpihelper.rank() <<": " << f.get() << std::endl; } { if(mpihelper.rank() == 0) std::cout << "check for MPI_SUM with double& ===========================" << std::endl; double answer = 42; auto f = cc.iallreduce>(answer); std::cout << "Allreduce result on rank " << mpihelper.rank() <<": " << f.get() << std::endl; } // that's wrong, MPIFuture will hold a dangeling reference: // Dune::MPIFuture g; // { // int i = 42; // g = cc.iallreduce>(i); // } // g.wait(); return 0; } dune-common-2.8.0/dune/common/parallel/test/mpigatherscattertest.cc000066400000000000000000000015531411343567400255310ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include using namespace Dune; int main(int argc, char** argv){ MPIHelper & mpihelper = MPIHelper::instance(argc, argv); auto cc = mpihelper.getCommunication(); int rank = cc.rank(); int size = cc.size(); std::array data = {1.0 + rank, 2.0 + rank}; auto gathered = cc.igather(data, std::vector(rank==0?2*size:0), 0).get(); for(auto& d : gathered) d += 1; cc.iscatter(gathered, data, 0).get(); if(data[0] != 2+rank || data[1] != 3+rank){ DUNE_THROW(Exception, "Wrong result after gather - scatter"); } return 0; } dune-common-2.8.0/dune/common/parallel/test/mpipacktest.cc000066400000000000000000000022551411343567400236070ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include constexpr int TAG = 42; int main(int argc, char** argv){ Dune::MPIHelper& helper = Dune::MPIHelper::instance(argc, argv); Dune::TestSuite suite; suite.require(helper.size() == 2) << "This test must be executed on two processes"; auto comm = helper.getCommunication(); Dune::MPIPack pack(comm); if(helper.rank() == 0){ pack << 3 << helper.rank(); pack << std::vector{4711, 42}; comm.send(pack, 1, TAG); } if(helper.rank() == 1){ Dune::MPIPack pack = comm.rrecv(Dune::MPIPack(comm), 0, TAG); int drei; pack >> drei; int rank_0; pack >> rank_0; std::vector vec; pack >> vec; suite.check(drei==3) << "received wrong value"; suite.check(rank_0==0) << "received wrong value"; suite.check(vec.size() == 2) << "vector has wrong size!"; suite.check(vec[0] == 4711 && vec[1] == 42) << "vector contains wrong values!"; } return 0; } dune-common-2.8.0/dune/common/parallel/test/remoteindicestest.cc000066400000000000000000000440501411343567400250140ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include #include #include #include #include #include #include #include enum GridFlags { owner, overlap, border }; class Array; std::ostream& operator<<(std::ostream& os, const Array& a); class Array { friend std::ostream& operator<<(std::ostream& os, const Array& a); public: typedef double value_type; Array() : vals_(0), size_(0) {} Array(int size) : size_(size) { vals_ = new double[size]; } void build(int size) { vals_ = new double[size]; size_ = size; } Array& operator+=(double d) { for(int i=0; i < size_; i++) vals_[i]+=d; return *this; } ~Array() { if(vals_!=0) delete[] vals_; } const double& operator[](int i) const { return vals_[i]; } double& operator[](int i) { return vals_[i]; } private: Array(const Array&) {} double *vals_; int size_; }; struct ArrayGatherScatter { static double gather(const Array& a, int i); static void scatter(Array& a, double v, int i); }; inline double ArrayGatherScatter::gather(const Array& a, int i) { return a[i]; } inline void ArrayGatherScatter::scatter(Array& a, double v, int i) { a[i]=v; } std::ostream& operator<<(std::ostream& os, const Array& a) { if(a.size_>0) os<< "{ "< LocalIndexType; typedef Dune::ParallelIndexSet,45> ParallelIndexSet; ParallelIndexSet distIndexSet; // global indexset ParallelIndexSet globalIndexSet; // Set up the indexsets. int start = std::max(rank*nx-1,0); int end = std::min((rank + 1) * nx+1, Nx); distIndexSet.beginResize(); int localIndex=0; int size = Ny*(end-start); Array distArray(size); Array* globalArray; int index=0; std::cout< void setupDistributed(Array& distArray, Dune::ParallelIndexSet >& distIndexSet, int rank, int procs) { // The local grid int nx = NX/procs; int mod = NX%procs; // Set up the indexsets. int start, end; int ostart, oend; if(rank0) ostart = start - 1; else ostart = start; if(rank=end-1); GridFlags flag = owner; if((i=end)) { distArray[localIndex]=-(i+j*NX+rank*NX*NY); flag = overlap; }else distArray[localIndex]=i+j*NX+rank*NX*NY; distIndexSet.add(i+j*NX, Dune::ParallelLocalIndex (localIndex++,flag,isPublic)); } distIndexSet.endResize(); } template void setupGlobal(Array& globalArray, Dune::ParallelIndexSet >& globalIndexSet) { // build global indexset on first process globalIndexSet.beginResize(); globalArray.build(NX*NY); int k=0; for(int j=0; j (i+j*NX,owner,false)); globalArray[i+j*NX]=-(i+j*NX); k++; } globalIndexSet.endResize(); } void testIndicesBuffered(MPI_Comm comm) { //using namespace Dune; // The global grid size const int Nx = 8; const int Ny = 1; // Process configuration int procs, rank, master=0; MPI_Comm_size(comm, &procs); MPI_Comm_rank(comm, &rank); typedef Dune::ParallelIndexSet > ParallelIndexSet; ParallelIndexSet distIndexSet; // global indexset ParallelIndexSet globalIndexSet; Array distArray; Array globalArray; setupDistributed(distArray, distIndexSet, rank, procs); if(rank==master) { setupGlobal(globalArray, globalIndexSet); } typedef Dune::RemoteIndices RemoteIndices; RemoteIndices accuIndices(distIndexSet, globalIndexSet, comm); accuIndices.rebuild(); std::cout<<"dist "<(); Dune::Interface accuInterface; Dune::Interface overlapInterface; Dune::EnumItem sourceFlags; Dune::Combine,Dune::EnumItem,GridFlags> destFlags; // Dune::Bool2Type flag; accuInterface.build(accuIndices, sourceFlags, destFlags); overlapInterface.build(overlapIndices, Dune::EnumItem(), Dune::EnumItem()); overlapInterface.print(); accuInterface.print(); //accuInterface.print(); Dune::BufferedCommunicator accumulator, overlapExchanger; accumulator.build(accuInterface); overlapExchanger.build(overlapInterface); std::cout<< rank<<": before forward distArray="<< distArray<(distArray, distArray); std::cout<(distArray); std::cout< > ParallelIndexSet; ParallelIndexSet sendIndexSet; // global indexset ParallelIndexSet receiveIndexSet; Array array, redistributedArray; // Set up the indexsets. { int start = std::max(rank*nx-1,0); int end = std::min((rank + 1) * nx+1, Nx); sendIndexSet.beginResize(); array.build(Ny*(end-start)); for(int j=0, localIndex=0; j=end-2); GridFlags flag = owner; if((i==start && i!=0)||(i==end-1 && i!=Nx-1)) flag = overlap; sendIndexSet.add(i+j*Nx, ParallelLocalIndex (localIndex,flag,isPublic)); array[localIndex]=i+j*Nx+rank*Nx*Ny; } sendIndexSet.endResize(); } { int newrank = (rank + 1) % procs; int start = std::max(newrank*nx-1,0); int end = std::min((newrank + 1) * nx+1, Nx); std::cout<=end-2); GridFlags flag = owner; if((i==start && i!=0)||(i==end-1 && i!=Nx-1)) flag = overlap; receiveIndexSet.add(i+j*Nx, ParallelLocalIndex (localIndex,flag,isPublic)); redistributedArray[localIndex]=-1; } receiveIndexSet.endResize(); } std::cout<< rank<<": distributed and global index set!"< RemoteIndices; RemoteIndices redistributeIndices(sendIndexSet, receiveIndexSet, comm); RemoteIndices overlapIndices(receiveIndexSet, receiveIndexSet, comm); redistributeIndices.rebuild(); overlapIndices.rebuild(); DatatypeCommunicator redistribute, overlapComm; EnumItem fowner; EnumItem foverlap; redistribute.build(redistributeIndices, fowner, array, fowner, redistributedArray); overlapComm.build(overlapIndices, fowner, redistributedArray, foverlap, redistributedArray); std::cout< > ParallelIndexSet; ParallelIndexSet sendIndexSet; // global indexset ParallelIndexSet receiveIndexSet; Array array, redistributedArray; std::vector neighbours; // Set up the indexsets. { int start = std::max(rank*nx-1,0); int end = std::min((rank + 1) * nx+1, Nx); neighbours.reserve(2); if(rank>0) neighbours.push_back(rank-1); if(rank=end-2); GridFlags flag = owner; if((i==start && i!=0)||(i==end-1 && i!=Nx-1)) flag = overlap; sendIndexSet.add(i+j*Nx, ParallelLocalIndex (localIndex,flag,isPublic)); array[localIndex]=i+j*Nx; //+rank*Nx*Ny; if(flag==overlap) array[localIndex]=-array[localIndex]; } sendIndexSet.endResize(); } { int newrank = (rank + 1) % procs; int start = std::max(newrank*nx-1,0); int end = std::min((newrank + 1) * nx+1, Nx); std::cout<=end-2); GridFlags flag = owner; if((i==start && i!=0)||(i==end-1 && i!=Nx-1)) flag = overlap; receiveIndexSet.add(i+j*Nx, ParallelLocalIndex (localIndex,flag,isPublic)); redistributedArray[localIndex]=-1; } receiveIndexSet.endResize(); } std::cout<< rank<<": distributed and global index set!"< RemoteIndices; RemoteIndices redistributeIndices(sendIndexSet, receiveIndexSet, comm); RemoteIndices overlapIndices(receiveIndexSet, receiveIndexSet, comm); RemoteIndices sendIndices(sendIndexSet, sendIndexSet, comm, neighbours); RemoteIndices sendIndices1(sendIndexSet, sendIndexSet, comm); overlapIndices.rebuild(); redistributeIndices.rebuild(); sendIndices.rebuild(); sendIndices1.rebuild(); if(rank==0) std::cout< fowner; EnumItem foverlap; redistributeInterface.build(redistributeIndices, fowner, fowner); overlapInterface.build(overlapIndices, fowner, foverlap); BufferedCommunicator redistribute; BufferedCommunicator overlapComm; redistribute.build(array, redistributedArray, redistributeInterface); overlapComm.build(overlapInterface); std::cout<(array, redistributedArray); std::cout<(redistributedArray); std::cout<(array, redistributedArray); std::cout<(array, redistributedArray); std::cout<firstRank) { if(rank==0) key = firstRank; if(rank==firstRank) key=0; } MPI_Comm_split(MPI_COMM_WORLD, 0, key, &comm); #ifdef DEBUG bool wait=1; while(size>1 && wait) ; #endif // testIndices(comm); testIndicesBuffered(comm); if(rank==0) std::cout< #include #include #include #include #include enum GridFlags { owner, overlap, border }; template int meassure(const T& selection) { /* return meassure<1>(selection); } template int meassure(const T& selection) {*/ typedef typename T::const_iterator iterator; const iterator end = selection.end(); int count=0; Dune::Timer timer; timer.reset(); for(int i=0; i<10; i++) for(iterator iter = selection.begin(); iter != end; ++iter) count+=*iter; std::cout<<" took "<< timer.elapsed()<<" seconds"< void test() { const int Nx = SIZE; const int Ny = SIZE; // Process configuration const int ALSIZE=55; Dune::ParallelIndexSet,ALSIZE> distIndexSet; distIndexSet.beginResize(); for(int y=0, i=0; y < Ny; y++) for(int x=0; x < Nx; x++, i++) { GridFlags flag = owner; if(x==0 || x == Nx-1 || y ==0 || y==Ny-1) flag = overlap; distIndexSet.add(i, Dune::ParallelLocalIndex (i, flag, true)); } distIndexSet.endResize(); Dune::UncachedSelection,int,Dune::ParallelLocalIndex,ALSIZE> ownerUncached(distIndexSet); Dune::Selection,int,Dune::ParallelLocalIndex,ALSIZE> ownerCached(distIndexSet); Dune::UncachedSelection,int,Dune::ParallelLocalIndex,ALSIZE> overlapUncached(distIndexSet); Dune::Selection,int,Dune::ParallelLocalIndex,ALSIZE> overlapCached(distIndexSet); int count=0; std::cout<<" Owner selection uncached:"; count+=meassure(ownerUncached); std::cout<<" Owner selection cached:"; count+=meassure(ownerCached); std::cout<<" Overlap selection uncached:"; count+=meassure(overlapUncached); std::cout<<" Overlap selection cached:"; count+=meassure(overlapCached); std::cout<(); } dune-common-2.8.0/dune/common/parallel/test/syncertest.cc000066400000000000000000000276061411343567400234750ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include "config.h" #include #include #include #include #include enum GridFlags { owner, overlap, border }; template void deleteOverlapEntries(T& indices, Dune::RemoteIndices& remoteIndices) { typedef typename T::iterator IndexIterator; typedef typename T::GlobalIndex GlobalIndex; typedef typename T::LocalIndex::Attribute Attribute; typedef Dune::RemoteIndices RemoteIndices; typedef typename RemoteIndices::RemoteIndexList::ModifyIterator RemoteModifier; typedef typename RemoteIndices::RemoteIndexList::const_iterator RemoteIterator; typedef Dune::SLList, typename RemoteIndices::RemoteIndexList::Allocator> GlobalList; typedef typename GlobalList::ModifyIterator GlobalModifier; typedef std::tuple IteratorTuple; typedef std::map IteratorMap; typedef typename RemoteIndices::const_iterator RemoteMapIterator; int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); std::map globalLists; IteratorMap iterators; RemoteMapIterator rmEnd = remoteIndices.end(); for(RemoteMapIterator remote = remoteIndices.begin(); remote != rmEnd; ++remote) { // Initialize global indices GlobalList& gList=globalLists[remote->first]; const RemoteIterator rend = remote->second.first->end(); for(RemoteIterator index= remote->second.first->begin(); index != rend; ++index) gList.push_back(std::make_pair(index->localIndexPair().global(), index->localIndexPair().local().attribute())); assert(gList.size()==remote->second.first->size()); std::cout << "Size of remote indices is "<first, IteratorTuple(remote->second.first->beginModify(), gList.beginModify(), rend, gList.end(), &gList, remote->second.first))); } indices.beginResize(); const IndexIterator endIndex = indices.end(); for(IndexIterator index = indices.begin(); index != endIndex; ++index) { if(index->local().attribute()==overlap) { std::cout << rank<<": Deleting "<<*index<(remote->second) != std::get<2>(remote->second) && *(std::get<1>(remote->second)) < *index) { // increment all iterators ++(std::get<0>(remote->second)); ++(std::get<1>(remote->second)); if(std::get<0>(remote->second)!=std::get<2>(remote->second)) assert(std::get<1>(remote->second)!=std::get<3>(remote->second)); } // Delete the entry if present if(std::get<0>(remote->second) != std::get<2>(remote->second)) { assert(std::get<1>(remote->second) != std::get<3>(remote->second)); if(*(std::get<1>(remote->second)) == *index) { std::cout<(remote->second)->first<<", "<< std::get<1>(remote->second)->second<<" of process " << remote->first<(remote->second).remove(); std::get<1>(remote->second).remove(); assert(std::get<4>(remote->second)->size()==std::get<5>(remote->second)->size()); } } } } } indices.endResize(); // Update the pointers to the local index pairs Dune::repairLocalIndexPointers(globalLists, remoteIndices, indices); globalLists.clear(); } template bool areEqual(T& indices, Dune::RemoteIndices& remoteIndices, T& oIndices, Dune::RemoteIndices& oRemoteIndices){ typedef typename T::iterator IndexIterator; typedef Dune::RemoteIndices RemoteIndices; typedef typename RemoteIndices::RemoteIndexList::iterator RemoteIterator; IndexIterator iEnd = indices.end(); bool ret=true; int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); // Test the index sets if(indices.size() != oIndices.size()) { std::cerr<< rank<<": Size of index set is unequal!"<global() != oIndex->global()) { std::cerr<global() <<" is missing!"<local().attribute() !=oIndex->local().attribute()) { std::cerr<global() <<" has wrong attribute: "<< index->local().attribute()<< "!= "<local().attribute()<second.first->size() != remote->second.first->size()) { std::cerr <first <<" does not match!"<second.first->end(); for(RemoteIterator rIndex= remote->second.first->begin(), oRIndex = oRemote->second.first->begin(); oRIndex != rEnd; ++rIndex, ++oRIndex) { if(rIndex->localIndexPair().global() != oRIndex->localIndexPair().global()) { std::cerr<localIndexPair().global() <<" is missing for process "<first<attribute() != oRIndex->attribute()) { std::cerr<localIndexPair().global() <<" for process "<< remote->first<<" is wrong: " <attribute()<<" != "<attribute()< void addFakeRemoteIndices(T& indices, T& oIndices, Dune::RemoteIndices& remoteIndices, Dune::RemoteIndices& oRemoteIndices){ typedef typename T::iterator IndexIterator; typedef typename T::GlobalIndex GlobalIndex; typedef typename T::LocalIndex::Attribute Attribute; typedef typename Dune::RemoteIndices::RemoteIndexList RemoteIndexList; assert(remoteIndices.neighbours()==0 && oRemoteIndices.neighbours()==0); RemoteIndexList* rlist = new RemoteIndexList(); RemoteIndexList* orlist = new RemoteIndexList(); int added=0; IndexIterator iEnd = indices.end(); for(IndexIterator index = indices.begin(), oIndex = oIndices.begin(); index != iEnd; ++index, ++oIndex) { assert(*index == *oIndex); if(index->local().attribute()==overlap) { added++; rlist->push_back(Dune::RemoteIndex(owner,&(*index))); orlist->push_back(Dune::RemoteIndex(owner,&(*oIndex))); } } remoteIndices.remoteIndices_.insert(std::make_pair(1,std::make_pair(rlist,rlist))); oRemoteIndices.remoteIndices_.insert(std::make_pair(1,std::make_pair(orlist,orlist))); std::cout<<"Added "< LocalIndexType; typedef Dune::ParallelIndexSet > ParallelIndexSet; ParallelIndexSet indexSet, changedIndexSet; // Set up the indexsets. int start,end, ostart, oend; if(rank0 &&start syncer(changedIndexSet, changedRemoteIndices); // return 0; std::cout<<"Syncing!"< void gather(B& buffer, int i) { if(!dataSendAt.insert(i).second) { std::cerr << rank << ": Gather() was called twice for index " << i << "!" << std::endl; std::abort(); } std::cout< void scatter(B& buffer, int i, int size) { if(!dataRecievedAt.insert(i).second) { std::cerr << rank << ": Scatter() was called twice for index " << i << "!" << std::endl; std::abort(); } std::cout<0;--size) { double index; buffer.read(index); std::cout< void scatter(B& buffer, int i, int size) { if(!dataRecievedAt.insert(i).second) { std::cerr << rank << ": Scatter() was called twice for index " << i << "!" << std::endl; std::abort(); } std::cout<0;--size) { double index; buffer.read(index); std::cout< dataSendAt; std::set dataRecievedAt; VarDataHandle(int r) : rank(r) {} int rank; typedef double DataType; bool fixedSize() { return false; } void verify(int procs, int start, int end) { std::vector indices; if(procs==1) { for(int k=0;k<=10;k+=2) { indices.push_back(k); } } else { if(rank && rank < procs) { indices.push_back(start-1); indices.push_back(start); } if(rank < procs-1) { indices.push_back(end-1); indices.push_back(end); } } std::set::iterator it; for(int idx : indices) { it = dataSendAt.find(idx); if(it == dataSendAt.end()) { std::cerr << rank << ": No data send at index " << idx << "!" << std::endl; std::abort(); } dataSendAt.erase(it); it = dataRecievedAt.find(idx); if(it == dataRecievedAt.end() && idx%5) { std::cerr << rank << ": No data recieved at index " << idx << "!" << std::endl; std::abort(); } else if(it != dataRecievedAt.end()) { dataRecievedAt.erase(it); } } for(const int &i : dataSendAt) { std::cerr << rank << ": Unexpected data send at index " << i << "!" << std::endl; std::abort(); } for(const int &i : dataRecievedAt) { std::cerr << rank << ": Unexpected data recieved at index " << i << "!" << std::endl; std::abort(); } } template void gather(B& buffer, int i) { if(!dataSendAt.insert(i).second) { std::cerr << rank << ": Gather() was called twice for index " << i << "!" << std::endl; std::abort(); } std::size_t s=i%5; std::cout<(i+j)); } template void scatter(B& buffer, int i, int size) { if(!dataRecievedAt.insert(i).second) { std::cerr << rank << ": Scatter() was called twice for index " << i << "!" << std::endl; std::abort(); } std::cout< void scatter(B& buffer, int i, int size) { if(!dataRecievedAt.insert(i).second) { std::cerr << rank << ": Scatter() was called twice for index " << i << "!" << std::endl; std::abort(); } std::cout<::InterfaceMap Interface; Dune::InterfaceInformation send, recv; send.reserve(6); for(std::size_t i=0; i<=10; i+=2) send.add(i); recv.reserve(6); for(std::size_t i=10; i<=10; i-=2) recv.add(i); Interface inf; inf[0]=std::make_pair(send, recv); Dune::VariableSizeCommunicator<> comm(MPI_COMM_SELF, inf, 6); MyDataHandle1D handle(0); comm.forward(handle); handle.verify(procs, 0, 0); std::cout<<"===================== backward ========================="<2) --procs; // Partition a consecutive set of indices among all active ranks // (where the final rank possibly excluded above is considered // inactive). Set up interfaces so each rank communicates with its // predecessors at the two indices next to the common partition // boundary, and likewise for the successor. Then use the data // handles defined at the top of this file to do some test // communications. int N=100000; // number of indices int num_per_proc=N/procs; // start is our first index, end is one-past our last index. int start, end; if(rank::InterfaceMap Interface; Interface inf; if(rank && rank comm(MPI_COMM_WORLD, inf, 6); MyDataHandle handle(rank); comm.forward(handle); MPI_Barrier(MPI_COMM_WORLD); handle.verify(procs, start, end); MPI_Barrier(MPI_COMM_WORLD); if(rank==0) std::cout<<"===================== backward ========================="< #include #include #include #include #include #include #include #include #include #include #include #include /** * @addtogroup Common_Parallel * * @{ */ /** * @file * @brief A communicator that only needs to know the number of elements per * index at the sender side. * @author Markus Blatt * @} */ namespace Dune { namespace Concept { struct HasFixedSize { template auto require(H &&h) -> decltype(h.fixedSize()); }; } // namespace Concept namespace Impl { template (), int> = 0> constexpr bool callFixedSize(H &&handle) { return handle.fixedSize(); } template (), int> = 0> [[deprecated("Using handles with fixedsize() (lower case s) is deprecated and " "will be removed after release 2.8. Implement fixedSize() " "(camelCase) instead!")]] constexpr bool callFixedSize(H &&handle) { return handle.fixedsize(); } } // namespace Impl namespace { /** * @brief A message buffer. * @tparam T The type of data that the buffer will hold. */ template > class MessageBuffer { public: /** * @brief Constructs a message. * @param size The number of elements that buffer should hold, */ explicit MessageBuffer(int size) : buffer_(new T[size]), size_(size), position_(0) {} /** * @brief Copy constructor. * @param o The instance to copy. */ explicit MessageBuffer(const MessageBuffer& o) : buffer_(new T[o.size_]), size_(o.size_), position_(o.position_) { } /** @brief Destructor. */ ~MessageBuffer() { delete[] buffer_; } /** * @brief Write an item to the buffer. * @param data The data item to write. */ void write(const T& data) { buffer_[position_++]=data; } /** * @brief Reads a data item from the buffer * @param[out] data Reference to where to store the read data. */ void read(T& data) { data=buffer_[position_++]; } /** * @brief Reset the buffer. * * On return the buffer will be positioned at the start again. */ void reset() { position_=0; } /** * @brief Test whether the whole buffer was read. * @return True if we read or wrot until the end of the buffer. */ bool finished() { return position_==size_; } /** * @brief Tests whether the buffer has enough space left to read/write data. * @param notItems The number of items to read or write. * @return True if there is enough space for noItems items. */ bool hasSpaceForItems(int noItems) { return position_+noItems<=size_; } /** * @brief Get the size of the buffer. * @return The number of elements the buffer can hold. */ std::size_t size() const { return size_; } /** * @brief Converts the buffer to a C array. * @return The underlying C array. */ operator T*() { return buffer_; } private: /** * @brief Pointer to the current insertion point of the buffer. */ T* buffer_; /** * @brief The size of the buffer */ std::size_t size_; /** * @brief The current position in the buffer. */ std::size_t position_; }; /** * @brief A tracker for the current position in a communication interface. */ class InterfaceTracker { public: /** * @brief Constructor. * @param rank The other rank that the interface communicates with. * @param info A list of local indices belonging to this interface. */ InterfaceTracker(int rank, InterfaceInformation info, std::size_t fixedsize=0, bool allocateSizes=false) : fixedSize(fixedsize),rank_(rank), index_(), interface_(info), sizes_() { if(allocateSizes) { sizes_.resize(info.size()); } } /** * @brief Moves to the next index in the interface. */ void moveToNextIndex() { index_++; assert(index_<=interface_.size()); skipZeroIndices(); } /** * @brief Increment index various times. * @param i The number of times to increment. */ void increment(std::size_t i) { index_+=i; assert(index_<=interface_.size()); } /** * @brief Checks whether all indices have been visited. * @return True if all indices have been visited. */ bool finished() const { return index_==interface_.size(); } void skipZeroIndices() { // skip indices with size zero! while(sizes_.size() && index_!=interface_.size() &&!size()) ++index_; } /** * @brief Get the current local index of the interface. * @return The current local index of the interface. */ std::size_t index() const { return interface_[index_]; } /** * @brief Get the size at the current index. */ std::size_t size() const { assert(sizes_.size()); return sizes_[index_]; } /** * @brief Get a pointer to the array with the sizes. */ std::size_t* getSizesPointer() { return &sizes_[0]; } /** * @brief Returns whether the interface is empty. * @return True if there are no entries in the interface. */ bool empty() const { return !interface_.size(); } /** * @brief Checks whether there are still indices waiting to be processed. * @return True if there are still indices waiting to be processed. */ std::size_t indicesLeft() const { return interface_.size()-index_; } /** * @brief The number of data items per index if it is fixed, 0 otherwise. */ std::size_t fixedSize; /** * @brief Get the process rank that this communication interface is with. */ int rank() const { return rank_; } /** * @brief Get the offset to the first index. */ std::size_t offset() const { return index_; } private: /** @brief The process rank that this communication interface is with. */ int rank_; /** @brief The other rank that this interface communcates with. */ std::size_t index_; /** @brief The list of local indices of this interface. */ InterfaceInformation interface_; std::vector sizes_; }; } // end unnamed namespace /** * @addtogroup Common_Parallel * * @{ */ /** * @brief A buffered communicator where the amount of data sent does not have to be known a priori. * * In contrast to BufferedCommunicator the amount of data is determined by the container * whose entries are sent and not known at the receiving side a priori. * * Note that there is no global index-space, only local index-spaces on each * rank. Note also that each rank has two index-spaces, one used for * gathering/sending, and one used for scattering/receiving. These may be the * identical, but they do not have to be. * * For data send from rank A to rank B, the order that rank A inserts its * indices into its send-interface for rank B has to be the same order that * rank B inserts its matching indices into its receive interface for rank A. * (This is because the `VariableSizeCommunicator` has no concept of a global * index-space, so the order used to insert the indices into the interfaces is * the only clue it has to know which source index should be communicated to * which target index.) * * It is permissible for a rank to communicate with itself, i.e. it can define * send- and receive-interfaces to itself. These interfaces do not need to * contain the same indices, as the local send index-space can be different * from the local receive index-space. This is useful for repartitioning or * for aggregating in AMG. * * Do not assume that gathering to an index happens before scattering to the * same index in the same communication, as `VariableSizeCommunicator` assumes * they are from different index-spaces. This is a pitfall if you want do * communicate a vector in-place, e.g. to sum up partial results from * different ranks. Instead, have separate source and target vectors and copy * the source vector to the target vector before communicating. */ template > > class VariableSizeCommunicator { public: /** * @brief The type of the map from process number to InterfaceInformation for * sending and receiving to and from it. */ typedef std::map, std::less, typename std::allocator_traits::template rebind_alloc< std::pair > > > InterfaceMap; #ifndef DUNE_PARALLEL_MAX_COMMUNICATION_BUFFER_SIZE /** * @brief Creates a communicator with the default maximum buffer size. * * The default size ist either what the macro DUNE_MAX_COMMUNICATION_BUFFER_SIZE * is set to or 32768 if is not set. */ VariableSizeCommunicator(MPI_Comm comm, const InterfaceMap& inf) : maxBufferSize_(32768), interface_(&inf) { MPI_Comm_dup(comm, &communicator_); } /** * @brief Creates a communicator with the default maximum buffer size. * @param inf The communication interface. */ VariableSizeCommunicator(const Interface& inf) : maxBufferSize_(32768), interface_(&inf.interfaces()) { MPI_Comm_dup(inf.communicator(), &communicator_); } #else /** * @brief Creates a communicator with the default maximum buffer size. * * The default size ist either what the macro DUNE_MAX_COMMUNICATION_BUFFER_SIZE * is set to or 32768 if is not set. */ VariableSizeCommunicator(MPI_Comm comm, InterfaceMap& inf) : maxBufferSize_(DUNE_PARALLEL_MAX_COMMUNICATION_BUFFER_SIZE), interface_(&inf) { MPI_Comm_dup(comm, &communicator_); } /** * @brief Creates a communicator with the default maximum buffer size. * @param inf The communication interface. */ VariableSizeCommunicator(const Interface& inf) : maxBufferSize_(DUNE_PARALLEL_MAX_COMMUNICATION_BUFFER_SIZE), interface_(&inf.interfaces()) { MPI_Comm_dup(inf.communicator(), &communicator_); } #endif /** * @brief Creates a communicator with a specific maximum buffer size. * @param comm The MPI communicator to use. * @param inf The communication interface. * @param max_buffer_size The maximum buffer size allowed. */ VariableSizeCommunicator(MPI_Comm comm, const InterfaceMap& inf, std::size_t max_buffer_size) : maxBufferSize_(max_buffer_size), interface_(&inf) { MPI_Comm_dup(comm, &communicator_); } /** * @brief Creates a communicator with a specific maximum buffer size. * @param inf The communication interface. * @param max_buffer_size The maximum buffer size allowed. */ VariableSizeCommunicator(const Interface& inf, std::size_t max_buffer_size) : maxBufferSize_(max_buffer_size), interface_(&inf.interfaces()) { MPI_Comm_dup(inf.communicator(), &communicator_); } ~VariableSizeCommunicator() { MPI_Comm_free(&communicator_); } /** * @brief Copy-constructs a communicator * @param other VariableSizeCommunicator that is copied. */ VariableSizeCommunicator(const VariableSizeCommunicator& other) { maxBufferSize_ = other.maxBufferSize_; interface_ = other.interface_; MPI_Comm_dup(other.communicator_, &communicator_); } /** * @brief Copy-assignes a communicator * @param other VariableSizeCommunicator that is copied. */ VariableSizeCommunicator& operator=(const VariableSizeCommunicator& other) { if(this == &other) // don't do anything if objects are the same return *this; maxBufferSize_ = other.maxBufferSize_; interface_ = other.interface_; MPI_Comm_free(&communicator_); MPI_Comm_dup(other.communicator_, &communicator_); return *this; } /** * @brief Communicate forward. * * @tparam DataHandle The type of the handle describing the data. This type has to adhere * to the following interface: * \code{.cpp} * // returns whether the number of data items per entry is fixed * bool fixedsize(); * // get the number of data items for an entry with index i * std::size_t size(std::size_t i); * // gather the data at index i * template * void gather(MessageBuffer& buf, std::size_t i); * // scatter the n data items to index i * template * void scatter(MessageBuffer& buf, std::size_t i, std::size_t n); * \endcode * @param handle A handle responsible for describing the data, gathering, and scattering it. */ template void forward(DataHandle& handle) { communicate(handle); } /** * @brief Communicate backwards. * * @tparam DataHandle The type of the handle describing the data. This type has to adhere * to the following interface: * \code{.cpp} * // returns whether the number of data items per entry is fixed * bool fixedsize(); * // get the number of data items for an entry with index i * std::size_t size(std::size_t i); * // gather the data at index i * template * void gather(MessageBuffer& buf, std::size_t i); * // scatter the n data items to index i * template * void scatter(MessageBuffer& buf, std::size_t i, std::size_t n); * \endcode * @param handle A handle responsible for describing the data, gathering, and scattering it. */ template void backward(DataHandle& handle) { communicate(handle); } private: template void communicateSizes(DataHandle& handle, std::vector& recv_trackers); /** * @brief Communicates data according to the interface. * @tparam forward If true sends data forwards, otherwise backwards along the interface. * @tparame DataHandle The type of the data handle @see forward for a description of the interface. * @param handle The handle describing the data and responsible for gather and scatter operations. */ template void communicate(DataHandle& handle); /** * @brief Initialize the trackers along the interface for the communication. * @tparam FORWARD If true we send in the forward direction. * @tparam DataHandle DataHandle The type of the data handle. * @param handle The handle describing the data and responsible for gather * and scatter operations. * @param[out] send_trackers The trackers for the sending side. * @param[out] recv_trackers The trackers for the receiving side. */ template void setupInterfaceTrackers(DataHandle& handle, std::vector& send_trackers, std::vector& recv_trackers); /** * @brief Communicate data with a fixed amount of data per entry. * @tparam FORWARD If true we send in the forward direction. * @tparam DataHandle DataHandle The type of the data handle. * @param handle The handle describing the data and responsible for gather * and scatter operations. */ template void communicateFixedSize(DataHandle& handle); /** * @brief Communicate data with a variable amount of data per entry. * @tparam FORWARD If true we send in the forward direction. * @tparam DataHandle DataHandle The type of the data handle. * @param handle The handle describing the data and responsible for gather * and scatter operations. */ template void communicateVariableSize(DataHandle& handle); /** * @brief The maximum size if the buffers used for gather and scatter. * * @note If this process has n neighbours, then a maximum of 2n buffers of this size * is allocate. Memory needed will be n*sizeof(std::size_t)+n*sizeof(Datahandle::DataType) */ std::size_t maxBufferSize_; /** * @brief description of the interface. * * This is a map of the neighboring process number to a pair of local index lists. * The first is a list of indices to gather data for sending from and the second is a list of * indices to scatter received data to during forward. */ const InterfaceMap* interface_; /** * @brief The communicator. * * This is a cloned communicator to ensure there are no interferences. */ MPI_Comm communicator_; }; /** @} */ namespace { /** * @brief A data handle for comunicating the sizes of variable sized data. */ template class SizeDataHandle { public: typedef std::size_t DataType; SizeDataHandle(DataHandle& data, std::vector& trackers) : data_(data), trackers_(trackers), index_() {} bool fixedSize() { return true; } std::size_t size([[maybe_unused]] std::size_t i) { return 1; } template void gather(B& buf, int i) { buf.write(data_.size(i)); } void setReceivingIndex(std::size_t i) { index_=i; } std::size_t* getSizesPointer() { return trackers_[index_].getSizesPointer(); } private: DataHandle& data_; std::vector& trackers_; int index_; }; template void setReceivingIndex(T&, int) {} template void setReceivingIndex(SizeDataHandle& t, int i) { t.setReceivingIndex(i); } /** * @brief Template meta program for choosing then send or receive interface * information based on the direction. * @tparam FORWARD If true the communication happens in the forward direction. */ template struct InterfaceInformationChooser { /** * @brief Get the interface information for the sending side. */ static const InterfaceInformation& getSend(const std::pair& info) { return info.first; } /** * @brief Get the interface information for the receiving side. */ static const InterfaceInformation& getReceive(const std::pair& info) { return info.second; } }; template<> struct InterfaceInformationChooser { static const InterfaceInformation& getSend(const std::pair& info) { return info.second; } static const InterfaceInformation& getReceive(const std::pair& info) { return info.first; } }; /** * @brief A functor that packs entries into the message buffer. * @tparam DataHandle The type of the data handle that describes * the communicated data. */ template struct PackEntries { int operator()(DataHandle& handle, InterfaceTracker& tracker, MessageBuffer& buffer, [[maybe_unused]] int i) const { return operator()(handle,tracker,buffer); } /** * @brief packs data. * @param handle The handle describing the data and the gather and scatter operations. * @param tracker The tracker of the interface to tell us where we are. * @param buffer The buffer to use for packing. * @return The number data entries that we packed. */ int operator()(DataHandle& handle, InterfaceTracker& tracker, MessageBuffer& buffer) const { if(tracker.fixedSize) // fixed size if variable is >0! { std::size_t noIndices=std::min(buffer.size()/tracker.fixedSize, tracker.indicesLeft()); for(std::size_t i=0; i< noIndices; ++i) { handle.gather(buffer, tracker.index()); tracker.moveToNextIndex(); } return noIndices*tracker.fixedSize; } else { int packed=0; tracker.skipZeroIndices(); while(!tracker.finished()) if(buffer.hasSpaceForItems(handle.size(tracker.index()))) { handle.gather(buffer, tracker.index()); packed+=handle.size(tracker.index()); tracker.moveToNextIndex(); } else break; return packed; } } }; /** * @brief A functor that unpacks entries from the message buffer. * @tparam DataHandle The type of the data handle that describes * the communicated data. */ template struct UnpackEntries{ /** * @brief packs data. * @param handle The handle describing the data and the gather and scatter operations. * @param tracker The tracker of the interface to tell us where we are. * @param buffer The buffer to use for packing. * @return The number data entries that we packed. */ bool operator()(DataHandle& handle, InterfaceTracker& tracker, MessageBuffer& buffer, int count=0) { if(tracker.fixedSize) // fixed size if variable is >0! { std::size_t noIndices=std::min(buffer.size()/tracker.fixedSize, tracker.indicesLeft()); for(std::size_t i=0; i< noIndices; ++i) { handle.scatter(buffer, tracker.index(), tracker.fixedSize); tracker.moveToNextIndex(); } return tracker.finished(); } else { assert(count); for(int unpacked=0;unpacked struct UnpackSizeEntries{ /** * @brief packs data. * @param handle The handle describing the data and the gather and scatter operations. * @param tracker The tracker of the interface to tell us where we are. * @param buffer The buffer to use for packing. * @return The number data entries that we packed. */ bool operator()(SizeDataHandle& handle, InterfaceTracker& tracker, MessageBuffer::DataType>& buffer) const { std::size_t noIndices=std::min(buffer.size(), tracker.indicesLeft()); std::copy(static_cast(buffer), static_cast(buffer)+noIndices, handle.getSizesPointer()+tracker.offset()); tracker.increment(noIndices); return noIndices; } bool operator()(SizeDataHandle& handle, InterfaceTracker& tracker, MessageBuffer::DataType>& buffer, int) const { return operator()(handle,tracker,buffer); } }; /** * @brief Sends the size in case of communicating a fixed amount of data per entry. * @param[in] send_trackers The trackers for the sending side. * @param[out] send_requests The request for the asynchronous send operations. * @param[in] recv_trackers The trackers for the receiving side. * @param[out] recv_requests The request for the asynchronous receive operations. */ void sendFixedSize(std::vector& send_trackers, std::vector& send_requests, std::vector& recv_trackers, std::vector& recv_requests, MPI_Comm communicator) { typedef std::vector::iterator TIter; std::vector::iterator mIter=recv_requests.begin(); for(TIter iter=recv_trackers.begin(), end=recv_trackers.end(); iter!=end; ++iter, ++mIter) { MPI_Irecv(&(iter->fixedSize), 1, MPITraits::getType(), iter->rank(), 933881, communicator, &(*mIter)); } // Send our size to all neighbours using non-blocking synchronous communication. std::vector::iterator mIter1=send_requests.begin(); for(TIter iter=send_trackers.begin(), end=send_trackers.end(); iter!=end; ++iter, ++mIter1) { MPI_Issend(&(iter->fixedSize), 1, MPITraits::getType(), iter->rank(), 933881, communicator, &(*mIter1)); } } /** * @brief Functor for setting up send requests. * @tparam DataHandle The type of the data handle for describing the data. */ template struct SetupSendRequest{ void operator()(DataHandle& handle, InterfaceTracker& tracker, MessageBuffer& buffer, MPI_Request& request, MPI_Comm comm) const { buffer.reset(); int size=PackEntries()(handle, tracker, buffer); // Skip indices of zero size. while(!tracker.finished() && !handle.size(tracker.index())) tracker.moveToNextIndex(); if(size) MPI_Issend(buffer, size, MPITraits::getType(), tracker.rank(), 933399, comm, &request); } }; /** * @brief Functor for setting up receive requests. * @tparam DataHandle The type of the data handle for describing the data. */ template struct SetupRecvRequest{ void operator()(DataHandle& /*handle*/, InterfaceTracker& tracker, MessageBuffer& buffer, MPI_Request& request, MPI_Comm comm) const { buffer.reset(); if(tracker.indicesLeft()) MPI_Irecv(buffer, buffer.size(), MPITraits::getType(), tracker.rank(), 933399, comm, &request); } }; /** * @brief A functor that does nothing. */ template struct NullPackUnpackFunctor { int operator()(DataHandle&, InterfaceTracker&, MessageBuffer&, int) { return 0; } int operator()(DataHandle&, InterfaceTracker&, MessageBuffer&) { return 0; } }; /** * @brief Check whether some of the requests finished and continue send/receive operation. * @tparam DataHandle The type of the data handle describing the data. * @tparam BufferFunctor A functor that packs or unpacks data from the buffer. * E.g. NullPackUnpackFunctor. * @tparam CommunicationFuntor A functor responsible for continuing the communication. * @param handle The data handle describing the data. * @param trackers The trackers indicating the current position in the communication. * @param requests The requests to test whether they finished. * @param requests2 The requests to use for setting up the continuing communication. Might * be the same as requests. * @param comm The MPI communicator to use. * @param buffer_func The functor that does the packing or unpacking of the data. */ template std::size_t checkAndContinue(DataHandle& handle, std::vector& trackers, std::vector& requests, std::vector& requests2, std::vector >& buffers, MPI_Comm comm, BufferFunctor buffer_func, CommunicationFunctor comm_func, bool valid=true, bool getCount=false) { std::size_t size=requests.size(); std::vector statuses(size); int no_completed; std::vector indices(size, -1); // the indices for which the communication finished. MPI_Testsome(size, &(requests[0]), &no_completed, &(indices[0]), &(statuses[0])); indices.resize(no_completed); for(std::vector::iterator index=indices.begin(), end=indices.end(); index!=end; ++index) { InterfaceTracker& tracker=trackers[*index]; setReceivingIndex(handle, *index); if(getCount) { // Get the number of entries received int count; MPI_Get_count(&(statuses[index-indices.begin()]), MPITraits::getType(), &count); // Communication completed, we can reuse the buffers, e.g. unpack or repack buffer_func(handle, tracker, buffers[*index], count); }else buffer_func(handle, tracker, buffers[*index]); tracker.skipZeroIndices(); if(!tracker.finished()){ // Maybe start another communication. comm_func(handle, tracker, buffers[*index], requests2[*index], comm); tracker.skipZeroIndices(); if(valid) --no_completed; // communication not finished, decrement counter for finished ones. } } return no_completed; } /** * @brief Receive the size per data entry and set up requests for receiving the data. * @tparam DataHandle The type of the data handle. * @param trackers The trackers indicating the indices where we send and from which rank. * @param size_requests The requests for receiving the size. * @param data_requests The requests for sending the data. * @param buffers The buffers to use for sending. * @param comm The mpi communicator to use. */ template std::size_t receiveSizeAndSetupReceive(DataHandle& handle, std::vector& trackers, std::vector& size_requests, std::vector& data_requests, std::vector >& buffers, MPI_Comm comm) { return checkAndContinue(handle, trackers, size_requests, data_requests, buffers, comm, NullPackUnpackFunctor(), SetupRecvRequest(), false); } /** * @brief Check whether send request completed and continue sending if necessary. * @tparam DataHandle The type of the data handle. * @param trackers The trackers indicating the indices where we send and from which rank. * @param requests The requests for the asynchronous communication. * @param buffers The buffers to use for sending. * @param comm The mpi communicator to use. */ template std::size_t checkSendAndContinueSending(DataHandle& handle, std::vector& trackers, std::vector& requests, std::vector >& buffers, MPI_Comm comm) { return checkAndContinue(handle, trackers, requests, requests, buffers, comm, NullPackUnpackFunctor(), SetupSendRequest()); } /** * @brief Check whether receive request completed and continue receiving if necessary. * @tparam DataHandle The type of the data handle. * @param trackers The trackers indicating the indices where we receive and from which rank. * @param requests The requests for the asynchronous communication. * @param buffers The buffers to use for receiving. * @param comm The mpi communicator to use. */ template std::size_t checkReceiveAndContinueReceiving(DataHandle& handle, std::vector& trackers, std::vector& requests, std::vector >& buffers, MPI_Comm comm) { return checkAndContinue(handle, trackers, requests, requests, buffers, comm, UnpackEntries(), SetupRecvRequest(), true, !Impl::callFixedSize(handle)); } bool validRecvRequests(const std::vector reqs) { for(std::vector::const_iterator i=reqs.begin(), end=reqs.end(); i!=end; ++i) if(*i!=MPI_REQUEST_NULL) return true; return false; } /** * @brief Sets up all the send requests for the data. * @tparam DataHandle The type of the data handle. * @tparam Functor The type of the functor to set up the request. * @param handle The data handle describing the data. * @param trackers The trackers for the communication interfaces. * @param buffers The buffers for the comunication. One for each neighbour. * @param requests The send requests for each neighbour. * @param setupFunctor The functor responsible for setting up the request. */ template std::size_t setupRequests(DataHandle& handle, std::vector& trackers, std::vector >& buffers, std::vector& requests, const Functor& setupFunctor, MPI_Comm communicator) { typedef typename std::vector::iterator TIter; typename std::vector >::iterator biter=buffers.begin(); typename std::vector::iterator riter=requests.begin(); std::size_t complete=0; for(TIter titer=trackers.begin(), end=trackers.end(); titer!=end; ++titer, ++biter, ++riter) { setupFunctor(handle, *titer, *biter, *riter, communicator); complete+=titer->finished(); } return complete; } } // end unnamed namespace template template void VariableSizeCommunicator::setupInterfaceTrackers(DataHandle& handle, std::vector& send_trackers, std::vector& recv_trackers) { if(interface_->size()==0) return; send_trackers.reserve(interface_->size()); recv_trackers.reserve(interface_->size()); int fixedsize=0; if(Impl::callFixedSize(handle)) ++fixedsize; typedef typename InterfaceMap::const_iterator IIter; for(IIter inf=interface_->begin(), end=interface_->end(); inf!=end; ++inf) { if(Impl::callFixedSize(handle) && InterfaceInformationChooser::getSend(inf->second).size()) fixedsize=handle.size(InterfaceInformationChooser::getSend(inf->second)[0]); assert(!Impl::callFixedSize(handle)||fixedsize>0); send_trackers.push_back(InterfaceTracker(inf->first, InterfaceInformationChooser::getSend(inf->second), fixedsize)); recv_trackers.push_back(InterfaceTracker(inf->first, InterfaceInformationChooser::getReceive(inf->second), fixedsize, fixedsize==0)); } } template template void VariableSizeCommunicator::communicateFixedSize(DataHandle& handle) { std::vector size_send_req(interface_->size()); std::vector size_recv_req(interface_->size()); std::vector send_trackers; std::vector recv_trackers; setupInterfaceTrackers(handle,send_trackers, recv_trackers); sendFixedSize(send_trackers, size_send_req, recv_trackers, size_recv_req, communicator_); std::vector data_send_req(interface_->size(), MPI_REQUEST_NULL); std::vector data_recv_req(interface_->size(), MPI_REQUEST_NULL); typedef typename DataHandle::DataType DataType; std::vector > send_buffers(interface_->size(), MessageBuffer(maxBufferSize_)), recv_buffers(interface_->size(), MessageBuffer(maxBufferSize_)); setupRequests(handle, send_trackers, send_buffers, data_send_req, SetupSendRequest(), communicator_); std::size_t no_size_to_recv, no_to_send, no_to_recv, old_size; no_size_to_recv = no_to_send = no_to_recv = old_size = interface_->size(); // Skip empty interfaces. typedef typename std::vector::const_iterator Iter; for(Iter i=recv_trackers.begin(), end=recv_trackers.end(); i!=end; ++i) if(i->empty()) --no_to_recv; for(Iter i=send_trackers.begin(), end=send_trackers.end(); i!=end; ++i) if(i->empty()) --no_to_send; while(no_size_to_recv+no_to_send+no_to_recv) { // Receive the fixedsize and setup receives accordingly if(no_size_to_recv) no_size_to_recv -= receiveSizeAndSetupReceive(handle,recv_trackers, size_recv_req, data_recv_req, recv_buffers, communicator_); // Check send completion and initiate other necessary sends if(no_to_send) no_to_send -= checkSendAndContinueSending(handle, send_trackers, data_send_req, send_buffers, communicator_); if(validRecvRequests(data_recv_req)) // Receive data and setup new unblocking receives if necessary no_to_recv -= checkReceiveAndContinueReceiving(handle, recv_trackers, data_recv_req, recv_buffers, communicator_); } // Wait for completion of sending the size. //std::vector statuses(interface_->size(), MPI_STATUSES_IGNORE); MPI_Waitall(size_send_req.size(), &(size_send_req[0]), MPI_STATUSES_IGNORE); } template template void VariableSizeCommunicator::communicateSizes(DataHandle& handle, std::vector& data_recv_trackers) { std::vector send_trackers; std::vector recv_trackers; std::size_t size = interface_->size(); std::vector send_requests(size, MPI_REQUEST_NULL); std::vector recv_requests(size, MPI_REQUEST_NULL); std::vector > send_buffers(size, MessageBuffer(maxBufferSize_)), recv_buffers(size, MessageBuffer(maxBufferSize_)); SizeDataHandle size_handle(handle,data_recv_trackers); setupInterfaceTrackers(size_handle,send_trackers, recv_trackers); setupRequests(size_handle, send_trackers, send_buffers, send_requests, SetupSendRequest >(), communicator_); setupRequests(size_handle, recv_trackers, recv_buffers, recv_requests, SetupRecvRequest >(), communicator_); // Count valid requests that we have to wait for. auto valid_req_func = [](const MPI_Request& req) { return req != MPI_REQUEST_NULL; }; auto size_to_send = std::count_if(send_requests.begin(), send_requests.end(), valid_req_func); auto size_to_recv = std::count_if(recv_requests.begin(), recv_requests.end(), valid_req_func); while(size_to_send+size_to_recv) { if(size_to_send) size_to_send -= checkSendAndContinueSending(size_handle, send_trackers, send_requests, send_buffers, communicator_); if(size_to_recv) // Could have done this using checkSendAndContinueSending // But the call below is more efficient as UnpackSizeEntries // uses std::copy. size_to_recv -= checkAndContinue(size_handle, recv_trackers, recv_requests, recv_requests, recv_buffers, communicator_, UnpackSizeEntries(), SetupRecvRequest >()); } } template template void VariableSizeCommunicator::communicateVariableSize(DataHandle& handle) { std::vector send_trackers; std::vector recv_trackers; setupInterfaceTrackers(handle, send_trackers, recv_trackers); std::vector send_requests(interface_->size(), MPI_REQUEST_NULL); std::vector recv_requests(interface_->size(), MPI_REQUEST_NULL); typedef typename DataHandle::DataType DataType; std::vector > send_buffers(interface_->size(), MessageBuffer(maxBufferSize_)), recv_buffers(interface_->size(), MessageBuffer(maxBufferSize_)); communicateSizes(handle, recv_trackers); // Setup requests for sending and receiving. setupRequests(handle, send_trackers, send_buffers, send_requests, SetupSendRequest(), communicator_); setupRequests(handle, recv_trackers, recv_buffers, recv_requests, SetupRecvRequest(), communicator_); // Determine number of valid requests. auto valid_req_func = [](const MPI_Request& req) { return req != MPI_REQUEST_NULL;}; auto no_to_send = std::count_if(send_requests.begin(), send_requests.end(), valid_req_func); auto no_to_recv = std::count_if(recv_requests.begin(), recv_requests.end(), valid_req_func); while(no_to_send+no_to_recv) { // Check send completion and initiate other necessary sends if(no_to_send) no_to_send -= checkSendAndContinueSending(handle, send_trackers, send_requests, send_buffers, communicator_); if(no_to_recv) // Receive data and setup new unblocking receives if necessary no_to_recv -= checkReceiveAndContinueReceiving(handle, recv_trackers, recv_requests, recv_buffers, communicator_); } } template template void VariableSizeCommunicator::communicate(DataHandle& handle) { if( interface_->size() == 0) // Simply return as otherwise we will index an empty container // either for MPI_Wait_all or MPI_Test_some. return; if(Impl::callFixedSize(handle)) communicateFixedSize(handle); else communicateVariableSize(handle); } } // end namespace Dune #endif // HAVE_MPI #endif dune-common-2.8.0/dune/common/parameterizedobject.hh000066400000000000000000000142421411343567400225440ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: #ifndef DUNE_COMMON_PARAMETERIZEDOBJECT_HH #define DUNE_COMMON_PARAMETERIZEDOBJECT_HH #include #include #include #include #include namespace Dune { /** * @brief A factory class for parameterized objects. * * It allows the construction of objects adhering to a certain interface that * might be constructed quite differently for one another. * * The Signature parameter defined the "virtual" constructor signature * in the form of Interface(Args...), where Interface is the type of * the (abstract) interface class and Args... is the set of * constrcutor parameters. * * Each type constructed by this factory is identified by a different key. This class * allows for easy registration of type with new keys. * * @tparam Signature Signature of the "virtual" constructor call in the form for Interface(Args...). For default constructors one can omit the ()-brackets. * @tparam KeyT The type of the objects that are used as keys in the lookup [DEFAULT: std::string]. */ template class ParameterizedObjectFactory; template class ParameterizedObjectFactory { public: /** @brief The typ of the keys. */ typedef KeyT Key; /** @brief The type of objects created by the factory. */ using Type = TypeT; protected: using Creator = std::function; template static constexpr auto has_proper_signature(Dune::PriorityTag<1>) -> decltype( std::declval()(std::declval()...), std::true_type()) { return {}; } template static constexpr std::false_type has_proper_signature(Dune::PriorityTag<0>) { return {}; } public: /** * @brief Creates an object identified by a key from given parameters * * @param key The key the object is registered with @see define. * @param args The parameters used for the construction. * @return The object wrapped as Type */ Type create(Key const& key, Args ... args) const { typename Registry::const_iterator i = registry_.find(key); if (i == registry_.end()) { DUNE_THROW(Dune::InvalidStateException, "ParametrizedObjectFactory: key ``" << key << "'' not registered"); } else return i->second(args...); } /** * @brief Registers a new type with a key. * * After registration objects of this type can be constructed with the * specified key using a matching default creation function. If Type * is a unique_ptr or shared_ptr, the object is created via make_unique * or make_shared, respectively. Otherwise a constructor of Impl * is called. * * @tparam Impl The type of objects to create. * * @param key The key associated with this type. */ template void define(Key const& key) { registry_[key] = DefaultCreator(); } /** * @brief Registers a new creator with a key. * * After registration objects can be constructed using * the given creator function. * * @tparam F Type of creator function. This must be callable with Args... . * * @param key The key associated with this type. * @param f Function for creation of objects of type Impl * * \todo Replace has_proper_signature by concept check */ template(PriorityTag<42>()), int>::type = 0> void define(Key const& key, F&& f) { registry_[key] = f; } /** * @brief Registers a new type with a key. * * After registration objects of this type can be created. * This method will store a copy of the given object and * create will hand out a copy to this. * * @tparam Impl The type of objects to create. * * @param key The key associated with this type. * @param t reference object, "create" will call the copy-constructor * * note, this does not work fundamental types */ template::value and not std::is_convertible::value, int>::type = 0> void define(Key const& key, Impl&& t) { registry_[key] = [=](Args...) { return t;}; } bool contains(Key const& key) const { return registry_.count(key); } private: template struct Tag{}; template struct DefaultCreator { template Type operator()(T&&... args) const { return DefaultCreator::create(Tag(), PriorityTag<42>(), std::forward(args)...); } template static Type create(Tag, PriorityTag<1>, T&& ... args) { return Impl(std::forward(args)...); } template static Type create(Tag>, PriorityTag<2>, T&& ... args) { return std::make_unique(std::forward(args)...); } template static Type create(Tag>, PriorityTag<3>, T&& ... args) { return std::make_shared(std::forward(args)...); } }; typedef std::map Registry; Registry registry_; }; } // end namespace Dune #endif // DUNE_COMMON_PARAMETERIZEDOBJECT_HH dune-common-2.8.0/dune/common/parametertree.cc000066400000000000000000000133551411343567400213530ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include using namespace Dune; ParameterTree::ParameterTree() {} const Dune::ParameterTree Dune::ParameterTree::empty_; void ParameterTree::report(std::ostream& stream, const std::string& prefix) const { typedef std::map::const_iterator ValueIt; ValueIt vit = values_.begin(); ValueIt vend = values_.end(); for(; vit!=vend; ++vit) stream << vit->first << " = \"" << vit->second << "\"" << std::endl; typedef std::map::const_iterator SubIt; SubIt sit = subs_.begin(); SubIt send = subs_.end(); for(; sit!=send; ++sit) { stream << "[ " << prefix + prefix_ + sit->first << " ]" << std::endl; (sit->second).report(stream, prefix); } } bool ParameterTree::hasKey(const std::string& key) const { std::string::size_type dot = key.find("."); if (dot != std::string::npos) { std::string prefix = key.substr(0,dot); if (subs_.count(prefix) == 0) return false; if (values_.count(prefix) > 0) DUNE_THROW(RangeError,"key " << prefix << " occurs as value and as subtree"); const ParameterTree& s = sub(prefix); return s.hasKey(key.substr(dot+1)); } else if (values_.count(key) != 0) { if (subs_.count(key) > 0) DUNE_THROW(RangeError,"key " << key << " occurs as value and as subtree"); return true; } else return false; } bool ParameterTree::hasSub(const std::string& key) const { std::string::size_type dot = key.find("."); if (dot != std::string::npos) { std::string prefix = key.substr(0,dot); if (subs_.count(prefix) == 0) return false; if (values_.count(prefix) > 0) DUNE_THROW(RangeError,"key " << prefix << " occurs as value and as subtree"); const ParameterTree& s = sub(prefix); return s.hasSub(key.substr(dot+1)); } else if (subs_.count(key) != 0) { if (values_.count(key) > 0) DUNE_THROW(RangeError,"key " << key << " occurs as value and as subtree"); return true; } else return false; } ParameterTree& ParameterTree::sub(const std::string& key) { std::string::size_type dot = key.find("."); if (dot != std::string::npos) { ParameterTree& s = sub(key.substr(0,dot)); return s.sub(key.substr(dot+1)); } else { if (values_.count(key) > 0) DUNE_THROW(RangeError,"key " << key << " occurs as value and as subtree"); if (subs_.count(key) == 0) subKeys_.push_back(key.substr(0,dot)); subs_[key].prefix_ = prefix_ + key + "."; return subs_[key]; } } const ParameterTree& ParameterTree::sub(const std::string& key, bool fail_if_missing) const { std::string::size_type dot = key.find("."); if (dot != std::string::npos) { const ParameterTree& s = sub(key.substr(0,dot)); return s.sub(key.substr(dot+1),fail_if_missing); } else { if (values_.count(key) > 0) DUNE_THROW(RangeError,"key " << key << " occurs as value and as subtree"); if (subs_.count(key) == 0) { if (fail_if_missing) { DUNE_THROW(Dune::RangeError, "SubTree '" << key << "' not found in ParameterTree (prefix " + prefix_ + ")"); } else return empty_; } return subs_.find(key)->second; } } std::string& ParameterTree::operator[] (const std::string& key) { std::string::size_type dot = key.find("."); if (dot != std::string::npos) { ParameterTree& s = sub(key.substr(0,dot)); return s[key.substr(dot+1)]; } else { if (! hasKey(key)) valueKeys_.push_back(key); return values_[key]; } } const std::string& ParameterTree::operator[] (const std::string& key) const { std::string::size_type dot = key.find("."); if (dot != std::string::npos) { const ParameterTree& s = sub(key.substr(0,dot)); return s[key.substr(dot+1)]; } else { if (! hasKey(key)) DUNE_THROW(Dune::RangeError, "Key '" << key << "' not found in ParameterTree (prefix " + prefix_ + ")"); return values_.find(key)->second; } } std::string ParameterTree::get(const std::string& key, const std::string& defaultValue) const { if (hasKey(key)) return (*this)[key]; else return defaultValue; } std::string ParameterTree::get(const std::string& key, const char* defaultValue) const { if (hasKey(key)) return (*this)[key]; else return defaultValue; } std::string ParameterTree::ltrim(const std::string& s) { std::size_t firstNonWS = s.find_first_not_of(" \t\n\r"); if (firstNonWS!=std::string::npos) return s.substr(firstNonWS); return std::string(); } std::string ParameterTree::rtrim(const std::string& s) { std::size_t lastNonWS = s.find_last_not_of(" \t\n\r"); if (lastNonWS!=std::string::npos) return s.substr(0, lastNonWS+1); return std::string(); } std::vector ParameterTree::split(const std::string & s) { std::vector substrings; std::size_t front = 0, back = 0, size = 0; while (front != std::string::npos) { // find beginning of substring front = s.find_first_not_of(" \t\n\r", back); back = s.find_first_of(" \t\n\r", front); size = back - front; if (size > 0) substrings.push_back(s.substr(front, size)); } return substrings; } const ParameterTree::KeyVector& ParameterTree::getValueKeys() const { return valueKeys_; } const ParameterTree::KeyVector& ParameterTree::getSubKeys() const { return subKeys_; } dune-common-2.8.0/dune/common/parametertree.hh000066400000000000000000000234641411343567400213670ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_PARAMETERTREE_HH #define DUNE_PARAMETERTREE_HH /** \file * \brief A hierarchical structure of string parameters */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Dune { /** \brief Hierarchical structure of string parameters * \ingroup Common */ class ParameterTree { // class providing a single static parse() function, used by the // generic get() method template struct Parser; public: /** \brief storage for key lists */ typedef std::vector KeyVector; /** \brief Create new empty ParameterTree */ ParameterTree(); /** \brief test for key * * Tests whether given key exists. * * \param key key name * \return true if key exists in structure, otherwise false */ bool hasKey(const std::string& key) const; /** \brief test for substructure * * Tests whether given substructure exists. * * \param sub substructure name * \return true if substructure exists in structure, otherwise false */ bool hasSub(const std::string& sub) const; /** \brief get value reference for key * * Returns reference to value for given key name. * This creates the key, if not existent. * * \param key key name * \return reference to corresponding value */ std::string& operator[] (const std::string& key); /** \brief get value reference for key * * Returns reference to value for given key name. * This creates the key, if not existent. * * \param key key name * \return reference to corresponding value * \throw Dune::RangeError if key is not found */ const std::string& operator[] (const std::string& key) const; /** \brief print distinct substructure to stream * * Prints all entries with given prefix. * * \param stream Stream to print to * \param prefix for key and substructure names */ void report(std::ostream& stream = std::cout, const std::string& prefix = "") const; /** \brief get substructure by name * * \param sub substructure name * \return reference to substructure */ ParameterTree& sub(const std::string& sub); /** \brief get const substructure by name * * \param sub substructure name * \param fail_if_missing if true, throw an error if substructure is missing * \return reference to substructure */ const ParameterTree& sub(const std::string& sub, bool fail_if_missing = false) const; /** \brief get value as string * * Returns pure string value for given key. * * \param key key name * \param defaultValue default if key does not exist * \return value as string */ std::string get(const std::string& key, const std::string& defaultValue) const; /** \brief get value as string * * Returns pure string value for given key. * * \todo This is a hack so get("my_key", "xyz") compiles * (without this method "xyz" resolves to bool instead of std::string) * \param key key name * \param defaultValue default if key does not exist * \return value as string */ std::string get(const std::string& key, const char* defaultValue) const; /** \brief get value converted to a certain type * * Returns value as type T for given key. * * \tparam T type of returned value. * \param key key name * \param defaultValue default if key does not exist * \return value converted to T */ template T get(const std::string& key, const T& defaultValue) const { if(hasKey(key)) return get(key); else return defaultValue; } /** \brief Get value * * \tparam T Type of the value * \param key Key name * \throws RangeError if key does not exist * \throws NotImplemented Type is not supported * \return value as T */ template T get(const std::string& key) const { if(not hasKey(key)) DUNE_THROW(Dune::RangeError, "Key '" << key << "' not found in ParameterTree (prefix " + prefix_ + ")"); try { return Parser::parse((*this)[key]); } catch(const RangeError& e) { // rethrow the error and add more information DUNE_THROW(RangeError, "Cannot parse value \"" << (*this)[key] << "\" for key \"" << prefix_ << "." << key << "\"" << e.what()); } } /** \brief get value keys * * Returns a vector of all keys associated to (key,values) entries in * order of appearance * * \return reference to entry vector */ const KeyVector& getValueKeys() const; /** \brief get substructure keys * * Returns a vector of all keys associated to (key,substructure) entries * in order of appearance * * \return reference to entry vector */ const KeyVector& getSubKeys() const; protected: static const ParameterTree empty_; std::string prefix_; KeyVector valueKeys_; KeyVector subKeys_; std::map values_; std::map subs_; static std::string ltrim(const std::string& s); static std::string rtrim(const std::string& s); static std::vector split(const std::string & s); // parse into a fixed-size range of iterators template static void parseRange(const std::string &str, Iterator it, const Iterator &end) { typedef typename std::iterator_traits::value_type Value; std::istringstream s(str); // make sure we are in locale "C" s.imbue(std::locale::classic()); std::size_t n = 0; for(; it != end; ++it, ++n) { s >> *it; if(!s) DUNE_THROW(RangeError, "as a range of items of type " << className() << " (" << n << " items were extracted successfully)"); } Value dummy; s >> dummy; // now extraction should have failed, and eof should be set if(not s.fail() or not s.eof()) DUNE_THROW(RangeError, "as a range of " << n << " items of type " << className() << " (more items than the range can hold)"); } }; template struct ParameterTree::Parser { static T parse(const std::string& str) { T val; std::istringstream s(str); // make sure we are in locale "C" s.imbue(std::locale::classic()); s >> val; if(!s) DUNE_THROW(RangeError, " as a " << className()); char dummy; s >> dummy; // now extraction should have failed, and eof should be set if ((! s.fail()) || (! s.eof())) DUNE_THROW(RangeError, " as a " << className()); return val; } }; // "How do I convert a string into a wstring in C++?" "Why, that very simple // son. You just need a these hundred lines of code." // Instead im gonna restrict myself to string with charT=char here template struct ParameterTree::Parser > { static std::basic_string parse(const std::string& str) { std::string trimmed = ltrim(rtrim(str)); return std::basic_string(trimmed.begin(), trimmed.end()); } }; template<> struct ParameterTree::Parser< bool > { struct ToLower { char operator()(char c) { return std::tolower(c, std::locale::classic()); } }; static bool parse(const std::string& str) { std::string ret = str; std::transform(ret.begin(), ret.end(), ret.begin(), ToLower()); if (ret == "yes" || ret == "true") return true; if (ret == "no" || ret == "false") return false; return (Parser::parse(ret) != 0); } }; template struct ParameterTree::Parser > { static FieldVector parse(const std::string& str) { FieldVector val; parseRange(str, val.begin(), val.end()); return val; } }; template struct ParameterTree::Parser > { static std::array parse(const std::string& str) { std::array val; parseRange(str, val.begin(), val.end()); return val; } }; template struct ParameterTree::Parser > { static std::bitset parse(const std::string& str) { std::bitset val; std::vector sub = split(str); if (sub.size() != n) DUNE_THROW(RangeError, "as a bitset<" << n << "> " << "because of unmatching size " << sub.size()); for (std::size_t i=0; i::parse(sub[i]); } return val; } }; template struct ParameterTree::Parser > { static std::vector parse(const std::string& str) { std::vector sub = split(str); std::vector vec; for (unsigned int i=0; i::parse(sub[i]); vec.push_back(val); } return vec; } }; } // end namespace Dune #endif // DUNE_PARAMETERTREE_HH dune-common-2.8.0/dune/common/parametertreeparser.cc000066400000000000000000000174701411343567400225720ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include "config.h" #endif #include "parametertreeparser.hh" #include #include #include #include #include #include #include #include #include #include std::string Dune::ParameterTreeParser::ltrim(const std::string& s) { std::size_t firstNonWS = s.find_first_not_of(" \t\n\r"); if (firstNonWS!=std::string::npos) return s.substr(firstNonWS); return std::string(); } std::string Dune::ParameterTreeParser::rtrim(const std::string& s) { std::size_t lastNonWS = s.find_last_not_of(" \t\n\r"); if (lastNonWS!=std::string::npos) return s.substr(0, lastNonWS+1); return std::string(); } Dune::ParameterTree Dune::ParameterTreeParser::readINITree(const std::string& file) { std::ifstream in(file); if (!in) DUNE_THROW(Dune::IOError, "Could not open configuration file " << file); Dune::ParameterTree pt; readINITree(in, pt, "file '" + file + "'", true); return pt; } Dune::ParameterTree Dune::ParameterTreeParser::readINITree(std::istream& in) { Dune::ParameterTree pt; readINITree(in, pt, "stream", true); return pt; } void Dune::ParameterTreeParser::readINITree(std::string file, ParameterTree& pt, bool overwrite) { std::ifstream in(file.c_str()); if (!in) DUNE_THROW(Dune::IOError, "Could not open configuration file " << file); readINITree(in, pt, "file '" + file + "'", overwrite); } void Dune::ParameterTreeParser::readINITree(std::istream& in, ParameterTree& pt, bool overwrite) { readINITree(in, pt, "stream", overwrite); } void Dune::ParameterTreeParser::readINITree(std::istream& in, ParameterTree& pt, const std::string srcname, bool overwrite) { std::string prefix; std::set keysInFile; while(!in.eof()) { std::string line; getline(in, line); line = ltrim(line); if (line.size() == 0) continue; switch (line[0]) { case '#' : break; case '[' : { size_t pos = line.find(']'); if (pos != std::string::npos) { prefix = rtrim(ltrim(line.substr(1, pos-1))); if (prefix != "") prefix += "."; } } break; default : std::string::size_type comment = line.find("#"); line = line.substr(0,comment); std::string::size_type mid = line.find("="); if (mid != std::string::npos) { std::string key = prefix+rtrim(ltrim(line.substr(0, mid))); std::string value = ltrim(line.substr(mid+1)); if (value.length()>0) { // handle quoted strings if ((value[0]=='\'') || (value[0]=='"')) { char quote = value[0]; value=value.substr(1); while (*(rtrim(value).rbegin())!=quote) { if (! in.eof()) { std::string l; getline(in, l); value = value+"\n"+l; } else value = value+quote; } value = rtrim(value); value = value.substr(0,value.length()-1); } else value = rtrim(value); } if (keysInFile.count(key) != 0) DUNE_THROW(ParameterTreeParserError, "Key '" << key << "' appears twice in " << srcname << " !"); else { if(overwrite || ! pt.hasKey(key)) pt[key] = value; keysInFile.insert(key); } } break; } } } void Dune::ParameterTreeParser::readOptions(int argc, char* argv [], ParameterTree& pt) { for(int i=1; i keywords, unsigned int required, bool allow_more, bool overwrite, std::vector help) { std::string helpstr = generateHelpString(argv[0], keywords, required, help); std::vector done(keywords.size(),false); std::size_t current = 0; for (std::size_t i=1; i= done.size()) DUNE_THROW(ParameterTreeParserError, "superfluous unnamed parameter" << "\n" << helpstr); // do we overwrite an existing entry? if (!overwrite && pt[keywords[current]] != "") DUNE_THROW(ParameterTreeParserError, "parameter " << keywords[current] << " already specified" << "\n" << helpstr); pt[keywords[current]] = opt; done[current] = true; // mark key as stored } } // check that we receive all required keywords std::string missing = ""; for (unsigned int i=0; i keywords, unsigned int required, std::vector help) { static const char braces[] = "<>[]"; std::string helpstr = ""; helpstr = helpstr + "Usage: " + progname; for (std::size_t i=0; i #include #include #include #include namespace Dune { /** \brief report parser error while reading ParameterTree */ class ParameterTreeParserError : public RangeError {}; /** \brief exception thrown if the user wants to see help string this exception is only thrown if the command line parameters contain an option --help or -h */ class HelpRequest : public Exception {}; /** \brief Parsers to set up a ParameterTree from various input sources * \ingroup Common * */ class ParameterTreeParser { static std::string ltrim(const std::string& s); static std::string rtrim(const std::string& s); public: /** @name Parsing methods for the INITree file format * * INITree files should look like this * \verbatim * # this file configures fruit colors in fruitsalad * * * #these are no fruit but could also appear in fruit salad * honeydewmelon = yellow * watermelon = green * * fruit.tropicalfruit.orange = orange * * [fruit] * strawberry = red * pomegranate = red * * [fruit.pipfruit] * apple = green/red/yellow * pear = green * * [fruit.stonefruit] * cherry = red * plum = purple * * \endverbatim * * * If a '[prefix]' statement appears all following entries use this prefix * until the next '[prefix]' statement. Fruitsalads for example contain: * \verbatim * honeydewmelon = yellow * fruit.tropicalfruit.orange = orange * fruit.pipfruit.apple = green/red/yellow * fruit.stonefruit.cherry = red * \endverbatim * * All keys with a common 'prefix.' belong to the same substructure called * 'prefix'. Leading and trailing spaces and tabs are removed from the * values unless you use single or double quotes around them. Using single * or double quotes you can also have multiline values. */ //@{ /** \brief parse C++ stream * * Parses C++ stream and build hierarchical config structure. * * \param in The stream to parse * \param[out] pt The parameter tree to store the config structure. * \param overwrite Whether to overwrite already existing values. * If false, values in the stream will be ignored * if the key is already present. */ static void readINITree(std::istream& in, ParameterTree& pt, bool overwrite); /** \brief parse C++ stream * * Parses C++ stream and returns hierarchical config structure. * * \param in The stream to parse */ static Dune::ParameterTree readINITree(std::istream& in); /** \brief parse C++ stream * * Parses C++ stream and build hierarchical config structure. * * \param in The stream to parse * \param[out] pt The parameter tree to store the config structure. * \param srcname Name of the configuration source for error * messages, "stdin" or a filename. * \param overwrite Whether to overwrite already existing values. * If false, values in the stream will be ignored * if the key is already present. */ static void readINITree(std::istream& in, ParameterTree& pt, const std::string srcname = "stream", bool overwrite = true); /** \brief parse file * * Parses file with given name and build hierarchical config structure. * * \param file filename * \param[out] pt The parameter tree to store the config structure. * \param overwrite Whether to overwrite already existing values. * If false, values in the stream will be ignored * if the key is already present. */ static void readINITree(std::string file, ParameterTree& pt, bool overwrite = true); /** \brief parse file and return tree * * Parses file with given name and returns hierarchical config structure. * * \param file filename */ static Dune::ParameterTree readINITree(const std::string& file); //@} /** \brief parse command line options and build hierarchical ParameterTree structure * * The list of command line options is searched for pairs of the type -key value * (note the hyphen in front of the key). * For each such pair of options a key-value pair with the corresponding names * is then created in the ParameterTree. * * \param argc arg count * \param argv arg values * \param[out] pt The parameter tree to store the config structure. */ static void readOptions(int argc, char* argv [], ParameterTree& pt); /** * \brief read [named] command line options and build hierarchical ParameterTree structure * * Similar to pythons named options we expect the parameters in the * ordering induced by keywords, but allow the user to pass named options * in the form of --key=value. Optionally the user can pass an additional * vector with help strings. * * \param argc arg count * \param argv arg values * \param[out] pt The parameter tree to store the config structure. * \param keywords vector with keywords names * \param required number of required options (the first n keywords are required, default is all are required) * \param allow_more allow more options than these listed in keywords (default = true) * \param overwrite allow to overwrite existing options (default = true) * \param help vector containing help strings */ static void readNamedOptions(int argc, char* argv[], ParameterTree& pt, std::vector keywords, unsigned int required = std::numeric_limits::max(), bool allow_more = true, bool overwrite = true, std::vector help = std::vector()); private: static std::string generateHelpString(std::string progname, std::vector keywords, unsigned int required, std::vector help); }; } // end namespace Dune #endif // DUNE_PARAMETER_PARSER_HH dune-common-2.8.0/dune/common/path.cc000066400000000000000000000130311411343567400174360ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include namespace Dune { /** * @addtogroup Path Filesystem Paths * @ingroup Common * @{ */ /** * @file * @author Jö Fahlke * @brief Utilites for handling filesystem paths */ //! concatenate two paths std::string concatPaths(const std::string& base, const std::string& p) { if(p == "") return base; if(p[0] == '/') return p; if(base == "") return p; if(hasSuffix(base, "/")) return base+p; else return base+'/'+p; } //! sanitize a path for further processing std::string processPath(const std::string& p) { std::string result = p; std::string::size_type src, dst; // append a '/' to non-empty paths if(result != "") result += '/'; // each path component now has a trailing '/' // collapse any occurrence of multiple '/' to a single '/' dst = src = 0; while(src < result.size()) { result[dst] = result[src]; ++src; if(result[dst] == '/') while(src < result.size() && result[src] == '/') ++src; ++dst; } result.resize(dst); // the path is now free of multiple '/' in a row // collapse any occurrence of "/./" to "/" dst = src = 0; while(src < result.size()) { result[dst] = result[src]; ++src; if(result[dst] == '/') while(src+1 < result.size() && result[src] == '.' && result[src+1] == '/') src+=2; ++dst; } result.resize(dst); // there may be at most one leading "./". If so, remove it if(hasPrefix(result, "./")) result.erase(0, 2); // the path is now free of "."-components // remove any "/../" pairs src = 0; while(true) { src = result.find("/../", src); if(src == std::string::npos) break; for(dst = src; dst > 0 && result[dst-1] != '/'; --dst) ; if(result.substr(dst, src-dst) == "..") { // don't remove "../../" src += 3; continue; } if(dst == src) // special case: "" is the empty component. This means we // found a leading "/../" in an absolute path, remove "/.." result.erase(0, 3); else { // remove "/../". result.erase(dst, src-dst+4); src = dst; // try to back up one character so we are at a '/' instead of at the // beginning of a component if(src > 0) --src; } } // absolute paths are now free of ".." components, and relative paths // contain only leading ".." components return result; } //! check whether the given path indicates that it is a directory bool pathIndicatesDirectory(const std::string& p) { if(p == "") return true; if(p == ".") return true; if(p == "..") return true; if(hasSuffix(p, "/")) return true; if(hasSuffix(p, "/.")) return true; if(hasSuffix(p, "/..")) return true; else return false; } //! pretty print path std::string prettyPath(const std::string& p, bool isDirectory) { std::string result = processPath(p); // current directory if(result == "") return "."; // root directory if(result == "/") return result; // remove the trailing '/' for now result.resize(result.size()-1); // if the result ends in "..", we don't need to append '/' to make clear // it's a directory if(result == ".." || hasSuffix(result, "/..")) return result; // if it's a directory, tuck the '/' back on if(isDirectory) result += '/'; return result; } //! pretty print path std::string prettyPath(const std::string& p) { return prettyPath(p, pathIndicatesDirectory(p)); } //! compute a relative path between two paths std::string relativePath(const std::string& newbase, const std::string& p) { bool absbase = hasPrefix(newbase, "/"); bool absp = hasPrefix(p, "/"); if(absbase != absp) DUNE_THROW(NotImplemented, "relativePath: paths must be either both " "relative or both absolute: newbase=\"" << newbase << "\" " "p=\"" << p << "\""); std::string mybase = processPath(newbase); std::string myp = processPath(p); // remove as many matching leading components as possible // determine prefix length std::string::size_type preflen = 0; while(preflen < mybase.size() && preflen < myp.size() && mybase[preflen] == myp[preflen]) ++preflen; // backup to the beginning of the component while(preflen > 0 && myp[preflen-1] != '/') --preflen; mybase.erase(0, preflen); myp.erase(0,preflen); // if mybase contains leading ".." components, we're screwed if(hasPrefix(mybase, "../")) DUNE_THROW(NotImplemented, "relativePath: newbase has too many leading " "\"..\" components: newbase=\"" << newbase << "\" " "p=\"" << p << "\""); // count the number of components in mybase typedef std::iterator_traits::difference_type count_t; count_t count = std::count(mybase.begin(), mybase.end(), '/'); std::string result; // prefix with that many leading components for(count_t i = 0; i < count; ++i) result += "../"; // append what is left of p result += myp; return result; } /** @} group Path */ } dune-common-2.8.0/dune/common/path.hh000066400000000000000000000201141411343567400174500ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_PATH_HH #define DUNE_COMMON_PATH_HH #include namespace Dune { /** * @addtogroup Path * @{ */ /** * @file * @author Jö Fahlke * @brief Utilities for handling filesystem paths */ //! concatenate two paths /** * \param base The base path. * \param p The path to concatenate onto base. * * If p is an absolute path, return p. Otherwise return the * string-concatenation of base and path, possibly with a '/' in between, if * necessary. * * Some examples: * * * * * * * * * * * * * * *
base p result
anything "/abs/path" "/abs/path"
"a" "b" "a/b"
"/a" "b" "/a/b"
"a/" "b" "a/b"
"a" "b/" "a/b/"
".." "b" "../b"
"a" ".." "a/.."
"." "b" "./b"
"a" "." "a/."
"" "b" "b"
"a" "" "a"
"" "" ""
* * If both base and p are sanitized as per processPath(), and if p does not * contain any leading "../", then the result will also be sanitized. */ std::string concatPaths(const std::string& base, const std::string& p); //! sanitize a path for further processing /** * Sanitize the path as far as possible to make further processing easier. * The resulting path has the following properties: *
    *
  • The path is a series of components, each followed by a single '/'. *
  • An absolute path starts with an empty component followed by a '/', * so its first character will be '/'. This is the only case where an * empty component can occur. *
  • The path does not contain any component ".". Any such component in * the input is removed. *
  • A ".." component may only occur in the following case: A relative * path may contain a series of ".." in the beginning. Any other * occurrences of ".." in the input is collapsed with a preceding * component or simply removed if it is at the beginning of an absolute * path. *
* * \note The result is really meant for processing only since it has two * unusual properties: First, any path denoting the current directory * in the input, such as "." will result in an empty path "". Second, * any non-empty result path will have a trailing '/'. For other * uses, prettyPath() may be more appropriate. * * Some examples: * * * * * * * * * * * * * * * * * * *
p result
"" ""
"." ""
"./" ""
"a/.." ""
".." "../"
"../a" "../a/"
"a" "a/"
"a//" "a/"
"a///b" "a/b/"
"/" "/"
"/." "/"
"/.." "/"
"/a/.." "/"
"/a" "/a/"
"/a/" "/a/"
"/../a/" "/a/"
*/ std::string processPath(const std::string& p); //! check whether the given path indicates that it is a directory /** * In particular the following kinds of paths indicate a directory: *
    *
  • The empty path (denotes the current directory), *
  • any path with a trailing '/', *
  • any path whose last component is "." or "..". *
*/ bool pathIndicatesDirectory(const std::string& p); //! pretty print path /** * \param p Path to pretty-print. * \param isDirectory Whether to append a '/' to make clear this is a * directory. * * Pretty print the path. This removes any duplicate '/' and any * superfluous occurrences of ".." and ".". The resulting path will have a * trailing '/' if it is the root path or if isDirectory is true. It will * however not have a trailing '/' if it is otherwise clear that it is a * directory -- i.e. if its last component is "." or "..". * * Some examples: * * * * * * * * * * * * * * * * * * * * * * * * * *
p isDirectory result
"" anything "."
"." anything "."
"./" anything "."
"a/.." anything "."
".." anything ".."
"../a" true "../a/"
"../a" false "../a"
"a" true "a/"
"a" false "a"
"a//" true "a/"
"a//" false "a"
"a///b" true "a/b/"
"a///b" false "a/b"
"/" anything "/"
"/." anything "/"
"/.." anything "/"
"/a/.." anything "/"
"/a" true "/a/"
"/a" false "/a"
"/a/" true "/a/"
"/a/" false "/a"
"/../a/" true "/a/"
"/../a/" false "/a"
*/ std::string prettyPath(const std::string& p, bool isDirectory); //! pretty print path /** * \param p Path to pretty-print. * * This is like prettyPath(const std::string& p, bool isDirectory) with * isDirectory automatically determined using pathIndicatesDirectory(p). */ std::string prettyPath(const std::string& p); //! compute a relative path between two paths /** * \param newbase Base path for the resulting relative path. * \param p Path re sulting path should resolve to, when taken * reltively to newbase. * * Compute a relative path from newbase to p. newbase is assumed to be a * directory. p and newbase should either both be absolute, or both be * relative. In the latter case they are assumed to both be relative to * the same unspecified directory. The has the form of something sanitized * by processPath(). * * \throw NotImplemented The condition that newbase and p must both be * relative or both be absolute does not hold. * \throw NotImplemented After sanitization newbase has more leading ".." * components than p. */ std::string relativePath(const std::string& newbase, const std::string& p); /** @} group Path */ } #endif // DUNE_COMMON_PATH_HH dune-common-2.8.0/dune/common/poolallocator.hh000066400000000000000000000342631411343567400214000ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_POOLALLOCATOR_HH #define DUNE_COMMON_POOLALLOCATOR_HH /** \file * \brief An stl-compliant pool allocator */ #include #include #include #include #include #ifndef DOXYGEN // forward declarations. // we need to know the test function to declare it friend template struct testPoolMain; #endif namespace Dune { template class Pool; template class PoolAllocator; } namespace std { /* template inline ostream& operator<<(ostream& os, Dune::Pool& pool) { os<<"pool="<<&pool<<" allocated_="< inline ostream& operator<<(ostream& os, Dune::PoolAllocator& pool) { os< class Pool { // make the test function friend friend struct ::testPoolMain; //friend std::ostream& std::operator<<<>(std::ostream&,Pool&); template< class, std::size_t > friend class PoolAllocator; private: /** @brief Reference to next free element. */ struct Reference { Reference *next_; }; public: /** @brief The type of object we allocate memory for. */ typedef T MemberType; enum { /** * @brief The size of a union of Reference and MemberType. */ unionSize = ((sizeof(MemberType) < sizeof(Reference)) ? sizeof(Reference) : sizeof(MemberType)), /** * @brief Size requirement. At least one object has to * stored. */ size = ((sizeof(MemberType) <= s && sizeof(Reference) <= s) ? s : unionSize), /** * @brief The alignment that suits both the MemberType and * the Reference (i.e. their least common multiple). */ alignment = std::lcm(alignof(MemberType), alignof(Reference)), /** * @brief The aligned size of the type. * * This size is bigger than sizeof of the type and a multiple of * the alignment requirement. */ alignedSize = ((unionSize % alignment == 0) ? unionSize : ((unionSize / alignment + 1) * alignment)), /** * @brief The size of each chunk memory chunk. * * Will be adapted to be a multiple of the alignment */ chunkSize = ((size % alignment == 0) ? size : ((size / alignment + 1)* alignment)), /** * @brief The number of element each chunk can hold. */ elements = (chunkSize / alignedSize) }; private: /** @brief Chunk of memory managed by the pool. */ struct Chunk { //friend int testPool(); /** @brief The memory we hold. */ alignas(alignment) char chunk_[chunkSize]; /** @brief The next element */ Chunk *next_; }; public: /** @brief Constructor. */ inline Pool(); /** @brief Destructor. */ inline ~Pool(); /** * @brief Get a new or recycled object * @return A pointer to the object memory. */ inline void* allocate(); /** * @brief Free an object. * @param o The pointer to memory block of the object. */ inline void free(void* o); /** * @brief Print elements in pool for debugging. */ inline void print(std::ostream& os); private: // Prevent Copying! Pool(const Pool&); void operator=(const Pool& pool) const; /** @brief Grow our pool.*/ inline void grow(); /** @brief The first free element. */ Reference *head_; /** @brief Our memory chunks. */ Chunk *chunks_; /* @brief The number of currently allocated elements. */ //size_t allocated_; }; /** * @brief An allocator managing a pool of objects for reuse. * * This allocator is specifically useful for small data types * where new and delete are too expensive. * * It uses a pool of memory chunks where the objects will be allocated. * This means that assuming that N objects fit into memory only every N-th * request for an object will result in memory allocation. * * @warning It is not suitable * for the use in standard containers as it cannot allocate * arrays of arbitrary size * * \tparam T The type that will be allocated. * \tparam s The number of elements to fit into one memory chunk. */ template class PoolAllocator { //friend std::ostream& std::operator<<<>(std::ostream&,PoolAllocator&); public: /** * @brief Type of the values we construct and allocate. */ typedef T value_type; enum { /** * @brief The number of objects to fit into one memory chunk * allocated. */ size=s*sizeof(value_type) }; /** * @brief The pointer type. */ typedef T* pointer; /** * @brief The constant pointer type. */ typedef const T* const_pointer; /** * @brief The reference type. */ typedef T& reference; /** * @brief The constant reference type. */ typedef const T& const_reference; /** * @brief The size type. */ typedef std::size_t size_type; /** * @brief The difference_type. */ typedef std::ptrdiff_t difference_type; /** * @brief Constructor. */ inline PoolAllocator(); /** * @brief Copy Constructor that does not copy the memory pool. */ template inline PoolAllocator(const PoolAllocator&) { // we allow copying but never copy the pool // to have a clear ownership of allocated pointers. } /// \brief Copy constructor that does not copy the memory pool. PoolAllocator(const PoolAllocator&) { // we allow copying but never copy the pool // to have a clear ownership of allocated pointers. // For this behaviour we have to implement // the copy constructor, because the default // one would copy the pool and deallocation // of it would break. } /** * @brief Allocates objects. * @param n The number of objects to allocate. Has to be one! * @param hint Ignored hint. * @return A pointer tp the allocated elements. */ inline pointer allocate(std::size_t n, const_pointer hint=0); /** * @brief Free objects. * * Does not call the destructor! * @param n The number of objects to free. Has to be one! * @param p Pointer to the first object. */ inline void deallocate(pointer p, std::size_t n); /** * @brief Construct an object. * @param p Pointer to the object. * @param value The value to initialize it to. */ inline void construct(pointer p, const_reference value); /** * @brief Destroy an object without freeing memory. * @param p Pointer to the object. */ inline void destroy(pointer p); /** * @brief Convert a reference to a pointer. */ inline pointer address(reference x) const { return &x; } /** * @brief Convert a reference to a pointer. */ inline const_pointer address(const_reference x) const { return &x; } /** * @brief Not correctly implemented, yet! */ inline int max_size() const noexcept { return 1; } /** * @brief Rebind the allocator to another type. */ template struct rebind { typedef PoolAllocator other; }; /** @brief The type of the memory pool we use. */ typedef Pool PoolType; private: /** * @brief The underlying memory pool. */ PoolType memoryPool_; }; // specialization for void template class PoolAllocator { public: typedef void* pointer; typedef const void* const_pointer; // reference to void members are impossible. typedef void value_type; template struct rebind { typedef PoolAllocator other; }; }; template bool operator==(const PoolAllocator&, const PoolAllocator&) { return false; } template bool operator!=(const PoolAllocator&, const PoolAllocator&) { return true; } template bool operator==(const PoolAllocator& p1, const PoolAllocator& p2) { return &p1==&p2; } template bool operator!=(const PoolAllocator& p1, const PoolAllocator& p2) { return &p1 != &p2; } template bool operator==(const PoolAllocator&, const PoolAllocator&) { return false; } template bool operator!=(const PoolAllocator&, const PoolAllocator&) { return true; } template bool operator==(const PoolAllocator& p1, const PoolAllocator& p2) { return &p1==&p2; } template bool operator!=(const PoolAllocator& p1, const PoolAllocator& p2) { return &p1!=&p2; } template inline Pool::Pool() : head_(0), chunks_(0) //, allocated_(0) { static_assert(sizeof(T)<=unionSize, "Library Error: type T is too big"); static_assert(sizeof(Reference)<=unionSize, "Library Error: type of referene is too big"); static_assert(unionSize<=alignedSize, "Library Error: alignedSize too small"); static_assert(sizeof(T)<=chunkSize, "Library Error: chunkSize must be able to hold at least one value"); static_assert(sizeof(Reference)<=chunkSize, "Library Error: chunkSize must be able to hold at least one reference"); static_assert(chunkSize % alignment == 0, "Library Error: compiler cannot calculate!"); static_assert(elements>=1, "Library Error: we need to hold at least one element!"); static_assert(elements*alignedSize<=chunkSize, "Library Error: aligned elements must fit into chuck!"); } template inline Pool::~Pool() { /* if(allocated_!=0) std::cerr<<"There are still "< " <(this)<<"! This is a memory leak and might result in segfaults" <next_; delete tmp; } } template inline void Pool::print(std::ostream& os) { Chunk* current=chunks_; while(current) { os<next_; } os< inline void Pool::grow() { Chunk *newChunk = new Chunk; newChunk->next_ = chunks_; chunks_ = newChunk; char* start = chunks_->chunk_; char* last = &start[elements*alignedSize]; Reference* ref = new (start) (Reference); // grow is only called if head==0, assert(!head_); head_ = ref; for(char* element=start+alignedSize; elementnext_ = next; ref = next; } ref->next_=0; } template inline void Pool::free(void* b) { if(b) { #ifndef NDEBUG Chunk* current=chunks_; while(current) { if(static_cast(current->chunk_)<=b && static_cast(current->chunk_+chunkSize)>b) break; current=current->next_; } if(!current) throw std::bad_alloc(); #endif Reference* freed = static_cast(b); freed->next_ = head_; head_ = freed; //--allocated_; } else { std::cerr<< "Tried to free null pointer! "< inline void* Pool::allocate() { if(!head_) grow(); Reference* p = head_; head_ = p->next_; //++allocated_; return p; } template inline PoolAllocator::PoolAllocator() { } template inline typename PoolAllocator::pointer PoolAllocator::allocate(std::size_t n, const_pointer) { if(n==1) return static_cast(memoryPool_.allocate()); else throw std::bad_alloc(); } template inline void PoolAllocator::deallocate(pointer p, std::size_t n) { for(size_t i=0; i inline void PoolAllocator::construct(pointer p, const_reference value) { ::new (static_cast(p))T(value); } template inline void PoolAllocator::destroy(pointer p) { p->~T(); } /** @} */ } #endif dune-common-2.8.0/dune/common/power.hh000066400000000000000000000017271411343567400176610ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_POWER_HH #define DUNE_COMMON_POWER_HH /** \file \brief Various implementations of the power function for run-time and static arguments */ #include namespace Dune { /** @addtogroup Common @{ */ /** \brief Calculates m^p at compile time * \deprecated Please use the method `power` from `math.hh` instead! */ template struct StaticPower { /** \brief power stores m^p */ static constexpr int power = Dune::power(m,p); }; /** \brief Compute power for a run-time mantissa and a compile-time integer exponent * * \deprecated Please use the method `power` from `math.hh` instead! * * \tparam p The exponent */ template struct Power { template static constexpr auto eval(const T & a) { return power(a,p); } }; } #endif dune-common-2.8.0/dune/common/precision.hh000066400000000000000000000017231411343567400205140ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_PRECISION_HH #define DUNE_PRECISION_HH /** \file * \brief Various precision settings for calculations with FieldMatrix and FieldVector */ #include namespace Dune { /** @addtogroup DenseMatVec @{ */ /** * @brief Precisions for calculations with FieldMatrix and FieldVector. */ template class FMatrixPrecision { public: //! return threshold to declare matrix singular static ctype absolute_limit () { return _absolute; } //! set singular threshold static void set_absolute_limit (ctype absthres) { _absolute = absthres; } private: // just to demonstrate some state information static ctype _absolute; }; template ctype FMatrixPrecision::_absolute = 1E-80; /** @} end documentation */ } // end namespace #endif dune-common-2.8.0/dune/common/promotiontraits.hh000066400000000000000000000020141411343567400217700ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_PROMOTIONTRAITS_HH #define DUNE_PROMOTIONTRAITS_HH #include namespace Dune { /** * @file * @brief Compute type of the result of an arithmetic operation involving two different number types. * * @author Matthias Wohlmuth */ /** @addtogroup Common * * @{ */ /** \brief Compute type of the result of an arithmetic operation involving two different number types. */ template struct PromotionTraits { typedef decltype(std::declval()+std::declval()) PromotedType; }; // Specialization for the case of two equal types // One should think that the generic template should handle this case as well. // However, the fvectortest.cc unit test fails without it if ENABLE_GMP is set. template struct PromotionTraits { typedef T1 PromotedType; }; /** @} */ } // end namespace #endif // DUNE_PROMOTIONTRAITS_HH dune-common-2.8.0/dune/common/propertymap.hh000066400000000000000000000176431411343567400211130ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_PROPERTYMAP_HH #define DUNE_PROPERTYMAP_HH #include #include #include namespace Dune { template struct PropertyMapTraits { /** * @brief The type of the key of the property map. */ typedef typename PM::KeyType KeyType; /** * @brief The type of the values of the property map. */ typedef typename PM::ValueType ValueType; /** * @brief The type of the reference to the values. */ typedef typename PM::Reference Reference; /** * @brief The category the property map belongs to. */ typedef typename PM::Category Category; }; /** @brief Tag for the category of readable property maps. */ struct ReadablePropertyMapTag {}; /** @brief Tag for the category of writable property maps. */ struct WritablePropertyMapTag {}; /** * @brief Tag for the category of readable and writable property * maps. */ struct ReadWritePropertyMapTag : public ReadablePropertyMapTag, public WritablePropertyMapTag {}; /** * @brief Tag for the category of lvalue property maps. */ struct LvaluePropertyMapTag : public ReadWritePropertyMapTag {}; template struct PropertyMapTraits { typedef T ValueType; typedef ValueType& Reference; typedef std::ptrdiff_t KeyType; typedef LvaluePropertyMapTag Category; }; template struct PropertyMapTraits { typedef T ValueType; typedef const ValueType& Reference; typedef std::ptrdiff_t KeyType; typedef LvaluePropertyMapTag Category; }; template struct RAPropertyMapHelper {}; template inline Reference get(const RAPropertyMapHelper& pmap, const Key& key) { return static_cast(pmap)[key]; } template inline void put(const RAPropertyMapHelper& pmap, const Key& key, const Value& value) { static_assert(std::is_convertible::value, "WritablePropertyMapTag required!"); static_cast(pmap)[key] = value; } /** * @brief Adapter to turn a random access iterator into a property map. */ template::value_type, class R = typename std::iterator_traits::reference> class IteratorPropertyMap : public RAPropertyMapHelper > { public: /** * @brief The type of the random access iterator. */ typedef RAI RandomAccessIterator; /** * @brief The type of the index map. * * This will convert the KeyType to std::ptrdiff_t via operator[](). */ typedef IM IndexMap; /** * @brief The key type of the property map. */ typedef typename IndexMap::KeyType KeyType; /** * @brief The value type of the property map. */ typedef T ValueType; /** * @brief The reference type of the property map. */ typedef R Reference; /** * @brief The category of this property map. */ typedef LvaluePropertyMapTag Category; /** * @brief Constructor. * @param iter The random access iterator that * provides the mapping. * @param im The index map that maps the KeyType * to the difference_type of the iterator. */ inline IteratorPropertyMap(RandomAccessIterator iter, const IndexMap& im=IndexMap()) : iter_(iter), indexMap_(im) {} /** @brief Constructor. */ inline IteratorPropertyMap() : iter_(), indexMap_() {} /** @brief Access the a value by reference. */ inline Reference operator[](KeyType key) const { return *(iter_ + get(indexMap_, key)); } private: /** @brief The underlying iterator. */ RandomAccessIterator iter_; /** @brief The index map to use for the lookup. */ IndexMap indexMap_; }; /** * @brief An adapter to turn an unique associative container * into a property map. */ template class AssociativePropertyMap : RAPropertyMapHelper > { /** * @brief The type of the unique associative container. */ typedef T UniqueAssociativeContainer; /** * @brief The key type of the property map. */ typedef typename UniqueAssociativeContainer::value_type::first_type KeyType; /** * @brief The value type of the property map. */ typedef typename UniqueAssociativeContainer::value_type::second_type ValueType; /** * @brief The reference type of the property map. */ typedef ValueType& Reference; /** * @brief The category of the property map. */ typedef LvaluePropertyMapTag Category; /** @brief Constructor */ inline AssociativePropertyMap() : map_(0) {} /** @brief Constructor. */ inline AssociativePropertyMap(UniqueAssociativeContainer& map) : map_(&map) {} /** * @brief Access a property. * @param key The key of the property. */ inline Reference operator[](KeyType key) const { return map_->find(key)->second; } private: UniqueAssociativeContainer* map_; }; /** * @brief An adaptor to turn an unique associative container * into a property map. */ template class ConstAssociativePropertyMap : RAPropertyMapHelper > { /** * @brief The type of the unique associative container. */ typedef T UniqueAssociativeContainer; /** * @brief The key type of the property map. */ typedef typename UniqueAssociativeContainer::value_type::first_type KeyType; /** * @brief The value type of the property map. */ typedef typename UniqueAssociativeContainer::value_type::second_type ValueType; /** * @brief The reference type of the property map. */ typedef const ValueType& Reference; /** * @brief The category of the property map. */ typedef LvaluePropertyMapTag Category; /** @brief Constructor */ inline ConstAssociativePropertyMap() : map_(0) {} /** @brief Constructor. */ inline ConstAssociativePropertyMap(const UniqueAssociativeContainer& map) : map_(&map) {} /** * @brief Access a property. * @param key The key of the property. */ inline Reference operator[](KeyType key) const { return map_->find(key)->second; } private: const UniqueAssociativeContainer* map_; }; /** * @brief A property map that applies the identity function to integers. */ struct IdentityMap : public RAPropertyMapHelper { /** @brief The key type of the map. */ typedef std::size_t KeyType; /** @brief The value type of the map. */ typedef std::size_t ValueType; /** @brief The reference type of the map. */ typedef std::size_t Reference; /** @brief The category of the map. */ typedef ReadablePropertyMapTag Category; inline ValueType operator[](const KeyType& key) const { return key; } }; /** * @brief Selector for the property map type. * * If present the type of the property map is accessible via the typedef Type. */ template struct PropertyMapTypeSelector { /** * @brief the tag identifying the property. */ typedef T Tag; /** * @brief The container type to whose entries the properties * are attached. */ typedef C Container; }; } #endif dune-common-2.8.0/dune/common/proxymemberaccess.hh000066400000000000000000000070051411343567400222530ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_PROXYMEMBERACCESS_HH #define DUNE_COMMON_PROXYMEMBERACCESS_HH /** * \file * \brief infrastructure for supporting operator->() on both references and proxies * \ingroup CxxUtilities */ #include #include namespace Dune { namespace Impl { // helper struct to store a temporary / proxy // for the duration of the member access template struct member_access_proxy_holder { // only support moving the temporary into the holder object member_access_proxy_holder(T&& t) : _t(std::move(t)) {} // The object is fundamentally a temporary, i.e. an rvalue, // const T* operator->() const { return &_t; } T _t; }; } // end Impl namespace #ifdef DOXYGEN //! Transparent support for providing member access to both lvalues and rvalues (temporary proxies). /** * If an iterator facade (like entity iterators) wants to allow the embedded implementation to * return either an (internally stored) reference or a temporary object and expose these two * behaviors to enable performance optimizations, operator->() needs special handling: If the * implementation returns a reference, operator->() in the facade can simply return the address * of the referenced object, but if the returned object is a temporary, we need to capture and * store it in a helper object to make sure it outlives the member access. This function transparently * supports both variants. It should be used like this: * * \code * class iterator * { * ... * * decltype(handle_proxy_member_access(implementation.dereference())) * operator->() const * { * return handle_proxy_member_access(implementation.dereference()); * } * * ... * }; * \endcode * * \note This function exploits the special type deduction rules for unqualified rvalue references * to distinguish between lvalues and rvalues and thus needs to be passed the object returned * by the implementation. * * \ingroup CxxUtilities */ template pointer_or_proxy_holder handle_proxy_member_access(T&& t); #else // DOXYGEN // This version matches lvalues (the C++ type deduction rules state that // the T&& signature deduces to a reference iff the argument is an lvalue). // As the argument is an lvalue, we do not have to worry about its lifetime // and can just return its address. template inline typename std::enable_if< std::is_lvalue_reference::value, typename std::add_pointer< typename std::remove_reference< T >::type >::type >::type handle_proxy_member_access(T&& target) { return ⌖ } // This version matches rvalues (the C++ type deduction rules state that // the T&& signature deduces to a non-reference iff the argument is an rvalue). // In this case, we have to capture the rvalue in a new object to make sure it // is kept alive for the duration of the member access. For this purpose, we move // it into a member_access_proxy_holder instance. template inline typename std::enable_if< !std::is_lvalue_reference::value, Impl::member_access_proxy_holder >::type handle_proxy_member_access(T&& target) { return {std::forward(target)}; } #endif // DOXYGEN } // namespace Dune #endif // DUNE_COMMON_PROXYMEMBERACCESS_HH dune-common-2.8.0/dune/common/quadmath.hh000066400000000000000000000452161411343567400203320ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_QUADMATH_HH #define DUNE_QUADMATH_HH #if HAVE_QUADMATH #include #include #include #include #include // abs #include #include #include #include #include #include namespace Dune { namespace Impl { // forward declaration class Float128; } // end namespace Impl using Impl::Float128; // The purpose of this namespace is to move the `` function overloads // out of namespace `Dune`, see AlignedNumber in debugalign.hh. namespace Impl { using float128_t = __float128; /// Wrapper for quad-precision type __float128 class Float128 { float128_t value_ = 0.0q; public: constexpr Float128() = default; constexpr Float128(const float128_t& value) noexcept : value_(value) {} // constructor from any floating-point or integer type template ::value, int> = 0> constexpr Float128(const T& value) noexcept : value_(value) {} // constructor from pointer to null-terminated byte string explicit Float128(const char* str) noexcept : value_(strtoflt128(str, NULL)) {} // accessors constexpr operator float128_t() const noexcept { return value_; } constexpr float128_t const& value() const noexcept { return value_; } constexpr float128_t& value() noexcept { return value_; } // I/O template friend std::basic_istream& operator>>(std::basic_istream& in, Float128& x) { std::string buf; buf.reserve(128); in >> buf; x.value() = strtoflt128(buf.c_str(), NULL); return in; } template friend std::basic_ostream& operator<<(std::basic_ostream& out, const Float128& x) { const std::size_t bufSize = 128; CharT buf[128]; std::string format = "%." + std::to_string(out.precision()) + "Q" + ((out.flags() | std::ios_base::scientific) ? "e" : "f"); const int numChars = quadmath_snprintf(buf, bufSize, format.c_str(), x.value()); if (std::size_t(numChars) >= bufSize) { DUNE_THROW(Dune::RangeError, "Failed to print Float128 value: buffer overflow"); } out << buf; return out; } // Increment, decrement constexpr Float128& operator++() noexcept { ++value_; return *this; } constexpr Float128& operator--() noexcept { --value_; return *this; } constexpr Float128 operator++(int) noexcept { Float128 tmp{*this}; ++value_; return tmp; } constexpr Float128 operator--(int) noexcept { Float128 tmp{*this}; --value_; return tmp; } // unary operators constexpr Float128 operator+() const noexcept { return Float128{+value_}; } constexpr Float128 operator-() const noexcept { return Float128{-value_}; } // assignment operators #define DUNE_ASSIGN_OP(OP) \ constexpr Float128& operator OP(const Float128& u) noexcept \ { \ value_ OP float128_t(u); \ return *this; \ } \ static_assert(true, "Require semicolon to unconfuse editors") DUNE_ASSIGN_OP(+=); DUNE_ASSIGN_OP(-=); DUNE_ASSIGN_OP(*=); DUNE_ASSIGN_OP(/=); #undef DUNE_ASSIGN_OP }; // end class Float128 // binary operators: // For symmetry provide overloads with arithmetic types // in the first or second argument. #define DUNE_BINARY_OP(OP) \ constexpr Float128 operator OP(const Float128& t, \ const Float128& u) noexcept \ { \ return Float128{float128_t(t) OP float128_t(u)}; \ } \ constexpr Float128 operator OP(const float128_t& t, \ const Float128& u) noexcept \ { \ return Float128{t OP float128_t(u)}; \ } \ constexpr Float128 operator OP(const Float128& t, \ const float128_t& u) noexcept \ { \ return Float128{float128_t(t) OP u}; \ } \ template ::value, int> = 0> \ constexpr Float128 operator OP(const T& t, \ const Float128& u) noexcept \ { \ return Float128{float128_t(t) OP float128_t(u)}; \ } \ template ::value, int> = 0> \ constexpr Float128 operator OP(const Float128& t, \ const U& u) noexcept \ { \ return Float128{float128_t(t) OP float128_t(u)}; \ } \ static_assert(true, "Require semicolon to unconfuse editors") DUNE_BINARY_OP(+); DUNE_BINARY_OP(-); DUNE_BINARY_OP(*); DUNE_BINARY_OP(/); #undef DUNE_BINARY_OP // logical operators: // For symmetry provide overloads with arithmetic types // in the first or second argument. #define DUNE_BINARY_BOOL_OP(OP) \ constexpr bool operator OP(const Float128& t, \ const Float128& u) noexcept \ { \ return float128_t(t) OP float128_t(u); \ } \ template ::value, int> = 0> \ constexpr bool operator OP(const T& t, \ const Float128& u) noexcept \ { \ return float128_t(t) OP float128_t(u); \ } \ template ::value, int> = 0> \ constexpr bool operator OP(const Float128& t, \ const U& u) noexcept \ { \ return float128_t(t) OP float128_t(u); \ } \ static_assert(true, "Require semicolon to unconfuse editors") DUNE_BINARY_BOOL_OP(==); DUNE_BINARY_BOOL_OP(!=); DUNE_BINARY_BOOL_OP(<); DUNE_BINARY_BOOL_OP(>); DUNE_BINARY_BOOL_OP(<=); DUNE_BINARY_BOOL_OP(>=); #undef DUNE_BINARY_BOOL_OP // Overloads for the cmath functions // function with name `name` redirects to quadmath function `func` #define DUNE_UNARY_FUNC(name,func) \ inline Float128 name(const Float128& u) noexcept \ { \ return Float128{func (float128_t(u))}; \ } \ static_assert(true, "Require semicolon to unconfuse editors") // like DUNE_UNARY_FUNC but with cutom return type #define DUNE_CUSTOM_UNARY_FUNC(type,name,func) \ inline type name(const Float128& u) noexcept \ { \ return (type)(func (float128_t(u))); \ } \ static_assert(true, "Require semicolon to unconfuse editors") // redirects to quadmath function with two arguments #define DUNE_BINARY_FUNC(name,func) \ inline Float128 name(const Float128& t, \ const Float128& u) noexcept \ { \ return Float128{func (float128_t(t), float128_t(u))}; \ } \ static_assert(true, "Require semicolon to unconfuse editors") DUNE_UNARY_FUNC(abs, fabsq); DUNE_UNARY_FUNC(acos, acosq); DUNE_UNARY_FUNC(acosh, acoshq); DUNE_UNARY_FUNC(asin, asinq); DUNE_UNARY_FUNC(asinh, asinhq); DUNE_UNARY_FUNC(atan, atanq); DUNE_UNARY_FUNC(atanh, atanhq); DUNE_UNARY_FUNC(cbrt, cbrtq); DUNE_UNARY_FUNC(ceil, ceilq); DUNE_UNARY_FUNC(cos, cosq); DUNE_UNARY_FUNC(cosh, coshq); DUNE_UNARY_FUNC(erf, erfq); DUNE_UNARY_FUNC(erfc, erfcq); DUNE_UNARY_FUNC(exp, expq); DUNE_UNARY_FUNC(expm1, expm1q); DUNE_UNARY_FUNC(fabs, fabsq); DUNE_UNARY_FUNC(floor, floorq); DUNE_CUSTOM_UNARY_FUNC(int, ilogb, ilogbq); DUNE_UNARY_FUNC(lgamma, lgammaq); DUNE_CUSTOM_UNARY_FUNC(long long int, llrint, llrintq); DUNE_CUSTOM_UNARY_FUNC(long long int, llround, llroundq); DUNE_UNARY_FUNC(log, logq); DUNE_UNARY_FUNC(log10, log10q); DUNE_UNARY_FUNC(log1p, log1pq); DUNE_UNARY_FUNC(log2, log2q); // DUNE_UNARY_FUNC(logb, logbq); // not available in gcc5 DUNE_CUSTOM_UNARY_FUNC(long int, lrint, lrintq); DUNE_CUSTOM_UNARY_FUNC(long int, lround, lroundq); DUNE_UNARY_FUNC(nearbyint, nearbyintq); DUNE_BINARY_FUNC(nextafter, nextafterq); DUNE_BINARY_FUNC(pow, powq); // overload for integer argument see below DUNE_UNARY_FUNC(rint, rintq); DUNE_UNARY_FUNC(round, roundq); DUNE_UNARY_FUNC(sin, sinq); DUNE_UNARY_FUNC(sinh, sinhq); DUNE_UNARY_FUNC(sqrt, sqrtq); DUNE_UNARY_FUNC(tan, tanq); DUNE_UNARY_FUNC(tanh, tanhq); DUNE_UNARY_FUNC(tgamma, tgammaq); DUNE_UNARY_FUNC(trunc, truncq); DUNE_CUSTOM_UNARY_FUNC(bool, isfinite, finiteq); DUNE_CUSTOM_UNARY_FUNC(bool, isinf, isinfq); DUNE_CUSTOM_UNARY_FUNC(bool, isnan, isnanq); DUNE_CUSTOM_UNARY_FUNC(bool, signbit, signbitq); #undef DUNE_UNARY_FUNC #undef DUNE_CUSTOM_UNARY_FUNC #undef DUNE_BINARY_FUNC // like DUNE_BINARY_FUNC but provide overloads with arithmetic // types in the first or second argument. #define DUNE_BINARY_ARITHMETIC_FUNC(name,func) \ inline Float128 name(const Float128& t, \ const Float128& u) noexcept \ { \ return Float128{func (float128_t(t), float128_t(u))}; \ } \ template ::value, int> = 0> \ inline Float128 name(const T& t, \ const Float128& u) noexcept \ { \ return Float128{func (float128_t(t), float128_t(u))}; \ } \ template ::value, int> = 0> \ inline Float128 name(const Float128& t, \ const U& u) noexcept \ { \ return Float128{func (float128_t(t), float128_t(u))}; \ } \ static_assert(true, "Require semicolon to unconfuse editors") DUNE_BINARY_ARITHMETIC_FUNC(atan2,atan2q); DUNE_BINARY_ARITHMETIC_FUNC(copysign,copysignq); DUNE_BINARY_ARITHMETIC_FUNC(fdim,fdimq); DUNE_BINARY_ARITHMETIC_FUNC(fmax,fmaxq); DUNE_BINARY_ARITHMETIC_FUNC(fmin,fminq); DUNE_BINARY_ARITHMETIC_FUNC(fmod,fmodq); DUNE_BINARY_ARITHMETIC_FUNC(hypot,hypotq); DUNE_BINARY_ARITHMETIC_FUNC(remainder,remainderq); #undef DUNE_BINARY_ARITHMETIC_FUNC // some more cmath functions with special signature inline Float128 fma(const Float128& t, const Float128& u, const Float128& v) { return Float128{fmaq(float128_t(t),float128_t(u),float128_t(v))}; } inline Float128 frexp(const Float128& u, int* p) { return Float128{frexpq(float128_t(u), p)}; } inline Float128 ldexp(const Float128& u, int p) { return Float128{ldexpq(float128_t(u), p)}; } inline Float128 remquo(const Float128& t, const Float128& u, int* quo) { return Float128{remquoq(float128_t(t), float128_t(u), quo)}; } inline Float128 scalbln(const Float128& u, long int e) { return Float128{scalblnq(float128_t(u), e)}; } inline Float128 scalbn(const Float128& u, int e) { return Float128{scalbnq(float128_t(u), e)}; } /// \brief Overload of `pow` function for integer exponents. // NOTE: This is much faster than a pow(x, Float128(p)) call // NOTE: This is a modified version of boost::math::cstdfloat::detail::pown // (adapted to the type Float128) that is part of the Boost 1.65 Math toolkit 2.8.0 // and is implemented by Christopher Kormanyos, John Maddock, and Paul A. Bristow, // distributed under the Boost Software License, Version 1.0 // (See http://www.boost.org/LICENSE_1_0.txt) template ::value, int> = 0> inline Float128 pow(const Float128& x, const Int p) { static const Float128 max_value = FLT128_MAX; static const Float128 min_value = FLT128_MIN; static const Float128 inf_value = float128_t{1} / float128_t{0}; const bool isneg = (x < 0); const bool isnan = (x != x); const bool isinf = (isneg ? bool(-x > max_value) : bool(+x > max_value)); if (isnan) { return x; } if (isinf) { return Float128{nanq("")}; } const Float128 abs_x = (isneg ? -x : x); if (p < Int(0)) { if (abs_x < min_value) return (isneg ? -inf_value : +inf_value); else return Float128(1) / pow(x, Int(-p)); } if (p == Int(0)) { return Float128(1); } if (p == Int(1)) { return x; } if (abs_x > max_value) return (isneg ? -inf_value : +inf_value); if (p == Int(2)) { return (x * x); } if (p == Int(3)) { return ((x * x) * x); } if (p == Int(4)) { const Float128 x2 = (x * x); return (x2 * x2); } Float128 result = ((p % Int(2)) != Int(0)) ? x : Float128(1); Float128 xn = x; // binary powers of x Int p2 = p; while (Int(p2 /= 2) != Int(0)) { xn *= xn; // Square xn for each binary power const bool has_binary_power = (Int(p2 % Int(2)) != Int(0)); if (has_binary_power) result *= xn; } return result; } } // end namespace Impl template <> struct IsNumber : public std::true_type {}; } // end namespace Dune namespace std { #ifndef NO_STD_NUMERIC_LIMITS_SPECIALIZATION template <> class numeric_limits { using Float128 = Dune::Impl::Float128; using float128_t = Dune::Impl::float128_t; public: static constexpr bool is_specialized = true; static constexpr Float128 min() noexcept { return FLT128_MIN; } static constexpr Float128 max() noexcept { return FLT128_MAX; } static constexpr Float128 lowest() noexcept { return -FLT128_MAX; } static constexpr int digits = FLT128_MANT_DIG; static constexpr int digits10 = 34; static constexpr int max_digits10 = 36; static constexpr bool is_signed = true; static constexpr bool is_integer = false; static constexpr bool is_exact = false; static constexpr int radix = 2; static constexpr Float128 epsilon() noexcept { return FLT128_EPSILON; } static constexpr Float128 round_error() noexcept { return float128_t{0.5}; } static constexpr int min_exponent = FLT128_MIN_EXP; static constexpr int min_exponent10 = FLT128_MIN_10_EXP; static constexpr int max_exponent = FLT128_MAX_EXP; static constexpr int max_exponent10 = FLT128_MAX_10_EXP; static constexpr bool has_infinity = true; static constexpr bool has_quiet_NaN = true; static constexpr bool has_signaling_NaN = false; static constexpr float_denorm_style has_denorm = denorm_present; static constexpr bool has_denorm_loss = false; static constexpr Float128 infinity() noexcept { return float128_t{1}/float128_t{0}; } static Float128 quiet_NaN() noexcept { return nanq(""); } static constexpr Float128 signaling_NaN() noexcept { return float128_t{}; } static constexpr Float128 denorm_min() noexcept { return FLT128_DENORM_MIN; } static constexpr bool is_iec559 = true; static constexpr bool is_bounded = false; static constexpr bool is_modulo = false; static constexpr bool traps = false; static constexpr bool tinyness_before = false; static constexpr float_round_style round_style = round_to_nearest; }; #endif } // end namespace std #endif // HAVE_QUADMATH #endif // DUNE_QUADMATH_HH dune-common-2.8.0/dune/common/rangeutilities.hh000066400000000000000000000703041411343567400215520ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_RANGE_UTILITIES_HH #define DUNE_COMMON_RANGE_UTILITIES_HH #include #include #include #include #include /** * \file * * \brief Utilities for reduction like operations on ranges * \author Christian Engwer */ namespace Dune { /** * @addtogroup RangeUtilities * @{ */ /** \brief compute the maximum value over a range overloads for scalar values, and ranges exist */ template ::value, int>::type = 0> typename T::value_type max_value(const T & v) { using std::max_element; return *max_element(v.begin(), v.end()); } template ::value, int>::type = 0> const T & max_value(const T & v) { return v; } /** \brief compute the minimum value over a range overloads for scalar values, and ranges exist */ template ::value, int>::type = 0> typename T::value_type min_value(const T & v) { using std::min_element; return *min_element(v.begin(), v.end()); } template ::value, int>::type = 0> const T & min_value(const T & v) { return v; } /** \brief similar to std::bitset::any() return true, if any entries is true overloads for scalar values, ranges, and std::bitset exist */ template ::value, int>::type = 0> bool any_true(const T & v) { bool b = false; for (const auto & e : v) b = b or bool(e); return b; } template ::value, int>::type = 0> bool any_true(const T & v) { return v; } template bool any_true(const std::bitset & b) { return b.any(); } /** \brief similar to std::bitset::all() return true, if any entries is true overloads for scalar values, ranges, and std::bitset exist */ template ::value, int>::type = 0> bool all_true(const T & v) { bool b = true; for (const auto & e : v) b = b and bool(e); return b; } template ::value, int>::type = 0> bool all_true(const T & v) { return v; } template bool all_true(const std::bitset & b) { return b.all(); } namespace Impl { template class IntegralRangeIterator { public: typedef std::random_access_iterator_tag iterator_category; typedef T value_type; typedef std::make_signed_t difference_type; typedef const T *pointer; typedef T reference; constexpr IntegralRangeIterator() noexcept : value_(0) {} constexpr explicit IntegralRangeIterator(value_type value) noexcept : value_(value) {} pointer operator->() const noexcept { return &value_; } constexpr reference operator*() const noexcept { return value_; } constexpr reference operator[]( difference_type n ) const noexcept { return (value_ + n); } constexpr bool operator==(const IntegralRangeIterator & other) const noexcept { return (value_ == other.value_); } constexpr bool operator!=(const IntegralRangeIterator & other) const noexcept { return (value_ != other.value_); } constexpr bool operator<(const IntegralRangeIterator & other) const noexcept { return (value_ <= other.value_); } constexpr bool operator<=(const IntegralRangeIterator & other) const noexcept { return (value_ <= other.value_); } constexpr bool operator>(const IntegralRangeIterator & other) const noexcept { return (value_ >= other.value_); } constexpr bool operator>=(const IntegralRangeIterator & other) const noexcept { return (value_ >= other.value_); } IntegralRangeIterator& operator++() noexcept { ++value_; return *this; } IntegralRangeIterator operator++(int) noexcept { IntegralRangeIterator copy( *this ); ++(*this); return copy; } IntegralRangeIterator& operator--() noexcept { --value_; return *this; } IntegralRangeIterator operator--(int) noexcept { IntegralRangeIterator copy( *this ); --(*this); return copy; } IntegralRangeIterator& operator+=(difference_type n) noexcept { value_ += n; return *this; } IntegralRangeIterator& operator-=(difference_type n) noexcept { value_ -= n; return *this; } friend constexpr IntegralRangeIterator operator+(const IntegralRangeIterator &a, difference_type n) noexcept { return IntegralRangeIterator(a.value_ + n); } friend constexpr IntegralRangeIterator operator+(difference_type n, const IntegralRangeIterator &a) noexcept { return IntegralRangeIterator(a.value_ + n); } friend constexpr IntegralRangeIterator operator-(const IntegralRangeIterator &a, difference_type n) noexcept { return IntegralRangeIterator(a.value_ - n); } constexpr difference_type operator-(const IntegralRangeIterator &other) const noexcept { return (static_cast(value_) - static_cast(other.value_)); } private: value_type value_; }; } // namespace Impl /** * \brief dynamic integer range for use in range-based for loops * * \note This range can also be used in Hybrid::forEach, resulting in a dynamic * for loop over the contained integers. * * \tparam T type of integers contained in the range **/ template class IntegralRange { public: /** \brief type of integers contained in the range **/ typedef T value_type; /** \brief type of iterator **/ typedef Impl::IntegralRangeIterator iterator; /** \brief unsigned integer type corresponding to value_type **/ typedef std::make_unsigned_t size_type; /** \brief construct integer range [from, to) **/ constexpr IntegralRange(value_type from, value_type to) noexcept : from_(from), to_(to) {} /** \brief construct integer range [0, to) **/ constexpr explicit IntegralRange(value_type to) noexcept : from_(0), to_(to) {} /** \brief construct integer range std::pair **/ constexpr IntegralRange(std::pair range) noexcept : from_(range.first), to_(range.second) {} /** \brief obtain a random-access iterator to the first element **/ constexpr iterator begin() const noexcept { return iterator(from_); } /** \brief obtain a random-access iterator past the last element **/ constexpr iterator end() const noexcept { return iterator(to_); } /** \brief access specified element **/ constexpr value_type operator[](const value_type &i) const noexcept { return (from_ + i); } /** \brief check whether the range is empty **/ constexpr bool empty() const noexcept { return (from_ == to_); } /** \brief obtain number of elements in the range **/ constexpr size_type size() const noexcept { return (static_cast(to_) - static_cast(from_)); } private: value_type from_, to_; }; /** * \brief static integer range for use in range-based for loops * * This is a compile-time static variant of the IntegralRange. Apart from * returning all range information statically, it casts into the corresponding * std::integer_sequence. * * \note This range can also be used in Hybrid::forEach, resulting in a static * for loop over the contained integers like a std::integer_sequence. * * \tparam T type of integers contained in the range * \tparam to first element not contained in the range * \tparam from first element contained in the range, defaults to 0 **/ template class StaticIntegralRange { template static std::integer_sequence shift_integer_sequence(std::integer_sequence); public: /** \brief type of integers contained in the range **/ typedef T value_type; /** \brief type of iterator **/ typedef Impl::IntegralRangeIterator iterator; /** \brief unsigned integer type corresponding to value_type **/ typedef std::make_unsigned_t size_type; /** \brief type of corresponding std::integer_sequence **/ typedef decltype(shift_integer_sequence(std::make_integer_sequence())) integer_sequence; /** \brief default constructor **/ constexpr StaticIntegralRange() noexcept = default; /** \brief cast into dynamic IntegralRange **/ constexpr operator IntegralRange() const noexcept { return {from, to}; } /** \brief cast into corresponding std::integer_sequence **/ constexpr operator integer_sequence() const noexcept { return {}; } /** \brief obtain a random-access iterator to the first element **/ static constexpr iterator begin() noexcept { return iterator(from); } /** \brief obtain a random-access iterator past the last element **/ static constexpr iterator end() noexcept { return iterator(to); } /** \brief access specified element (static version) **/ template constexpr auto operator[](const std::integral_constant &) const noexcept -> std::integral_constant(i)> { return {}; } /** \brief access specified element (dynamic version) **/ constexpr value_type operator[](const size_type &i) const noexcept { return (from + static_cast(i)); } /** \brief check whether the range is empty **/ static constexpr std::integral_constant empty() noexcept { return {}; } /** \brief obtain number of elements in the range **/ static constexpr std::integral_constant(to) - static_cast(from) > size() noexcept { return {}; } }; /** \brief free standing function for setting up a range based for loop over an integer range for (auto i: range(0,10)) // 0,1,2,3,4,5,6,7,8,9 or for (auto i: range(-10,10)) // -10,-9,..,8,9 or for (auto i: range(10)) // 0,1,2,3,4,5,6,7,8,9 */ template, std::decay_t>::value, int> = 0, std::enable_if_t>::value, int> = 0> inline static IntegralRange> range(T &&from, U &&to) noexcept { return IntegralRange>(std::forward(from), std::forward(to)); } template>::value, int> = 0> inline static IntegralRange> range(T &&to) noexcept { return IntegralRange>(std::forward(to)); } template>::value, int> = 0> inline static IntegralRange>> range(T &&to) noexcept { return IntegralRange>>(std::forward(to)); } template inline static StaticIntegralRange range(std::integral_constant, std::integral_constant) noexcept { return {}; } template inline static StaticIntegralRange range(std::integral_constant) noexcept { return {}; } /** * \brief Tag to enable value based transformations in TransformedRangeView */ struct ValueTransformationTag {}; /** * \brief Tag to enable iterator based transformations in TransformedRangeView */ struct IteratorTransformationTag {}; namespace Impl { // Helper class to mimic a pointer for proxy objects. // This is needed to implement operator-> on an iterator // using proxy-values. It stores the proxy value but // provides operator-> like a pointer. template class PointerProxy { public: PointerProxy(ProxyType&& p) : p_(p) {} ProxyType* operator->() { return &p_; } ProxyType p_; }; // An iterator transforming a wrapped iterator using // an unary function. It inherits the iterator-category // of the underlying iterator. template ::iterator_category> class TransformedRangeIterator; template class TransformedRangeIterator { protected: static decltype(auto) transform(const F& f, const I& it) { if constexpr (std::is_same_v) return f(it); else return f(*it); } public: using iterator_category = std::forward_iterator_tag; using reference = decltype(transform(std::declval(), std::declval())); using value_type = std::decay_t; using pointer = PointerProxy; // If we later want to allow standalone TransformedRangeIterators, // we could customize the FunctionPointer to be a default-constructible, // copy-assignable type storing a function but acting like a pointer // to function. using FunctionPointer = const F*; constexpr TransformedRangeIterator(const I& it, FunctionPointer f) noexcept : it_(it), f_(f) {} // Explicitly initialize members. Using a plain // // constexpr TransformedRangeIterator() noexcept {} // // would default-initialize the members while // // constexpr TransformedRangeIterator() noexcept : it_(), f_() {} // // leads to value-initialization. This is a case where // both are really different. If it_ is a raw pointer (i.e. POD) // then default-initialization leaves it uninitialized while // value-initialization zero-initializes it. constexpr TransformedRangeIterator() noexcept : it_(), f_() {} // Dereferencing returns a value created by the function constexpr reference operator*() const noexcept { return transform(*f_, it_); } // Dereferencing returns a value created by the function pointer operator->() const noexcept { return transform(*f_, it_); } constexpr TransformedRangeIterator& operator=(const TransformedRangeIterator& other) = default; constexpr bool operator==(const TransformedRangeIterator& other) const noexcept { return (it_ == other.it_); } constexpr bool operator!=(const TransformedRangeIterator& other) const noexcept { return (it_ != other.it_); } TransformedRangeIterator& operator++() noexcept { ++it_; return *this; } TransformedRangeIterator operator++(int) noexcept { TransformedRangeIterator copy(*this); ++(*this); return copy; } protected: I it_; FunctionPointer f_; }; template class TransformedRangeIterator : public TransformedRangeIterator { protected: using Base = TransformedRangeIterator; using Base::it_; using Base::f_; public: using iterator_category = std::bidirectional_iterator_tag; using reference = typename Base::reference; using value_type = typename Base::value_type; using pointer = typename Base::pointer; using FunctionPointer = typename Base::FunctionPointer; using Base::Base; // Member functions of the forward_iterator that need // to be redefined because the base class methods return a // forward_iterator. constexpr TransformedRangeIterator& operator=(const TransformedRangeIterator& other) = default; TransformedRangeIterator& operator++() noexcept { ++it_; return *this; } TransformedRangeIterator operator++(int) noexcept { TransformedRangeIterator copy(*this); ++(*this); return copy; } // Additional member functions of bidirectional_iterator TransformedRangeIterator& operator--() noexcept { --(this->it_); return *this; } TransformedRangeIterator operator--(int) noexcept { TransformedRangeIterator copy(*this); --(*this); return copy; } }; template class TransformedRangeIterator : public TransformedRangeIterator { protected: using Base = TransformedRangeIterator; using Base::it_; using Base::f_; public: using iterator_category = std::random_access_iterator_tag; using reference = typename Base::reference; using value_type = typename Base::value_type; using pointer = typename Base::pointer; using difference_type = typename std::iterator_traits::difference_type; using FunctionPointer = typename Base::FunctionPointer; using Base::Base; // Member functions of the forward_iterator that need // to be redefined because the base class methods return a // forward_iterator. constexpr TransformedRangeIterator& operator=(const TransformedRangeIterator& other) = default; TransformedRangeIterator& operator++() noexcept { ++it_; return *this; } TransformedRangeIterator operator++(int) noexcept { TransformedRangeIterator copy(*this); ++(*this); return copy; } // Member functions of the bidirectional_iterator that need // to be redefined because the base class methods return a // bidirectional_iterator. TransformedRangeIterator& operator--() noexcept { --(this->it_); return *this; } TransformedRangeIterator operator--(int) noexcept { TransformedRangeIterator copy(*this); --(*this); return copy; } // Additional member functions of random_access_iterator TransformedRangeIterator& operator+=(difference_type n) noexcept { it_ += n; return *this; } TransformedRangeIterator& operator-=(difference_type n) noexcept { it_ -= n; return *this; } bool operator<(const TransformedRangeIterator& other) noexcept { return it_(const TransformedRangeIterator& other) noexcept { return it_>other.it_; } bool operator>=(const TransformedRangeIterator& other) noexcept { return it_>=other.it_; } reference operator[](difference_type n) noexcept { return Base::transform(*f_, it_+n); } friend TransformedRangeIterator operator+(const TransformedRangeIterator& it, difference_type n) noexcept { return TransformedRangeIterator(it.it_+n, it.f_); } friend TransformedRangeIterator operator+(difference_type n, const TransformedRangeIterator& it) noexcept { return TransformedRangeIterator(n+it.it_, it.f_); } friend TransformedRangeIterator operator-(const TransformedRangeIterator& it, difference_type n) noexcept { return TransformedRangeIterator(it.it_-n, it.f_); } friend difference_type operator-(const TransformedRangeIterator& first, const TransformedRangeIterator& second) noexcept { return first.it_-second.it_; } }; } // namespace Impl /** * \brief A range transforming the values of another range on-the-fly * * This behaves like a range providing `begin()` and `end()`. * The iterators over this range internally iterate over * the wrapped range. When dereferencing the iterator, * the value is transformed on-the-fly using a given * transformation function leaving the underlying range * unchanged. * * The transformation may either return temporary values * or l-value references. In the former case the range behaves * like a proxy-container. In the latter case it forwards these * references allowing, e.g., to sort a subset of some container * by applying a transformation to an index-range for those values. * * The iterators of the TransformedRangeView have the same * iterator_category as the ones of the wrapped container. * * If range is given as r-value, then the returned TransformedRangeView * stores it by value, if range is given as (const) l-value, then the * TransformedRangeView stores it by (const) reference. * * If R is a value type, then the TransformedRangeView stores the wrapped range by value, * if R is a reference type, then the TransformedRangeView stores the wrapped range by reference. * * \tparam R Underlying range. * \tparam F Unary function used to transform the values in the underlying range. * \tparam T Class for describing how to apply the transformation * * T has to be either ValueTransformationTag (default) or IteratorTransformationTag. * In the former case, the transformation is applied to the values * obtained by dereferencing the wrapped iterator. In the latter case * it is applied to the iterator directly, allowing to access non-standard * functions of the iterator. **/ template class TransformedRangeView { using RawConstIterator = std::decay_t().begin())>; using RawIterator = std::decay_t().begin())>; public: /** * \brief Const iterator type * * This inherits the iterator_category of the iterators * of the underlying range. */ using const_iterator = Impl::TransformedRangeIterator; /** * \brief Iterator type * * This inherits the iterator_category of the iterators * of the underlying range. */ using iterator = Impl::TransformedRangeIterator; /** * \brief Export type of the wrapped untransformed range. * * Notice that this will always be the raw type with references * removed, even if a reference is stored. */ using RawRange = std::remove_reference_t; /** * \brief Construct from range and function */ template constexpr TransformedRangeView(RR&& rawRange, const F& f) noexcept : rawRange_(std::forward(rawRange)), f_(f) { static_assert(std::is_same_v or std::is_same_v, "The TransformationType passed to TransformedRangeView has to be either ValueTransformationTag or IteratorTransformationTag."); } /** * \brief Obtain a iterator to the first element * * The life time of the returned iterator is bound to * the life time of the range since it only contains a * pointer to the transformation function stored * in the range. */ constexpr const_iterator begin() const noexcept { return const_iterator(rawRange_.begin(), &f_); } constexpr iterator begin() noexcept { return iterator(rawRange_.begin(), &f_); } /** * \brief Obtain a iterator past the last element * * The life time of the returned iterator is bound to * the life time of the range since it only contains a * pointer to the transformation function stored * in the range. */ constexpr const_iterator end() const noexcept { return const_iterator(rawRange_.end(), &f_); } constexpr iterator end() noexcept { return iterator(rawRange_.end(), &f_); } /** * \brief Obtain the size of the range * * This is only available if the underlying range * provides a size() method. In this case size() * just forwards to the underlying range's size() method. * * Attention: Don't select the template parameters explicitly. * They are only used to implement SFINAE. */ template().size())>> auto size() const { return rawRange_.size(); } /** * \brief Export the wrapped untransformed range. */ const RawRange& rawRange() const { return rawRange_; } /** * \brief Export the wrapped untransformed range. */ RawRange& rawRange() { return rawRange_; } private: R rawRange_; F f_; }; /** * \brief Create a TransformedRangeView * * \param range The range to transform * \param f Unary function that should the applied to the entries of the range. * * This behaves like a range providing `begin()` and `end()`. * The iterators over this range internally iterate over * the wrapped range. When dereferencing the iterator, * the wrapped iterator is dereferenced, * the given transformation function is applied on-the-fly, * and the result is returned. * I.e, if \code it \endcode is the wrapped iterator * and \code f \endcode is the transformation function, * then the result of \code f(*it) \endcode is returned * * The transformation may either return temporary values * or l-value references. In the former case the range behaves * like a proxy-container. In the latter case it forwards these * references allowing, e.g., to sort a subset of some container * by applying a transformation to an index-range for those values. * * The iterators of the TransformedRangeView have the same * iterator_category as the ones of the wrapped container. * * If range is an r-value, then the TransformedRangeView stores it by value, * if range is an l-value, then the TransformedRangeView stores it by reference. **/ template auto transformedRangeView(R&& range, const F& f) { return TransformedRangeView(std::forward(range), f); } /** * \brief Create a TransformedRangeView using an iterator transformation * * \param range The range to transform * \param f Unary function that should the applied to the entries of the range. * * This behaves like a range providing `begin()` and `end()`. * The iterators over this range internally iterate over * the wrapped range. When dereferencing the iterator, * the given transformation function is applied to the wrapped * iterator on-the-fly and the result is returned. * I.e, if \code it \endcode is the wrapped iterator * and \code f \endcode is the transformation function, * then the result of \code f(it) \endcode is returned. * * The transformation may either return temorary values * or l-value references. In the former case the range behaves * like a proxy-container. In the latter case it forwards these * references allowing, e.g., to sort a subset of some container * by applying a transformation to an index-range for those values. * * The iterators of the TransformedRangeView have the same * iterator_category as the ones of the wrapped container. * * If range is an r-value, then the TransformedRangeView stores it by value, * if range is an l-value, then the TransformedRangeView stores it by reference. **/ template auto iteratorTransformedRangeView(R&& range, const F& f) { return TransformedRangeView(std::forward(range), f); } /** * \brief Allow structured-binding for-loops for sparse iterators * * Given a sparse range `R` whose iterators `it` * provide (additionally to dereferencing) a method * `it->index()` for accessing the index of the current entry in the * sparse range, this allows to write code like * \code * for(auto&& [A_i, i] : sparseRange(R)) * doSomethingWithValueAndIndex(A_i, i); * \endcode */ template auto sparseRange(Range&& range) { return Dune::iteratorTransformedRangeView(std::forward(range), [](auto&& it) { return std::tuple(*it, it.index()); }); } /** * @} */ } #endif // DUNE_COMMON_RANGE_UTILITIES_HH dune-common-2.8.0/dune/common/reservedvector.hh000066400000000000000000000124711411343567400215650ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_RESERVEDVECTOR_HH #define DUNE_COMMON_RESERVEDVECTOR_HH /** \file * \brief An stl-compliant random-access container which stores everything on the stack */ #include #include #include #include #include #include #ifdef CHECK_RESERVEDVECTOR #define CHECKSIZE(X) assert(X) #else #define CHECKSIZE(X) {} #endif namespace Dune { /** \brief A Vector class with statically reserved memory. ReservedVector is something between std::array and std::vector. It is a dynamically sized vector which can be extended and shrunk using methods like push_back and pop_back, but reserved memory is statically predefined. This implies that the vector cannot grow bigger than the predefined maximum size. \tparam T The data type ReservedVector stores. \tparam n The maximum number of objects the ReservedVector can store. */ template class ReservedVector { public: /** @{ Typedefs */ //! The type of object, T, stored in the vector. typedef T value_type; //! Pointer to T. typedef T* pointer; //! Reference to T typedef T& reference; //! Const reference to T typedef const T& const_reference; //! An unsigned integral type. typedef size_t size_type; //! A signed integral type. typedef std::ptrdiff_t difference_type; //! Iterator used to iterate through a vector. typedef Dune::GenericIterator iterator; //! Const iterator used to iterate through a vector. typedef Dune::GenericIterator const_iterator; /** @} */ /** @{ Constructors */ //! Constructor ReservedVector() = default; ReservedVector(std::initializer_list const &l) { assert(l.size() <= n);// Actually, this is not needed any more! sz = l.size(); std::copy_n(l.begin(), sz, data); } /** @} */ bool operator == (const ReservedVector & other) const { bool eq = (sz == other.sz); for (size_type i=0; ii); return data[i]; } //! Returns a const reference to the i'th element. const_reference operator[] (size_type i) const { CHECKSIZE(sz>i); return data[i]; } //! Returns reference to first element of vector. reference front() { CHECKSIZE(sz>0); return data[0]; } //! Returns const reference to first element of vector. const_reference front() const { CHECKSIZE(sz>0); return data[0]; } //! Returns reference to last element of vector. reference back() { CHECKSIZE(sz>0); return data[sz-1]; } //! Returns const reference to last element of vector. const_reference back() const { CHECKSIZE(sz>0); return data[sz-1]; } /** @} */ /** @{ Informative Methods */ //! Returns number of elements in the vector. size_type size () const { return sz; } //! Returns true if vector has no elements. bool empty() const { return sz==0; } //! Returns current capacity (allocated memory) of the vector. static constexpr size_type capacity() { return n; } //! Returns the maximum length of the vector. static constexpr size_type max_size() { return n; } /** @} */ //! Send ReservedVector to an output stream friend std::ostream& operator<< (std::ostream& s, const ReservedVector& v) { for (size_t i=0; i)) #undef CHECKSIZE #endif // DUNE_COMMON_RESERVEDVECTOR_HH dune-common-2.8.0/dune/common/scalarmatrixview.hh000066400000000000000000000116501411343567400221060ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_SCALARMATRIXVIEW_HH #define DUNE_COMMON_SCALARMATRIXVIEW_HH #include #include #include #include #include #include #include #include #include namespace Dune { namespace Impl { /** @addtogroup DenseMatVec @{ */ /*! \file * \brief Implements a scalar matrix view wrapper around an existing scalar. */ /** \brief A wrapper making a scalar look like a matrix * * This stores a pointer to a scalar of type K and * provides the interface of a matrix with a single row * and column represented by the data behind the pointer. */ template class ScalarMatrixView : public DenseMatrix> { ScalarVectorView data_; using Base = DenseMatrix>; template friend class ScalarMatrixView; public: //===== type definitions and constants //! We are at the leaf of the block recursion enum { //! The number of block levels we contain. //! This is always one for this type. blocklevel = 1 }; using size_type = typename Base::size_type; using row_type = typename Base::row_type; using row_reference = typename Base::row_reference; using const_row_reference = typename Base::const_row_reference; //! export size enum { //! \brief The number of rows. //! This is always one for this type. rows = 1, //! \brief The number of columns. //! This is always one for this type. cols = 1 }; //===== constructors /** \brief Default constructor */ constexpr ScalarMatrixView () : data_() {} /** \brief Construct from a pointer to a scalar */ ScalarMatrixView (K* p) : data_(p) {} //! Copy constructor ScalarMatrixView (const ScalarMatrixView &other) : Base(), data_(other.data_) {} //! Move constructor ScalarMatrixView (ScalarMatrixView &&other) : Base(), data_( other.data_ ) {} //! Copy assignment operator ScalarMatrixView& operator= (const ScalarMatrixView& other) { data_ = other.data_; return *this; } template ScalarMatrixView& operator= (const ScalarMatrixView& other) { data_ = other.data_; return *this; } //! Assignment operator from a scalar template::value, int> = 0> inline ScalarMatrixView& operator= (const T& k) { data_ = k; return *this; } // make this thing a matrix static constexpr size_type mat_rows() { return 1; } static constexpr size_type mat_cols() { return 1; } row_reference mat_access ([[maybe_unused]] size_type i) { DUNE_ASSERT_BOUNDS(i == 0); return data_; } const_row_reference mat_access ([[maybe_unused]] size_type i) const { DUNE_ASSERT_BOUNDS(i == 0); return data_; } }; // class ScalarMatrixView /** \brief Sends the matrix to an output stream */ template std::ostream& operator<< (std::ostream& s, const ScalarMatrixView& a) { s << a[0][0]; return s; } /** \brief Wrap a scalar as a 1-1-matrix */ template::value, int> = 0> auto asMatrix(T& t) { return ScalarMatrixView{&t}; } /** \brief Wrap a const scalar as a const 1-1-matrix */ template::value, int> = 0> auto asMatrix(const T& t) { return ScalarMatrixView{&t}; } /** \brief Non-scalar types are assumed to be matrices, and simply forwarded */ template::value, int> = 0> T& asMatrix(T& t) { return t; } /** \brief Non-scalar types are assumed to be matrices, and simply forwarded */ template::value, int> = 0> const T& asMatrix(const T& t) { return t; } /** @} end documentation */ } // end namespace Impl template struct FieldTraits> : public FieldTraits> {}; template struct DenseMatVecTraits> { using derived_type = Impl::ScalarMatrixView; using row_type = Impl::ScalarVectorView; using row_reference = row_type&; using const_row_reference = const row_type&; using value_type = std::remove_const_t; using size_type = std::size_t; }; template struct AutonomousValueType> { using type = FieldMatrix,1,1>; }; } // end namespace Dune #endif // DUNE_COMMON_SCALARMATRIXVIEW_HH dune-common-2.8.0/dune/common/scalarvectorview.hh000066400000000000000000000117731411343567400221120ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_SCALARVECTORVIEW_HH #define DUNE_COMMON_SCALARVECTORVIEW_HH #include #include #include #include #include #include #include namespace Dune { namespace Impl { /** @addtogroup DenseMatVec @{ */ /*! \file * \brief Implements a scalar vector view wrapper around an existing scalar. */ /** \brief A wrapper making a scalar look like a vector * * This stores a pointer to a scalar of type K and * provides the interface of a vector with a single * entry represented by the data behind the pointer. */ template class ScalarVectorView : public DenseVector> { K* dataP_; using Base = DenseVector>; template friend class ScalarVectorView; public: //! export size enum { //! The size of this vector. dimension = 1 }; /** \brief The type used for array indices and sizes */ using size_type = typename Base::size_type; /** \brief The type used for references to the vector entry */ using reference = std::decay_t&; /** \brief The type used for const references to the vector entry */ using const_reference = const K&; //===== construction /** \brief Default constructor */ constexpr ScalarVectorView () : dataP_(nullptr) {} /** \brief Construct from a pointer to a scalar */ ScalarVectorView (K* p) : dataP_(p) {} //! Copy constructor ScalarVectorView (const ScalarVectorView &other) : Base(), dataP_(other.dataP_) {} //! Move constructor ScalarVectorView (ScalarVectorView &&other) : Base(), dataP_( other.dataP_ ) {} //! Copy assignment operator ScalarVectorView& operator= (const ScalarVectorView& other) { assert(dataP_); assert(other.dataP_); *dataP_ = *(other.dataP_); return *this; } template ScalarVectorView& operator= (const ScalarVectorView& other) { assert(dataP_); assert(other.dataP_); *dataP_ = *(other.dataP_); return *this; } //! Assignment operator from a scalar template::value, int> = 0> inline ScalarVectorView& operator= (const T& k) { *dataP_ = k; return *this; } /** \brief Container size -- this is always 1 */ static constexpr size_type size () { return 1; } /** \brief Random access operator, actually disregards its argument */ K& operator[] ([[maybe_unused]] size_type i) { DUNE_ASSERT_BOUNDS(i == 0); return *dataP_; } /** \brief Const random access operator, actually disregards its argument */ const K& operator[] ([[maybe_unused]] size_type i) const { DUNE_ASSERT_BOUNDS(i == 0); return *dataP_; } }; // class ScalarVectorView } // namespace Impl template< class K> struct DenseMatVecTraits< Impl::ScalarVectorView > { using derived_type = Impl::ScalarVectorView; using value_type = std::remove_const_t; using size_type = std::size_t; }; template< class K > struct FieldTraits< Impl::ScalarVectorView > : public FieldTraits> {}; template struct AutonomousValueType> { using type = FieldVector,1>; }; namespace Impl { /** \brief Read a ScalarVectorView from an input stream * \relates ScalarVectorView * * \note This operator is STL compliant, i.e., the content of v is only * changed if the read operation is successful. * * \param[in] in std :: istream to read from * \param[out] v ScalarVectorView to be read * * \returns the input stream (in) */ template inline std::istream &operator>> ( std::istream &in, ScalarVectorView &v ) { K w; if(in >> w) v = w; return in; } /** \brief Wrap a scalar as a 1-vector */ template::value, int> = 0> auto asVector(T& t) { return ScalarVectorView{&t}; } /** \brief Wrap a const scalar as a const 1-vector */ template::value, int> = 0> auto asVector(const T& t) { return ScalarVectorView{&t}; } /** \brief Non-scalar types are assumed to be arrays, and simply forwarded */ template::value, int> = 0> T& asVector(T& t) { return t; } /** \brief Non-scalar types are assumed to be arrays, and simply forwarded */ template::value, int> = 0> const T& asVector(const T& t) { return t; } } // end namespace Impl } // end namespace Dune #endif // DUNE_COMMON_SCALARVECTORVIEW_HH dune-common-2.8.0/dune/common/shared_ptr.hh000066400000000000000000000065111411343567400206540ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_SHARED_PTR_HH #define DUNE_SHARED_PTR_HH #include #include /** * @file * @brief This file implements several utilities related to std::shared_ptr * @author Markus Blatt */ namespace Dune { /** @brief implements the Deleter concept of shared_ptr without deleting anything @relates shared_ptr If you allocate an object on the stack, but want to pass it to a class or function as a shared_ptr, you can use this deleter to avoid accidental deletion of the stack-allocated object. For convenience we provide two free functions to create a shared_ptr from a stack-allocated object (\see stackobject_to_shared_ptr): 1) Convert a stack-allocated object to a shared_ptr: @code int i = 10; std::shared_ptr pi = stackobject_to_shared_ptr(i); @endcode 2) Convert a stack-allocated object to a std::shared_ptr of a base class @code class A {}; class B : public A {}; ... B b; std::shared_ptr
pa = stackobject_to_shared_ptr(b); @endcode @tparam T type of the stack-allocated object */ template struct null_deleter { void operator() (T*) const {} }; /** @brief Create a shared_ptr for a stack-allocated object @relatesalso null_deleter @code #include @endcode Usage: @code int i = 10; std::shared_ptr pi = stackobject_to_shared_ptr(i); @endcode The @c std::shared_ptr points to the object on the stack, but its deleter is set to an instance of @c null_deleter so that nothing happens when the @c shared_ptr is destroyed. @sa null_deleter */ template inline std::shared_ptr stackobject_to_shared_ptr(T & t) { return std::shared_ptr(&t, null_deleter()); } /** * \brief Capture R-value reference to shared_ptr * * This will store a copy of the passed object in * a shared_ptr. * * The two overloads of wrap_or_move are intended * to capture references and temporaries in a unique * way without creating copies and only moving if * necessary. * * Be careful: Only use this function if you are * aware of it's implications. You can e.g. easily * end up storing a reference to a temporary if * you use this inside of another function without * perfect forwarding. */ template auto wrap_or_move(T&& t) { return std::make_shared>(std::forward(t)); } /** * \brief Capture L-value reference to std::shared_ptr * * This will store a pointer for the passed reference * in a non-owning std::shared_ptr. * * The two overloads of wrap_or_move are intended * to capture references and temporaries in a unique * way without creating copies and only moving if * necessary. * * Be careful: Only use this function if you are * aware of it's implications. You can e.g. easily * end up storing a reference to a temporary if * you use this inside of another function without * perfect forwarding. */ template auto wrap_or_move(T& t) { return stackobject_to_shared_ptr(t); } } #endif dune-common-2.8.0/dune/common/simd.hh000066400000000000000000000334641411343567400174640ustar00rootroot00000000000000#ifndef DUNE_COMMON_SIMD_HH #define DUNE_COMMON_SIMD_HH #warning dune/common/simd.hh is deprecated. #warning Use the new infrastructure from dune/common/simd/simd.h instead. /** \file \brief Abstractions for support of dedicated SIMD data types Libraries like Vc (https://github.com/VcDevel/Vc) add high-level data types for SIMD (or vectorization) support in C++. Most of these operations mimic the behavior of a numerical data type. Some boolean operations can not be implemented in a compatible way to trivial data types. This header contains additional abstractions to help writing code that works with trivial numerical data types (like double) and Vc vectorization data types. See also the conditional.hh and range_utils.hh headers. \deprecated Use the newer simd architecture from dune/common/simd/simd.hh instead. */ #include #include #include #include #include #include #include #if HAVE_VC // include Vc part of new simd interface to provide compatibility for // functionality that has been switched over. #include #endif #include #include namespace Dune { #if HAVE_VC namespace VcImpl { //! A reference-like proxy for elements of random-access vectors. /** * This is necessary because Vc's lane-access operation return a proxy * that cannot constructed by non-Vc code (i.e. code that isn't * explicitly declared `friend`). This means in particular that there * is no copy/move constructor, meaning we cannot return such proxies * from our own functions, such as `lane()`. To work around this, we * define our own proxy class which internally holds a reference to the * vector and a lane index. */ template class Proxy { static_assert(std::is_same >::value, "Class Proxy " "may only be instantiated with unqualified types"); public: using value_type = typename V::value_type; private: static_assert(std::is_arithmetic::value, "Only artihmetic types are supported"); V &vec_; std::size_t idx_; public: Proxy(std::size_t idx, V &vec) : vec_(vec), idx_(idx) { } operator value_type() const { return vec_[idx_]; } // postfix operators template::value> > value_type operator++(int) { return vec_[idx_]++; } template::value> > value_type operator--(int) { return vec_[idx_]--; } // unary (prefix) operators template::value> > Proxy &operator++() { ++(vec_[idx_]); return *this; } template::value> > Proxy &operator--() { --(vec_[idx_]); return *this; } decltype(auto) operator!() const { return !(vec_[idx_]); } decltype(auto) operator+() const { return +(vec_[idx_]); } decltype(auto) operator-() const { return -(vec_[idx_]); } template::value> > decltype(auto) operator~() const { return ~(vec_[idx_]); } // binary operators #define DUNE_SIMD_VC_BINARY_OP(OP) \ template \ auto operator OP(T &&o) const \ -> decltype(vec_[idx_] OP valueCast(std::forward(o))) \ { \ return vec_[idx_] OP valueCast(std::forward(o)); \ } \ static_assert(true, "Require semicolon to unconfuse editors") DUNE_SIMD_VC_BINARY_OP(*); DUNE_SIMD_VC_BINARY_OP(/); DUNE_SIMD_VC_BINARY_OP(%); DUNE_SIMD_VC_BINARY_OP(+); DUNE_SIMD_VC_BINARY_OP(-); DUNE_SIMD_VC_BINARY_OP(<<); DUNE_SIMD_VC_BINARY_OP(>>); DUNE_SIMD_VC_BINARY_OP(<); DUNE_SIMD_VC_BINARY_OP(>); DUNE_SIMD_VC_BINARY_OP(<=); DUNE_SIMD_VC_BINARY_OP(>=); DUNE_SIMD_VC_BINARY_OP(==); DUNE_SIMD_VC_BINARY_OP(!=); DUNE_SIMD_VC_BINARY_OP(&); DUNE_SIMD_VC_BINARY_OP(^); DUNE_SIMD_VC_BINARY_OP(|); DUNE_SIMD_VC_BINARY_OP(&&); DUNE_SIMD_VC_BINARY_OP(||); #undef DUNE_SIMD_VC_BINARY_OP #define DUNE_SIMD_VC_ASSIGNMENT(OP) \ template \ auto operator OP(T &&o) \ -> std::enable_if_t(o)) \ )>::value, Proxy&> \ { \ vec_[idx_] OP valueCast(std::forward(o)); \ return *this; \ } \ static_assert(true, "Require semicolon to unconfuse editors") DUNE_SIMD_VC_ASSIGNMENT(=); DUNE_SIMD_VC_ASSIGNMENT(*=); DUNE_SIMD_VC_ASSIGNMENT(/=); DUNE_SIMD_VC_ASSIGNMENT(%=); DUNE_SIMD_VC_ASSIGNMENT(+=); DUNE_SIMD_VC_ASSIGNMENT(-=); DUNE_SIMD_VC_ASSIGNMENT(<<=); DUNE_SIMD_VC_ASSIGNMENT(>>=); DUNE_SIMD_VC_ASSIGNMENT(&=); DUNE_SIMD_VC_ASSIGNMENT(^=); DUNE_SIMD_VC_ASSIGNMENT(|=); #undef DUNE_SIMD_VC_ASSIGNMENT // swap on proxies swaps the proxied vector entries. As such, it // applies to rvalues of proxies too, not just lvalues template friend void swap(Proxy, Proxy); template friend void swap(Proxy p1, T& s2) { // don't use swap() ourselves -- not supported by Vc 1.3.0 (but is // supported by Vc 1.3.2) T tmp = p1.vec_[p1.idx_]; p1.vec_[p1.idx_] = s2; s2 = tmp; } template friend void swap(T& s1, Proxy p2) { T tmp = s1; s1 = p2.vec_[p2.idx_]; p2.vec_[p2.idx_] = tmp; } }; template void swap(Proxy p1, Proxy p2) { typename V1::value_type tmp = p1.vec_[p1.idx_]; p1.vec_[p1.idx_] = p2.vec_[p2.idx_]; p2.vec_[p2.idx_] = tmp; } } // namespace VcImpl #endif // HAVE_VC template struct SimdScalarTypeTraits { using type = T; }; template using SimdScalar = typename SimdScalarTypeTraits::type; #if HAVE_VC /* Add Vc specializations for the SimdScalarTypeTraits trais class */ template struct SimdScalarTypeTraits< Vc::Vector > { using type = T; }; template struct SimdScalarTypeTraits< Vc::SimdArray > { using type = T; }; #endif // HAVE_VC //! deduce the underlying scalar data type of an AlignedNumber template struct SimdScalarTypeTraits< AlignedNumber > { using type = T; }; template struct SimdIndexTypeTraits { using type = std::size_t; }; //! An simd vector of indices corresponding to a simd vector V /** * lanes(T()) == lanes(SimdIndex()) holds. * * \note The size of the elements of a SimdIndex isn't very well-defined. * Be careful. */ template using SimdIndex = typename SimdIndexTypeTraits::type; #if HAVE_VC template struct SimdIndexTypeTraits > { using type = typename Vc::Vector::index_type; }; template struct SimdIndexTypeTraits > { using type = typename Vc::SimdArray::index_type; }; #endif // HAVE_VC template struct SimdMaskTypeTraits { using type = bool; }; //! A simd vector of truth values corresponding to a simd vector V /** * lanes(T()) == lanes(SimdMask()) holds. */ template using SimdMask = typename SimdMaskTypeTraits::type; #if HAVE_VC template struct SimdMaskTypeTraits > { using type = typename Vc::Vector::mask_type; }; template struct SimdMaskTypeTraits > { using type = typename Vc::SimdArray::mask_type; }; #endif // HAVE_VC #if HAVE_VC /* Add Vc specializations for cond(), see conditional.hh */ template Vc::Vector cond(const Vc::Mask & b, const Vc::Vector & v1, const Vc::Vector & v2) { return std::move(Vc::iif(b, v1, v2)); } template Vc::SimdArray cond(const typename Vc::SimdArray::mask_type & b, const Vc::SimdArray & v1, const Vc::SimdArray & v2) { return std::move(Vc::iif(b, v1, v2)); } #endif // HAVE_VC #if HAVE_VC /* Add Vc specializations for several boolean operations, see rangeutitlities.hh: max_value, min_value, any_true, all_true */ template T max_value(const Vc::Vector & v) { return v.max(); } template double max_value(const Vc::SimdArray & v) { return v.max(); } template T min_value(const Vc::Vector & v) { return v.min(); } template double min_value(const Vc::SimdArray & v) { return v.min(); } template bool any_true(const Vc::Mask & v) { return Vc::any_of(v); } template bool any_true(const Vc::SimdMaskArray & v) { return Vc::any_of(v); } template bool all_true(const Vc::Mask & v) { return Vc::all_of(v); } template bool all_true(const Vc::SimdMaskArray & v) { return Vc::all_of(v); } #endif // HAVE_VC //! get the number of lanes of a simd vector (scalar version) template std::size_t lanes(const T &) { return 1; } //! access a lane of a simd vector (scalar version) template T lane(std::size_t l, const T &v) { assert(l == 0); return v; } //! access a lane of a simd vector (scalar version) template T &lane(std::size_t l, T &v) { assert(l == 0); return v; } #if HAVE_VC template std::size_t lanes(const Vc::Vector &) { return Vc::Vector::size(); } template T lane(std::size_t l, const Vc::Vector &v) { assert(l < lanes(v)); return v[l]; } template auto lane(std::size_t l, Vc::Vector &v) { assert(l < lanes(v)); return VcImpl::Proxy >{l, v}; } template std::size_t lanes(const Vc::SimdArray &) { return n; } template T lane(std::size_t l, const Vc::SimdArray &v) { assert(l < n); return v[l]; } template auto lane(std::size_t l, Vc::SimdArray &v) { assert(l < n); return VcImpl::Proxy >{l, v}; } template std::size_t lanes(const Vc::SimdMaskArray &) { return n; } template bool lane(std::size_t l, const Vc::SimdMaskArray &v) { assert(l < n); return v[l]; } template auto lane(std::size_t l, Vc::SimdMaskArray &v) { assert(l < n); return VcImpl::Proxy >{l, v}; } #endif // HAVE_VC //! masked Simd assignment (scalar version) /** * Assign \c src to \c dest for those lanes where \c mask is true. */ template void assign(T &dst, const T &src, bool mask) { if(mask) dst = src; } #if HAVE_VC /* Add Vc specializations for masked assignment */ template void assign(Vc::Vector &dst, const Vc::Vector &src, typename Vc::Vector::mask_type mask) { dst(mask) = src; } template void assign(Vc::SimdArray &dst, const Vc::SimdArray &src, typename Vc::SimdArray::mask_type mask) { dst(mask) = src; } #endif // HAVE_VC template void swap(T &v1, T &v2, bool mask) { using std::swap; if(mask) swap(v1, v2); } #if HAVE_VC /* Add Vc specializations for masked swap */ template void swap(Vc::Vector &v1, Vc::Vector &v2, typename Vc::Vector::mask_type mask) { auto tmp = v1; v1(mask) = v2; v2(mask) = tmp; } template void swap(Vc::SimdArray &v1, Vc::SimdArray &v2, typename Vc::SimdArray::mask_type mask) { auto tmp = v1; v1(mask) = v2; v2(mask) = tmp; } #endif // HAVE_VC } // end namespace Dune #endif // DUNE_COMMON_SIMD_HH dune-common-2.8.0/dune/common/simd/000077500000000000000000000000001411343567400171315ustar00rootroot00000000000000dune-common-2.8.0/dune/common/simd/CMakeLists.txt000066400000000000000000000004641411343567400216750ustar00rootroot00000000000000add_subdirectory(test) if(NOT VC_FOUND) exclude_dir_from_headercheck() endif() #install headers install(FILES base.hh defaults.hh interface.hh io.hh loop.hh simd.hh standard.hh test.hh # may be used from dependent modules vc.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/common/simd) dune-common-2.8.0/dune/common/simd/DESIGN.md000066400000000000000000000245441411343567400204350ustar00rootroot00000000000000This document is a collection of thoughts and rationals on a proper SIMD interface for Dune. What do we want? ================ We want an abstraction layer for SIMD-libraries, that allows the core library to handle simd-vector-like types where (until now) it could only handle scalar types. It is expected that those parts of the core library that want to support vector-like types will need some adaptation to account for corner cases that appear only when vectorizing. However, it should usually be uneccessary to maintain a scalar version of the code -- the vectorized version should be able to handle both vectorized and scalar data types. What this abstraction layer does not provide (at least initially) is a way to actually create vector types from scratch. It must however provide a way to create corresponding types to a type that already exist. I.e. if your code got simd-vector-type argument, the abstraction layer will provide you with the the number of lanes, and the type of the entries. It will also provide you with a way to create simd types with the same number of lanes but a different entry type. Built-in Types ============== We generally do not want to have to modify existing interfaces. This implies that the built-in types must be a valid "vectorization library" that the abstraction layer can deal with. Since the built-in types are not classes, this precludes certain idioms that are widespread among vectorization libraries. For instance if `x` is of a vector type, in many libraries one would access the `i`'th lane of `x` with the expression `x[i]`. We cannot support this expression if `x` is of a scalar built-in type, because we can overload `operator[]` only for class types. An alternative syntax is to use a free-standing access function `lane(i, x)`. Restriction on Vectorization Libraries ====================================== We generally expect vectorization libraries to provide all the usual operators (arithmetic operations, assignment, comparisons) for their vector types. Comparisons should yield mask types specific to that vectorization library; these must be summarized to `bool` with functions of the abstraction layer (like `anyTrue()`) before they can be used in `if`-conditions. We may require them to provide conversions from scalar types to vector types to some extend, however, an exact specification needs more experience. Specifically for vectors (or masks) `v1` and `v2` of type `V`, with associated scalar type `T=Scalar`, we require - for any unary arithmetic expression `@v1` (where `@` is one of `+`, `-`, or `~`): `lane(l,@v1) == T(@lane(l,v1))` for all `l` there are no side-effects - for any binary arithmetic expression `v1@v2` (where `@` is one of `+`, `-`, `*`, `/`, `%`, `<<`, `>>`, `&`, `|`, `^`): `lane(l,v1@v2) == T(lane(l,v1)@lane(l,v2))` for all `l` there are no side-effects - for any compound assignment expression `v1@=v2` (where `@` is one of`+`, `-`, `*`, `/`, `%`, `<<`, `>>`, `&`, `|`, `^`): `v1@=v2` has the same side-effects as `lane(l,v1)@=lane(l,v2)` for all `l` the result of `v1@=v2` is an lvalue denoting `v1` - for any comparison expression `v1@v2` (where `@` is one of `==`, `!=`, `<`, `<=`, `>` or `>=`): `lane(l,v1@v2) == lane(l,v1)@lane(l,v2)` for all `l` The result of `v1@v2` is a prvalue of type `Mask` there are no side-effects - for the unary logic expression `!v1`: `lane(l,!v1) == !lane(l,v1)` for all `l` The result of `!v1` is a prvalue of type `Mask` there are no side-effects - for any binary logic expression `v1@v2` (where `@` is one of `&&` or `||`): `lane(l,v1@v2) == lane(l,v1)@lane(l,v2)` for all `l` The result of `v1@v2` is a prvalue of type `Mask` there are no side-effects Note 1: Short-circuiting may or may not happen for `&&` and `||` -- it will happen for the built-in types, but it cannot happen for proper multi-lane simd types. Note 2: For all expressions there is a lane-wise equality requirement with the scalar operation. This requirement is formulated such that promotions of arguments are permitted, but not required. This is neccessary to allow both the built-in types (which are promoted) and proper simd types (which typically are not promoted to stay within the same simd register). Note 3: The `==` in the lane-wise equality requirement may be overloaded to account for proxies returned by `lane()`. Note 4: Any expression that is invalid for the scalar case is not required for the simd case either. `#include` Structure ==================== There will be one header that ensures that the interface names are available. This include also pulls in the part of the abstraction layer that enables use of the built-in scalar types. Any code that only makes use of the abstraction layer needs to include this header, and only this header. Any compilation unit (generally a `.cc`-file) that creates vectorized types (other then the scalar built-in types) using some vectorization library, and hands those types to vectorization-enabled dune code, is responsible for 1. including the neccessary headers providing the abstraction for that vectorization library, as specified in the documentation of the abstraction, and 2. making sure the compilation with all the compiler/linker settings (flags, defines, libraries) needed by the vectorization library. The ADL-Problem =============== Consider the following example of a vectorization of `Dune::FooVector::two_norm()`, which is implemented in `dune/common/foovector.hh`: ```c++ // SIMD interface and implementation for scalar built-ins #include namespace Dune { template class FooVector { T data_[FOO]; public: T two_norm2() const { using Dune::Simd::lane; using Dune::Simd::lanes; T sum(0); for(const auto &entry : data_) { // break vectorization for demonstration purposes for(std::size_t l = 0; l < lanes(entry); ++l) lane(l, sum) += lane(l, entry) * lane(l, entry); } return sum; } }; } ``` This can then be used like this: ```c++ #include // provide dune-abstraction for mysimdlib // also pulls in the neccessary includes for mysimdlib #include int main() { using T = mysimdlib::Vector; Dune::FooVector x(T(0)); x.two_norm2(); } ``` This will not work. At least not with a straightforward implementation of `lane()` and `lanes()`, where `dune/common/simd/simdlib.hh` simply puts overloads into the `Dune::Simd` namespace. Here's why. The compiler has several ways to find functions that are not qualified by namespaces (or something similar). One way is unqualified lookup: the compiler looks for functions that are in some enclosing scope _at the time the template containing the function call is read_ (early binding). Another is argument-dependend lookup (ADL): the compiler looks for functions in the namespaces associated with the types of its arguments _at the time the function call is instantiated_ (late binding). In the example above, `T` a.k.a. `mysimdlib::Vector` is defined in the namespace `mysimdlib`, which is unlikely to contain the functions `lane()` and `lanes()`. The abstraction layer could put overloads of those functions into that namespace, but, well, you're not supposed to meddle in foreign namespace unless given special permission. As a consequence, `lane()` and `lanes()` cannot be found by ADL. And they cannot be found by any other lookup either. After preprocessing the compiler will see something like this: ```c++ // from dune/common/simd/interface.hh namespace Dune::Simd { std::size_t lanes(double) { return 1; } double lane(std::size_t, double v) { return v; } double& lane(std::size_t, double& v) { return v; } } // from dune/common/foovector.hh namespace Dune { template class FooVector { T data_[FOO]; public: T two_norm2() const { using Dune::Simd::lane; using Dune::Simd::lanes; T sum(0); for(const auto &entry : data_) { // break vectorization for demonstration purposes for(std::size_t l = 0; l < lanes(entry); ++l) lane(l, sum) += lane(l, entry) * lane(l, entry); } return sum; } }; } // from some mysimdlib-specific header namespace mysimdlib { class Vector { /*...*/ }; } // from dune/common/simd/mysimdlib.hh namespace Dune::Simd { std::size_t lanes(mysimdlib::Vector v); double lane(std::size_t, mysimdlib::Vector); double& lane(std::size_t, mysimdlib::Vector&); } // from myprog.cc int main() { using T = mysimdlib::Vector; Dune::FooVector x(T(0)); x.two_norm2(); } ``` At the time when the definition of `Dune::FooVector::two_norm2()` is read, only the declarations for `lane()` and `lanes()` for scalar built-in types are visible. By the time `Dune::FooVector::two_norm2()` is instanciated, the proper declarations for `lane()` and `lanes()` are visible. But that is too late, because unqualified lookup does early binding. It would be OK for late binding, but only ADL does that, and ADL does not work as noted above. Note that ADL is the _only_ type of lookup that does late binding. So we cannot simply require the user to use another type of lookup. Working around the ADL Problem ============================== To get around the ADL problem, we can attempt the following: ```c++ // dune/common/simd/interface.hh namespace Dune::Simd { namespace Overloads { struct ADLTag {}; } template std::size_t lanes(T v) { return lanes(Overloads::ADLTag(), v); } template auto lane(std::size_t i, T v) { return lane(Overloads::ADLTag(), i, v); } //... // implementation for scalar built-ins namespace Overloads { std::size_t lanes(ADLTag, double) { return 1; } double lane(ADLTag, std::size_t, double v) { return v; } // etc... } } ``` And for each vectorization library: ```c++ // dune/common/simd/mysimdlib.hh #include #include namespace Dune::Simd::Overloads { std::size_t lanes(ADLTag, mysimdlib::Vector v); double lane(ADLTag, std::size_t, mysimdlib::Vector v); // etc... } ``` Core Dune code can then use the functions in `Dune::Simd` without restrictions. These functions themselves make sure to find the implementation functions via ADL, so that the lookup uses late binding and thus can find functions that are declared later. dune-common-2.8.0/dune/common/simd/base.hh000066400000000000000000000212061411343567400203650ustar00rootroot00000000000000#ifndef DUNE_COMMON_SIMD_BASE_HH #define DUNE_COMMON_SIMD_BASE_HH /** @file * @brief Basic definitions for SIMD Implementations * @ingroup SIMDAbstract * * This file provides basic definitions and template declarations that are * used to write SIMD abtraction layers. * * This file should never be included by users of the SIMD * abstraction. Include instead. */ /** @defgroup SIMD Vectorization * @ingroup Common * @brief Abstractions for using vectorization libraries * * This vectorization abstraction targets three kinds of developers: * * - Application developers create SIMD types (usually with the help of some * vectorization library) and pass them to the Dune library. They are * responsible for a compilation unit, typically a .cc file that is compiled * into a program or part of a library. Since they create the type, they * have the knowledge which library abstraction is needed and are * responsible for including that, as well as making sure the correct * compiler flags are provided. * * - Library developers implement support in Dune for handling SIMD types, * e.g. by extending some existing class. By using the interfaces provided * here, they should not have to worry about the exact vectorization library * beeing used, or whether a vectorization library is used at all. * * - Abstraction developers provide the necessary hooks to make a * vectorization library known to this interface. They are also responsible * for documenting for application developers how to meet the prerequisites * for using the abstraction, e.g. which headers to include and how to add * the necessary compiler flags. */ /** @defgroup SIMDApp Application Developer's Interface * @ingroup SIMD * @brief How to request vectorization from Dune * * This module describes how to pass vectorized types to Dune classes. It * lists the supported vectorization libraries and how to include each * (although it cannot list those libraries where support is not part of the * dune core). */ /** @defgroup SIMDLib Library Developer's Interface * @ingroup SIMD * @brief How to support vectorization in Dune classes * * This module describes how a Dune library developer can add support for * vectorization to library facilities. */ /** @defgroup SIMDAbstract Abstraction Developer's Interface * @ingroup SIMD * @brief How to add support for a new vectorization library * * This module describes the interface that you must implement if you want to * provide an abstraction layer for some vectorization library. To understand * some of the design choices, have a look at dune/common/simd/DESIGN.md in * dune-common's source. * * Everything an abstraction implementation needs to provide is in namespace * `Dune::Simd::Overloads`. * * An implementation must specialize all the template classes in namespace * `Overloads` (with the exception of `Overloads::ADLTag`, see below). To * make it possible for certain specializations not to participate in overload * resolution, each template class provides a dummy template parameter \c * SFINAETag that defaults to \c void. * * An implementation must overload all functions within namespace `Overloads` * that are defined deleted. It may overload other functions if the default * behaviour is not suitable. All functions take a value of type * `Overloads::ADLTag` as their first argument to enable * argument-dependent lookup, to be able to prioritize different overloads * with respect to each other, and to be able to inhibit certain overloads * from taking part in overload resolution. See the documentation for * `Overloads::ADLTag` for a detailed explanation. * * An abstraction implementation may not specialize `Overloads::ADLTag`, and * may not introduce new names into namespace `Overloads`. */ namespace Dune { namespace Simd { //! @brief Namespace for the overloads and specializations that make up a //! SIMD implementation /** * @ingroup SIMDAbstract * * This namespace contains three sets of things: the struct ADLTag, which * is used to look up functions in this namespace using argument-dependet * lookup, traits classes that must be specialized by abstraction * implementations, and functions that must/can be overloaded by * abstraction implementations. * * \note Only introduce new names into this namespace to extend the * interface. This applies in particular to people in the * "abstraction developer" role; they may meddle in this namespace * only by providing overloads and/or specializations for existing * names (and for `ADLTag` even that is prohibited). */ namespace Overloads { //! @addtogroup SIMDAbstract //! @{ //! Tag used to force late-binding lookup in Dune::Simd::Overloads /** * This tag is used by functions in \c Dune::Simd to make * argument-dependent lookups (ADL) for functions in \c * Dune::Simd::Overloads. The property of ADL that is used here is that * it binds the names of functions late, i.e. at the time of * instantiation, while all other lookups bind early, i.e. at the time * when the function call is parsed. Using late binding enables a * function \c foo() to find a functions \c Overloads::foo() that has * been declared only after \c foo() itself has been defined: * * \code * template * void foo(V v) * { * foo(Overloads::ADLTag<6>{}, v); * } * * struct MyType {}; * namespace Overloads { * void foo(ADLTag<4>, MyType v); * } * \endcode * * \note It is generally an error to declare a function with an ADLTag * argument outside of namespace Simd::Overloads. An exception * would be an abstraction implementation that declares all its * implementation functions in its own implementation namespace, * and then pulls them into the namespace Overloads by way of \c * using. * * `ADLTag` derives from `ADLTag`. Thus it is possible to * prioritize overloads by choosing an appropriate \c i. The following * values for \c i are predefined: * - `i==0,1`: these are reserved for the defaults. * - `i==2,3`: these are reserved for the implementation for standard * types. * - `i==5,6`: these should normally be used by other implementations * * The lower priority should be used by default. The higher priority * can be used by an implementation to resolve ambiguities, e.g. between * an overload with a by-value argument and an overload with an * lvalue-reference argument. * * The folloing priorities should not normally be used. However, they * may sometimes be necessary: * - \c i==4: override standard implementation, but prefer other * implementations * - \c i==7: try to override other implementations * * \c i==7 is the highest supported priority. * * The second (bool) template argument is to make writing abstraction * implementations that use SFINAE to remove (some of) their functions * from the overload set more concise. \c ADLTag is not * defined, so instead of * \code * std::enable_if_t > * \endcode * you may write the equivalent * \code * ADLTag<4, cond> * \endcode */ template struct ADLTag; template struct ADLTag : ADLTag {}; template<> struct ADLTag<0> {}; //! should have a member type \c type /** * Implements `Simd::Scalar`. `V` will never have cv or reference * qualifiers, no need to strip those. */ template struct ScalarType; //! should have a member type \c type /** * Implements `Simd::Rebind`. `V` and `S` will never have cv or * reference qualifiers, no need to strip those. */ template struct RebindType; //! should be derived from a `Dune::index_constant` /** * Implements `Simd::lanes()`. `V` will never have cv or reference * qualifiers, no need to strip those. */ template struct LaneCount; //! @} Group SIMDAbstract } // namespace Overloads } // namespace Simd } // namespace Dune #endif // DUNE_COMMON_SIMD_BASE_HH dune-common-2.8.0/dune/common/simd/defaults.hh000066400000000000000000000116051411343567400212640ustar00rootroot00000000000000#ifndef DUNE_COMMON_SIMD_DEFAULTS_HH #define DUNE_COMMON_SIMD_DEFAULTS_HH /** @file * @brief Default implementations for SIMD Implementations * @ingroup SIMDAbstract * * This file provides default overloads for SIMD implementation functions, and * deleted placeholders where there are no default implementations. * * This file should never be included by users of the SIMD * abstraction. Include instead. */ #include #include #include #include #include #include #include #include namespace Dune { namespace Simd { namespace Overloads { /** * @addtogroup SIMDAbstract * @{ */ /** @name Overloadable and default functions * * This group contains functions that you, as an abstraction developer, * must implement. All functions that are deleted must be provided, * functions that have a default implementation may be left * unimplemented if the default behaviour is satisfactory. * * @{ */ //! implements Simd::lane() template decltype(auto) lane(ADLTag<0>, std::size_t l, V v) = delete; //! implements Simd::implCast(V) template constexpr V implCast(ADLTag<0>, MetaType, const V &u) { return u; } //! implements Simd::implCast(U) template constexpr V implCast(ADLTag<0>, MetaType, const U &u) { V result(Simd::Scalar(0)); for(auto l : range(Simd::lanes(u))) Simd::lane(l, result) = Simd::lane(l, u); return result; } //! implements Simd::broadcast() template auto broadcast(ADLTag<0>, MetaType, S s) { return V(Simd::Scalar(s)); } //! implements Simd::cond() template V cond(ADLTag<0>, const Mask &mask, const V &ifTrue, const V &ifFalse) = delete; //! implements binary Simd::max() template auto max(ADLTag<0>, const V &v1, const V &v2) { using std::max; return max(v1, v2); } //! implements binary Simd::min() template auto min(ADLTag<0>, const V &v1, const V &v2) { using std::min; return min(v1, v2); } //! implements Simd::anyTrue() template bool anyTrue(ADLTag<0>, const Mask &mask) = delete; //! implements Simd::allTrue() /** * Default uses Simd::anyTrue() */ template bool allTrue(ADLTag<0>, const Mask &mask) { return !Dune::Simd::anyTrue(!mask); } //! implements Simd::anyFalse() /** * Default uses Simd::anyTrue() */ template bool anyFalse(ADLTag<0>, const Mask &mask) { return Dune::Simd::anyTrue(!mask); } //! implements Simd::allFalse() /** * Default uses Simd::anyTrue() */ template bool allFalse(ADLTag<0>, const Mask &mask) { return !Dune::Simd::anyTrue(mask); } //! implements Simd::maxValue() template auto max(ADLTag<0>, const V &v) { Scalar m = Simd::lane(0, v); for(std::size_t l = 1; l < Simd::lanes(v); ++l) if(m < Simd::lane(l, v)) m = Simd::lane(l, v); return m; } //! implements Simd::minValue() template auto min(ADLTag<0>, const V &v) { Scalar m = Simd::lane(0, v); for(std::size_t l = 1; l < Simd::lanes(v); ++l) if(Simd::lane(l, v) < m) m = Simd::lane(l, v); return m; } //! implements Simd::mask() template Mask mask(ADLTag<0, std::is_same >::value>, const V &v) { return v; } //! implements Simd::mask() template auto mask(ADLTag<0, !std::is_same >::value>, const V &v) { using Copy = AutonomousValue; // just in case we are handed a proxy return v != Copy(Scalar(0)); } //! implements Simd::maskOr() template auto maskOr(ADLTag<0>, const V1 &v1, const V2 &v2) { return Simd::mask(v1) || Simd::mask(v2); } //! implements Simd::maskAnd() template auto maskAnd(ADLTag<0>, const V1 &v1, const V2 &v2) { return Simd::mask(v1) && Simd::mask(v2); } //! @} Overloadable and default functions //! @} Group SIMDAbstract } // namespace Overloads } // namespace Simd } // namespace Dune #endif // DUNE_COMMON_SIMD_DEFAULTS_HH dune-common-2.8.0/dune/common/simd/interface.hh000066400000000000000000000517631411343567400214260ustar00rootroot00000000000000#ifndef DUNE_COMMON_SIMD_INTERFACE_HH #define DUNE_COMMON_SIMD_INTERFACE_HH /** @file * @brief User interface of the SIMD abstraction * @ingroup SIMDLib * * This file provides the user interface functions of the SIMD abstraction * layer. * * This file should never be included by users of the SIMD * abstraction. Include instead. */ #include #include #include #include #include #include namespace Dune { //! @brief Namespace for vectorization interface functions used by library //! developers /** * @ingroup SIMDLib */ namespace Simd { /** @addtogroup SIMDLib * * @{ * * @section understand_simd Understanding SIMD types * * The (idealized) model of a SIMD type `V` used in this abstraction layer * is that they are fixed-length vectors of some scalar type `S`. * Operations and operators that take values of type `S` as arguments, * except for `operator,()`, should be overloaded to support values of * type `V` too. These operations should apply element-wise. If the * operation takes more than one argument, it should accept arbitrary * combinations of `V` and `S`. The exception is the combination of `S` * on the left hand side and `V` on the right hand side of one of the * assignment operators, which does not make sense. * * The result of a boolean operation is a mask type `M`, which is a SIMD * type with scalar type `bool` with the same number of elements as `V`. * The result of all other operations is again of type `V`, or of some * type convertible to `V`. * * This is very similar to `std::valarray`, with the main difference * being that `std::valarray` is dynamic in size, while for this * abstraction the size is static. * * @section SIMDLibPromoWarn Type promotion issues * * True SIMD types have an issue with type promotion, which means they * cannot behave completely analogous to built-in integral types (this is * a non-issue with floating point types). Essentially, operations on * true SIMD types cannot promote their arguments, because the promoted * types typically require more storage than the original types, meaning * an argument that was passed in a single vector register would need * multiple vector registers after promotion, which would mean greater * register pressure. Also, there would be conversion operations * required, which (at least on x86) is not typically the case for * promotions of the built-in types. Lastly, with larger types the vector * units can typically operate on fewer lanes at a time. * * Omitting integral promotions has in many cases no negative impact, * because many programmers do not really expect them anyway. There are * however cases where they matter, and for illustration I want to explain * one that crept up during unit testing. * * Here is a simplified (and somewhat pseudo-code) version of the test. * The test checks the result of unary `-` on `Vc::Vector` * by comparing the result of unary `-` when applied to the complete * vector to the result of unary `-` when applied to each lane * individually. * \code * Vc::Vector varg; * for(std::size_t l = 0; l < lanes(varg); ++l) * lane(l, varg) = l + 1; * auto vresult = -varg; * for(std::size_t l = 0; l < lanes(varg); ++l) * assert(lane(l, vresult) == -lane(l, varg)); * \endcode * The test fails in lane 0. On the left side of the `==`, `lane(0, * vresult)` is `(unsigned short)65535`, which is the same as `(unsigned * short)-1`, as it should be. On the right side, `lane(0, varg)` is * `(unsigned short)1`. `-` promotes its argument, so that becomes * `(int)1`, and the result of the negation is `(int)-1`. * * Now the comparison is `(unsigned short)65535 == (int)-1`. The * comparison operator applies the *usual arithmetic conversions* to bring * both operands to the same type. In this case this boils down to * converting the left side to `int` via integral promotions and the * comparison becomes `(int)65535 == (int)-1`. The result is of course * `false` and the assertion triggers. * * The only way to thoroughly prevent this kind of problem is to convert * the result of any operation back to the expected type. In the above * example, the assertion would need to be written as `assert(lane(l, * vresult) == static_cast(-lane(l, varg)));`. In * practice, this should only be a problem with operations on unsigned * types where the result may be "negative". Most code in Dune will want * to operate on floating point types, where this is a non-issue. * * (Of couse, this is also a problem for code that operates on untrusted * input, but you should not be doing that with Dune anyway). * * Still, when writing code using the SIMD abstractions, you should be * aware that in the following snippet * \code * auto var1 = lane(0, -vec); * auto var2 = -lane(0, vec); * \endcode * the exact types of `var1` and `var2` may be somewhat surprising. * * @section simd_abstraction_limit Limitations of the Abstraction Layer * * Since the abstraction layer cannot overload operators of SIMD types * (that would be meddling with the domain of the library that provides * the SIMD types), nor provide it's own constructors, there are severe * limitations in what the abstraction layer guarantees. Besides the * standard types, the first SIMD library supported is Vc, so that is * where most of the limitations stem from; see \ref SIMDVcRestrictions in * \ref SIMDVc. * * The biggest limitations are with masks. In Vc masks support a very * restricted set of operations compared to other SIMD types, so in what * follows we will distinguish between masks with a very small set of * operations and between vectors with a larger set of operations. * * Here is a compact table of the limitations as a quick reference, * together with suggested workarounds for the constructs that don't work. * `s` denotes a scalar object/expression (i.e. of type `double` or in the * case of masks `bool`). `v` denotes a vector/mask object/expression. * `sv` means that both scalar and vector arguments are accepted. `V` * denotes a vector/mask type. `@` means any applicable operator that is * not otherwise listed. * * * \code | | Vectors | workaround | Masks | workaround | |-------------------------+---------+----------------------------+-------------+------------------| | V v(s); | y | | y | | | V v = s; | y | V v(s); | *N* | V v(s); | | V v{s}; | *N* | V v(s); | y | V v(s); | | V v = {s}; | *N* | V v(s); | y | V v(s); | |-------------------------+---------+----------------------------+-------------+------------------| | v = s; | y | v = V(s); | *N* | v = V(s); | | v = {s}; | *N* | v = V(s); | *N* | v = V(s); | |-------------------------+---------+----------------------------+-------------+------------------| | v++; ++v; | *N* | v += Scalar(1); | *N*(n/a)[2] | v = V(true); | | v--; --v; | *N* | v -= Scalar(1); | n/a | | |-------------------------+---------+----------------------------+-------------+------------------| | +v; -v; | y | | *N* | none | | !v; | y | | y | | | ~v; | y | | *N* | none | |-------------------------+---------+----------------------------+-------------+------------------| | sv @ sv; but see below | y | | *N* | none | |-------------------------+---------+----------------------------+-------------+------------------| | s << v; s >> v; | *N* | v << V(s); | *N* | none | |-------------------------+---------+----------------------------+-------------+------------------| | v == v; v != v; | y | | *N* [1] | !(v ^ v); v ^ v; | |-------------------------+---------+----------------------------+-------------+------------------| | v & v; v ^ v; v ¦ v; | y | | y | | | v && v; v ¦¦ v; | *N* | maskAnd(v,v); maskOr(v,v); | y | | |-------------------------+---------+----------------------------+-------------+------------------| | v @= sv; but see below | y | | *N* | none | | v &= v; v ^= v; v ¦= v; | y | | y | | |-------------------------+---------+----------------------------+-------------+------------------| | v, v;[3,4] | *N* | void(v), v; | y | | * \endcode * * Notes: * * - [1] In Vc, mask-mask `==` and `!=` operations exist, but the result * is of type `bool`, i.e. a scalar. * * - [2] `++` (either kind) on bools is deprecated by the standard. Our * test suite does not check for it on masks, but it was supported by Vc * masks at some point. * * - [3] Contrary to the other operators, the expected result for `(sv1, * sv2)` is exactly `sv2`, no broadcasting applied. * * - [4] Try to avoid the use of `operator,` unless both operands are * built-in types if possible. Libraries had a tendency to overload * `operator,` to provide for things like container initialization * before C++11, and these overloads may still be present in the library * you are using and replace the default meaning of `operator,`. * * Support levels: * * - `y`: operation generally works; some instances of the operation may * not apply * * - `*N*`: operation generally does not work; some instances of the * operation may not apply * * - `n/a`: operation does not apply (i.e. bitwise operations to * floating-point operands, `--` (and in the future possibly `++`) to * boolean operands, assignment operators to scalar left hand sides) */ /** @name Basic interface * * Templates and functions in this group are directly implemented by * templates and functions in namespace Overloads. * * @{ */ //! Element type of some SIMD type /** * \tparam V The SIMD (mask or vector) type. `const`, `volatile` or * reference qualifiers are automatically ignored. * * Not all operations that access the element of a vector return (a * reference to) the scalar type -- some may return proxy objects instead. * Use `autoCopy()` to make sure you are getting a prvalue of the scalar * type. * * Implemented by `Overloads::ScalarType`. */ template using Scalar = typename Overloads::ScalarType >::type; //! Construct SIMD type with different scalar type /** * \tparam S The new scalar type * \tparam V The SIMD (mask or vector) type. * * The resulting type a SIMD vector of `S` with the same number of lanes * as `V`. `const`, `volatile` or reference qualifiers in `S` and `V` are * automatically ignored, and the result will have no such qualifiers. * * Implementations shall rebind to `LoopSIMD()>` if they can't * support a particular rebind natively. * * Implemented by `Overloads::RebindType`. */ template using Rebind = typename Overloads::RebindType, std::decay_t>::type; //! @} group Basic interface /** @name Syntactic Sugar * * Templates and functions in this group provide syntactic sugar, they are * implemented using the functionality from @ref SimdInterfaceBase, and * are not customizable by implementations. * * @{ */ //! Mask type type of some SIMD type /** * \tparam V The SIMD (mask or vector) type. `const`, `volatile` or * reference qualifiers are automatically ignored. * * The mask type is kind of a SIMD vector of `bool` with the same number * of lanes as `V`. It results from comparison operations between values * of type `V`. It is only "kind of" a SIMD vector, because the * guaranteed supported operations are extremely limited. At the moment * only the logical operators `&&`, `||` and `!` and the "bitwise" * operators `&`, `^` and `|` between masks are supported, and even with * those operators you cannot rely on automatic broadcasting of `bool` * values. * * \note In particular, masks do not support comparison. As a workaround * you can use `^` instead of `!=` and `!(m1 ^ m2)` instead of `m1 * == m2`. (The reason why comparison is not supported is because * in Vc `==` and `!=` between masks yield a single `bool` result * and not a mask.) * * This is an alias for `Rebind`. */ template using Mask = Rebind; //! @} group Syntactic Sugar /** @name Basic interface * @{ */ //! Number of lanes in a SIMD type /** * \tparam V The SIMD (mask or vector) type. `const`, `volatile` * or reference qualifiers are automatically ignored. * * Implemented by `Overloads::LaneCount`. */ template constexpr std::size_t lanes() { return Overloads::LaneCount>::value; } //! Extract an element of a SIMD type /** * \param l Number of lane to extract * \param v SIMD object to extract from * * \return If `v` is a non-`const` lvalue, a reference * `Scalar>&`, or a proxy object through which the * element of `v` may be modified. Overwise, `v` is a `const` * lvalue or an rvalue, and the result is a prvalue (a temporary) * of type `Scalar>`. * * Implemented by `Overloads::lane()`. */ template decltype(auto) lane(std::size_t l, V &&v) { assert(l < lanes()); return lane(Overloads::ADLTag<7>{}, l, std::forward(v)); } //! Cast an expression from one implementation to another /** * Implemented by `Overloads::implCast()` * * Requires the scalar type and the number of lanes to match exactly. * * This is particularly useful for masks, which often know the type they * were derived from. This can become a problem when doing a conditional * operation e.g. on some floating point vector type, but with a mask * derived from some index vector type. * * \note One of the few functions that explicitly take a template * argument (`V` in this case). */ template constexpr V implCast(U &&u) { static_assert(std::is_same, Scalar >::value, "Scalar types must match exactly in implCast"); static_assert(lanes() == lanes(), "Number of lanes must match in implCast"); return implCast(Overloads::ADLTag<7>{}, MetaType >{}, std::forward(u)); } //! Broadcast a scalar to a vector explicitly /** * Implemented by `Overloads::broadcast()` * * This is useful because the syntax for broadcasting can vary wildly * between implementations. * * \note One of the few functions that explicitly take a template * argument (`V` in this case). */ template constexpr V broadcast(S s) { return broadcast(Overloads::ADLTag<7>{}, MetaType >{}, std::move(s)); } //! Like the ?: operator /** * Equivalent to * \code * V result; * for(std::size_t l = 0; l < lanes(mask); ++l) * lane(l, result) = * ( lane(l, mask) ? lane(l, ifTrue) : lane(l ifFalse) ); * return result; * \endcode * * Implemented by `Overloads::cond()`. */ template V cond(M &&mask, const V &ifTrue, const V &ifFalse) { return cond(Overloads::ADLTag<7>{}, implCast >(std::forward(mask)), ifTrue, ifFalse); } //! Like the ?: operator /** * Overload for plain bool masks, accepting any simd type * * Implemented by `Overloads::cond()`. */ template V cond(bool mask, const V &ifTrue, const V &ifFalse) { return mask ? ifTrue : ifFalse; } //! The binary maximum value over two simd objects /** * Implemented by `Overloads::max()`. */ template auto max(const V &v1, const V &v2) { return max(Overloads::ADLTag<7>{}, v1, v2); } //! The binary minimum value over two simd objects /** * Implemented by `Overloads::min()`. */ template auto min(const V &v1, const V &v2) { return min(Overloads::ADLTag<7>{}, v1, v2); } //! Whether any entry is `true` /** * Implemented by `Overloads::anyTrue()`. */ template bool anyTrue(const Mask &mask) { return anyTrue(Overloads::ADLTag<7>{}, mask); } //! Whether all entries are `true` /** * Implemented by `Overloads::allTrue()`. */ template bool allTrue(const Mask &mask) { return allTrue(Overloads::ADLTag<7>{}, mask); } //! Whether any entry is `false` /** * Implemented by `Overloads::anyFalse()`. */ template bool anyFalse(const Mask &mask) { return anyFalse(Overloads::ADLTag<7>{}, mask); } //! Whether all entries are `false` /** * Implemented by `Overloads::allFalse()`. */ template bool allFalse(const Mask &mask) { return allFalse(Overloads::ADLTag<7>{}, mask); } //! The horizontal maximum value over all lanes /** * Implemented by `Overloads::max()`. */ template Scalar max(const V &v) { return max(Overloads::ADLTag<7>{}, v); } //! The horizontal minimum value over all lanes /** * Implemented by `Overloads::min()`. */ template Scalar min(const V &v) { return min(Overloads::ADLTag<7>{}, v); } //! Convert to mask, analogue of bool(s) for scalars /** * Implemented by `Overloads::mask()`. */ template auto mask(const V &v) { return mask(Overloads::ADLTag<7>{}, v); } //! Logic or of masks /** * Implemented by `Overloads::maskOr()`. */ template auto maskOr(const V1 &v1, const V2 &v2) { return maskOr(Overloads::ADLTag<7>{}, v1, v2); } //! Logic and of masks /** * Implemented by `Overloads::maskAnd()`. */ template auto maskAnd(const V1 &v1, const V2 &v2) { return maskAnd(Overloads::ADLTag<7>{}, v1, v2); } //! @} group Basic interface /** @name Syntactic Sugar * * Templates and functions in this group provide syntactic sugar, they are * implemented using the functionality from @ref SimdInterfaceBase, and * are not customizable by implementations. * * @{ */ //! Number of lanes in a SIMD type /** * \tparam V The SIMD (mask or vector) type. * * The value of the parameter is ignored; the call is simply forwarded to * `lanes()`. */ template std::size_t lanes(const V &) { return lanes(); } //! @} group Syntactic Sugar //! @} Group SIMDLib } // namespace Simd } // namespace Dune #endif // DUNE_COMMON_SIMD_INTERFACE_HH dune-common-2.8.0/dune/common/simd/io.hh000066400000000000000000000054251411343567400200670ustar00rootroot00000000000000#ifndef DUNE_COMMON_SIMD_IO_HH #define DUNE_COMMON_SIMD_IO_HH /** @file * @brief IO interface of the SIMD abstraction * @ingroup SIMDLib * * This file provides IO interface functions of the SIMD abstraction layer. * * This file is intended for direct inclusion by header making use of the IO * interface. */ #include #include #include #include #include namespace Dune { namespace SimdImpl { template class Inserter { T value_; public: Inserter(const T &value) : value_(value) {} template::value> > friend Stream& operator<<(Stream &out, const Inserter &ins) { const char *sep = "<"; for(auto l : range(Simd::lanes(ins.value_))) { out << sep << autoCopy(Simd::lane(l, ins.value_)); sep = ", "; } out << '>'; return out; } }; template() != 1> > Inserter io(const V &v) { return { v }; } template() == 1> > Simd::Scalar io(const V &v) { return Simd::lane(0, v); } } namespace Simd { /** @addtogroup SIMDLib * * @{ * */ /** @name IO interface * * Templates and functions in this group provide syntactic sugar for IO. * They are implemented using the functionality from @ref * SimdInterfaceBase, and are not customizable by implementations. * * @{ */ //! construct a stream inserter /** * \tparam V The SIMD (mask or vector) type. * * Construct an object that can be inserted into an output stream. * Insertion prints the vector values separated by a comma and a space, * and surrounded by angular brackets. */ template auto vio(const V &v) { return SimdImpl::Inserter{ v }; } //! construct a stream inserter /** * \tparam V The SIMD (mask or vector) type. * * Construct an object that can be inserted into an output stream. For * one-lane vectors, behaves the same as scalar insertion. For multi-lane * vectors, behaves as the inserter returned by `vio()`: insertion prints * the vector values separated by a comma and a space, and surrounded by * angular brackets. */ template auto io(const V &v) { return SimdImpl::io(v); } //! @} group IO interface //! @} Group SIMDLib } // namespace Simd } // namespace Dune #endif // DUNE_COMMON_SIMD_IO_HH dune-common-2.8.0/dune/common/simd/loop.hh000066400000000000000000000560031411343567400204270ustar00rootroot00000000000000#ifndef DUNE_COMMON_SIMD_LOOP_HH #define DUNE_COMMON_SIMD_LOOP_HH #include #include #include #include #include #include #include #include namespace Dune { /* * silence warnings from GCC about using integer operands on a bool * (when instantiated for T=bool) */ #if __GNUC__ >= 7 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wbool-operation" # pragma GCC diagnostic ignored "-Wint-in-bool-context" #endif /** * This class specifies a vector-like type deriving from std::array * for memory management and basic accessibility. * This type is capable of dealing with all (well-defined) operators * and is usable with the SIMD-interface. * * @tparam T Base type. Could also be vectorized type. * @tparam S Size * @tparam minimum alignment. It is inherited to rebound types. */ template class alignas(A==0?alignof(T):A) LoopSIMD : public std::array { public: //default constructor LoopSIMD() { assert(reinterpret_cast(this) % std::min(alignof(LoopSIMD),alignof(std::max_align_t)) == 0); } // broadcast constructor initializing the content with a given value LoopSIMD(Simd::Scalar i) : LoopSIMD() { this->fill(i); } template explicit LoopSIMD(const LoopSIMD& other) : std::array(other) { assert(reinterpret_cast(this) % std::min(alignof(LoopSIMD),alignof(std::max_align_t)) == 0); } /* * Definition of basic operators */ //Prefix operators #define DUNE_SIMD_LOOP_PREFIX_OP(SYMBOL) \ auto operator SYMBOL() { \ for(std::size_t i=0; i out; \ for(std::size_t i=0; i> out; for(std::size_t i=0; i out = *this; \ SYMBOL(*this); \ return out; \ } \ static_assert(true, "expecting ;") DUNE_SIMD_LOOP_POSTFIX_OP(++); DUNE_SIMD_LOOP_POSTFIX_OP(--); #undef DUNE_SIMD_LOOP_POSTFIX_OP //Assignment operators #define DUNE_SIMD_LOOP_ASSIGNMENT_OP(SYMBOL) \ auto operator SYMBOL(const Simd::Scalar s) { \ for(std::size_t i=0; i &v) { \ for(std::size_t i=0; i>=); DUNE_SIMD_LOOP_ASSIGNMENT_OP(&=); DUNE_SIMD_LOOP_ASSIGNMENT_OP(|=); DUNE_SIMD_LOOP_ASSIGNMENT_OP(^=); #undef DUNE_SIMD_LOOP_ASSIGNMENT_OP }; //Arithmetic operators #define DUNE_SIMD_LOOP_BINARY_OP(SYMBOL) \ template \ auto operator SYMBOL(const LoopSIMD &v, const Simd::Scalar s) { \ LoopSIMD out; \ for(std::size_t i=0; i \ auto operator SYMBOL(const Simd::Scalar s, const LoopSIMD &v) { \ LoopSIMD out; \ for(std::size_t i=0; i \ auto operator SYMBOL(const LoopSIMD &v, \ const LoopSIMD &w) { \ LoopSIMD out; \ for(std::size_t i=0; i \ auto operator SYMBOL(const LoopSIMD &v, const U s) { \ LoopSIMD out; \ for(std::size_t i=0; i \ auto operator SYMBOL(const LoopSIMD &v, \ const LoopSIMD &w) { \ LoopSIMD out; \ for(std::size_t i=0; i>); #undef DUNE_SIMD_LOOP_BITSHIFT_OP //Comparison operators #define DUNE_SIMD_LOOP_COMPARISON_OP(SYMBOL) \ template \ auto operator SYMBOL(const LoopSIMD &v, const U s) { \ Simd::Mask> out; \ for(std::size_t i=0; i \ auto operator SYMBOL(const Simd::Scalar s, const LoopSIMD &v) { \ Simd::Mask> out; \ for(std::size_t i=0; i \ auto operator SYMBOL(const LoopSIMD &v, \ const LoopSIMD &w) { \ Simd::Mask> out; \ for(std::size_t i=0; i); DUNE_SIMD_LOOP_COMPARISON_OP(<=); DUNE_SIMD_LOOP_COMPARISON_OP(>=); DUNE_SIMD_LOOP_COMPARISON_OP(==); DUNE_SIMD_LOOP_COMPARISON_OP(!=); #undef DUNE_SIMD_LOOP_COMPARISON_OP //Boolean operators #define DUNE_SIMD_LOOP_BOOLEAN_OP(SYMBOL) \ template \ auto operator SYMBOL(const LoopSIMD &v, const Simd::Scalar s) { \ Simd::Mask> out; \ for(std::size_t i=0; i \ auto operator SYMBOL(const Simd::Mask s, const LoopSIMD &v) { \ Simd::Mask> out; \ for(std::size_t i=0; i \ auto operator SYMBOL(const LoopSIMD &v, \ const LoopSIMD &w) { \ Simd::Mask> out; \ for(std::size_t i=0; i std::ostream& operator<< (std::ostream &os, const LoopSIMD &v) { os << "["; for(std::size_t i=0; i struct ScalarType> { using type = Simd::Scalar; }; template struct RebindType> { using type = LoopSIMD,S,A>; }; //Implementation of SIMD-interface-functionality template struct LaneCount> : index_constant()> {}; template auto lane(ADLTag<5>, std::size_t l, LoopSIMD &&v) -> decltype(std::move(Simd::lane(l%lanes(), v[l/lanes()]))) { return std::move(Simd::lane(l%lanes(), v[l/lanes()])); } template auto lane(ADLTag<5>, std::size_t l, const LoopSIMD &v) -> decltype(Simd::lane(l%lanes(), v[l/lanes()])) { return Simd::lane(l%lanes(), v[l/lanes()]); } template auto lane(ADLTag<5>, std::size_t l, LoopSIMD &v) -> decltype(Simd::lane(l%lanes(), v[l/lanes()])) { return Simd::lane(l%lanes(), v[l/lanes()]); } template auto cond(ADLTag<5>, Simd::Mask> mask, LoopSIMD ifTrue, LoopSIMD ifFalse) { LoopSIMD out; for(std::size_t i=0; i auto cond(ADLTag<5, std::is_same >::value && Simd::lanes() == Simd::lanes >()>, M mask, LoopSIMD ifTrue, LoopSIMD ifFalse) { LoopSIMD out; for(auto l : range(Simd::lanes(mask))) Simd::lane(l, out) = Simd::lane(l, mask) ? Simd::lane(l, ifTrue) : Simd::lane(l, ifFalse); return out; } template bool anyTrue(ADLTag<5>, LoopSIMD mask) { bool out = false; for(std::size_t i=0; i bool allTrue(ADLTag<5>, LoopSIMD mask) { bool out = true; for(std::size_t i=0; i bool anyFalse(ADLTag<5>, LoopSIMD mask) { bool out = false; for(std::size_t i=0; i bool allFalse(ADLTag<5>, LoopSIMD mask) { bool out = true; for(std::size_t i=0; i>::value> > \ auto expr(const LoopSIMD &v) { \ using std::expr; \ LoopSIMD out; \ for(std::size_t i=0; i>::value> > \ auto expr(const LoopSIMD &v) { \ using std::expr; \ LoopSIMD out; \ for(std::size_t i=0; i \ auto expr(const LoopSIMD &v) { \ using std::expr; \ LoopSIMD out; \ for(std::size_t i=0; i \ auto expr(const LoopSIMD,S,A> &v) { \ using std::expr; \ LoopSIMD out; \ for(std::size_t i=0; i \ auto expr(const LoopSIMD &v, const LoopSIMD &w) { \ using std::expr; \ LoopSIMD out; \ for(std::size_t i=0; i auto isNaN(const LoopSIMD &v, PriorityTag<3>, ADLTag) { Simd::Mask> out; for(auto l : range(S)) out[l] = Dune::isNaN(v[l]); return out; } template auto isInf(const LoopSIMD &v, PriorityTag<3>, ADLTag) { Simd::Mask> out; for(auto l : range(S)) out[l] = Dune::isInf(v[l]); return out; } template auto isFinite(const LoopSIMD &v, PriorityTag<3>, ADLTag) { Simd::Mask> out; for(auto l : range(S)) out[l] = Dune::isFinite(v[l]); return out; } } //namepace MathOverloads template struct IsNumber> : public std::integral_constant::value>{ }; #if __GNUC__ >= 7 # pragma GCC diagnostic pop #endif } //namespace Dune #endif dune-common-2.8.0/dune/common/simd/simd.hh000066400000000000000000000005771411343567400204170ustar00rootroot00000000000000#ifndef DUNE_COMMON_SIMD_SIMD_HH #define DUNE_COMMON_SIMD_SIMD_HH /** @file * @brief Include file for users of the SIMD abstraction layer * * Include this file if you want to be able to handle SIMD types -- do not * include the internal headers directly. */ #include #include #endif // DUNE_COMMON_SIMD_SIMD_HH dune-common-2.8.0/dune/common/simd/standard.hh000066400000000000000000000073731411343567400212640ustar00rootroot00000000000000#ifndef DUNE_COMMON_SIMD_STANDARD_HH #define DUNE_COMMON_SIMD_STANDARD_HH /** @file * @ingroup SIMDStandard * @brief SIMD abstractions for the standard built-in types * * This file should not normally be included by users of the SIMD abstraction * (i.e. other Dune headers). Neither should it be included by the * translation units passing built-in types to Dune headers that in turn * support SIMD types through the SIMD abstraction. Dune-functionality always * supports built-in types. Either because that functionality does not * support SIMD types and so only supports built-in types, or if it does * support SIMD types it must include ``, which in * turn includes this header. */ #include #include #include #include #include #include /** @defgroup SIMDStandard SIMD Abstraction Implementation for standard types * @ingroup SIMDApp * * This implements the vectorization interface for scalar types. It applies * to any type that does not have a specialized interface implementation. * * As an application developer, there is nothing special you need to do to get * support for standard types in the vectorization abstraction. If the dune * classes you are using provide support for vectorization, they will include * ``, which will pull in the abstraction for * standard types automatically. You simply need to make sure that the types * themselves are supported: * - for built-in types there is nothing you need to do, * - for `std::complex`, you need to `#include ` * - etc. */ namespace Dune { namespace Simd { namespace Overloads { /** @name Specialized classes and overloaded functions * @ingroup SIMDStandard * @{ */ //! should have a member type \c type /** * Implements Simd::Scalar */ template struct ScalarType { using type = V; }; //! should have a member type \c type /** * Implements Simd::Rebind */ template struct RebindType { using type = S; }; //! should be derived from an Dune::index_constant /** * Implements Simd::lanes() */ template struct LaneCount : public index_constant<1> { }; //! implements Simd::lane() /** * This binds to rvalues and const lvalues. It would bind to non-const * lvalues too, but those are caught by the overload with ADLTag<3>. * Using a universal reference here would bind to any argument with a * perfect match. This would mean ambiguous overloads with other * abstractions, if those only declare overloads for `const TheirType &` * and `TheirType &`, because because universal references match * perfectly. */ template V lane(ADLTag<2>, std::size_t, V v) { return v; } template V &lane(ADLTag<3>, std::size_t, V &v) { return v; } // No Simd::cond() implementation, the overload for bool masks in the // interface is sufficient //! implements Simd::anyTrue() inline bool anyTrue(ADLTag<2>, bool mask) { return mask; } //! implements Simd::allTrue() inline bool allTrue(ADLTag<2>, bool mask) { return mask; } //! implements Simd::anyFalse() inline bool anyFalse(ADLTag<2>, bool mask) { return !mask; } //! implements Simd::allFalse() inline bool allFalse(ADLTag<2>, bool mask) { return !mask; } //! @} group SIMDStandard } // namespace Overloads } // namespace Simd } // namespace Dune #endif // DUNE_COMMON_SIMD_STANDARD_HH dune-common-2.8.0/dune/common/simd/test.cc000066400000000000000000000012421411343567400204160ustar00rootroot00000000000000#include #include #include #include void Dune::Simd::UnitTest::complain(const char *file, int line, const char *func, const char *expr) { log_ << file << ":" << line << ": In " << func << ": Error: check (" << expr << ") failed" << std::endl; good_ = false; } void Dune::Simd::UnitTest:: complain(const char *file, int line, const char *func, const std::string &opname, const char *expr) { log_ << file << ":" << line << ": In " << func << ", while testing " << opname << ": Error: check (" << expr << ") failed" << std::endl; good_ = false; } dune-common-2.8.0/dune/common/simd/test.hh000066400000000000000000002336611411343567400204440ustar00rootroot00000000000000#ifndef DUNE_COMMON_SIMD_TEST_HH #define DUNE_COMMON_SIMD_TEST_HH /** @file * @brief Common tests for simd abstraction implementations * * This file is an interface header and may be included without restrictions. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Dune { namespace Simd { namespace Impl { template struct CanCall; // not defined unless Expr has the form Op(Args...) template struct CanCall : std::false_type {}; template struct CanCall > > : std::true_type {}; template struct LessThenComparable : std::false_type {}; template struct LessThenComparable() < std::declval())> > : std::true_type {}; template struct CopyConstHelper { using type = Dst; }; template struct CopyConstHelper { using type = std::add_const_t; }; template struct CopyVolatileHelper { using type = Dst; }; template struct CopyVolatileHelper { using type = std::add_volatile_t; }; template struct CopyReferenceHelper { using type = Dst; }; template struct CopyReferenceHelper { using type = std::add_lvalue_reference_t; }; template struct CopyReferenceHelper { using type = std::add_rvalue_reference_t; }; template using CopyRefQual = typename CopyReferenceHelper< typename CopyVolatileHelper< typename CopyConstHelper< std::decay_t, std::remove_reference_t >::type, std::remove_reference_t >::type, Src >::type; template::value - 1> > struct RemoveEnd; template struct RemoveEnd> { using Back = TypeListEntry_t::value - 1, Types>; static_assert(std::is_same::value, "TypeList not terminated by proper EndMark"); using type = TypeList...>; }; template struct TypeInList; template struct TypeInList > : std::false_type {}; template struct TypeInList > : std::true_type {}; template struct TypeInList, std::enable_if_t::value> > : TypeInList >::type {}; template struct IsLoop : std::false_type {}; template struct IsLoop > : std::true_type {}; // used inside static_assert to trick the compiler into printing a list // of types: // // static_assert(debugTypes(Std::bool_constant{}), "msg"); // // Should include what the type `V` expands to in the error message. template constexpr bool debugTypes(std::true_type) { return true; } template [[deprecated]] constexpr bool debugTypes(std::false_type) { return false; } } // namespace Impl //! final element marker for `RebindList` struct EndMark {}; //! A list of types with the final element removed /** * This is `TypeList`, where `NoEndTypes...` is `Types...` * with the final element removed. The final element in `Types...` is * required to be `EndMark`. * * This is useful to construct type lists in generated source files, since * you don't need to avoid generating a trailing `,` in the list -- just * terminate it with `EndMark`. */ template using RebindList = typename Impl::RemoveEnd >::type; //! check whether a type is an instance of LoopSIMD template using IsLoop = typename Impl::IsLoop::type; class UnitTest { bool good_ = true; std::ostream &log_ = std::cerr; // records the types for which checks have started running to avoid // infinite recursion std::unordered_set seen_; //////////////////////////////////////////////////////////////////////// // // Helper functions // void complain(const char *file, int line, const char *func, const char *expr); void complain(const char *file, int line, const char *func, const std::string &opname, const char *expr); // This macro is defined only within this file, do not use anywhere // else. Doing the actual printing in an external function dramatically // reduces memory use during compilation. Defined in such a way that // the call will only happen for failed checks. #define DUNE_SIMD_CHECK(expr) \ ((expr) ? void() : complain(__FILE__, __LINE__, __func__, #expr)) // the function using this macro must define a way to compute the // operator name in DUNE_SIMD_OPNAME #define DUNE_SIMD_CHECK_OP(expr) \ ((expr) ? void() : complain(__FILE__, __LINE__, __func__, \ DUNE_SIMD_OPNAME, #expr)) // "cast" into a prvalue template static std::decay_t prvalue(T &&t) { return std::forward(t); } // whether the vector is 42 in all lanes template static bool is42(const V &v) { bool good = true; for(std::size_t l = 0; l < lanes(v); ++l) // need to cast in case we have a mask type good &= (lane(l, v) == Scalar(42)); return good; } // make a vector that contains the sequence { 1, 2, ... } template static V make123() { // initialize to avoid undefined behaviour if assigning to lane() // involves lvalue-to-rvalue conversions, e.g. due to bitmask // operations. Avoid using broadcast() for initialization to avoid // test interdependencies. V vec(Scalar(0)); for(std::size_t l = 0; l < lanes(vec); ++l) lane(l, vec) = l + 1; return vec; } // whether the vector contains the sequence { 1, 2, ... } template static bool is123(const V &v) { bool good = true; for(std::size_t l = 0; l < lanes(v); ++l) // need to cast in case we have a mask type good &= (lane(l, v) == Scalar(l+1)); return good; } template static V leftVector() { // Avoid using broadcast() for initialization to avoid test // interdependencies. V res(Scalar(0)); for(std::size_t l = 0; l < lanes(res); ++l) lane(l, res) = Scalar(l+1); return res; } template static V rightVector() { // Avoid using broadcast() for initialization to avoid test // interdependencies. V res(Scalar(0)); for(std::size_t l = 0; l < lanes(res); ++l) // do not exceed number of bits in char (for shifts) // avoid 0 (for / and %) lane(l, res) = Scalar((l)%7+1); return res; } template static T leftScalar() { return T(42); } template static T rightScalar() { // do not exceed number of bits in char (for shifts) // avoid 0 (for / and %) return T(5); } template using CanCall = Impl::CanCall; template using CopyRefQual = Impl::CopyRefQual; // test whether the Op supports the operation on scalars. We do not use // `lane()` to obtain the scalars, because that might return a proxy // object, and we are interested in what exactly the scalar type can do, // no a proxy that might have more overloads than needed. In addition, // `lane()` may not preserve `const` and reference qualifiers. template using ScalarResult = decltype(std::declval(). scalar(std::declval, Vectors> >()...)); ////////////////////////////////////////////////////////////////////// // // Check associated types // template void checkScalar() { // check that the type Scalar exists using T = Scalar; static_assert(std::is_same >::value, "Scalar types " "must not be references, and must not include " "cv-qualifiers"); [[maybe_unused]] T a{}; } template [[deprecated("Warning: please include bool in the Rebinds for " "simd type V, as Masks are not checked otherwise.")]] void warnMissingMaskRebind(std::true_type) {} template void warnMissingMaskRebind(std::false_type) {} template class RebindPrune, template class RebindAccept, class Recurse> void checkRebindOf(Recurse recurse) { Hybrid::forEach(Rebinds{}, [this,recurse](auto target) { using T = typename decltype(target)::type; // check that the rebound type exists using W = Rebind; log_ << "Type " << className() << " rebound to " << className() << " is " << className() << std::endl; static_assert(std::is_same >::value, "Rebound " "types must not be references, and must not include " "cv-qualifiers"); static_assert(lanes() == lanes(), "Rebound types must have " "the same number of lanes as the original vector " "types"); static_assert(std::is_same >::value, "Rebound types " "must have the bound-to scalar type"); if constexpr (RebindPrune{}) { log_ << "Pruning check of Simd type " << className() << std::endl; } else { using Impl::debugTypes; static_assert(debugTypes(RebindAccept{}), "Rebind is W, but that is not accepted " "by RebindAccept"); recurse(MetaType{}); } }); static_assert(std::is_same, V>, V>::value, "A type " "rebound to its own scalar type must be the same type " "as the original type"); static_assert(std::is_same, Mask >::value, "A type " "rebound to bool must be the mask type for that type"); constexpr bool hasBool = Impl::TypeInList::value; warnMissingMaskRebind(Std::bool_constant{}); } ////////////////////////////////////////////////////////////////////// // // Fundamental checks // template void checkLanes() { // check lanes static_assert(std::is_same())>::value, "return type of lanes() should be std::size_t"); static_assert(std::is_same::value, "return type of lanes(V{}) should be std::size_t"); // the result of lanes() must be constexpr [[maybe_unused]] constexpr auto size = lanes(); // but the result of lanes(vec) does not need to be constexpr DUNE_SIMD_CHECK(lanes() == lanes(V{})); } template void checkDefaultConstruct() { { [[maybe_unused]] V vec; } { [[maybe_unused]] V vec{}; } { [[maybe_unused]] V vec = {}; } } template void checkLane() { // Avoid using broadcast() for initialization to avoid test // interdependencies. V vec(Scalar(0)); // check lane() on mutable lvalues for(std::size_t l = 0; l < lanes(vec); ++l) lane(l, vec) = l + 1; for(std::size_t l = 0; l < lanes(vec); ++l) DUNE_SIMD_CHECK(lane(l, vec) == Scalar(l + 1)); using MLRes = decltype(lane(0, vec)); static_assert(std::is_same&>::value || std::is_same >::value, "Result of lane() on a mutable lvalue vector must " "either be a mutable reference to a scalar of that " "vector or a proxy object (which itself may not be a " "reference nor const)."); // check lane() on const lvalues const V &vec2 = vec; for(std::size_t l = 0; l < lanes(vec); ++l) DUNE_SIMD_CHECK(lane(l, vec2) == Scalar(l + 1)); using CLRes = decltype(lane(0, vec2)); static_assert(std::is_same&>::value || std::is_same >::value, "Result of lane() on a const lvalue vector must " "either be a const lvalue reference to a scalar of that " "vector or a proxy object (which itself may not be a " "reference nor const)."); static_assert(!std::is_assignable >::value, "Result of lane() on a const lvalue vector must not be " "assignable from a scalar."); // check lane() on rvalues for(std::size_t l = 0; l < lanes(vec); ++l) DUNE_SIMD_CHECK(lane(l, prvalue(vec)) == Scalar(l + 1)); using RRes = decltype(lane(0, prvalue(vec))); // TODO: do we really want to allow Scalar&& here? If we allow it, // then `auto &&res = lane(0, vec*vec);` creates a dangling reference, // and the scalar (and even the vector types) are small enough to be // passed in registers anyway. On the other hand, the only comparable // accessor function in the standard library that I can think of is // std::get(), and that does return an rvalue reference in this // situation. However, that cannot assume anything about the size of // the returned types. static_assert(std::is_same >::value || std::is_same&&>::value, "Result of lane() on a rvalue vector V must be " "Scalar or Scalar&&."); // Can't assert non-assignable, fails for any typical class, // e.g. std::complex<>. Would need to return const Scalar or const // Scalar&&, which would inhibit moving from the return value. // static_assert(!std::is_assignable >::value, // "Result of lane() on a rvalue vector must not be " // "assignable from a scalar."); } // check non-default constructors template void checkCopyMoveConstruct() { // elided copy/move constructors { V vec (make123()); DUNE_SIMD_CHECK(is123(vec)); } { V vec = make123() ; DUNE_SIMD_CHECK(is123(vec)); } { V vec {make123()}; DUNE_SIMD_CHECK(is123(vec)); } { V vec = {make123()}; DUNE_SIMD_CHECK(is123(vec)); } // copy constructors { V ref(make123()); V vec (ref); DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); } { V ref(make123()); V vec = ref ; DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); } { V ref(make123()); V vec {ref}; DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); } { V ref(make123()); V vec = {ref}; DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); } { const V ref(make123()); V vec (ref); DUNE_SIMD_CHECK(is123(vec)); } { const V ref(make123()); V vec = ref ; DUNE_SIMD_CHECK(is123(vec)); } { const V ref(make123()); V vec {ref}; DUNE_SIMD_CHECK(is123(vec)); } { const V ref(make123()); V vec = {ref}; DUNE_SIMD_CHECK(is123(vec)); } // move constructors { V ref(make123()); V vec (std::move(ref)); DUNE_SIMD_CHECK(is123(vec)); } { V ref(make123()); V vec = std::move(ref) ; DUNE_SIMD_CHECK(is123(vec)); } { V ref(make123()); V vec {std::move(ref)}; DUNE_SIMD_CHECK(is123(vec)); } { V ref(make123()); V vec = {std::move(ref)}; DUNE_SIMD_CHECK(is123(vec)); } } template void checkBroadcastVectorConstruct() { // broadcast copy constructors { Scalar ref = 42; V vec (ref); DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref == Scalar(42)); } { Scalar ref = 42; V vec = ref ; DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref == Scalar(42)); } // { Scalar ref = 42; V vec {ref}; // DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref == Scalar(42)); } // { Scalar ref = 42; V vec = {ref}; // DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref == Scalar(42)); } { const Scalar ref = 42; V vec (ref); DUNE_SIMD_CHECK(is42(vec)); } { const Scalar ref = 42; V vec = ref ; DUNE_SIMD_CHECK(is42(vec)); } // { const Scalar ref = 42; V vec {ref}; // DUNE_SIMD_CHECK(is42(vec)); } // { const Scalar ref = 42; V vec = {ref}; // DUNE_SIMD_CHECK(is42(vec)); } // broadcast move constructors { Scalar ref = 42; V vec (std::move(ref)); DUNE_SIMD_CHECK(is42(vec)); } { Scalar ref = 42; V vec = std::move(ref) ; DUNE_SIMD_CHECK(is42(vec)); } // { Scalar ref = 42; V vec {std::move(ref)}; // DUNE_SIMD_CHECK(is42(vec)); } // { Scalar ref = 42; V vec = {std::move(ref)}; // DUNE_SIMD_CHECK(is42(vec)); } } template void checkBroadcastMaskConstruct() { // broadcast copy constructors { Scalar ref = 42; V vec (ref); DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref == Scalar(42)); } // { Scalar ref = 42; V vec = ref ; // DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref == Scalar(42)); } { Scalar ref = 42; V vec {ref}; DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref == Scalar(42)); } // { Scalar ref = 42; V vec = {ref}; // DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref == Scalar(42)); } { const Scalar ref = 42; V vec (ref); DUNE_SIMD_CHECK(is42(vec)); } // { const Scalar ref = 42; V vec = ref ; // DUNE_SIMD_CHECK(is42(vec)); } { const Scalar ref = 42; V vec {ref}; DUNE_SIMD_CHECK(is42(vec)); } // { const Scalar ref = 42; V vec = {ref}; // DUNE_SIMD_CHECK(is42(vec)); } // broadcast move constructors { Scalar ref = 42; V vec (std::move(ref)); DUNE_SIMD_CHECK(is42(vec)); } // { Scalar ref = 42; V vec = std::move(ref) ; // DUNE_SIMD_CHECK(is42(vec)); } { Scalar ref = 42; V vec {std::move(ref)}; DUNE_SIMD_CHECK(is42(vec)); } // { Scalar ref = 42; V vec = {std::move(ref)}; // DUNE_SIMD_CHECK(is42(vec)); } } // check the implCast function template void checkImplCast() { { // lvalue arg FromV fromVec = make123(); auto toVec = implCast(fromVec); static_assert(std::is_same::value, "Unexpected result type for implCast(FromV&)"); DUNE_SIMD_CHECK(is123(fromVec)); DUNE_SIMD_CHECK(is123(toVec)); } { // const lvalue arg const FromV fromVec = make123(); auto toVec = implCast(fromVec); static_assert(std::is_same::value, "Unexpected result type for implCast(const " "FromV&)"); DUNE_SIMD_CHECK(is123(toVec)); } { // rvalue arg auto toVec = implCast(make123()); static_assert(std::is_same::value, "Unexpected result type for implCast(FromV&&)"); DUNE_SIMD_CHECK(is123(toVec)); } } // check the implCast function template void checkImplCast() { // check against LoopSIMD using LoopV = Dune::LoopSIMD, lanes()>; checkImplCast(); checkImplCast(); checkImplCast(); } // check the broadcast function template void checkBroadcast() { // broadcast function { // lvalue arg Scalar ref = 42; auto vec = broadcast(ref); static_assert(std::is_same::value, "Unexpected result type for broadcast()"); DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref == Scalar(42)); } { // const lvalue arg const Scalar ref = 42; auto vec = broadcast(ref); static_assert(std::is_same::value, "Unexpected result type for broadcast()"); DUNE_SIMD_CHECK(is42(vec)); } { // rvalue arg auto vec = broadcast(Scalar(42)); static_assert(std::is_same::value, "Unexpected result type for broadcast()"); DUNE_SIMD_CHECK(is42(vec)); } { // int arg auto vec = broadcast(42); static_assert(std::is_same::value, "Unexpected result type for broadcast()"); DUNE_SIMD_CHECK(is42(vec)); } { // double arg auto vec = broadcast(42.0); static_assert(std::is_same::value, "Unexpected result type for broadcast()"); DUNE_SIMD_CHECK(is42(vec)); } } template void checkBracedAssign() { // copy assignment { V ref = make123(); V vec; vec = {ref}; DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); } { const V ref = make123(); V vec; vec = {ref}; DUNE_SIMD_CHECK(is123(vec)); DUNE_SIMD_CHECK(is123(ref)); } // move assignment { V vec; vec = {make123()}; DUNE_SIMD_CHECK(is123(vec)); } } template void checkBracedBroadcastAssign() { // nothing works here // // broadcast copy assignment // { Scalar ref = 42; V vec; vec = {ref}; // DUNE_SIMD_CHECK(is42(vec)); DUNE_SIMD_CHECK(ref == Scalar(42)); } // { const Scalar ref = 42; V vec; vec = {ref}; // DUNE_SIMD_CHECK(is42(vec)); } // // broadcast move assignment // { Scalar ref = 42; V vec; vec = {std::move(ref)}; // DUNE_SIMD_CHECK(is42(vec)); } } ////////////////////////////////////////////////////////////////////// // // checks for unary operators // #define DUNE_SIMD_POSTFIX_OP(NAME, SYMBOL) \ struct OpPostfix##NAME \ { \ template \ auto operator()(V&& v) const \ -> decltype(std::forward(v) SYMBOL) \ { \ return std::forward(v) SYMBOL; \ } \ } #define DUNE_SIMD_PREFIX_OP(NAME, SYMBOL) \ struct OpPrefix##NAME \ { \ template \ auto operator()(V&& v) const \ -> decltype(SYMBOL std::forward(v)) \ { \ return SYMBOL std::forward(v); \ } \ } DUNE_SIMD_POSTFIX_OP(Decrement, -- ); DUNE_SIMD_POSTFIX_OP(Increment, ++ ); DUNE_SIMD_PREFIX_OP (Decrement, -- ); DUNE_SIMD_PREFIX_OP (Increment, ++ ); DUNE_SIMD_PREFIX_OP (Plus, + ); DUNE_SIMD_PREFIX_OP (Minus, - ); DUNE_SIMD_PREFIX_OP (LogicNot, ! ); // Do not warn about ~ being applied to bool. (1) Yes, doing that is // weird, but we do want to test the weird stuff too. (2) It avoids // running into on // g++-7.0 through 7.2. Also, ignore -Wpragmas to not warn about an // unknown -Wbool-operation on compilers that do not know that option. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpragmas" #pragma GCC diagnostic ignored "-Wunknown-warning-option" // clang 6.0.1 #pragma GCC diagnostic ignored "-Wbool-operation" DUNE_SIMD_PREFIX_OP (BitNot, ~ ); #pragma GCC diagnostic pop #undef DUNE_SIMD_POSTFIX_OP #undef DUNE_SIMD_PREFIX_OP template std::enable_if_t< CanCall())))>::value> checkUnaryOpV(Op op) { #define DUNE_SIMD_OPNAME (className()) // arguments auto val = leftVector>(); // copy the arguments in case V is a references auto arg = val; auto &&result = op(static_cast(arg)); using T = Scalar >; for(std::size_t l = 0; l < lanes(val); ++l) { // `op` might promote the argument. This is a problem if the // argument of the operation on the right of the `==` is // e.g. `(unsigned short)1` and the operation is e.g. unary `-`. // Then the argument is promoted to `int` before applying the // negation, and the result is `(int)-1`. However, the left side of // the `==` is still `(unsigned short)-1`, which typically is the // same as `(unsigned short)65535`. The `==` promotes the left side // before comparing, so that becomes `(int)65535`. It will then // compare `(int)65535` and `(int)-1` and rightly declare them to be // not equal. // To work around this, we explicitly convert the right side of the // `==` to the scalar type before comparing. DUNE_SIMD_CHECK_OP (lane(l, result) == static_cast(op(lane(l, static_cast(val))))); } // op might modify val, verify that any such modification also happens // in the vector case for(std::size_t l = 0; l < lanes >(); ++l) DUNE_SIMD_CHECK_OP(lane(l, val) == lane(l, arg)); #undef DUNE_SIMD_OPNAME } template std::enable_if_t< !CanCall())))>::value> checkUnaryOpV(Op op) { // log_ << "No " << className())))>() // << std::endl // << " ==> Not checking " << className() << std::endl; } template void checkUnaryOpsV(Op op) { checkUnaryOpV(op); checkUnaryOpV(op); checkUnaryOpV(op); } ////////////////////////////////////////////////////////////////////// // // checks for binary operators // // The operators contain an `operator()`, which will be invoked for both // scalar and vector arguments. The function `scalar()` is used the // test whether the scalar types support the operation (via // `ScalarResult`). The difference is that `scalar()` should only ever // receive `const`-ref-qualified version of `Scalar`, while the // `operator()` may also be called with proxies representing scalars. #define DUNE_SIMD_INFIX_OP(NAME, SYMBOL) \ struct OpInfix##NAME \ { \ template \ decltype(auto) operator()(V1&& v1, V2&& v2) const \ { \ return std::forward(v1) SYMBOL std::forward(v2); \ } \ template \ auto scalar(S1&& s1, S2&& s2) const \ -> decltype(std::forward(s1) SYMBOL std::forward(s2)); \ } // for assign ops, accept only non-const lvalue arguments for scalars. // This is needed for class scalars (e.g. std::complex) because // non-const class rvalues are actually usually assignable. Though that // assignment happens to a temporary, and thus is lost. Except that the // tests would bind the result of the assignment to a reference. And // because that result is returned from a function by reference, even // though it is a temporary passed as an argument to that function, // accessing the result later is undefined behaviour. #define DUNE_SIMD_ASSIGN_OP(NAME, SYMBOL) \ struct OpInfix##NAME \ { \ template \ decltype(auto) operator()(V1&& v1, V2&& v2) const \ { \ return std::forward(v1) SYMBOL std::forward(v2); \ } \ template \ auto scalar(S1& s1, S2&& s2) const \ -> decltype(s1 SYMBOL std::forward(s2)); \ } #define DUNE_SIMD_REPL_OP(NAME, REPLFN, SYMBOL) \ struct OpInfix##NAME \ { \ template \ decltype(auto) operator()(V1&& v1, V2&& v2) const \ { \ return Simd::REPLFN(std::forward(v1), std::forward(v2)); \ } \ template \ auto scalar(S1&& s1, S2&& s2) const \ -> decltype(std::forward(s1) SYMBOL std::forward(s2)); \ } DUNE_SIMD_INFIX_OP(Mul, * ); DUNE_SIMD_INFIX_OP(Div, / ); DUNE_SIMD_INFIX_OP(Remainder, % ); DUNE_SIMD_INFIX_OP(Plus, + ); DUNE_SIMD_INFIX_OP(Minus, - ); DUNE_SIMD_INFIX_OP(LeftShift, << ); DUNE_SIMD_INFIX_OP(RightShift, >> ); DUNE_SIMD_INFIX_OP(Less, < ); DUNE_SIMD_INFIX_OP(Greater, > ); DUNE_SIMD_INFIX_OP(LessEqual, <= ); DUNE_SIMD_INFIX_OP(GreaterEqual, >= ); DUNE_SIMD_INFIX_OP(Equal, == ); DUNE_SIMD_INFIX_OP(NotEqual, != ); DUNE_SIMD_INFIX_OP(BitAnd, & ); DUNE_SIMD_INFIX_OP(BitXor, ^ ); DUNE_SIMD_INFIX_OP(BitOr, | ); // Those are not supported in any meaningful way by vectorclass // We need to test replacement functions maskAnd() and maskOr() instead. DUNE_SIMD_REPL_OP(LogicAnd, maskAnd, && ); DUNE_SIMD_REPL_OP(LogicOr, maskOr, || ); DUNE_SIMD_ASSIGN_OP(Assign, = ); DUNE_SIMD_ASSIGN_OP(AssignMul, *= ); DUNE_SIMD_ASSIGN_OP(AssignDiv, /= ); DUNE_SIMD_ASSIGN_OP(AssignRemainder, %= ); DUNE_SIMD_ASSIGN_OP(AssignPlus, += ); DUNE_SIMD_ASSIGN_OP(AssignMinus, -= ); DUNE_SIMD_ASSIGN_OP(AssignLeftShift, <<=); DUNE_SIMD_ASSIGN_OP(AssignRightShift, >>=); DUNE_SIMD_ASSIGN_OP(AssignAnd, &= ); DUNE_SIMD_ASSIGN_OP(AssignXor, ^= ); DUNE_SIMD_ASSIGN_OP(AssignOr, |= ); #undef DUNE_SIMD_INFIX_OP #undef DUNE_SIMD_REPL_OP #undef DUNE_SIMD_ASSIGN_OP // just used as a tag struct OpInfixComma {}; template void checkCommaOp(const std::decay_t &val1, const std::decay_t &val2) { #define DUNE_SIMD_OPNAME (className()) static_assert(std::is_same(), std::declval())), T2>::value, "Type and value category of the comma operator must " "match that of the second operand"); // copy the arguments in case T1 or T2 are references auto arg1 = val1; auto arg2 = val2; // Do not warn that the left side of the comma operator is unused. // Seems to work for g++-4.9 and clang++-3.8. Appears to be harmless // for icpc (14 and 17), and icpc does not seem to issue a warning // anyway. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-value" auto &&result = (static_cast(arg1), static_cast(arg2)); #pragma GCC diagnostic pop if(std::is_reference::value) { // comma should return the same object as the second argument for // lvalues and xvalues DUNE_SIMD_CHECK_OP(&result == &arg2); // it should not modify any arguments DUNE_SIMD_CHECK_OP(allTrue(val1 == arg1)); DUNE_SIMD_CHECK_OP(allTrue(val2 == arg2)); } else { // comma should return the same value as the second argument for // prvalues DUNE_SIMD_CHECK_OP(allTrue(result == arg2)); // it should not modify any arguments DUNE_SIMD_CHECK_OP(allTrue(val1 == arg1)); // second argument is a prvalue, any modifications happen to a // temporary and we can't detect them } #undef DUNE_SIMD_OPNAME } ////////////////////////////////////////////////////////////////////// // // checks for vector-vector binary operations // // We check the following candidate operation // // vopres = vop1 @ vop2 // // against the reference operation // // arefres[l] = aref1[l] @ aref2[l] foreach l // // v... variables are simd-vectors and a... variables are arrays. The // operation may modify the operands, but if is does the modification // needs to happen in both the candidate and the reference. // // We do the following checks: // 1. lanes(vopres) == lanes(vop1) // 2. lane(l, vopres) == arefres[l] foreach l // 3. lane(l, vop1) == aref1[l] foreach l // 4. lane(l, vop2) == aref2[l] foreach l template std::enable_if_t > checkBinaryOpVV(MetaType, MetaType, Op op) { #define DUNE_SIMD_OPNAME (className()) static_assert(std::is_same, std::decay_t >::value, "Internal testsystem error: called with two types that " "don't decay to the same thing"); // reference arguments auto vref1 = leftVector>(); auto vref2 = rightVector>(); // candidate arguments auto vop1 = vref1; auto vop2 = vref2; // candidate operation auto &&vopres = op(static_cast(vop1), static_cast(vop2)); using VR = decltype(vopres); // check 1. lanes(vopres) == lanes(vop1) static_assert(lanes >() == lanes >(), "The result must have the same number of lanes as the " "operands."); // do the reference operation, and simultaneously // check 2. lane(l, vopres) == arefres[l] foreach l using T = Scalar >; for(auto l : range(lanes(vopres))) { // see the lengthy comment in `checkUnaryOpV()` as to why the // `static_cast` around the `op()` is necessary DUNE_SIMD_CHECK_OP (lane(l, vopres) == static_cast(op(lane(l, static_cast(vref1)), lane(l, static_cast(vref2))))); } // check 3. lane(l, vop1) == aref1[l] foreach l for(auto l : range(lanes(vop1))) DUNE_SIMD_CHECK_OP(lane(l, vop1) == lane(l, vref1)); // check 4. lane(l, vop2) == aref2[l] foreach l for(auto l : range(lanes(vop2))) DUNE_SIMD_CHECK_OP(lane(l, vop2) == lane(l, vref2)); #undef DUNE_SIMD_OPNAME } template std::enable_if_t > checkBinaryOpVV(MetaType, MetaType, Op op) { // log_ << "No " << className())), // decltype(lane(0, std::declval())))>() // << std::endl // << " ==> Not checking " << className() << std::endl; } template void checkBinaryOpVV(MetaType, MetaType, OpInfixComma) { static_assert(std::is_same, std::decay_t >::value, "Internal testsystem error: called with two types that " "don't decay to the same thing"); checkCommaOp(leftVector>(), rightVector>()); } ////////////////////////////////////////////////////////////////////// // // checks for vector-scalar binary operations // // We check the following candidate operation // // vopres = vop1 @ sop2 // // against the reference operation // // arefres[l] = aref1[l] @ sref2 foreach l // // v... variables are simd-vectors, a... variables are arrays, and // s... variables are scalars. The operation may modify the left // operand, but if is does the modifications needs to happen in both the // candidate and the reference. // // We do the following checks: // 1. lanes(vopres) == lanes(vop1) // 2. lane(l, vopres) == arefres[l] foreach l // 3. lane(l, vop1) == aref1[l] foreach l // 4. sop2 is never modified // 5. sref2 is never modified // // In fact, if the property "sref2 is never modified" is violated that // means the operation is unsuitable for an automatic broadcast of the // second operand and should not be checked. There are no operations in // the standard where the second operand is modified like this, but // there are operations where the first operand is modified -- and this // check is used for those ops as well by exchanging the first and second // argument below. template std::enable_if_t > checkBinaryOpVS(MetaType, MetaType, Op op) { #define DUNE_SIMD_OPNAME (className()) static_assert(std::is_same >, std::decay_t >::value, "Internal testsystem error: called with a scalar that " "does not match the vector type."); // initial values auto sinit2 = rightScalar>(); // reference arguments auto vref1 = leftVector>(); auto sref2 = sinit2; // candidate arguments auto vop1 = vref1; auto sop2 = sref2; // candidate operation auto &&vopres = op(static_cast(vop1), static_cast(sop2)); using VR = decltype(vopres); // check 1. lanes(vopres) == lanes(vop1) static_assert(lanes >() == lanes >(), "The result must have the same number of lanes as the " "operands."); // check 4. sop2 is never modified DUNE_SIMD_CHECK_OP(sop2 == sinit2); // do the reference operation, and simultaneously check 2. and 5. using T = Scalar >; for(auto l : range(lanes(vopres))) { // check 2. lane(l, vopres) == arefres[l] foreach l // see the lengthy comment in `checkUnaryOpV()` as to why the // `static_cast` around the `op()` is necessary DUNE_SIMD_CHECK_OP (lane(l, vopres) == static_cast(op(lane(l, static_cast(vref1)), static_cast(sref2) ))); // check 5. sref2 is never modified DUNE_SIMD_CHECK_OP(sref2 == sinit2); } // check 3. lane(l, vop1) == aref1[l] foreach l for(auto l : range(lanes(vop1))) DUNE_SIMD_CHECK_OP(lane(l, vop1) == lane(l, vref1)); #undef DUNE_SIMD_OPNAME } template std::enable_if_t > checkBinaryOpVS(MetaType, MetaType, Op op) { // log_ << "No " // << className())), T2)>() // << std::endl // << " ==> Not checking " << className() << std::endl; } template void checkBinaryOpVS(MetaType, MetaType, OpInfixComma) { static_assert(std::is_same >, std::decay_t >::value, "Internal testsystem error: called with a scalar that " "does not match the vector type."); checkCommaOp(leftVector>(), rightScalar>()); } ////////////////////////////////////////////////////////////////////// // // cross-check scalar-vector binary operations against vector-vector // // We check the following candidate operation // // vopres = vop1 @ vop2, where vop2 = broadcast(sref2) // // against the reference operation // // vrefres = vref1 @ sref2 // // v... variables are simd-vectors, a... variables are arrays, and // s... variables are scalars. // // We could check the following properties // 1. lanes(vopres) == lanes(vop1) // 2. lane(l, vopres) == lane(l, vrefres) foreach l // 3. lane(l, vop1) == lane(l, vref1) foreach l // but these are given by checking the operation against the scalar // operation in the vector@vector and vector@scalar cases above. // // The only thing left to check is: // 4. lane(l, vop2) foreach l is never modified template std::enable_if_t > checkBinaryOpVVAgainstVS(MetaType, MetaType, Op op) { #define DUNE_SIMD_OPNAME (className()) static_assert(std::is_same >, std::decay_t >::value, "Internal testsystem error: called with a scalar that " "does not match the vector type."); // initial values auto sinit2 = rightScalar>(); // reference arguments auto vop1 = leftVector>(); using V2 = CopyRefQual; std::decay_t vop2(sinit2); // candidate operation op(static_cast(vop1), static_cast(vop2)); // 4. lane(l, vop2) foreach l is never modified for(auto l : range(lanes(vop2))) DUNE_SIMD_CHECK_OP(lane(l, vop2) == sinit2); #undef DUNE_SIMD_OPNAME } template std::enable_if_t > checkBinaryOpVVAgainstVS(MetaType, MetaType, Op op) { // log_ << "No " // << className())), T2)>() // << std::endl // << " ==> Not checking " << className() << std::endl; } template void checkBinaryOpVVAgainstVS(MetaType, MetaType, OpInfixComma) { } ////////////////////////////////////////////////////////////////////// // // checks for vector-proxy binary operations // // We check the following candidate operation // // vopres = vop1 @ pop2 // // against the reference operation // // arefres[l] = aref1[l] @ sref2 foreach l // // v... variables are simd-vectors, a... variables are arrays, // p... variables are proxies of simd-vector entries and s... variables // are scalars. The operation may modify the left operand, but if is // does the modifications needs to happen in both the candidate and the // reference. // // We do the following checks: // 1. lanes(vopres) == lanes(vop1) // 2. lane(l, vopres) == arefres[l] foreach l // 3. lane(l, vop1) == aref1[l] foreach l // 4. pop2 is never modified // 5. sref2 is never modified // // In fact, if the property "sref2 is never modified" is violated that // means the operation is unsuitable for an automatic broadcast of the // second operand and should not be checked. There are no operations in // the standard where the second operand is modified like this, but // there are operations where the first operand is modified -- and this // check is used for those ops as well by exchanging the first and second // argument below. template std::enable_if_t > checkBinaryOpVP(MetaType, MetaType, Op op) { using P2 = decltype(lane(0, std::declval())); using T2 = CopyRefQual, V2>; #define DUNE_SIMD_OPNAME (className()) static_assert(std::is_same, Scalar >::value, "Internal testsystem error: called with two vector " "types whose scalar types don't match."); // initial values auto sinit2 = rightScalar>(); // reference arguments auto vref1 = leftVector>(); auto sref2 = sinit2; // candidate arguments auto vop1 = vref1; auto vop2 = std::decay_t(Scalar(0)); lane(0, vop2) = sref2; // pop2 is just a name for `lane(0, vop2)` // candidate operation auto &&vopres = op(static_cast(vop1), lane(0, static_cast(vop2))); using VR = decltype(vopres); // check 1. lanes(vopres) == lanes(vop1) static_assert(lanes >() == lanes >(), "The result must have the same number of lanes as the " "operands."); // check 4. pop2 is never modified DUNE_SIMD_CHECK_OP(lane(0, vop2) == sinit2); // do the reference operation, and simultaneously check 2. and 5. using T = Scalar; for(auto l : range(lanes(vopres))) { // check 2. lane(l, vopres) == arefres[l] foreach l // see the lengthy comment in `checkUnaryOpV()` as to why the // `static_cast` around the `op()` is necessary DUNE_SIMD_CHECK_OP (lane(l, vopres) == static_cast(op(lane(l, static_cast(vref1)), static_cast(sref2) ))); // check 5. sref2 is never modified DUNE_SIMD_CHECK_OP(sref2 == sinit2); } // check 3. lane(l, vop1) == aref1[l] foreach l for(auto l : range(lanes(vop1))) DUNE_SIMD_CHECK_OP(lane(l, vop1) == lane(l, vref1)); #undef DUNE_SIMD_OPNAME } template std::enable_if_t > checkBinaryOpVP(MetaType, MetaType, Op op) { // log_ << "No " // << className())), T2)>() // << std::endl // << " ==> Not checking " << className() << std::endl; } template void checkBinaryOpVP(MetaType, MetaType, OpInfixComma) { // Don't really know how to check comma operator for proxies } ////////////////////////////////////////////////////////////////////// // // checks for (scalar/proxy)-vector binary operations // template struct OpInfixSwappedArgs { Op orig; template decltype(auto) operator()(V1&& v1, V2&& v2) const { return orig(std::forward(v2), std::forward(v1)); } template auto scalar(S1&& s1, S2&& s2) const -> decltype(orig.scalar(std::forward(s2), std::forward(s1))); }; template void checkBinaryOpSV(MetaType t1, MetaType v2, Op op) { checkBinaryOpVS(v2, t1, OpInfixSwappedArgs{op}); } template void checkBinaryOpSV(MetaType, MetaType, OpInfixComma) { static_assert(std::is_same, Scalar > >::value, "Internal testsystem error: called with a scalar that " "does not match the vector type."); checkCommaOp(leftScalar>(), rightVector>()); } template void checkBinaryOpPV(MetaType v1, MetaType v2, Op op) { checkBinaryOpVP(v2, v1, OpInfixSwappedArgs{op}); } template void checkBinaryOpPV(MetaType, MetaType, OpInfixComma) { // Don't really know how to check comma operator for proxies } ////////////////////////////////////////////////////////////////////// // // cross-check scalar-vector binary operations against vector-vector // // We check the following candidate operation // // vopres = vop1 @ vop2, where vop2 = broadcast(sref2) // // against the reference operation // // vrefres = vref1 @ sref2 // // v... variables are simd-vectors, a... variables are arrays, and // s... variables are scalars. // // We could check the following properties // 1. lanes(vopres) == lanes(vop1) // 2. lane(l, vopres) == lane(l, vrefres) foreach l // 3. lane(l, vop1) == lane(l, vref1) foreach l // but these are given by checking the operation against the scalar // operation in the vector@vector and vector@scalar cases above. // // The only thing left to check is: // 4. lane(l, vop2) foreach l is never modified template void checkBinaryOpVVAgainstSV(MetaType t1, MetaType v2, Op op) { checkBinaryOpVVAgainstVS(v2, t1, OpInfixSwappedArgs{op}); } template void checkBinaryOpVVAgainstSV(MetaType, MetaType, OpInfixComma) { } ////////////////////////////////////////////////////////////////////// // // Invoke the checks for all combinations // template void checkBinaryRefQual(Checker checker) { if constexpr (condition) { Hybrid::forEach(TypeList{}, [=] (auto t1) { Hybrid::forEach(TypeList{}, [=] (auto t2) { checker(t1, t2); }); }); } } template void checkBinaryOps(Checker checker) { using Std::bool_constant; constexpr bool isMask = std::is_same, bool>::value; constexpr bool do_ = false; constexpr bool do_SV = true; constexpr bool do_VV = true; constexpr bool do_VS = true; #define DUNE_SIMD_DO(M1, M2, M3, V1, V2, V3, NAME) \ checker(bool_constant{}, \ bool_constant{}, \ bool_constant{}, \ Op##NAME{}) // (Mask , Vector , Name ); DUNE_SIMD_DO( , , , SV, VV, VS, InfixMul ); DUNE_SIMD_DO( , , , SV, VV, VS, InfixDiv ); DUNE_SIMD_DO( , , , SV, VV, VS, InfixRemainder ); DUNE_SIMD_DO( , , , SV, VV, VS, InfixPlus ); DUNE_SIMD_DO( , , , SV, VV, VS, InfixMinus ); DUNE_SIMD_DO( , , , , VV, VS, InfixLeftShift ); DUNE_SIMD_DO( , , , , VV, VS, InfixRightShift ); DUNE_SIMD_DO( , , , SV, VV, VS, InfixLess ); DUNE_SIMD_DO( , , , SV, VV, VS, InfixGreater ); DUNE_SIMD_DO( , , , SV, VV, VS, InfixLessEqual ); DUNE_SIMD_DO( , , , SV, VV, VS, InfixGreaterEqual ); DUNE_SIMD_DO( , , , SV, VV, VS, InfixEqual ); DUNE_SIMD_DO( , , , SV, VV, VS, InfixNotEqual ); DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitAnd ); DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitXor ); DUNE_SIMD_DO( , VV, , SV, VV, VS, InfixBitOr ); DUNE_SIMD_DO(SV, VV, VS, SV, VV, VS, InfixLogicAnd ); DUNE_SIMD_DO(SV, VV, VS, SV, VV, VS, InfixLogicOr ); DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssign ); DUNE_SIMD_DO( , , , , VV, VS, InfixAssignMul ); DUNE_SIMD_DO( , , , , VV, VS, InfixAssignDiv ); DUNE_SIMD_DO( , , , , VV, VS, InfixAssignRemainder ); DUNE_SIMD_DO( , , , , VV, VS, InfixAssignPlus ); DUNE_SIMD_DO( , , , , VV, VS, InfixAssignMinus ); DUNE_SIMD_DO( , , , , VV, VS, InfixAssignLeftShift ); DUNE_SIMD_DO( , , , , VV, VS, InfixAssignRightShift); DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignAnd ); DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignXor ); DUNE_SIMD_DO( , VV, , , VV, VS, InfixAssignOr ); DUNE_SIMD_DO(SV, VV, VS, SV, , VS, InfixComma ); #undef DUNE_SIMD_DO } ////////////////////////////////////////////////////////////////////// // // SIMD interface functions // template void checkAutoCopy() { using RValueResult = decltype(autoCopy(lane(0, std::declval()))); static_assert(std::is_same >::value, "Result of autoCopy() must always be Scalar"); using MutableLValueResult = decltype(autoCopy(lane(0, std::declval()))); static_assert(std::is_same >::value, "Result of autoCopy() must always be Scalar"); using ConstLValueResult = decltype(autoCopy(lane(0, std::declval()))); static_assert(std::is_same >::value, "Result of autoCopy() must always be Scalar"); V vec = make123(); for(std::size_t l = 0; l < lanes(vec); ++l) DUNE_SIMD_CHECK(autoCopy(lane(l, vec)) == Scalar(l+1)); } // may only be called for mask types template void checkBoolReductions() { M trueVec(true); // mutable lvalue DUNE_SIMD_CHECK(allTrue (static_cast(trueVec)) == true); DUNE_SIMD_CHECK(anyTrue (static_cast(trueVec)) == true); DUNE_SIMD_CHECK(allFalse(static_cast(trueVec)) == false); DUNE_SIMD_CHECK(anyFalse(static_cast(trueVec)) == false); // const lvalue DUNE_SIMD_CHECK(allTrue (static_cast(trueVec)) == true); DUNE_SIMD_CHECK(anyTrue (static_cast(trueVec)) == true); DUNE_SIMD_CHECK(allFalse(static_cast(trueVec)) == false); DUNE_SIMD_CHECK(anyFalse(static_cast(trueVec)) == false); // rvalue DUNE_SIMD_CHECK(allTrue (M(true)) == true); DUNE_SIMD_CHECK(anyTrue (M(true)) == true); DUNE_SIMD_CHECK(allFalse(M(true)) == false); DUNE_SIMD_CHECK(anyFalse(M(true)) == false); M falseVec(false); // mutable lvalue DUNE_SIMD_CHECK(allTrue (static_cast(falseVec)) == false); DUNE_SIMD_CHECK(anyTrue (static_cast(falseVec)) == false); DUNE_SIMD_CHECK(allFalse(static_cast(falseVec)) == true); DUNE_SIMD_CHECK(anyFalse(static_cast(falseVec)) == true); // const lvalue DUNE_SIMD_CHECK(allTrue (static_cast(falseVec)) == false); DUNE_SIMD_CHECK(anyTrue (static_cast(falseVec)) == false); DUNE_SIMD_CHECK(allFalse(static_cast(falseVec)) == true); DUNE_SIMD_CHECK(anyFalse(static_cast(falseVec)) == true); // rvalue DUNE_SIMD_CHECK(allTrue (M(false)) == false); DUNE_SIMD_CHECK(anyTrue (M(false)) == false); DUNE_SIMD_CHECK(allFalse(M(false)) == true); DUNE_SIMD_CHECK(anyFalse(M(false)) == true); auto mixedVec = broadcast(0); for(std::size_t l = 0; l < lanes(mixedVec); ++l) lane(l, mixedVec) = (l % 2); // mutable lvalue DUNE_SIMD_CHECK (allTrue (static_cast(mixedVec)) == false); DUNE_SIMD_CHECK (anyTrue (static_cast(mixedVec)) == (lanes() > 1)); DUNE_SIMD_CHECK (allFalse(static_cast(mixedVec)) == (lanes() == 1)); DUNE_SIMD_CHECK (anyFalse(static_cast(mixedVec)) == true); // const lvalue DUNE_SIMD_CHECK (allTrue (static_cast(mixedVec)) == false); DUNE_SIMD_CHECK (anyTrue (static_cast(mixedVec)) == (lanes() > 1)); DUNE_SIMD_CHECK (allFalse(static_cast(mixedVec)) == (lanes() == 1)); DUNE_SIMD_CHECK (anyFalse(static_cast(mixedVec)) == true); // rvalue DUNE_SIMD_CHECK(allTrue (M(mixedVec)) == false); DUNE_SIMD_CHECK(anyTrue (M(mixedVec)) == (lanes() > 1)); DUNE_SIMD_CHECK(allFalse(M(mixedVec)) == (lanes() == 1)); DUNE_SIMD_CHECK(anyFalse(M(mixedVec)) == true); } template void checkCond() { using M = Mask; static_assert (std::is_same(), std::declval(), std::declval())), V>::value, "The result of cond(M, V, V) should have exactly the type V"); static_assert (std::is_same(), std::declval(), std::declval())), V>::value, "The result of cond(const M&, const V&, const V&) should have " "exactly the type V"); static_assert (std::is_same(), std::declval(), std::declval())), V>::value, "The result of cond(M&, V&, V&) should have exactly the type V"); V vec1 = leftVector(); V vec2 = rightVector(); DUNE_SIMD_CHECK(allTrue(cond(M(true), vec1, vec2) == vec1)); DUNE_SIMD_CHECK(allTrue(cond(M(false), vec1, vec2) == vec2)); auto mixedResult = broadcast(0); auto mixedMask = broadcast(false); for(std::size_t l = 0; l < lanes(mixedMask); ++l) { lane(l, mixedMask ) = (l % 2); lane(l, mixedResult) = lane(l, (l % 2) ? vec1 : vec2); } DUNE_SIMD_CHECK(allTrue(cond(mixedMask, vec1, vec2) == mixedResult)); } template void checkBoolCond() { static_assert (std::is_same(), std::declval(), std::declval())), V>::value, "The result of cond(bool, V, V) should have exactly the type V"); static_assert (std::is_same(), std::declval(), std::declval())), V>::value, "The result of cond(const bool&, const V&, const V&) should have " "exactly the type V"); static_assert (std::is_same(), std::declval(), std::declval())), V>::value, "The result of cond(bool&, V&, V&) should have exactly the type V"); V vec1 = leftVector(); V vec2 = rightVector(); DUNE_SIMD_CHECK(allTrue(cond(true, vec1, vec2) == vec1)); DUNE_SIMD_CHECK(allTrue(cond(false, vec1, vec2) == vec2)); } template std::enable_if_t >::value> checkHorizontalMinMax() {} template std::enable_if_t >::value> checkHorizontalMinMax() { static_assert (std::is_same())), Scalar >::value, "The result of max(V) should be exactly Scalar"); static_assert (std::is_same())), Scalar >::value, "The result of min(V) should be exactly Scalar"); static_assert (std::is_same())), Scalar >::value, "The result of max(V) should be exactly Scalar"); static_assert (std::is_same())), Scalar >::value, "The result of min(V) should be exactly Scalar"); const V vec1 = leftVector(); DUNE_SIMD_CHECK(max(vec1) == Scalar(lanes(vec1))); DUNE_SIMD_CHECK(min(vec1) == Scalar(1)); } template std::enable_if_t >::value> checkBinaryMinMax() {} template std::enable_if_t >::value> checkBinaryMinMax() { using std::max; using std::min; static_assert (std::is_same(), std::declval())), V>::value, "The result of Simd::max(V, V) should be exactly V"); static_assert (std::is_same(), std::declval())), V>::value, "The result of Simd::min(V, V) should be exactly V"); static_assert (std::is_same(), std::declval())), V>::value, "The result of Simd::max(V&, V&) should be exactly V"); static_assert (std::is_same(), std::declval())), V>::value, "The result of Simd::min(V&, V&) should be exactly V"); const V arg1 = leftVector(); const V arg2 = rightVector(); V maxExp(Scalar(0)), minExp(Scalar(0)); for(auto l : range(lanes())) { lane(l, maxExp) = max(lane(l, arg1), lane(l, arg2)); lane(l, minExp) = min(lane(l, arg1), lane(l, arg2)); } DUNE_SIMD_CHECK(allTrue(maxExp == Simd::max(arg1, arg2))); DUNE_SIMD_CHECK(allTrue(minExp == Simd::min(arg1, arg2))); } template void checkIO() { const V vec1 = leftVector(); std::string reference; { const char *sep = ""; for(auto l : range(lanes(vec1))) { std::ostringstream stream; stream << lane(l, vec1); reference += sep; reference += stream.str(); sep = ", "; } } { std::ostringstream stream; stream << io(vec1); if(lanes(vec1) == 1) DUNE_SIMD_CHECK(stream.str() == reference); else DUNE_SIMD_CHECK(stream.str() == "<" + reference + ">"); } { std::ostringstream stream; stream << vio(vec1); DUNE_SIMD_CHECK(stream.str() == "<" + reference + ">"); } } #undef DUNE_SIMD_CHECK public: /** * @name Test instantiation points * * These functions should not be called directly, but serve as explicit * instantiation points to keep memory usage bounded during compilation. * There should be an explicit instantiation declaration (`extern * template ...`) in the the overall header of your unit test for each * type that is tested (possibly implicitly tested due to recursive * checks). Similarly, there should be an explicit instantiation * definition (`template ...`) in a separate translation unit. Ideally, * there should be one translation unit per explicit instantiation * definition, otherwise each of them will contribute to the overall * memory used during compilation. * * If explicitly instantiating the top-level instantiation point * `checkType()` is not sufficient, there are further instantiation * points for improved granularity. The hierarchy of instantiation * points is: * - `checkType()` * - `checkNonOps()` * - `checkUnaryOps()` * - `checkBinaryOps()` * - `checkBinaryOpsVectorVector()` * - `checkBinaryOpsScalarVector()` * - `checkBinaryOpsVectorScalar()` * - `checkBinaryOpsProxyVector()` * - `checkBinaryOpsVectorProxy()` * * Each instantiation point in the hierarchy implicitly instantiates its * descendants, unless there are explicit instantiation declarations for * them. However, for future-proofing it can make sense to explicitly * instantiate nodes in the hierarchy even if all their children are * already explicitly instantiated. This will limit the impact of * instantiation points added in the future. * * For an example of how to do the instantiations, look at * `standardtest`, there is cmake machinery to support you. * * Background: The compiler can use a lot of memory when compiling a * unit test for many Simd vector types. E.g. for standardtest.cc, * which tests all the fundamental arithmetic types plus \c * std::complex, g++ 4.9.2 (-g -O0 -Wall on x86_64 GNU/Linux) used * ~6GByte. * * One mitigation was to explicitly instantiate \c checkVector() (a * previous, now obsolete incarnation of this instantiation machinery) * for the types that are tested. Still after doing that, * standardtest.cc needed ~1.5GByte during compilation, which is more * than the compilation units that actually instantiated \c * checkVector() (which clocked in at maximum at around 800MB, depending * on how many instantiations they contained). * * The second mitigation was to define \c checkVector() outside of the * class. I have no idea why this helped, but it made compilation use * less than ~100MByte. (Yes, functions defined inside the class are * implicitly \c inline, but the function is a template so it has inline * semantics even when defined outside of the class. And I tried \c * __attribute__((__noinline__)), which had no effect on memory * consumption.) * * @{ */ template void checkType(); template void checkNonOps(); template void checkUnaryOps(); template void checkBinaryOps(); template void checkBinaryOpsVectorVector(); template void checkBinaryOpsScalarVector(); template void checkBinaryOpsVectorScalar(); template void checkBinaryOpsProxyVector(); template void checkBinaryOpsVectorProxy(); /** @} Group Test instantiation points */ //! run unit tests for simd vector type V /** * This function will also ensure that `check()` is run, for any type * `W = Rebind` where `R` is in `Rebinds`, and * `RebindPrune::value == false`. No test will be run twice for a * given type. * * If the result of `Rebind` is not pruned by `RebindPrune`, it will be * passed to `RebindAccept`. If that rejects the type, a static * assertion will trigger. * * \tparam Rebinds A list of types, usually in the form of a * `TypeList`. * \tparam RebindPrune A type predicate determining whether to run * `check()` for types obtained from `Rebinds`. * \tparam RebindAccept A type predicate determining whether a type is * acceptable as the result of a `Rebind`. */ template class RebindPrune = IsLoop, template class RebindAccept = Dune::AlwaysTrue> void check() { // check whether the test for this type already started if(seen_.emplace(typeid (V)).second == false) { // type already seen, nothing to do return; } // do these first so everything that appears after "Checking SIMD type // ..." really pertains to that type auto recurse = [this](auto w) { using W = typename decltype(w)::type; this->template check(); }; checkRebindOf(recurse); checkType(); } //! whether all tests succeeded bool good() const { return good_; } }; // class UnitTest template void UnitTest::checkType() { static_assert(std::is_same >::value, "Simd types " "must not be references, and must not include " "cv-qualifiers"); log_ << "Checking SIMD type " << className() << std::endl; checkNonOps(); checkUnaryOps(); checkBinaryOps(); } template void UnitTest::checkNonOps() { constexpr auto isMask = typename std::is_same, bool>::type{}; checkLanes(); checkScalar(); checkDefaultConstruct(); checkLane(); checkCopyMoveConstruct(); checkImplCast(); checkBroadcast(); if constexpr (isMask) this->template checkBroadcastMaskConstruct(); else this->template checkBroadcastVectorConstruct(); checkBracedAssign(); checkBracedBroadcastAssign(); checkAutoCopy(); checkCond(); checkBoolCond(); if constexpr (isMask) this->template checkBoolReductions(); // checkBoolReductions() is not applicable for non-masks checkHorizontalMinMax(); checkBinaryMinMax(); checkIO(); } template void UnitTest::checkUnaryOps() { if constexpr (std::is_same_v, bool>) { // check mask auto check = [this](auto op) { this->template checkUnaryOpsV(op); }; // postfix // check(OpPostfixDecrement{}); // clang deprecation warning if bool++ is tested // check(OpPostfixIncrement{}); // prefix // check(OpPrefixDecrement{}); // clang deprecation warning if ++bool is tested // check(OpPrefixIncrement{}); // check(OpPrefixPlus{}); // check(OpPrefixMinus{}); check(OpPrefixLogicNot{}); // check(OpPrefixBitNot{}); } else { // check vector auto check = [this](auto op) { this->template checkUnaryOpsV(op); }; // postfix // check(OpPostfixDecrement{}); // check(OpPostfixIncrement{}); // prefix // check(OpPrefixDecrement{}); // check(OpPrefixIncrement{}); // check(OpPrefixPlus{}); check(OpPrefixMinus{}); check(OpPrefixLogicNot{}); check(OpPrefixBitNot{}); } } template void UnitTest::checkBinaryOps() { checkBinaryOpsVectorVector(); checkBinaryOpsScalarVector(); checkBinaryOpsVectorScalar(); checkBinaryOpsProxyVector(); checkBinaryOpsVectorProxy(); } template void UnitTest::checkBinaryOpsVectorVector() { auto checker = [this](auto doSV, auto doVV, auto doVS, auto op) { auto check = [this,op](auto t1, auto t2) { this->checkBinaryOpVV(t1, t2, op); }; this->checkBinaryRefQual(check); }; checkBinaryOps(checker); } template void UnitTest::checkBinaryOpsScalarVector() { auto checker = [this](auto doSV, auto doVV, auto doVS, auto op) { auto check = [this,op](auto t1, auto t2) { this->checkBinaryOpSV(t1, t2, op); }; this->checkBinaryRefQual, V, doSV>(check); auto crossCheck = [this,op](auto t1, auto t2) { this->checkBinaryOpVVAgainstSV(t1, t2, op); }; this->checkBinaryRefQual, V, doSV && doVV>(crossCheck); }; checkBinaryOps(checker); } template void UnitTest::checkBinaryOpsVectorScalar() { auto checker = [this](auto doSV, auto doVV, auto doVS, auto op) { auto check = [this,op](auto t1, auto t2) { this->checkBinaryOpVS(t1, t2, op); }; this->checkBinaryRefQual, doVS>(check); auto crossCheck = [this,op](auto t1, auto t2) { this->checkBinaryOpVVAgainstVS(t1, t2, op); }; this->checkBinaryRefQual, doVV && doVS>(crossCheck); }; checkBinaryOps(checker); } template void UnitTest::checkBinaryOpsProxyVector() { auto checker = [this](auto doSV, auto doVV, auto doVS, auto op) { auto check = [this,op](auto t1, auto t2) { this->checkBinaryOpPV(t1, t2, op); }; this->checkBinaryRefQual(check); }; checkBinaryOps(checker); } template void UnitTest::checkBinaryOpsVectorProxy() { auto checker = [this](auto doSV, auto doVV, auto doVS, auto op) { auto check = [this,op](auto t1, auto t2) { this->checkBinaryOpVP(t1, t2, op); }; this->checkBinaryRefQual(check); }; checkBinaryOps(checker); } } // namespace Simd } // namespace Dune #endif // DUNE_COMMON_SIMD_TEST_HH dune-common-2.8.0/dune/common/simd/test/000077500000000000000000000000001411343567400201105ustar00rootroot00000000000000dune-common-2.8.0/dune/common/simd/test/CMakeLists.txt000066400000000000000000000074711411343567400226610ustar00rootroot00000000000000include(DuneCMakeCompat) # We need to explicitly instantiate the tests for small groups of types -- # else the compiler will eat excessive amounts of memory. This way it seems # to stay below 1GByte (with g++ 4.9.2 -O0 -g on x86_64 GNU/Linux, looking at # standardtest). include(DuneInstance) set(TYPES char "unsigned char" "signed char" short int long "long long" "unsigned short" unsigned "unsigned long" "unsigned long long" bool float double "long double" std::complex std::complex "std::complex" ) # Generate files with instanciations, external declarations, and also the # invocations in the test for each instance. dune_instance_begin(FILES looptest.hh looptest.cc) foreach(SCALAR IN LISTS TYPES) dune_instance_add(ID "${SCALAR}") foreach(POINT IN ITEMS Type BinaryOpsScalarVector BinaryOpsVectorScalar) dune_instance_add(TEMPLATE POINT ID "${POINT}_${SCALAR}" FILES looptest_vector.cc) endforeach() endforeach() dune_instance_end() list(FILTER DUNE_INSTANCE_GENERATED INCLUDE REGEX [[\.cc$]]) dune_add_test(NAME looptest SOURCES ${DUNE_INSTANCE_GENERATED} LINK_LIBRARIES dunecommon ) # no need to install looptest.hh, used by looptest*.cc only set(TYPES char "unsigned char" "signed char" short int long "long long" "unsigned short" unsigned "unsigned long" "unsigned long long" bool float double "long double" std::complex std::complex "std::complex") # Generate files with instanciations, external declarations, and also the # invocations in the test for each instance. dune_instance_begin(FILES standardtest.hh standardtest.cc) foreach(SCALAR IN LISTS TYPES) dune_instance_add(ID "${SCALAR}" FILES standardtest_vector.cc) endforeach() dune_instance_end() list(FILTER DUNE_INSTANCE_GENERATED INCLUDE REGEX [[\.cc$]]) dune_add_test(NAME standardtest SOURCES ${DUNE_INSTANCE_GENERATED} LINK_LIBRARIES dunecommon ) # no need to install standardtest.hh, used by standardtest*.cc only # as of Vc-1.3.2: Vc/common/simdarray.h:561: SimdArray may only be used # with T = { double, float, int32_t, uint32_t, int16_t, uint16_t } set(VCTEST_TYPES std::int16_t std::uint16_t std::int32_t std::uint32_t float double) # Generate files with instanciations, external declarations, and also the # invocations in the test for each instance. dune_instance_begin(FILES vcarraytest.hh vcarraytest.cc) foreach(SCALAR IN LISTS VCTEST_TYPES) dune_instance_add(ID "${SCALAR}") foreach(POINT IN ITEMS Type BinaryOpsScalarVector BinaryOpsVectorScalar BinaryOpsProxyVector BinaryOpsVectorProxy) dune_instance_add(TEMPLATE POINT ID "${POINT}_${SCALAR}" FILES vctest_simdarray.cc vctest_simdmaskarray.cc) endforeach() endforeach() dune_instance_end() list(FILTER DUNE_INSTANCE_GENERATED INCLUDE REGEX [[\.cc$]]) dune_add_test(NAME vcarraytest SOURCES ${DUNE_INSTANCE_GENERATED} LINK_LIBRARIES dunecommon CMAKE_GUARD Vc_FOUND ) add_dune_vc_flags(vcarraytest) # no need to install vcarraytest.hh, used by vctest*.cc only # Generate files with instanciations, external declarations, and also the # invocations in the test for each instance. dune_instance_begin(FILES vcvectortest.hh vcvectortest.cc) foreach(SCALAR IN LISTS VCTEST_TYPES) dune_instance_add(ID "${SCALAR}") foreach(POINT IN ITEMS Type BinaryOpsScalarVector BinaryOpsVectorScalar BinaryOpsProxyVector BinaryOpsVectorProxy) dune_instance_add(TEMPLATE POINT ID "${POINT}_${SCALAR}" FILES vctest_vector.cc vctest_mask.cc) endforeach() endforeach() dune_instance_end() list(FILTER DUNE_INSTANCE_GENERATED INCLUDE REGEX [[\.cc$]]) dune_add_test(NAME vcvectortest SOURCES ${DUNE_INSTANCE_GENERATED} LINK_LIBRARIES dunecommon CMAKE_GUARD Vc_FOUND ) add_dune_vc_flags(vcvectortest) # no need to install vcvectortest.hh, used by vctest*.cc only dune-common-2.8.0/dune/common/simd/test/looptest.cc.in000066400000000000000000000022321411343567400226740ustar00rootroot00000000000000// @GENERATED_SOURCE@ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include template struct RebindAccept : std::false_type {}; #cmake @template@ template struct RebindAccept > : std::true_type {}; template struct RebindAccept, 5, A2> > : std::true_type {}; #cmake @endtemplate@ using Rebinds = Dune::Simd::RebindList< #cmake @template@ @SCALAR@, #cmake @endtemplate@ Dune::Simd::EndMark>; int main() { Dune::Simd::UnitTest test; #cmake @template@ test.check, Rebinds, Dune::AlwaysFalse, RebindAccept>(); test.check, Rebinds, Dune::AlwaysFalse, RebindAccept>(); test.check, 5>, Rebinds, Dune::AlwaysFalse, RebindAccept>(); #cmake @endtemplate@ return test.good() ? EXIT_SUCCESS : EXIT_FAILURE; } dune-common-2.8.0/dune/common/simd/test/looptest.hh.in000066400000000000000000000011531411343567400227070ustar00rootroot00000000000000// @GENERATED_SOURCE@ #ifndef DUNE_COMMON_SIMD_TEST_LOOPTEST_HH #define DUNE_COMMON_SIMD_TEST_LOOPTEST_HH #include // as inserted by substitutions #include #include namespace Dune { namespace Simd { #cmake @template POINT@ extern template void UnitTest::check@POINT@ >(); extern template void UnitTest::check@POINT@ >(); extern template void UnitTest::check@POINT@, 5> >(); #cmake @endtemplate@ } //namespace Simd } // namespace Dune #endif dune-common-2.8.0/dune/common/simd/test/looptest_vector.cc.in000066400000000000000000000006061411343567400242610ustar00rootroot00000000000000// @GENERATED_SOURCE@ #include #include namespace Dune { namespace Simd { template void UnitTest::check@POINT@ >(); template void UnitTest::check@POINT@ >(); template void UnitTest::check@POINT@, 5> >(); } //namespace Simd } // namespace Dune dune-common-2.8.0/dune/common/simd/test/standardtest.cc.in000066400000000000000000000013141411343567400235230ustar00rootroot00000000000000// @GENERATED_SOURCE@ #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include template struct RebindAccept : std::false_type {}; #cmake @template@ template<> struct RebindAccept<@SCALAR@> : std::true_type {}; #cmake @endtemplate@ using Rebinds = Dune::Simd::RebindList< #cmake @template@ @SCALAR@, #cmake @endtemplate@ Dune::Simd::EndMark>; int main() { Dune::Simd::UnitTest test; #cmake @template@ test.check<@SCALAR@, Rebinds, Dune::AlwaysFalse, RebindAccept>(); #cmake @endtemplate@ return test.good() ? EXIT_SUCCESS : EXIT_FAILURE; } dune-common-2.8.0/dune/common/simd/test/standardtest.hh.in000066400000000000000000000006501411343567400235370ustar00rootroot00000000000000// @GENERATED_SOURCE@ #ifndef DUNE_COMMON_SIMD_TEST_STANDARDTEST_HH #define DUNE_COMMON_SIMD_TEST_STANDARDTEST_HH #include // for substituted types #include namespace Dune { namespace Simd { #cmake @template@ extern template void UnitTest::checkType<@SCALAR@>(); #cmake @endtemplate@ } // namespace Simd } // namespace Dune #endif // DUNE_COMMON_SIMD_TEST_STANDARDTEST_HH dune-common-2.8.0/dune/common/simd/test/standardtest_vector.cc.in000066400000000000000000000004051411343567400251050ustar00rootroot00000000000000// @GENERATED_SOURCE@ #include #include #include namespace Dune { namespace Simd { template void UnitTest::checkType<@SCALAR@>(); } // namespace Simd } // namespace Dune dune-common-2.8.0/dune/common/simd/test/vcarraytest.cc.in000066400000000000000000000020441411343567400233730ustar00rootroot00000000000000// @GENERATED_SOURCE@ #if HAVE_CONFIG_H #include "config.h" #endif #if !HAVE_VC #error Inconsistent buildsystem. This program should not be built in the \ absence of Vc. #endif #include #include #include #include #include #include #include template struct RebindAccept : std::false_type {}; #cmake @template@ template<> struct RebindAccept > : std::true_type {}; template<> struct RebindAccept > : std::true_type {}; #cmake @endtemplate@ using Rebinds = Dune::TypeList< #cmake @template@ @SCALAR@, #cmake @endtemplate@ bool, std::size_t>; int main() { using Vc::Vector; using Vc::SimdArray; Dune::Simd::UnitTest test; #@template@ test.check, Rebinds, Dune::Simd::IsLoop, RebindAccept>(); #@endtemplate@ return test.good() ? EXIT_SUCCESS : EXIT_FAILURE; } dune-common-2.8.0/dune/common/simd/test/vcarraytest.hh.in000066400000000000000000000012341411343567400234050ustar00rootroot00000000000000// @GENERATED_SOURCE@ #ifndef DUNE_COMMON_SIMD_TEST_VCTEST_HH #define DUNE_COMMON_SIMD_TEST_VCTEST_HH #if HAVE_VC #include #include // for std::[u]int#_t as substituted #include #include constexpr std::size_t lanes = 4; namespace Dune { namespace Simd { #cmake @template POINT@ extern template void UnitTest::check@POINT@ >(); extern template void UnitTest::check@POINT@ >(); #cmake @endtemplate@ } // namespace Simd } // namespace Dune #endif // HAVE_VC #endif // DUNE_COMMON_SIMD_TEST_VCTEST_HH dune-common-2.8.0/dune/common/simd/test/vctest_mask.cc.in000066400000000000000000000003571411343567400233540ustar00rootroot00000000000000// @GENERATED_SOURCE@ #include #include namespace Dune { namespace Simd { template void UnitTest::check@POINT@ >(); } // namespace Simd } // namespace Dune dune-common-2.8.0/dune/common/simd/test/vctest_simdarray.cc.in000066400000000000000000000004001411343567400244010ustar00rootroot00000000000000// @GENERATED_SOURCE@ #include #include namespace Dune { namespace Simd { template void UnitTest::check@POINT@ >(); } // namespace Simd } // namespace Dune dune-common-2.8.0/dune/common/simd/test/vctest_simdmaskarray.cc.in000066400000000000000000000004041411343567400252610ustar00rootroot00000000000000// @GENERATED_SOURCE@ #include #include namespace Dune { namespace Simd { template void UnitTest::check@POINT@ >(); } // namespace Simd } // namespace Dune dune-common-2.8.0/dune/common/simd/test/vctest_vector.cc.in000066400000000000000000000003611411343567400237160ustar00rootroot00000000000000// @GENERATED_SOURCE@ #include #include namespace Dune { namespace Simd { template void UnitTest::check@POINT@ >(); } // namespace Simd } // namespace Dune dune-common-2.8.0/dune/common/simd/test/vcvectortest.cc.in000066400000000000000000000023151411343567400235600ustar00rootroot00000000000000// @GENERATED_SOURCE@ #if HAVE_CONFIG_H #include "config.h" #endif #if !HAVE_VC #error Inconsistent buildsystem. This program should not be built in the \ absence of Vc. #endif #include #include #include #include #include #include #include template struct RebindAccept : std::false_type {}; #cmake @template@ template<> struct RebindAccept > : std::true_type {}; template<> struct RebindAccept > : std::true_type {}; #cmake @endtemplate@ // ignore rebinds to LoopSIMD as well as Vc::SimdArray template struct Prune : Dune::Simd::IsLoop {}; template struct Prune > : std::true_type {}; using Rebinds = Dune::TypeList< #cmake @template@ @SCALAR@, #cmake @endtemplate@ bool, std::size_t>; int main() { using Vc::Vector; using Vc::SimdArray; Dune::Simd::UnitTest test; #@template@ test.check, Rebinds, Prune, RebindAccept>(); #@endtemplate@ return test.good() ? EXIT_SUCCESS : EXIT_FAILURE; } dune-common-2.8.0/dune/common/simd/test/vcvectortest.hh.in000066400000000000000000000010771411343567400235760ustar00rootroot00000000000000// @GENERATED_SOURCE@ #ifndef DUNE_COMMON_SIMD_TEST_VCTEST_HH #define DUNE_COMMON_SIMD_TEST_VCTEST_HH #if HAVE_VC #include #include #include #include namespace Dune { namespace Simd { #cmake @template POINT@ extern template void UnitTest::check@POINT@ >(); extern template void UnitTest::check@POINT@ >(); #cmake @endtemplate@ } // namespace Simd } // namespace Dune #endif // HAVE_VC #endif // DUNE_COMMON_SIMD_TEST_VCTEST_HH dune-common-2.8.0/dune/common/simd/vc.hh000066400000000000000000000745251411343567400200770ustar00rootroot00000000000000#ifndef DUNE_COMMON_SIMD_VC_HH #define DUNE_COMMON_SIMD_VC_HH /** @file * @ingroup SIMDVc * @brief SIMD abstractions for Vc */ #include #include #include #include #include #include // for anyFalse() #include #include #include /** @defgroup SIMDVc SIMD Abstraction Implementation for Vc * @ingroup SIMDApp * * This implements the vectorization interface for Vc types, namely * `Vc::Vector`, `Vc::Mask`, `Vc::SimdArray` and `Vc::SimdMask`. * * As an application developer, you need to `#include * `. You need to make sure that `HAVE_VC` is true * before doing so: * * - If your program works both in the presence and the absence of Vc, wrap * the include in `#if HAVE_VC` and `#endif` * * - If you write a unit test, in your `CMakeLists.txt` use * `dune_add_test(... CMAKE_GUARD Vc_FOUND)` * * You also need to make sure that the compiler uses the correct flags and * that the linker can find the library. (The compilation flags include one * that ensures a name mangling scheme that can distiguish the * compiler-intrinsic vector types from non-vector types is used.) * * - Either use `add_dune_vc_flags(your_application)` in `CMakeLists.txt`, * * - or use `dune_enable_all_packages()` in your module's toplevel * `CMakeLists.txt`. * * There should be no need to explicitly call `find_package(Vc)` in your * `CMakeLists.txt`, dune-common already does that. If your module can't live * without Vc, you may however want to do something like this in your * `cmake/modules/YourModuleMacros.cmake`: * \code * if(NOT Vc_FOUND) * message(SEND_ERROR "This module requires Vc") * endif(NOT Vc_FOUND) * \endcode * * If you just want to compile dune, and have Vc installed to a location where * cmake is not looking by default, you need to add that location to * `CMAKE_PREFIX_PATH`. E.g. pass `-DCMAKE_PREFIX_PATH=$VCDIR` to cmake, for * instance by including that in the variable `CMAKE_FLAGS` in the options * file that you pass to dunecontrol. `$VCDIR` should be the same directory * that you passed in `-DCMAKE_INSTALL_PREFIX=...` to cmake when you compiled * Vc, i.e. Vc's main include file should be found under * `$VCDIR/include/Vc/Vc`, and the library under `$VCDIR/lib/libVc.a` or * similar. * * @section SIMDVcRestrictions Restrictions * * During thorough testing of the Vc abstraction implementation it turned out * that certain operations were not supported, or were buggy. This meant that * the tests had to be relaxed, and/or some restrictions had to made as to how * things must be done through the SIMD abstraction, see @ref * simd_abstraction_limit. * * For future reference, here is a detailed list of things that certain Vc * types do or don't support. `s` denotes a scalar object/expression (i.e. of * type `double` or in the case of masks `bool`). `v` denotes a vector/mask * object/expression. `sv` means that both scalar and vector arguments are * accepted. `V` denotes a vector/mask type. `@` means any applicable * operator that is not otherwise listed. * * * \code | | Vector | Vector | SimdArray | SimdArray | Masks[4] | | | AVX | SSE | | | | |-------------------------+--------------+-----------+------------+-----------+-----------| | V v(s); | y | y | y | y | y | | V v = s; | y | y | y | y | *N* | | V v{s}; | *N* | y | *N* | *N* | y | | V v = {s}; | *N* | y | *N* | *N* | *N* | |-------------------------+--------------+-----------+------------+-----------+-----------| | v = s; | y | y | y | y | *N* | | v = {s}; | *N* | *N* | *N* | *N* | *N* | |-------------------------+--------------+-----------+------------+-----------+-----------| | v++; ++v; | y | y | *N* | *N* | y(n/a)[2] | | v--; --v; | y | y | *N* | *N* | n/a | |-------------------------+--------------+-----------+------------+-----------+-----------| | +v; -v; | y | y | y | y | *N* | | !v; | y | y | y | y | y | | ~v; | n/a | y | n/a | y | *N* | |-------------------------+--------------+-----------+------------+-----------+-----------| | sv @ sv; but see below | y | y | y | y | *N* | |-------------------------+--------------+-----------+------------+-----------+-----------| | s << v; s >> v; | n/a | *N* | n/a | *N* | *N* | |-------------------------+--------------+-----------+------------+-----------+-----------| | v == v; v != v; | y | y | y | y | *N* [1] | |-------------------------+--------------+-----------+------------+-----------+-----------| | v & v; v ^ v; v ¦ v; | n/a | y | n/a | y | y | | sv && sv; sv ¦¦ sv; | y | y | *N* | *N* | *N* | | v && v; v ¦¦ v; | y | y | *N* | *N* | y | |-------------------------+--------------+-----------+------------+-----------+-----------| | v @= sv; but see below | y | y | y | y | *N* | | v &= v; v ^= v; v ¦= v; | n/a | y | n/a | y | y | |-------------------------+--------------+-----------+------------+-----------+-----------| | v, v;[3] | *N* | *N* | y | y | y | * \endcode * * Notes: * * - [1] The result of the mask-mask `==` and `!=` operation is a scalar. * * - [2] `++` (either kind) on bools is deprecated by the standard * * - [3] contrary to the other operators, the expected result for `(sv1, sv2)` * is exactly `sv2`, no broadcasting applied. * * - [4] Checked with `Vector::Mask` [SSE] and `SimdArray::Mask`, * which behaved identical * * Support levels: * * - `y`: operation generally works; some instances of the operation may not * apply * * - `*N*`: operation generally does not work; some instances of the operation * may not apply * * - `n/a`: operation does not apply (i.e. bitwise operations to * floating-point operands, `--` (and in the future possibly `++`) to * boolean operands, assignment operators to scalar left hand sides) * * Each operation was tested with the full set of combinations of possible * `const`/non-`const` lvalue/xvalue arguments. Each combination of constness * and value category was applied to the scalar type and the operation tried * in an SFINAE context; combinations that failed here were skipped for vector * arguments too. */ namespace Dune { namespace Simd { namespace VcImpl { //! specialized to true for Vc mask types template struct IsMask : std::false_type {}; template struct IsMask > : std::true_type {}; template struct IsMask > : std::true_type {}; //! specialized to true for Vc vector and mask types template struct IsVector : IsMask {}; template struct IsVector > : std::true_type {}; template struct IsVector > : std::true_type {}; template struct IsVectorizable : std::false_type {}; template<> struct IsVectorizable : std::true_type {}; template<> struct IsVectorizable : std::true_type {}; template<> struct IsVectorizable : std::true_type {}; template<> struct IsVectorizable : std::true_type {}; template<> struct IsVectorizable : std::true_type {}; template<> struct IsVectorizable : std::true_type {}; //! A reference-like proxy for elements of random-access vectors. /** * This is necessary because Vc's lane-access operation return a proxy * that cannot constructed by non-Vc code (i.e. code that isn't * explicitly declared `friend`). This means in particular that there * is no copy/move constructor, meaning we cannot return such proxies * from our own functions, such as `lane()`. To work around this, we * define our own proxy class which internally holds a reference to the * vector and a lane index. * * Note: this should be unnecessary with C++17, as just returning a * temporary object should not involve copying it. */ template class Proxy { static_assert(std::is_same >::value, "Class Proxy " "may only be instantiated with unqualified types"); public: using value_type = typename V::value_type; private: static_assert(std::is_arithmetic::value, "Only artihmetic types are supported"); V &vec_; std::size_t idx_; public: Proxy(std::size_t idx, V &vec) : vec_(vec), idx_(idx) { } Proxy(const Proxy&) = delete; // allow move construction so we can return proxies from functions Proxy(Proxy&&) = default; operator value_type() const { return vec_[idx_]; } // assignment operators #define DUNE_SIMD_VC_ASSIGNMENT(OP) \ template() OP \ autoCopy(std::declval()) )> \ Proxy operator OP(T &&o) && \ { \ vec_[idx_] OP autoCopy(std::forward(o)); \ return { idx_, vec_ }; \ } DUNE_SIMD_VC_ASSIGNMENT(=); DUNE_SIMD_VC_ASSIGNMENT(*=); DUNE_SIMD_VC_ASSIGNMENT(/=); DUNE_SIMD_VC_ASSIGNMENT(%=); DUNE_SIMD_VC_ASSIGNMENT(+=); DUNE_SIMD_VC_ASSIGNMENT(-=); DUNE_SIMD_VC_ASSIGNMENT(<<=); DUNE_SIMD_VC_ASSIGNMENT(>>=); DUNE_SIMD_VC_ASSIGNMENT(&=); DUNE_SIMD_VC_ASSIGNMENT(^=); DUNE_SIMD_VC_ASSIGNMENT(|=); #undef DUNE_SIMD_VC_ASSIGNMENT // unary (prefix) operators template::value> > Proxy operator++() { ++(vec_[idx_]); return *this; } template::value> > Proxy operator--() { --(vec_[idx_]); return *this; } // postfix operators template::value> > value_type operator++(int) { return vec_[idx_]++; } template::value> > value_type operator--(int) { return vec_[idx_]--; } // swap on proxies swaps the proxied vector entries. As such, it // applies to rvalues of proxies too, not just lvalues friend void swap(const Proxy &a, const Proxy &b) { // don't use swap() ourselves -- not supported by Vc 1.3.0 (but is // supported by Vc 1.3.2) value_type tmp = std::move(a.vec_[a.idx_]); a.vec_[a.idx_] = std::move(b.vec_[b.idx_]); b.vec_[b.idx_] = std::move(tmp); } friend void swap(value_type &a, const Proxy &b) { // don't use swap() ourselves -- not supported by Vc 1.3.0 (but is // supported by Vc 1.3.2) value_type tmp = std::move(a); a = std::move(b.vec_[b.idx_]); b.vec_[b.idx_] = std::move(tmp); } friend void swap(const Proxy &a, value_type &b) { // don't use swap() ourselves -- not supported by Vc 1.3.0 (but is // supported by Vc 1.3.2) value_type tmp = std::move(a.vec_[a.idx_]); a.vec_[a.idx_] = std::move(b); b = std::move(tmp); } // binary operators // // Normally, these are provided by the conversion operator in // combination with C++'s builtin binary operators. Other classes // that need to provide the binary operators themselves should either // 1. deduce the "foreign" operand type independently, i.e. use // template // auto operator@(MyClass, Foreign); // or // 2. not deduce anything from the foreign argument, i.e. // template // auto operator@(MyClass, // typename MyClass::value_type); // or // template // struct MyClass { // auto operator@(T); // } // or // template // struct MyClass { // friend auto operator@(MyClass, T); // } // // This allows either for an exact match (in the case of option 1.) or // for conversions to be applied to the foreign argument (options 2.). // In contrast, allowing some of the template parameters being deduced // from the self argument also being deduced from the foreign argument // will likely lead to ambigous deduction when the foreign argument is // a proxy: // template // auto operator@(MyClass, T); // One class that suffers from this problem ist std::complex. // // Note that option 1. is a bit dangerous, as the foreign argument is // catch-all. This seems tempting in the case of a proxy class, as // the operator could just be forwarded to the proxied object with the // foreign argument unchanged, immediately creating interoperability // with arbitrary foreign classes. However, if the foreign class also // choses option 1., this will result in ambigous overloads, and there // is no clear guide to decide which class should provide the overload // and which should not. // // Fortunately, deferring to the conversion and the built-in operators // mostly works in the case of this proxy class, because only built-in // types can be proxied anyway. Unfortunately, the Vc vectors and // arrays suffer from a slightly different problem. They chose option // 1., but they can't just accept the argument type they are given, // since they need to somehow implement the operation in terms of // intrinsics. So they check the argument whether it is one of the // expected types, and remove the operator from the overload set if it // isn't via SFINAE. Of course, this proxy class is not one of the // expected types, even though it would convert to them... // // So what we have to do here, unfortunately, is to provide operators // for the Vc types explicitly, and hope that there won't be some Vc // version that gets the operators right, thus creating ambigous // overloads. Well, if guess it will be #ifdef time if it comes to // that. #define DUNE_SIMD_VC_BINARY(OP) \ template \ friend auto operator OP(const Vc::Vector &l, Proxy&& r) \ -> decltype(l OP std::declval()) \ { \ return l OP value_type(r); \ } \ template \ auto operator OP(const Vc::Vector &r) && \ -> decltype(std::declval() OP r) \ { \ return value_type(*this) OP r; \ } \ template \ friend auto \ operator OP(const Vc::SimdArray &l, Proxy&& r) \ -> decltype(l OP std::declval()) \ { \ return l OP value_type(r); \ } \ template \ auto operator OP(const Vc::SimdArray &r) && \ -> decltype(std::declval() OP r) \ { \ return value_type(*this) OP r; \ } DUNE_SIMD_VC_BINARY(*); DUNE_SIMD_VC_BINARY(/); DUNE_SIMD_VC_BINARY(%); DUNE_SIMD_VC_BINARY(+); DUNE_SIMD_VC_BINARY(-); DUNE_SIMD_VC_BINARY(<<); DUNE_SIMD_VC_BINARY(>>); DUNE_SIMD_VC_BINARY(&); DUNE_SIMD_VC_BINARY(^); DUNE_SIMD_VC_BINARY(|); DUNE_SIMD_VC_BINARY(<); DUNE_SIMD_VC_BINARY(>); DUNE_SIMD_VC_BINARY(<=); DUNE_SIMD_VC_BINARY(>=); DUNE_SIMD_VC_BINARY(==); DUNE_SIMD_VC_BINARY(!=); #undef DUNE_SIMD_VC_BINARY // this is needed to implement broadcast construction from proxy as // the unadorned assignment operator cannot be a non-member template::value> > operator Vc::Vector() && { return value_type(*this); } template::value> > operator Vc::SimdArray() && { return value_type(*this); } #define DUNE_SIMD_VC_ASSIGN(OP) \ template \ friend auto operator OP(Vc::Vector &l, Proxy&& r) \ -> decltype(l OP std::declval()) \ { \ return l OP value_type(r); \ } DUNE_SIMD_VC_ASSIGN(*=); DUNE_SIMD_VC_ASSIGN(/=); DUNE_SIMD_VC_ASSIGN(%=); DUNE_SIMD_VC_ASSIGN(+=); DUNE_SIMD_VC_ASSIGN(-=); DUNE_SIMD_VC_ASSIGN(&=); DUNE_SIMD_VC_ASSIGN(^=); DUNE_SIMD_VC_ASSIGN(|=); // The shift assignment would not be needed for Vc::Vector since it // has overloads for `int` rhs and the proxy can convert to that -- // except that there is also overloads for Vector, and because of the // conversion operator needed to support unadorned assignments, the // proxy can convert to that, too. DUNE_SIMD_VC_ASSIGN(<<=); DUNE_SIMD_VC_ASSIGN(>>=); #undef DUNE_SIMD_VC_ASSIGN }; } // namespace VcImpl namespace Overloads { /** @name Specialized classes and overloaded functions * @ingroup SIMDVc * @{ */ //! should have a member type \c type /** * Implements Simd::Scalar */ template struct ScalarType::value> > { using type = typename V::value_type; }; //! should have a member type \c type /** * Implements Simd::Rebind * * This specialization covers * - Mask -> bool * - Vector -> Scalar */ template struct RebindType, V, std::enable_if_t::value> > { using type = V; }; //! should have a member type \c type /** * Implements Simd::Rebind * * This specialization covers * - Vector -> bool */ template struct RebindType::value && !VcImpl::IsMask::value>> { using type = typename V::mask_type; }; //! should have a member type \c type /** * Implements Simd::Rebind * * This specialization covers * - Mask -> Scalar */ template struct RebindType, M, std::enable_if_t::value>> { using type = typename M::Vector; }; //! should have a member type \c type /** * Implements Simd::Rebind * * This specialization covers * - Mask -> Vc-vectorizable type except bool, Scalar */ template struct RebindType::value && VcImpl::IsVectorizable::value && !std::is_same >::value > > { using type = Vc::SimdArray()>; }; //! should have a member type \c type /** * Implements Simd::Rebind * * This specialization covers * - Vector -> Vc-vectorizable type except bool, Scalar */ template struct RebindType::value && !VcImpl::IsMask::value && VcImpl::IsVectorizable::value && !std::is_same >::value> > { using type = Vc::SimdArray()>; }; //! should have a member type \c type /** * Implements Simd::Rebind * * This specialization covers * - Mask -> non-Vc-vectorizable type except bool * - Vector -> non-Vc-vectorizable type except bool */ template struct RebindType::value && !VcImpl::IsVectorizable::value && !std::is_same::value && !std::is_same >::value> > { using type = LoopSIMD()>; }; //! should be derived from an Dune::index_constant /** * Implements Simd::lanes() */ template struct LaneCount::value> > : public index_constant { }; //! implements Simd::lane() template VcImpl::Proxy lane(ADLTag<5, VcImpl::IsVector::value>, std::size_t l, V &v) { return { l, v }; } //! implements Simd::lane() template Scalar lane(ADLTag<5, VcImpl::IsVector::value>, std::size_t l, const V &v) { return v[l]; } //! implements Simd::lane() /* * The hack with the SFINAE is necessary, because if I use just * Scalar as the return type, the compiler still errors out if V is * an lvalue-reference T&. You'd think he'd notice that he can't * instantiate this declaration for this template parameter, and would * simply remove it from the overload set, but no... */ template::value> > Scalar lane(ADLTag<5, VcImpl::IsVector::value>, std::size_t l, V &&v) { return std::forward(v)[l]; } //! implements Simd::cond() template V cond(ADLTag<5, VcImpl::IsVector::value && !VcImpl::IsMask::value>, const Mask &mask, const V &ifTrue, const V &ifFalse) { return Vc::iif(mask, ifTrue, ifFalse); } //! implements Simd::cond() /* * Kludge because iif seems to be unimplemented for masks */ template V cond(ADLTag<5, VcImpl::IsMask::value>, const V &mask, const V &ifTrue, const V &ifFalse) { return (mask && ifTrue) || (!mask && ifFalse); } //! implements binary Simd::max() template auto max(ADLTag<5, VcImpl::IsVector::value && !VcImpl::IsMask::value>, const V &v1, const V &v2) { return Simd::cond(v1 < v2, v2, v1); } //! implements binary Simd::max() template auto max(ADLTag<5, VcImpl::IsMask::value>, const M &m1, const M &m2) { return m1 || m2; } //! implements binary Simd::min() template auto min(ADLTag<5, VcImpl::IsVector::value && !VcImpl::IsMask::value>, const V &v1, const V &v2) { return Simd::cond(v1 < v2, v1, v2); } //! implements binary Simd::min() template auto min(ADLTag<5, VcImpl::IsMask::value>, const M &m1, const M &m2) { return m1 && m2; } //! implements Simd::anyTrue() template bool anyTrue (ADLTag<5, VcImpl::IsMask::value>, const M &mask) { return Vc::any_of(mask); } //! implements Simd::allTrue() template bool allTrue (ADLTag<5, VcImpl::IsMask::value>, const M &mask) { return Vc::all_of(mask); } // nothing like anyFalse() in Vc, so let defaults.hh handle it //! implements Simd::allFalse() template bool allFalse(ADLTag<5, VcImpl::IsMask::value>, const M &mask) { return Vc::none_of(mask); } //! implements Simd::maxValue() template auto max(ADLTag<5, VcImpl::IsVector::value && !VcImpl::IsMask::value>, const V &v) { return v.max(); } //! implements Simd::maxValue() template bool max(ADLTag<5, VcImpl::IsMask::value>, const M &mask) { return Vc::any_of(mask); } //! implements Simd::minValue() template auto min(ADLTag<5, VcImpl::IsVector::value && !VcImpl::IsMask::value>, const V &v) { return v.min(); } //! implements Simd::minValue() template bool min(ADLTag<5, VcImpl::IsMask::value>, const M &mask) { return !Vc::any_of(!mask); } //! implements Simd::maskAnd() template auto maskAnd(ADLTag<5, std::is_same, bool>::value && VcImpl::IsVector::value>, const S1 &s1, const V2 &v2) { return Simd::Mask(Simd::mask(s1)) && Simd::mask(v2); } //! implements Simd::maskAnd() template auto maskAnd(ADLTag<5, VcImpl::IsVector::value && std::is_same, bool>::value>, const V1 &v1, const S2 &s2) { return Simd::mask(v1) && Simd::Mask(Simd::mask(s2)); } //! implements Simd::maskOr() template auto maskOr(ADLTag<5, std::is_same, bool>::value && VcImpl::IsVector::value>, const S1 &s1, const V2 &v2) { return Simd::Mask(Simd::mask(s1)) || Simd::mask(v2); } //! implements Simd::maskOr() template auto maskOr(ADLTag<5, VcImpl::IsVector::value && std::is_same, bool>::value>, const V1 &v1, const S2 &s2) { return Simd::mask(v1) || Simd::Mask(Simd::mask(s2)); } //! @} group SIMDVc } // namespace Overloads } // namespace Simd /* * Specialize IsNumber for Vc::SimdArray and Vc::Vector to be able to use * it as a scalar in DenseMatrix etc. */ template struct IsNumber> : public std::integral_constant::value> { }; template struct IsNumber> : public std::integral_constant::value> { }; //! Specialization of AutonomousValue for Vc proxies template struct AutonomousValueType > : AutonomousValueType::value_type> {}; } // namespace Dune #endif // DUNE_COMMON_SIMD_VC_HH dune-common-2.8.0/dune/common/singleton.hh000066400000000000000000000033211411343567400205170ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_SINGLETON_HH #define DUNE_SINGLETON_HH #include /** * @file * @brief Useful wrapper for creating singletons. * * Inspired by the article * CodeGuru: A Leak-Free Singleton class */ namespace Dune { /** * @brief An adapter to turn a class into a singleton. * * The class represented by the template parameter T must * have a parameterless constructor. * * Class T can be publicly derived from Singleton: * * \code * #include * class Foo : public Dune::Singleton * { * public: * Foo() * { * bytes = new char[1000]; * } * * ~Foo() * { * delete[] bytes; * } * private: * char* bytes; * }; * \endcode * * Or one can construct a Singleton of an existing class. Say Foo1 is a class * with parameterless constructor then * \code * typedef Dune::Singleton FooSingleton; * Foo1 instance& = FooSingleton::instance(); * \endcode * Creates a singleton of that class and accesses its instance. */ template class Singleton { protected: /* @brief Protected constructor. */ Singleton() = default; public: Singleton(const Singleton&) = delete; void operator=(const Singleton&) = delete; /** * @brief Get the instance of the singleton. * @return The instance of the singleton. */ DUNE_EXPORT static T& instance() { static T instance_; return instance_; } }; } // namespace Dune #endif dune-common-2.8.0/dune/common/sllist.hh000066400000000000000000000470441411343567400200410ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_SLLIST_HH #define DUNE_SLLIST_HH #include #include #include "iteratorfacades.hh" #include namespace Dune { /** * @addtogroup Common * * @{ */ /** * @file * \brief Implements a singly linked list together with * the necessary iterators. * @author Markus Blatt */ template class SLListIterator; template class SLListConstIterator; template class SLListModifyIterator; /** * @brief A single linked list. * * The list is capable of insertions at the front and at * the end and of removing elements at the front. Those * operations require constant time. */ template > class SLList { struct Element; friend class SLListIterator; friend class SLListConstIterator; public: /** * @brief The size type. */ typedef typename A::size_type size_type; /** * @brief The type we store. */ typedef T MemberType; /** * @brief The allocator to use. */ using Allocator = typename std::allocator_traits::template rebind_alloc; /** * @brief The mutable iterator of the list. */ typedef SLListIterator iterator; /** * @brief The constant iterator of the list. */ typedef SLListConstIterator const_iterator; /** * @brief Constructor. */ SLList(); /** * @brief Copy constructor with type conversion. */ template SLList(const SLList& other); /** * @brief Copy constructor. */ SLList(const SLList& other); /** * @brief Destructor. * * Deallocates all elements in the list. */ ~SLList(); /** * @brief The type of the iterator capable of deletion * and insertion. */ typedef SLListModifyIterator ModifyIterator; /** * @brief Assignment operator. */ SLList& operator=(const SLList& other); /** * @brief Add a new entry to the end of the list. * @param item The item to add. */ inline void push_back(const MemberType& item); /** * @brief Add a new entry to the beginning of the list. * @param item The item to add. */ inline void push_front(const MemberType& item); /** * @brief Remove the first item in the list. */ inline void pop_front(); /** @brief Remove all elements from the list. */ inline void clear(); /** * @brief Get an iterator pointing to the first * element in the list. * * @return An iterator pointing to the first * element or the end if the list is empty. */ inline iterator begin(); /** * @brief Get an iterator pointing to the first * element in the list. * * @return An iterator pointing to the first * element or the end if the list is empty. */ inline const_iterator begin() const; /** * @brief Get an iterator capable of deleting and * inserting elements. * * @return Modifying iterator positioned at the beginning * of the list. */ inline ModifyIterator beginModify(); /** * @brief Get an iterator capable of deleting and * inserting elements. * * @return Modifying iterator positioned after the end * of the list. */ inline ModifyIterator endModify(); /** * @brief Get an iterator pointing to the * end of the list. * * @return An iterator pointing to the end. */ inline iterator end(); /** * @brief Get an iterator pointing to the * end of the list. * * @return An iterator pointing to the end. */ inline const_iterator end() const; /** * @brief Check whether the list is empty. * * @return True if the list is empty; */ inline bool empty() const; /** * @brief Get the number of elements the list * contains. */ inline int size() const; bool operator==(const SLList& sl) const; bool operator!=(const SLList& sl) const; private: /** \todo Please doc me! */ struct Element { /** * @brief The next element in the list. */ Element* next_; /** * @brief The element we hold. */ MemberType item_; Element(const MemberType& item, Element* next_=0); Element(); ~Element(); }; /** * @brief Delete the next element in the list. * @param current Element whose next element should be deleted. */ void deleteNext(Element* current); /** * @brief Copy the elements from another list. * @param other The other list. */ void copyElements(const SLList& other); /** * @brief Delete the next element in the list. * * If the template parameter watchForTail is true, it is checked whether * the deleted element is the tail and therefore the tail must be updated. * @param current Element whose next element should be deleted. */ template void deleteNext(Element* current); /** * @brief Insert an element after another one in the list. * @param current The element after which we insert. * @param item The item to insert. */ void insertAfter(Element* current, const T& item); /** @brief Pseudo element before the first entry. */ Element beforeHead_; /** * @brief Pointer to he last element in the list. * * If list is empty this will point to beforeHead_ */ Element* tail_; /** @brief The allocator we use. */ Allocator allocator_; /** brief The number of elements the list holds. */ int size_; }; /** * @brief A mutable iterator for the SLList. */ template class SLListIterator : public Dune::ForwardIteratorFacade, T, T&, std::size_t> { friend class SLListConstIterator; friend class SLListModifyIterator; friend class SLList; public: inline SLListIterator(typename SLList::Element* item, SLList* sllist) : current_(item), list_(sllist) {} inline SLListIterator() : current_(0), list_(0) {} inline SLListIterator(const SLListModifyIterator& other) : current_(other.iterator_.current_), list_(other.iterator_.list_) {} /** * @brief Dereferencing function for the iterator facade. * @return A reference to the element at the current position. */ inline T& dereference() const { return current_->item_; } /** * @brief Equality test for the iterator facade. * @param other The other iterator to check. * @return true If the other iterator is at the same position. */ inline bool equals(const SLListConstIterator& other) const { return current_==other.current_; } /** * @brief Equality test for the iterator facade. * @param other The other iterator to check. * @return true If the other iterator is at the same position. */ inline bool equals(const SLListIterator& other) const { return current_==other.current_; } /** * @brief Equality test for the iterator facade. * @param other The other iterator to check. * @return true If the other iterator is at the same position. */ inline bool equals(const SLListModifyIterator& other) const { return current_==other.iterator_.current_; } /** * @brief Increment function for the iterator facade. */ inline void increment() { current_ = current_->next_; } /** * @brief Insert an element in the underlying list after * the current position. * @param v The value to insert. */ inline void insertAfter(const T& v) const { assert(list_ ); list_->insertAfter(current_, v); } /** * @brief Delete the entry after the current position. * * @warning This will invalidate all iterators positioned at the delete position! Use with care! */ inline void deleteNext() const { assert(list_); list_->deleteNext(current_); } private: /** @brief The current element. */ typename SLList::Element* current_; /** @brief The list we iterate over. */ SLList* list_; }; /** * @brief A constant iterator for the SLList. */ template class SLListConstIterator : public Dune::ForwardIteratorFacade, const T, const T&, std::size_t> { friend class SLListIterator; friend class SLList; public: inline SLListConstIterator() : current_(0) {} inline SLListConstIterator(typename SLList::Element* item) : current_(item) {} inline SLListConstIterator(const SLListIterator& other) : current_(other.current_) {} inline SLListConstIterator(const SLListConstIterator& other) : current_(other.current_) {} inline SLListConstIterator(const SLListModifyIterator& other) : current_(other.iterator_.current_) {} /** * @brief Dereferencing function for the facade. * @return A reference to the element at the current position. */ inline const T& dereference() const { return current_->item_; } /** * @brief Equality test for the iterator facade. * @param other The other iterator to check. * @return true If the other iterator is at the same position. */ inline bool equals(const SLListConstIterator& other) const { return current_==other.current_; } /** * @brief Increment function for the iterator facade. */ inline void increment() { current_ = current_->next_; } private: /** @brief The current element. */ typename SLList::Element* current_; }; /** * @brief A mutable iterator for the SLList. */ template class SLListModifyIterator : public Dune::ForwardIteratorFacade, T, T&, std::size_t> { friend class SLListConstIterator; friend class SLListIterator; public: inline SLListModifyIterator(SLListIterator beforeIterator, SLListIterator _iterator) : beforeIterator_(beforeIterator), iterator_(_iterator) {} inline SLListModifyIterator(const SLListModifyIterator& other) : beforeIterator_(other.beforeIterator_), iterator_(other.iterator_) {} inline SLListModifyIterator() : beforeIterator_(), iterator_() {} /** * @brief Dereferencing function for the iterator facade. * @return A reference to the element at the current position. */ inline T& dereference() const { return *iterator_; } /** * @brief Test whether another iterator is equal. * @return true if the other iterator is at the same position as * this one. */ inline bool equals(const SLListConstIterator& other) const { return iterator_== other; } /** * @brief Test whether another iterator is equal. * @return true if the other iterator is at the same position as * this one. */ inline bool equals(const SLListIterator& other) const { return iterator_== other; } /** * @brief Test whether another iterator is equal. * @return true if the other iterator is at the same position as * this one. */ inline bool equals(const SLListModifyIterator& other) const { return iterator_== other.iterator_; } /** * @brief Increment function for the iterator facade. */ inline void increment() { ++iterator_; ++beforeIterator_; } /** * @brief Insert an element at the current position. * * Starting from the element at the current position all * elements will be shifted by one position to the back. * The iterator will point to the same element as before * after the insertion, i.e the number of increments to * reach the same position from a begin iterator increases * by one. * This means the inserted element is the one before the one * the iterator points to. * @param v The value to insert. */ inline void insert(const T& v) { beforeIterator_.insertAfter(v); ++beforeIterator_; } /** * @brief Delete the entry at the current position. * * The iterator will be positioned at the next position after the * deletion * @warning This will invalidate all iterators positioned at the delete position! Use with care! */ inline void remove() { ++iterator_; beforeIterator_.deleteNext(); } private: /** @brief Iterator positioned at the position before the current. */ SLListIterator beforeIterator_; /** @brief Iterator positioned at the current position. */ SLListIterator iterator_; }; template std::ostream& operator<<(std::ostream& os, const SLList& sllist) { typedef typename SLList::const_iterator Iterator; Iterator end = sllist.end(); Iterator current= sllist.begin(); os << "{ "; if(current!=end) { os<<*current<<" ("<(&(*current))<<")"; ++current; for(; current != end; ++current) os<<", "<<*current<<" ("<(&(*current))<<")"; } os<<"} "; return os; } template SLList::Element::Element(const MemberType& item, Element* next) : next_(next), item_(item) {} template SLList::Element::Element() : next_(0), item_() {} template SLList::Element::~Element() { next_=0; } template SLList::SLList() : beforeHead_(), tail_(&beforeHead_), allocator_(), size_(0) { beforeHead_.next_=0; assert(&beforeHead_==tail_); assert(tail_->next_==0); } template SLList::SLList(const SLList& other) : beforeHead_(), tail_(&beforeHead_), allocator_(), size_(0) { copyElements(other); } template template SLList::SLList(const SLList& other) : beforeHead_(), tail_(&beforeHead_), allocator_(), size_(0) { copyElements(other); } template void SLList::copyElements(const SLList& other) { assert(tail_==&beforeHead_); assert(size_==0); typedef typename SLList::const_iterator Iterator; Iterator iend = other.end(); for(Iterator element=other.begin(); element != iend; ++element) push_back(*element); assert(other.size()==size()); } template SLList::~SLList() { clear(); } template bool SLList::operator==(const SLList& other) const { if(size()!=other.size()) return false; for(const_iterator iter=begin(), oiter=other.begin(); iter != end(); ++iter, ++oiter) if(*iter!=*oiter) return false; return true; } template bool SLList::operator!=(const SLList& other) const { if(size()==other.size()) { for(const_iterator iter=begin(), oiter=other.begin(); iter != end(); ++iter, ++oiter) if(*iter!=*oiter) return true; return false; }else return true; } template SLList& SLList::operator=(const SLList& other) { clear(); copyElements(other); return *this; } template inline void SLList::push_back(const MemberType& item) { assert(size_>0 || tail_==&beforeHead_); tail_->next_ = allocator_.allocate(1); assert(size_>0 || tail_==&beforeHead_); tail_ = tail_->next_; ::new (static_cast(&(tail_->item_)))T(item); tail_->next_=0; assert(tail_->next_==0); ++size_; } template inline void SLList::insertAfter(Element* current, const T& item) { assert(current); #ifndef NDEBUG bool changeTail = (current == tail_); #endif // Save old next element Element* tmp = current->next_; assert(!changeTail || !tmp); // Allocate space current->next_ = allocator_.allocate(1); // Use copy constructor to initialize memory std::allocator_traits::construct(allocator_, current->next_, Element(item,tmp)); //::new(static_cast(&(current->next_->item_))) T(item); if(!current->next_->next_) { // Update tail assert(changeTail); tail_ = current->next_; } ++size_; assert(!tail_->next_); } template inline void SLList::push_front(const MemberType& item) { if(tail_ == &beforeHead_) { // list was empty beforeHead_.next_ = tail_ = allocator_.allocate(1, 0); ::new(static_cast(&beforeHead_.next_->item_))T(item); beforeHead_.next_->next_=0; }else{ Element* added = allocator_.allocate(1, 0); ::new(static_cast(&added->item_))T(item); added->next_=beforeHead_.next_; beforeHead_.next_=added; } assert(tail_->next_==0); ++size_; } template inline void SLList::deleteNext(Element* current) { this->template deleteNext(current); } template template inline void SLList::deleteNext(Element* current) { assert(current->next_); Element* next = current->next_; if(watchForTail) if(next == tail_) { // deleting last element changes tail! tail_ = current; } current->next_ = next->next_; std::allocator_traits::destroy(allocator_, next); allocator_.deallocate(next, 1); --size_; assert(!watchForTail || &beforeHead_ != tail_ || size_==0); } template inline void SLList::pop_front() { deleteNext(&beforeHead_); } template inline void SLList::clear() { while(beforeHead_.next_ ) { this->template deleteNext(&beforeHead_); } assert(size_==0); // update the tail! tail_ = &beforeHead_; } template inline bool SLList::empty() const { return (&beforeHead_ == tail_); } template inline int SLList::size() const { return size_; } template inline SLListIterator SLList::begin() { return iterator(beforeHead_.next_, this); } template inline SLListConstIterator SLList::begin() const { return const_iterator(beforeHead_.next_); } template inline SLListIterator SLList::end() { return iterator(); } template inline SLListModifyIterator SLList::endModify() { return SLListModifyIterator(iterator(tail_, this),iterator()); } template inline SLListModifyIterator SLList::beginModify() { return SLListModifyIterator(iterator(&beforeHead_, this), iterator(beforeHead_.next_, this)); } template inline SLListConstIterator SLList::end() const { return const_iterator(); } /** }@ */ } #endif dune-common-2.8.0/dune/common/std/000077500000000000000000000000001411343567400167675ustar00rootroot00000000000000dune-common-2.8.0/dune/common/std/CMakeLists.txt000066400000000000000000000002601411343567400215250ustar00rootroot00000000000000install( FILES apply.hh functional.hh make_array.hh optional.hh type_traits.hh utility.hh variant.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/common/std) dune-common-2.8.0/dune/common/std/apply.hh000066400000000000000000000006671411343567400204460ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_STD_APPLY_HH #define DUNE_COMMON_STD_APPLY_HH #include namespace Dune { namespace Std { /// Invoke the Callable object f with a tuple of arguments. /// \deprecated Use `std::apply` directly. using std::apply; } // namespace Std } // namespace Dune #endif // #ifndef DUNE_COMMON_STD_APPLY_HH dune-common-2.8.0/dune/common/std/functional.hh000066400000000000000000000015351411343567400214560ustar00rootroot00000000000000// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set ts=8 sw=2 et sts=2: #ifndef DUNE_COMMON_STD_FUNCTIONAL_HH #define DUNE_COMMON_STD_FUNCTIONAL_HH #include namespace Dune { namespace Std { /** * @brief A function object type whose operator() returns its argument unchanged * @note Equivalent to: `return std::forward(t);` * @warning When passing `r-values`, the result must be, at most, used for direct * consumption in an outer function call */ #if DUNE_HAVE_CXX_STD_IDENTITY using std::identity; #else //DUNE_HAVE_CXX_STD_IDENTITY struct identity { template constexpr T&& operator()(T&& t ) const noexcept {return std::forward(t);} }; #endif } // namespace Std } // namespace Dune #endif // #ifndef DUNE_COMMON_STD_FUNCTIONAL_HH dune-common-2.8.0/dune/common/std/make_array.hh000066400000000000000000000030141411343567400214210ustar00rootroot00000000000000#ifndef DUNE_COMMON_STD_MAKE_ARRAY_HH #define DUNE_COMMON_STD_MAKE_ARRAY_HH #include #include #if DUNE_HAVE_CXX_EXPERIMENTAL_MAKE_ARRAY #include #endif namespace Dune { namespace Std { #if DUNE_HAVE_CXX_EXPERIMENTAL_MAKE_ARRAY /// \deprecated Use deduction guide of `std::array` or `std::to_array`. using std::experimental::make_array; #else // DUNE_HAVE_CXX_EXPERIMENTAL_MAKE_ARRAY //! Create and initialize an array /** * \note This method is a somewhat limited dune-specific version of * make_array() as proposed for C++17 (see N4391, * accepted May * 2015). The differences are that this version should * never be used with expliclitly given template arguments, or * with std::reference_wrapper<...> arguments, and we do not * give a diagnostic when anyone happens to do that. * * \ingroup CxxUtilities * \deprecated Use deduction guide of `std::array` or `std::to_array`. */ template std::array::type, sizeof...(Args)> make_array(const Args&... args) { std::array::type, sizeof...(Args)> result = {{args...}}; return result; } #endif // DUNE_HAVE_CXX_EXPERIMENTAL_MAKE_ARRAY } } #endif dune-common-2.8.0/dune/common/std/optional.hh000066400000000000000000000015601411343567400211370ustar00rootroot00000000000000#ifndef DUNE_COMMON_STD_OPTIONAL_HH #define DUNE_COMMON_STD_OPTIONAL_HH #include #include #include #include #include #include #warning dune/common/std/optional.hh is deprecated and will be removed after Dune 2.8.\ Include instead namespace Dune { namespace Std { // In case of C++ standard >= 17 we forward optionals into our namespace template< class T > using optional = std::optional< T >; using nullopt_t = std::nullopt_t; using in_place_t = std::in_place_t; namespace { const std::nullopt_t nullopt = std::nullopt; const std::in_place_t in_place = std::in_place; } // anonymous namespace using bad_optional_access = std::bad_optional_access; } // namespace Std } // namespace Dune #endif // #ifndef DUNE_COMMON_STD_OPTIONAL_HH dune-common-2.8.0/dune/common/std/type_traits.hh000066400000000000000000000406551411343567400216710ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_STD_TYPE_TRAITS_HH #define DUNE_COMMON_STD_TYPE_TRAITS_HH #include #include #include #if __has_include() #include #endif namespace Dune { //! Namespace for features backported from new C++ standards /** * The namespace Dune::Std contains library features of new C++ standards and * technical specifications backported to older compilers. Most features are * detected and pulled into this namespace from the standard library if your * compiler has native support. If it doesn't, we provide a fallback implementation * on a best-effort basis. * * \ingroup CxxUtilities */ namespace Std { // to_false_type // ------------- /** \class to_false_type * * \brief template mapping a type to std::false_type * \deprecated Use Dune::AlwaysFalse (from dune/common/typetraits.hh) instead * \tparam T Some type * * Suppose you have a template class. You want to document the required * members of this class in the non-specialized template, but you know that * actually instantiating the non-specialized template is an error. You can * try something like this: * \code * template * struct Traits * { * static_assert(false, * "Instanciating this non-specialized template is an " * "error. You should use one of the specializations " * "instead."); * //! The type used to frobnicate T * typedef void FrobnicateType; * }; * \endcode * This will trigger static_assert() as soon as the compiler reads the * definition for the Traits template, since it knows that "false" can never * become true, no matter what the template parameters of Traits are. As a * workaround you can use to_false_type: replace false by * to_false_type::value, like this: * \code * template * struct Traits * { * static_assert(Std::to_false_type::value, * "Instanciating this non-specialized template is an " * "error. You should use one of the specializations " * "instead."); * //! The type used to frobnicate T * typedef void FrobnicateType; * }; * \endcode * Since there might be an specialization of to_false_type for template * parameter T, the compiler cannot trigger static_assert() until the type * of T is known, that is, until Traits is instantiated. * * \ingroup CxxUtilities */ template< typename T > struct [[deprecated("Will be removed after release 2.8. Use Dune::AlwaysFalse (from dune/common/typetraits.hh)")]] to_false_type : public std::false_type {}; // to_true_type // ------------ /** \class to_true_type * * \brief template mapping a type to std::true_type * \deprecated Use Dune::AlwaysFalse (from dune/common/typetraits.hh) instead * \tparam T Some type * * \note This class exists mostly for consistency with to_false_type. * * \ingroup CxxUtilities */ template< typename T > struct [[deprecated("Will be removed after release 2.8. Use Dune::AlwaysTrue (from dune/common/typetraits.hh)")]] to_true_type : public std::true_type {}; /// A helper alias template std::bool_constant imported into the namespace Dune::Std /// \deprecated Use the `std::bool_constant` directly. using std::bool_constant; namespace Impl { // If R is void we only need to check if F can be called // with given Args... list. If this is not possible // result_of_t is not defined and this overload is disabled. template>, R>::value , int> = 0> std::true_type is_callable_helper(PriorityTag<2>) { return {}; } // Check if result of F(Args...) can be converted to R. // If F cannot even be called with given Args... then // result_of_t is not defined and this overload is disabled. template, R>::value , int> = 0> std::true_type is_callable_helper(PriorityTag<1>) { return {}; } // If none of the above matches, F can either not be called // with given Args..., or the result cannot be converted to // void, or R is not void. template std::false_type is_callable_helper(PriorityTag<0>) { return {}; } } /** * \brief Traits class to check if function is callable * \deprecated Use std::is_invocable from * * \tparam D Function descriptor * \tparam R Return value * * If D = F(Args...) this checks if F can be called with an * argument list of type Args..., and if the return value can * be converted to R. If R is void, any return type is accepted. * The result is encoded by deriving from std::integral_constant. * * If D is not of the form D = F(Args...) this class is not defined. * * This implements std::is_callable as proposed in N4446 for C++17. * * \ingroup CxxUtilities */ template struct is_callable; /** * \brief Traits class to check if function is callable * \deprecated Use std::is_invocable from * * \tparam D Function descriptor * \tparam R Return value * * If D = F(Args...) this checks if F can be called with an * argument list of type Args..., and if the return value can * be converted to R. If R is void, any return type is accepted. * The result is encoded by deriving from std::integral_constant. * * If D is not of the form D = F(Args...) this class is not defined. * * This implements std::is_callable as proposed in N4446 for C++17. * * \ingroup CxxUtilities */ template struct [[deprecated("Use std::is_invocable from . Will be removed after release 2.8")]] is_callable< F(Args...), R> : decltype(Impl::is_callable_helper(PriorityTag<42>())) {}; /** * \brief Traits class to check if function is invocable * \deprecated Use std::is_invocable from * * \tparam F Function to check * \tparam Args Function arguments to check * * This checks if F can be called with an arguments list of type Args.... * The result is encoded by deriving from std::integral_constant. * * This implements std::is_invocable from C++17. * * \ingroup CxxUtilities */ template struct [[deprecated("Use std::is_invocable from . Will be removed after release 2.8")]] is_invocable : decltype(Impl::is_callable_helper(PriorityTag<42>())) {}; /** * \brief Traits class to check if function is invocable and the return type is compatible * \deprecated Use std::is_invocable_r from * * \tparam R Desired result type * \tparam F Function to check * \tparam Args Function arguments to check * * This checks if F can be called with an arguments list of type Args..., and * if the return value can be converted to R. * The result is encoded by deriving from std::integral_constant. * * This implements std::is_invocable_r from C++17. * * \ingroup CxxUtilities */ template struct [[deprecated("Use std::is_invocable_r from . Will be removed after release 2.8")]] is_invocable_r : decltype(Impl::is_callable_helper(PriorityTag<42>())) {}; #if DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED using std::experimental::nonesuch; using std::experimental::detected_or; using std::experimental::is_detected; using std::experimental::detected_t; using std::experimental::is_detected_v; using std::experimental::detected_or_t; using std::experimental::is_detected_exact; using std::experimental::is_detected_exact_v; using std::experimental::is_detected_convertible; using std::experimental::is_detected_convertible_v; #else // DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED // fallback version of std::experimental::is_detected et al., heavily scribbled // from cppreference.com (but there is actually not much implementation to the thing) #ifndef DOXYGEN namespace Impl { // default version of detector, this gets matched on failure template class Op, typename... Args> struct detector { using value_t = std::false_type; using type = Default; }; // specialization of detector that matches if Op can be instantiated template class Op, typename... Args> struct detector>, Op, Args...> { using value_t = std::true_type; using type = Op; }; } #endif // DOXYGEN //! Type representing a lookup failure by std::detected_or and friends. /** * This type cannot be constructed, destroyed or copied. * * \note This functionality is part of the C++ library fundamentals TS v2 and might * or might not became part of C++2a. * * \ingroup CxxUtilities */ struct nonesuch { nonesuch() = delete; ~nonesuch() = delete; nonesuch(const nonesuch&) = delete; void operator=(const nonesuch&) = delete; }; //! Detects whether `Op` is valid and makes the result available. /** * This alias template is an alias for an unspecified class type with two * nested `typedefs` `value_t` and `type`. It can be used to detect whether * the meta function call `Op` is valid and access the result of * the call by inspecting the returned type, which is defined as follows: * * * If `Op` can be instantiated, `value_t` is an alias for `std::true_type` * and `type` is an alias for `Op`. * * If `Op` is invalid, `value_t` is an alias for `std::false_type` * and `type` is an alias for `Default`. * * This can be used to safely extract a nested `typedef` from a type `T` that * might not define the `typedef`: \code struct A { using size_type = int ; }; struct B; template using SizeType = typename T::size_type; // this extracts the nested typedef for int using st_a = typename detected_or::type; // as there is no nested typedef in B, this yields std::size_t using st_b = typename detected_or::type; \endcode * * \note This functionality is part of the C++ library fundamentals TS v2 and might * or might not became part of C++2a. * * \ingroup CxxUtilities */ template class Op, typename... Args> using detected_or = Impl::detector; //! Detects whether `Op` is valid. /** * This alias template checks whether `Op` can be instantiated. It is * equivalent to `typename detected_or::value_t`. * * \note This functionality is part of the C++ library fundamentals TS v2 and might * or might not became part of C++2a. * * \ingroup CxxUtilities */ template class Op, typename... Args> using is_detected = typename detected_or::value_t; #ifdef __cpp_variable_templates //! Detects whether `Op` is valid and makes the result available as a value. /** * This constexpr variable checks whether `Op` can be instantiated. It is * equivalent to `is_detected::value`. * * \note This functionality is part of the C++ library fundamentals TS v2 and might * or might not became part of C++2a. * * \ingroup CxxUtilities */ template class Op, typename... Args> constexpr bool is_detected_v = is_detected::value; #endif // __cpp_variable_templates //! Returns `Op` if that is valid; otherwise returns nonesuch. /** * This alias template can be used to instantiate `Op` in a context that is * not SFINAE-safe by appropriately wrapping the instantiation. If instantiation fails, * the marker type nonesuch is returned instead. * * \note This functionality is part of the C++ library fundamentals TS v2 and might * or might not became part of C++2a. * * \ingroup CxxUtilities */ template class Op, typename... Args> using detected_t = typename detected_or::type; //! Returns `Op` if that is valid; otherwise returns the fallback type `Default`. /** * This alias template can be used to instantiate `Op` in a context that is * not SFINAE-safe by appropriately wrapping the instantiation and automatically falling back * to `Default` if instantiation fails. * * \note This functionality is part of the C++ library fundamentals TS v2 and might * or might not became part of C++2a. * * \ingroup CxxUtilities */ template class Op, typename... Args> using detected_or_t = typename detected_or::type; //! Checks whether `Op` is `Expected` without causing an error if `Op` is invalid. /** * \note This functionality is part of the C++ library fundamentals TS v2 and might * or might not became part of C++2a. * * \ingroup CxxUtilities */ template class Op, typename... Args> using is_detected_exact = std::is_same>; #ifdef __cpp_variable_templates //! Convenient access to the result value of is_detected_exact. /** * \note This functionality is part of the C++ library fundamentals TS v2 and might * or might not became part of C++2a. * * \ingroup CxxUtilities */ template class Op, typename... Args> constexpr bool is_detected_exact_v = is_detected_exact::value; #endif // __cpp_variable_templates //! Checks whether `Op` is convertible to `Target` without causing an error if `Op` is invalid. /** * \note This functionality is part of the C++ library fundamentals TS v2 and might * or might not became part of C++2a. * * \ingroup CxxUtilities */ template class Op, typename... Args> using is_detected_convertible = std::is_convertible>; #ifdef __cpp_variable_templates //! Convenient access to the result value of is_detected_convertible. /** * \note This functionality is part of the C++ library fundamentals TS v2 and might * or might not became part of C++2a. * * \ingroup CxxUtilities */ template class Op, typename... Args> constexpr bool is_detected_convertible_v = is_detected_convertible::value; #endif // __cpp_variable_templates #endif // DUNE_HAVE_CXX_EXPERIMENTAL_IS_DETECTED // conjunction // ----------- /** * \brief forms the logical conjunction of the type traits B... * * \note This functionality is part of the C++17 standard. * * \ingroup CxxUtilities **/ template< class... B > struct [[deprecated("Will be removed after release 2.8. Use std::conjuction instead.")]] conjunction : std::conjunction {}; // disjunction // ----------- /** * \brief forms the logical disjunction of the type traits B... * * \note This functionality is part of the C++17 standard. * * \ingroup CxxUtilities **/ template< class... B > struct [[deprecated("Will be removed after release 2.8. Use std::disjunction instead.")]] disjunction : std::disjunction {}; // negation // -------- /** * \brief forms the logical negation of the type traits B... * * \note This functionality is part of the C++17 standard. * * \ingroup CxxUtilities **/ template struct [[deprecated("Will be removed after release 2.8. Use std::negation instead.")]] negation : std::negation {}; } // namespace Std } // namespace Dune #endif // #ifndef DUNE_COMMON_STD_TYPE_TRAITS_HH dune-common-2.8.0/dune/common/std/utility.hh000066400000000000000000000007731411343567400210220ustar00rootroot00000000000000#ifndef DUNE_COMMON_STD_UTILITY_HH #define DUNE_COMMON_STD_UTILITY_HH #include #warning dune/common/std/utility.hh is deprecated and will be removed after Dune 2.8.\ Include instead namespace Dune { namespace Std { using std::integer_sequence; using std::index_sequence; using std::make_integer_sequence; using std::make_index_sequence; using std::index_sequence_for; } // namespace Std } // namespace Dune #endif // #ifndef DUNE_COMMON_STD_UTILITY_HH dune-common-2.8.0/dune/common/std/variant.hh000066400000000000000000000010351411343567400207530ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_STD_VARIANT_HH #define DUNE_COMMON_STD_VARIANT_HH #warning dune/common/std/variant.hh is deprecated and will be removed after Dune 2.8.\ Include instead #include namespace Dune { namespace Std { using std::variant; using std::visit; using std::variant_size; using std::variant_size_v; using std::get; using std::get_if; using std::holds_alternative; using std::monostate; } } #endif dune-common-2.8.0/dune/common/stdstreams.cc000066400000000000000000000023571411343567400207040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "stdstreams.hh" namespace Dune { /* The standard debug streams declared in stdstreams.hh exist in this file so that they can be compiled into libdune */ /* stream for very verbose output: information on the lowest level. This is expected to report insane amounts of information. Use of the activation-flag to only generate output near the problem is recommended */ DVVerbType dvverb(std::cout); /* stream for verbose output: information that helps to trace in more detail what the modules do */ DVerbType dverb(std::cout); /* stream for informative output: summary infos on what a module does, runtimes, etc. */ DInfoType dinfo(std::cout); /* stream for warnings: messages which may indicate problems */ DWarnType dwarn(std::cerr); /* stream for strong warnings: when a failure */ DGraveType dgrave(std::cerr); /* stream for error messages: only packages integrating Dune completely will redirect it. The output of derr is independent of the debug-level, only the activation-flag is checked */ DErrType derr(std::cerr); } dune-common-2.8.0/dune/common/stdstreams.hh000066400000000000000000000112611411343567400207100ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /** \file \brief Standard Dune debug streams The standard debug streams are compiled into libdune to exist globally. This file declares the stream types and the global debug level. */ #ifndef DUNE_COMMON_STDSTREAMS_HH #define DUNE_COMMON_STDSTREAMS_HH #include "debugstream.hh" namespace Dune { /** \addtogroup DebugOut @{ standard debug streams with level below MINIMAL_DEBUG_LEVEL will collapse to doing nothing if output is requested. MINIMAL_DEBUG_LEVEL is set to DUNE_MINIMAL_DEBUG_LEVEL, which is defined in config.h and can be changed by the configure option @code --with-minimal-debug-level=[grave|warn|info|verb|vverb] @endcode For a Dune-Release this should be set to at least 4 so that only important messages are active. Dune-developers may adapt this setting to their debugging needs locally Keep in mind that libdune has to be recompiled if this value is changed! The singleton instances of the available debug streams can be found in the \ref DebugOut "Standard Debug Streams" module @} */ /** \defgroup StdStreams Standard Debug Streams \ingroup DebugOut @{ Dune defines several standard output streams for the library routines. Applications may control the standard streams via the attach/detach, push/pop interface but should define an independent set of streams (see \ref DebugAppl ) */ /** @brief The default minimum debug level. If the level of a stream is bigger than this value it will be activated. */ #ifndef DUNE_MINIMAL_DEBUG_LEVEL #define DUNE_MINIMAL_DEBUG_LEVEL 4 #endif static const DebugLevel MINIMAL_DEBUG_LEVEL = DUNE_MINIMAL_DEBUG_LEVEL; /** @brief The level of the very verbose debug stream. @see dvverb */ static const DebugLevel VERY_VERBOSE_DEBUG_LEVEL = 1; /** @brief Type of very verbose debug stream. @see dvverb */ typedef DebugStream DVVerbType; /** \brief stream for very verbose output. \code #include \endcode Information on the lowest level. This is expected to report insane amounts of information. Use of the activation-flag to only generate output near the problem is recommended. */ extern DVVerbType dvverb; /** @brief The level of the verbose debug stream. @see dvverb */ static const DebugLevel VERBOSE_DEBUG_LEVEL = 2; /** @brief Type of more verbose debug stream. @see dverb */ typedef DebugStream DVerbType; /** @brief Singleton of verbose debug stream. \code #include \endcode */ extern DVerbType dverb; /** @brief The level of the informative debug stream. @see dinfo */ static const DebugLevel INFO_DEBUG_LEVEL = 3; /** @brief Type of debug stream with info level. @see dinfo */ typedef DebugStream DInfoType; /** @brief Stream for informative output. \code #include \endcode Summary infos on what a module does, runtimes, etc. */ extern DInfoType dinfo; /** @brief The level of the debug stream for warnings. @see dwarn */ static const DebugLevel WARN_DEBUG_LEVEL = 4; /** @brief Type of debug stream with warn level. @see dwarn */ typedef DebugStream DWarnType; /** @brief Stream for warnings indicating problems. \code #include \endcode */ extern DWarnType dwarn; /** @brief The level of the debug stream for fatal errors. @see dgrave */ static const DebugLevel GRAVE_DEBUG_LEVEL = 5; /** @brief Type of debug stream for fatal errors.*/ typedef DebugStream DGraveType; /** @brief Stream for warnings indicating fatal errors. \code #include \endcode */ extern DGraveType dgrave; /** @brief The type of the stream used for error messages. */ typedef DebugStream<1> DErrType; /** @brief Stream for error messages. \code #include \endcode Only packages integrating Dune completely will redirect it. The output of derr is independent of the debug-level, only the activation-flag is checked. */ extern DErrType derr; /** }@ */ } #endif dune-common-2.8.0/dune/common/stdthread.cc000066400000000000000000000047621411343567400204770ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include #endif #include #include #include #include #include namespace Dune { namespace { void printCallOnceError(const char *file, int line, const char *function, const char *msg) { if(file) std::cerr << file << ":" << line << ": "; std::cerr << "error: "; if(function) std::cerr << "(in " << function << "()) "; std::cerr << "std::call_once() is broken.\n" << "\n" << msg << std::endl; } void setBool(bool *v) { *v = true; } } // anonymous namespace void doAssertCallOnce(const char *file, int line, const char *function) { std::once_flag once; bool works = false; try { // pass address to works since call_once passes by value std::call_once(once, setBool, &works); } catch(...) { printCallOnceError(file, line, function, "std::call_once() throws an exception. This suggests that the program was\n" "linked without a threading library. Common ways to link to a threading\n" "library is to specify one of the following during linking: -pthread, \n" "-lpthread, or -pthreads. The build system should have tried various of\n" "these options, but unfortunately that is only a guess and we cannot verify\n" "that we found a working configuration until runtime.\n" "\n" "Going to rethrow the exception now to give the system library a chance to\n" "print more information about it, just in case that helps with debugging.\n" ); throw; } if(!works) { printCallOnceError(file, line, function, "std::call_once() never calls the function. This suggests that your\n" "libctdc++ or your gcc built without threading support (--disable-threads,\n" "see https://gcc.gnu.org/install/configure.html). This is probably a bug in\n" "__gthread_once() in /usr/include/c++/4.7/x86_64-linux-gnu/bits/gthr-single.h\n" "(which should not silently return success without doing anything, but\n" "apparently does so in some versions).\n" "\n" "To fix the issue, either recompile gcc with a working threading\n" "implementation, or file a bug for gthr-single.h, or file a bug at\n" "https://dune-project.org/flyspray/ and request a workaround at the dune-side." ); std::abort(); } } } // namespace Dune dune-common-2.8.0/dune/common/stdthread.hh000066400000000000000000000037341411343567400205070ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_STDTHREAD_HH #define DUNE_COMMON_STDTHREAD_HH namespace Dune { // used internally by assertCallOnce for the actual check void doAssertCallOnce(const char *file, int line, const char *function); //! \brief Make sure call_once() works and provide a helpful error message //! otherwise. /** * For call_once() to work, certain versions of libstdc++ need to be * _linked_ with -pthread or similar flags. If that is not the case, * call_once() will throw an exception. This function checks that * call_once() can indeed be used, i.e. that it does not throw an exception * when it should not, and that the code does indeed get executed. If * call_once() cannot be used, assertCallOnce() aborts the program with a * helpful error message. * * The check is only actually executed the first time assertCallOnce() is * called. * * The arguments \c file and \c line specify the filename and line number * that should appear in the error message. They are ignored if \c file is * 0. The argument \c function specifies the name of the function to appear * in the error message. It is ignored if \c function is 0. */ inline void assertCallOnce(const char *file = nullptr, int line = -1, const char *function = nullptr) { // make sure to call this only the first time this function is invoked [[maybe_unused]] static const bool works = (doAssertCallOnce(file, line, function), true); } //! \brief Make sure call_once() works and provide a helpful error message //! otherwise. /** * This calls assertCallOnce() and automatically provides information about * the caller in the error message. */ #define DUNE_ASSERT_CALL_ONCE() \ ::Dune::assertCallOnce(__FILE__, __LINE__, __func__) } // namespace Dune #endif // DUNE_COMMON_STDTHREAD_HH dune-common-2.8.0/dune/common/streamoperators.hh000066400000000000000000000026521411343567400217550ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_STREAMOPERATORS_HH #define DUNE_STREAMOPERATORS_HH /** \file \brief Implementation of stream operators for std::array and std::tuple */ #include #include #include #include namespace Dune { /** @addtogroup Common @{ */ //! Print a std::tuple template inline Stream& operator<<(Stream& stream, const std::tuple& t) { stream<<"["; if(sizeof...(Ts)>0) { Hybrid::forEach(std::make_index_sequence{}, [&](auto i){stream<(t)<<",";}); stream<(t); } stream<<"]"; return stream; } //! Read a std::tuple template inline Stream& operator>>(Stream& stream, std::tuple& t) { Hybrid::forEach(std::make_index_sequence{}, [&](auto i){stream>>std::get(t);}); return stream; } //! Print a std::array template inline Stream& operator<<(Stream& stream, const std::array& a) { stream<<"["; if(N>0) { for(std::size_t i=0; i #include #include #include #include #include #include #include #include namespace Dune { /** * @addtogroup StringUtilities * * @{ */ /** \brief Check whether a character container has a given prefix * * The container must support the begin() and size() methods. */ template bool hasPrefix(const C& c, const char* prefix) { std::size_t len = std::strlen(prefix); return c.size() >= len && std::equal(prefix, prefix+len, c.begin()); } /** \brief Check whether a character container has a given suffix * * The container must support the begin() and size() methods and the * const_iterator member type. * * \note This is slow for containers which don't have random access iterators. * In the case of containers with bidirectional iterators, this * slowness is unnecessary. */ template bool hasSuffix(const C& c, const char* suffix) { std::size_t len = std::strlen(suffix); if(c.size() < len) return false; typename C::const_iterator it = c.begin(); std::advance(it, c.size() - len); return std::equal(suffix, suffix+len, it); } /** * \brief Format values according to printf format string * * \param s The format string to be used * \param args The valued to be formatted * * This is a wrapper to std::snprintf that provides * overflow save printf functionality. For up to 1000 * characters a static buffer is used. If this is not sufficient * a dynamic buffer of appropriate size is allocated. */ template static std::string formatString(const std::string& s, const T&... args) { static const int bufferSize=1000; char buffer[bufferSize]; // try to format with static buffer int r = std::snprintf(buffer, bufferSize, s.c_str(), args...); // negative return values correspond to errors if (r<0) DUNE_THROW(Dune::Exception,"Could not convert format string using given arguments."); // if buffer was large enough return result as string if (r dynamicBuffer; try { dynamicBuffer = std::make_unique(dynamicBufferSize); } catch (const std::bad_alloc&) { DUNE_THROW(Dune::Exception,"Could allocate large enough dynamic buffer in formatString."); } // convert and check for errors again r = std::snprintf(dynamicBuffer.get(), dynamicBufferSize, s.c_str(), args...); if (r<0) DUNE_THROW(Dune::Exception,"Could not convert format string using given arguments."); // the new buffer should always be large enough assert(r #include #include #include #include #include #include #include template void checkAlignment(Dune::TestSuite &test) { std::vector> defaultalignment(4); test.check(Dune::isAligned(defaultalignment.data(), std::alignment_of::value), "defaultalignment isAligned") << "alignment(" << std::alignment_of::value << ") not detected for " << Dune::className(); std::vector> alignment16(4); test.check(Dune::isAligned(alignment16.data(), 16), "alignment16 isAligned") << "alignment(16) not detected for " << Dune::className(); } int main(int argc, char **argv) { Dune::TestSuite test; using ArithmeticTypes = std::tuple< char, signed char, unsigned char, short, unsigned short, int, unsigned, long, long unsigned, long long, long long unsigned, wchar_t, char16_t, char32_t, float, double, long double>; Dune::Hybrid::forEach(ArithmeticTypes(), [&](auto val) { using T = decltype(val); checkAlignment(test); }); return test.exit(); } dune-common-2.8.0/dune/common/test/arithmetictestsuite.hh000066400000000000000000000554001411343567400236040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_TEST_ARITHMETICTESTSUITE_HH #define DUNE_COMMON_TEST_ARITHMETICTESTSUITE_HH #include #include #include #include #include namespace Dune { /* * silence warnings from GCC about using integer operands on a bool * (when instantiated for T=bool) */ #if __GNUC__ >= 7 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wbool-operation" # pragma GCC diagnostic ignored "-Wint-in-bool-context" #endif //! Test suite for arithmetic types /** * You usually want to call the member function `checkArithmetic()`. The * individual component tests are however available for special needs. */ class ArithmeticTestSuite : public TestSuite { public: // inherit all constructors from TestSuite using TestSuite::TestSuite; //! tag denoting any arithmetic type struct Arithmetic {}; //! tag denoting integral types struct Integral : Arithmetic {}; //! tag denoting boolean types struct Boolean : Integral {}; //! tag denoting signed integral types struct Signed : Integral {}; //! tag denoting unsigned integral types struct Unsigned : Integral {}; //! tag denoting floating point types struct Floating : Arithmetic {}; private: static const char *name(Arithmetic) { return "Arithmetic"; } static const char *name(Integral ) { return "Integral"; } static const char *name(Boolean ) { return "Boolean"; } static const char *name(Signed ) { return "Signed"; } static const char *name(Unsigned ) { return "Unsigned"; } static const char *name(Floating ) { return "Floating"; } template using Cond = typename std::conditional::type; public: //! determine arithmetic tag for the given type /** * `T` can be either one of the fundamental arithmetic types, in which * case a default-constructed tag object for that type is returned. Or it * can be a class derived from `Arithmetic`, in which case a * default-constructed object of that class is is returned. */ template constexpr static auto tag(T = T{}) { return Cond, T, Cond, Floating, Cond, Cond, Boolean, Cond, Signed, Cond, Unsigned > > > > > >{}; } #define DUNE_TEST_FUNCTION(T, tag) \ static const auto function = \ std::string(__func__) + "<" + className() + ">(" + name(tag) + ")" #define DUNE_TEST_CHECK(expr) \ (check((expr), function) \ << __FILE__ << ":" << __LINE__ << ": Check \"" << #expr << "\"") // // check basic operations: construct, copy, compare // //! check the default constructors template void checkDefaultConstruct([[maybe_unused]] Arithmetic arithmetic_tag) { [[maybe_unused]] T t0; (void)T(); [[maybe_unused]] T t1{}; [[maybe_unused]] T t2 = {}; } //! check explicit conversion from and to int template void checkExplicitIntConvert(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); // this test may be applied to boolean-type types. 0 and 1 are the only // values that survive that. T t0(0); DUNE_TEST_CHECK(int(t0) == 0); T t1(1); DUNE_TEST_CHECK(int(t1) == 1); } //! check the move constructor template void checkMoveConstruct(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i : { 0, 1 }) { T t0(i); T t1(std::move(t0)); T t2 = std::move(t1); T t3{ std::move(t2) }; T t4 = { std::move(t3) }; DUNE_TEST_CHECK(bool(t4 == T(i))); } } //! check the copy constructor template void checkCopyConstruct(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i : { 0, 1 }) { T t0(i); T t1(t0); T t2 = t1; T t3{ t2 }; T t4 = { t3 }; DUNE_TEST_CHECK(bool(t0 == T(i))); DUNE_TEST_CHECK(bool(t1 == T(i))); DUNE_TEST_CHECK(bool(t2 == T(i))); DUNE_TEST_CHECK(bool(t3 == T(i))); DUNE_TEST_CHECK(bool(t4 == T(i))); } } //! check the move assignment operator template void checkMoveAssign(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i : { 0, 1 }) { T t0(i); T t2, t4; t2 = std::move(t0); t4 = { std::move(t2) }; DUNE_TEST_CHECK(bool(t4 == T(i))); } } //! check the copy assignment operator template void checkCopyAssign(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i : { 0, 1 }) { T t0(i); T t2, t4; t2 = t0; t4 = { t2 }; DUNE_TEST_CHECK(bool(t0 == T(i))); DUNE_TEST_CHECK(bool(t2 == T(i))); DUNE_TEST_CHECK(bool(t4 == T(i))); } } //! check `==` and `!=` /** * \note We do not require the result to be _implicitly_ convertible to * bool, but it must be contextually convertible to bool. */ template void checkEqual(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); T t0(0); T t1(1); DUNE_TEST_CHECK(bool(t0 == T(0))); DUNE_TEST_CHECK(bool(t1 == T(1))); DUNE_TEST_CHECK(!bool(t0 == T(1))); DUNE_TEST_CHECK(!bool(t1 == T(0))); DUNE_TEST_CHECK(!bool(t0 == t1)); DUNE_TEST_CHECK(!bool(t0 != T(0))); DUNE_TEST_CHECK(!bool(t1 != T(1))); DUNE_TEST_CHECK(bool(t0 != T(1))); DUNE_TEST_CHECK(bool(t1 != T(0))); DUNE_TEST_CHECK(bool(t0 != t1)); } // // checks for unary operators // //! check postfix `++` /** * Applies to boolean (deprecated), integral, and floating point. */ template void checkPostfixInc(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); T t0(0); DUNE_TEST_CHECK(bool(T(t0++) == T(0))); DUNE_TEST_CHECK(bool(t0 == T(1))); } template void checkPostfixInc(Boolean) {} //! check postfix `--` /** * Applies to integral (no boolean), and floating point. */ template void checkPostfixDec(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); T t1(1); DUNE_TEST_CHECK(bool(T(t1--) == T(1))); DUNE_TEST_CHECK(bool(t1 == T(0))); } template void checkPostfixDec(Boolean) {} //! check prefix `+` /** * Applies to boolean, integral, and floating point. */ template void checkPrefixPlus(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(+T(0)) == T(0))); DUNE_TEST_CHECK(bool(T(+T(1)) == T(1))); } //! check prefix `-` /** * Applies to boolean, integral, and floating point. */ template void checkPrefixMinus(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(-T(0)) == T( 0))); DUNE_TEST_CHECK(bool(T(-T(1)) == T(-1))); } //! check prefix `!` /** * Applies to boolean, integral, and floating point. */ template void checkPrefixNot(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(!T(0))); DUNE_TEST_CHECK(!bool(!T(1))); } //! check prefix `~` /** * Applies to boolean and integral. */ template void checkPrefixBitNot(Boolean arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(~T(0)))); } template void checkPrefixBitNot(Integral arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(~T(0)))); DUNE_TEST_CHECK(bool(T(~T(1)))); DUNE_TEST_CHECK(bool(T(~T(~T(0))) == T(0))); DUNE_TEST_CHECK(bool(T(~T(~T(1))) == T(1))); } template void checkPrefixBitNot(Unsigned arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); checkPrefixBitNot(Integral{}); DUNE_TEST_CHECK(bool(T(~T(0)) == T(-1))); DUNE_TEST_CHECK(bool(T(~T(1)) == T(-2))); } template void checkPrefixBitNot(Floating) {} //! check postfix `++` /** * Applies to boolean (deprecated), integral, and floating point. */ template void checkPrefixInc(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); T t0(0); DUNE_TEST_CHECK(bool(T(++t0) == T(1))); DUNE_TEST_CHECK(bool(t0 == T(1))); ++t0 = T(0); DUNE_TEST_CHECK(bool(t0 == T(0))); } template void checkPrefixInc(Boolean) {} //! check postfix `--` /** * Applies to integral (no boolean), and floating point. */ template void checkPrefixDec(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); T t1(1); DUNE_TEST_CHECK(bool(T(--t1) == T(0))); DUNE_TEST_CHECK(bool(t1 == T(0))); t1 = T(1); --t1 = T(1); DUNE_TEST_CHECK(bool(t1 == T(1))); } template void checkPrefixDec(Boolean) {} // // checks for infox operators // //! check infix `*` /** * Applies to boolean, integral, and floating point. */ template void checkInfixMul(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(T(0)*T(0)) == T(0))); DUNE_TEST_CHECK(bool(T(T(1)*T(0)) == T(0))); DUNE_TEST_CHECK(bool(T(T(0)*T(1)) == T(0))); DUNE_TEST_CHECK(bool(T(T(1)*T(1)) == T(1))); } //! check infix `/` /** * Applies to boolean, integral, and floating point. */ template void checkInfixDiv(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(T(0)/T(1)) == T(0))); DUNE_TEST_CHECK(bool(T(T(1)/T(1)) == T(1))); } //! check infix `%` /** * Applies to boolean and integral. */ template void checkInfixRem(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(T(0)%T(1)) == T(0))); DUNE_TEST_CHECK(bool(T(T(1)%T(1)) == T(0))); } template void checkInfixRem(Floating) {} //! check infix `+` /** * Applies to boolean, integral, and floating point. */ template void checkInfixPlus(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(T(0)+T(0)) == T(0))); DUNE_TEST_CHECK(bool(T(T(1)+T(0)) == T(1))); DUNE_TEST_CHECK(bool(T(T(0)+T(1)) == T(1))); DUNE_TEST_CHECK(bool(T(T(1)+T(1)) == T(2))); } //! check infix `-` /** * Applies to boolean, integral, and floating point. */ template void checkInfixMinus(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(T(0)-T(0)) == T( 0))); DUNE_TEST_CHECK(bool(T(T(1)-T(0)) == T( 1))); DUNE_TEST_CHECK(bool(T(T(0)-T(1)) == T(-1))); DUNE_TEST_CHECK(bool(T(T(1)-T(1)) == T( 0))); } //! check infix `<<` /** * Applies to boolean and integral. */ template void checkInfixLShift(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(T(0)< void checkInfixLShift(Floating) {} //! check infix `>>` /** * Applies to boolean and integral. */ template void checkInfixRShift(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(T(0)>>T(0)) == T(0))); DUNE_TEST_CHECK(bool(T(T(1)>>T(0)) == T(1))); DUNE_TEST_CHECK(bool(T(T(0)>>T(1)) == T(0))); DUNE_TEST_CHECK(bool(T(T(1)>>T(1)) == T(0))); } template void checkInfixRShift(Floating) {} //! check infix `<` /** * Applies to boolean, integral, and floating point. */ template void checkInfixLess(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); DUNE_TEST_CHECK(bool(T(0) void checkInfixLess(Signed arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); checkInfixLess(Integral{}); DUNE_TEST_CHECK(bool(T(-1) void checkInfixLess(Unsigned arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); checkInfixLess(Integral{}); DUNE_TEST_CHECK(bool(T(-1)` /** * Applies to boolean, integral, and floating point. */ template void checkInfixGreater(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); int values[] = { -1, 0, 1 }; for(int i : values) for(int j : values) DUNE_TEST_CHECK(bool(T(i) > T(j)) == bool(T(j) < T(i))); } //! check infix `<=` /** * Applies to boolean, integral, and floating point. */ template void checkInfixLessEqual(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); int values[] = { -1, 0, 1 }; for(int i : values) for(int j : values) DUNE_TEST_CHECK(bool(T(i) <= T(j)) != bool(T(j) < T(i))); } //! check infix `>=` /** * Applies to boolean, integral, and floating point. */ template void checkInfixGreaterEqual(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); int values[] = { -1, 0, 1 }; for(int i : values) for(int j : values) DUNE_TEST_CHECK(bool(T(i) >= T(j)) != bool(T(i) < T(j))); } //! check infix `&` /** * Applies to boolean and integral. */ template void checkInfixBitAnd(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i = 0; i < 4; ++i) for(int j = 0; j < 4; ++j) DUNE_TEST_CHECK(bool(T(T(i) & T(j)) == T(i&j))); } template void checkInfixBitAnd(Boolean arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i = 0; i < 2; ++i) for(int j = 0; j < 2; ++j) DUNE_TEST_CHECK(bool(T(T(i) & T(j)) == T(i&j))); } template void checkInfixBitAnd(Floating) {} //! check infix `^` /** * Applies to boolean and integral. */ template void checkInfixBitXor(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i = 0; i < 4; ++i) for(int j = 0; j < 4; ++j) DUNE_TEST_CHECK(bool(T(T(i) ^ T(j)) == T(i^j))); } template void checkInfixBitXor(Boolean arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i = 0; i < 2; ++i) for(int j = 0; j < 2; ++j) // compare the bit-flipped versions so we don't depend on the number // of bits in T. DUNE_TEST_CHECK(bool(T(~T(T(i) ^ T(j))) == T(~(i^j)))); } template void checkInfixBitXor(Floating) {} //! check infix `|` /** * Applies to boolean and integral. */ template void checkInfixBitOr(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i = 0; i < 4; ++i) for(int j = 0; j < 4; ++j) DUNE_TEST_CHECK(bool(T(T(i) | T(j)) == T(i|j))); } template void checkInfixBitOr(Boolean arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i = 0; i < 2; ++i) for(int j = 0; j < 2; ++j) DUNE_TEST_CHECK(bool(T(T(i) | T(j)) == T(i|j))); } template void checkInfixBitOr(Floating) {} //! check infix `&&` /** * Applies to boolean, integral and floating point. */ template void checkInfixAnd(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i = 0; i < 4; ++i) for(int j = 0; j < 4; ++j) DUNE_TEST_CHECK(bool(T(i) && T(j)) == (i && j)); } //! check infix `||` /** * Applies to boolean, integral and floating point. */ template void checkInfixOr(Arithmetic arithmetic_tag) { DUNE_TEST_FUNCTION(T, arithmetic_tag); for(int i = 0; i < 4; ++i) for(int j = 0; j < 4; ++j) DUNE_TEST_CHECK(bool(T(i) || T(j)) == (i || j)); } // // checks for compound assignment operators // #define DUNE_TEST_PEEL(...) __VA_ARGS__ #define DUNE_TEST_ASSIGN(OP, name, Tag, lrange, rrange) \ template \ void checkAssign##name(Tag arithmetic_tag) \ { \ DUNE_TEST_FUNCTION(T, arithmetic_tag); \ \ for(int i : { DUNE_TEST_PEEL lrange }) \ for(int j : { DUNE_TEST_PEEL rrange }) \ { \ T t(i); \ DUNE_TEST_CHECK(bool((t OP##= T(j)) == T(T(i) OP T(j)))); \ DUNE_TEST_CHECK(bool(t == T(T(i) OP T(j)))); \ } \ } #define DUNE_TEST_ASSIGN_DISABLE(name, Tag) \ template \ void checkAssign##name(Tag) {} DUNE_TEST_ASSIGN(*, Mul, Arithmetic, (0, 1, 2, 3), (0, 1, 2, 3)) DUNE_TEST_ASSIGN(/, Div, Arithmetic, (0, 1, 2, 3), ( 1, 2, 4)) DUNE_TEST_ASSIGN(%, Rem, Arithmetic, (0, 1, 2, 3), ( 1, 2, 3)) DUNE_TEST_ASSIGN_DISABLE(Rem, Floating) DUNE_TEST_ASSIGN(+, Plus, Arithmetic, (0, 1, 2, 3), (0, 1, 2, 3)) DUNE_TEST_ASSIGN(-, Minus, Arithmetic, (0, 1, 2, 3), (0, 1, 2, 3)) DUNE_TEST_ASSIGN(<<, LShift, Integral, (0, 1, 2, 3), (0, 1, 2, 3)) DUNE_TEST_ASSIGN(>>, RShift, Integral, (0, 1, 2, 3), (0, 1, 2, 3)) DUNE_TEST_ASSIGN(<<, LShift, Boolean, (0, 1 ), (0, 1 )) DUNE_TEST_ASSIGN(>>, RShift, Boolean, (0, 1 ), (0, 1 )) DUNE_TEST_ASSIGN_DISABLE(LShift, Floating) DUNE_TEST_ASSIGN_DISABLE(RShift, Floating) DUNE_TEST_ASSIGN(&, BitAnd, Integral, (0, 1, 2, 3), (0, 1, 2, 3)) DUNE_TEST_ASSIGN(^, BitXor, Integral, (0, 1, 2, 3), (0, 1, 2, 3)) DUNE_TEST_ASSIGN(|, BitOr, Integral, (0, 1, 2, 3), (0, 1, 2, 3)) DUNE_TEST_ASSIGN_DISABLE(BitAnd, Floating) DUNE_TEST_ASSIGN_DISABLE(BitXor, Floating) DUNE_TEST_ASSIGN_DISABLE(BitOr, Floating) #undef DUNE_TEST_ASSIGN_DISABLE #undef DUNE_TEST_ASSIGN #undef DUNE_TEST_PEEL #undef DUNE_TEST_FUNCTION #undef DUNE_TEST_CHECK // // checks collections // //! run the full arithmetic type testsuite /** * `T` is the type to check. `Tag` determines the arithmetic category; it * is one of the classes derived from `Arithmetic`. Alternatively, `Tag` * may be one of the fundamental arithmetic types, in which case it will * be converted to the appropriate category tag automatically. * * To check an extended unsigned integer type, you might use one of the * following calls: * \code * test.checkArithmetic(); * test.checkArithmetic(0u); * test.checkArithmetic(); * test.checkArithmetic(ArithemticTestSuite::Unsigned{}); * \endcode */ template void checkArithmetic(Tag = Tag{}) { auto arithmetic_tag = this->tag(); checkDefaultConstruct(arithmetic_tag); checkExplicitIntConvert(arithmetic_tag); checkMoveConstruct(arithmetic_tag); checkCopyConstruct(arithmetic_tag); checkMoveAssign(arithmetic_tag); checkCopyAssign(arithmetic_tag); checkEqual(arithmetic_tag); checkPostfixInc(arithmetic_tag); checkPostfixDec(arithmetic_tag); checkPrefixPlus(arithmetic_tag); checkPrefixMinus(arithmetic_tag); checkPrefixNot(arithmetic_tag); checkPrefixBitNot(arithmetic_tag); checkPrefixInc(arithmetic_tag); checkPrefixDec(arithmetic_tag); checkInfixMul(arithmetic_tag); checkInfixDiv(arithmetic_tag); checkInfixRem(arithmetic_tag); checkInfixPlus(arithmetic_tag); checkInfixMinus(arithmetic_tag); checkInfixLShift(arithmetic_tag); checkInfixRShift(arithmetic_tag); checkInfixLess(arithmetic_tag); checkInfixGreater(arithmetic_tag); checkInfixLessEqual(arithmetic_tag); checkInfixGreaterEqual(arithmetic_tag); checkInfixBitAnd(arithmetic_tag); checkInfixBitXor(arithmetic_tag); checkInfixBitOr(arithmetic_tag); checkInfixAnd(arithmetic_tag); checkInfixOr(arithmetic_tag); checkAssignMul(arithmetic_tag); checkAssignDiv(arithmetic_tag); checkAssignRem(arithmetic_tag); checkAssignPlus(arithmetic_tag); checkAssignMinus(arithmetic_tag); checkAssignLShift(arithmetic_tag); checkAssignRShift(arithmetic_tag); checkAssignBitAnd(arithmetic_tag); checkAssignBitXor(arithmetic_tag); checkAssignBitOr(arithmetic_tag); } }; #if __GNUC__ >= 7 # pragma GCC diagnostic pop #endif } // namespace Dune #endif // DUNE_COMMON_TEST_ARITHMETICTESTSUITE_HH dune-common-2.8.0/dune/common/test/arithmetictestsuitetest.cc000066400000000000000000000013031411343567400244630ustar00rootroot00000000000000#include #include #include #include #include int main(int argc, char **argv) { Dune::MPIHelper::instance(argc, argv); Dune::ArithmeticTestSuite test; using ArithmeticTypes = std::tuple< bool, char, signed char, unsigned char, short, unsigned short, int, unsigned, long, long unsigned, long long, long long unsigned, wchar_t, char16_t, char32_t, float, double, long double>; Dune::Hybrid::forEach(ArithmeticTypes(), [&](auto val) { using T = decltype(val); test.checkArithmetic(); }); return test.exit(); } dune-common-2.8.0/dune/common/test/arraylisttest.cc000066400000000000000000000101551411343567400223770ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include class Double { public: double val; Double() : val(0){} Double(double d) : val(d){} Double& operator=(double d){ val=d; return *this; } }; bool operator<(Double a, Double b){ return a.val void randomizeList(Dune::ArrayList& alist){ using namespace Dune; srand(300); int lowest=0, highest=1000, range=(highest-lowest)+1; for(int i=0; i < 250; i++) alist.push_back(T(static_cast(range*(rand()/(RAND_MAX+1.0))))); } int testSorting(){ using namespace Dune; ArrayList alist; randomizeList(alist); std::sort(alist.begin(), alist.end()); double last=-1; for(ArrayList::iterator iter=alist.begin(), end=alist.end(); iter != end; ++iter) { if((*iter)>=last) { last=*iter; }else{ std::cerr << last<<">"<<(*iter)<<" List is not sorted! "<<__FILE__ <<":"<<__LINE__< void initConsecutive(Dune::ArrayList& alist){ using namespace Dune; for(int i=0; i < 100; i++) alist.push_back(i); } int testIteratorRemove(){ using namespace Dune; ArrayList alist; initConsecutive(alist); ArrayList::iterator iter=alist.begin(); iter+=8; iter.eraseToHere(); ++iter; if((*iter)!=10) { std::cerr<<"Removing from iterator failed! "<<__FILE__<<":"<<__LINE__< alist; initConsecutive(alist); ArrayList::iterator iter=alist.begin(); for(int i=0; i < 100; i++) { if(iter[i]!=i) { std::cerr << "Random Access failed: "< alist; initConsecutive(alist); ArrayList::iterator iter=alist.begin(), iter1=alist.begin(); iter1=iter+5; iter1=iter-5; iter1=iter+5; if(!(iter="<<*iter1<<" Operator< seems to be wrong! "<< __FILE__ <<__LINE__<iter)) { std::cerr<<"operator> seems to be wrong! "<< __FILE__ <<__LINE__<=iter)) { std::cerr<<"operator>= seems to be wrong! "<< __FILE__ <<__LINE__< alist; randomizeList(alist); int ret=testIterator(alist); if(0!=testComparison()) { ret++; cerr<< "Comparison failed!"< #include #include #include #include #include template void f(const std::array &a) { using Dune::operator<<; std::cout << "Got a " << Dune::className(a) << " with elements " << a << std::endl; } int main() { // check that make_array works f(Dune::Std::make_array(1, 2)); f(Dune::Std::make_array(1, 2, 3)); f(Dune::Std::make_array(1, 2, 3, 4)); f(Dune::Std::make_array(1, 2, 3, 4, 5)); f(Dune::Std::make_array(1, 2, 3, 4, 5, 6)); f(Dune::Std::make_array(1, 2, 3, 4, 5, 6, 7)); f(Dune::Std::make_array(1, 2, 3, 4, 5, 6, 7, 8)); f(Dune::Std::make_array(1, 2, 3, 4, 5, 6, 7, 8, 9)); f(Dune::Std::make_array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); Dune::FieldVector x(0); f(Dune::Std::make_array(x, x)); } dune-common-2.8.0/dune/common/test/assertandreturntest.cc000066400000000000000000000050061411343567400236100ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #ifdef NDEBUG #undef NDEBUG #endif #ifdef TEST_NDEBUG #define NDEBUG TEST_NDEBUG #endif #include #include #include #include struct Foo { static constexpr auto lessAndReturn([[maybe_unused]] int a, [[maybe_unused]] int b, int x) { return DUNE_ASSERT_AND_RETURN(a::value != 3) DUNE_THROW(Dune::Exception, "DUNE_ASSERT_AND_RETURN returned incorrect value in constexpr context"); // If EXPECT_FAIL would work with failing assertions, // we could test if the assertion is triggered with // a target // // dune_add_test(NAME assertandreturntest_runtime_fail // SOURCES assertandreturntest.cc // LINK_LIBRARIES dunecommon // COMPILE_DEFINITIONS "TEST_RUNTIME_FAIL" // EXPECT_FAIL // LABELS quick) // // and the following code: #ifdef TEST_RUNTIME_FAIL // This should fail at runtime because 0>-3 if (Foo::lessAndReturn(0,-1,3) != 3) DUNE_THROW(Dune::Exception, "DUNE_ASSERT_AND_RETURN returned incorrect value in dynamic context"); #endif #ifdef TEST_COMPILETIME_FAIL // This should fail at compile time because 0>-3 if (std::integral_constant::value != 3) DUNE_THROW(Dune::Exception, "DUNE_ASSERT_AND_RETURN returned incorrect value in constexpr context"); #endif #ifdef TEST_NDEBUG // This should not fail because NDEBUG is set if (Foo::lessAndReturn(0,-1,3) != 3) DUNE_THROW(Dune::Exception, "DUNE_ASSERT_AND_RETURN returned incorrect value in dynamic context"); // This should not fail because NDEBUG is set if (std::integral_constant::value != 3) DUNE_THROW(Dune::Exception, "DUNE_ASSERT_AND_RETURN returned incorrect value in constexpr context"); #endif return 0; } catch( Dune::Exception &e ) { std::cerr << "Dune reported error: " << e << std::endl; return 1; } catch(...) { std::cerr << "Unknown exception thrown!" << std::endl; return 1; } dune-common-2.8.0/dune/common/test/autocopytest.cc000066400000000000000000000023031411343567400222240ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include template constexpr auto doAutoCopy(T &&v) { return Dune::autoCopy(std::forward(v)); } // an example expression object that evaluates to int(0) struct ZeroExpr { constexpr operator int() const volatile { return 0; } }; namespace Dune { template<> struct AutonomousValueType { using type = int; }; // doAutoCopy should not pick up this overload constexpr auto autoCopy(ZeroExpr) = delete; } // namespace Dune int main() { { std::vector v{true}; auto ref = v[0]; static_assert(!std::is_same::value, "sanity check failed"); auto val = Dune::autoCopy(v[0]); static_assert(std::is_same::value, "vector::reference not resolved"); } { constexpr ZeroExpr zexpr{}; auto val = doAutoCopy(zexpr); static_assert(std::is_same::value, "Custom type was not resolved"); static_assert(doAutoCopy(zexpr) == 0, "Resolution is not constexpr"); } } dune-common-2.8.0/dune/common/test/bigunsignedinttest.cc000066400000000000000000000107511411343567400234000ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #define CHECK(x) \ do { \ if (!(x)) { \ pass = false; \ std::cerr << "FAILED: " << #x << std::endl; \ } \ } while(false) int main() { bool pass = true; typedef Dune::bigunsignedint<16> ShortInteger; typedef Dune::bigunsignedint<128> BigInteger; /* Test std::numeric_limits for ShortInteger (should be same as for uint16_t) */ CHECK(std::numeric_limits::min() == std::numeric_limits::min()); CHECK(std::numeric_limits::max() == std::numeric_limits::max()); CHECK(std::numeric_limits::digits == std::numeric_limits::digits); CHECK(std::numeric_limits::epsilon() == std::numeric_limits::epsilon()); CHECK(std::numeric_limits::round_error() == std::numeric_limits::round_error()); CHECK(std::numeric_limits::is_exact); CHECK(std::numeric_limits::is_integer); CHECK(!std::numeric_limits::is_signed); /* Test std::numeric_limits for BigInteger */ CHECK(std::numeric_limits::min() == 0u); CHECK(std::numeric_limits::digits == 128); CHECK(std::numeric_limits::epsilon() == 0u); CHECK(std::numeric_limits::round_error() == 0u); CHECK(std::numeric_limits::is_exact); CHECK(std::numeric_limits::is_integer); CHECK(!std::numeric_limits::is_signed); /* Test constructor */ CHECK(BigInteger(10u) == 10u); CHECK(BigInteger(10) == BigInteger(10u)); try { BigInteger tmp(-10); pass = false; std::cerr << "FAILED: BigInteger(-10) should throw an exception." << std::endl; } catch(const Dune::Exception&) { /* Ignore */ } catch(...) { pass = false; std::cerr << "FAILED: BigInteger(-10) threw an unexpected exception." << std::endl; } /* Test conversion */ CHECK(BigInteger(10u).touint() == 10u); CHECK(BigInteger(10u).todouble() == 10.0); /* Check BigInteger arithmetic */ CHECK(BigInteger(10u) + BigInteger(3u) == BigInteger(10u + 3u)); BigInteger tmp(10u); tmp += BigInteger(3u); CHECK(tmp == BigInteger(10u + 3u)); CHECK(BigInteger(10u) - BigInteger(3u) == BigInteger(10u - 3u)); tmp = BigInteger(10u); tmp -= BigInteger(3u); CHECK(tmp == BigInteger(10u - 3u)); CHECK(BigInteger(10u) * BigInteger(3u) == BigInteger(10u * 3u)); tmp = BigInteger(10u); tmp *= BigInteger(3u); CHECK(tmp == BigInteger(10u * 3u)); CHECK(BigInteger(10u) / BigInteger(3u) == BigInteger(10u / 3u)); tmp = BigInteger(10u); tmp /= BigInteger(3u); CHECK(tmp == BigInteger(10u / 3u)); CHECK(BigInteger(10u) % BigInteger(3u) == BigInteger(10u % 3u)); tmp = BigInteger(10u); tmp %= BigInteger(3u); CHECK(tmp == BigInteger(10u % 3u)); CHECK(BigInteger(100000u) + BigInteger(30000u) == BigInteger(100000u + 30000u)); tmp = BigInteger(100000u); tmp += BigInteger(30000u); CHECK(tmp == BigInteger(100000u + 30000u)); CHECK(BigInteger(100000u) - BigInteger(30000u) == BigInteger(100000u - 30000u)); tmp = BigInteger(100000u); tmp -= BigInteger(30000u); CHECK(tmp == BigInteger(100000u - 30000u)); CHECK(BigInteger(70000u) - BigInteger(30000u) == BigInteger(70000u - 30000u)); tmp = BigInteger(70000u); tmp -= BigInteger(30000u); CHECK(tmp == BigInteger(70000u - 30000u)); CHECK(BigInteger(100000u) * BigInteger(30000u) == BigInteger(100000u * 30000u)); tmp = BigInteger(100000u); tmp *= BigInteger(30000u); CHECK(tmp == BigInteger(100000u * 30000u)); CHECK(BigInteger(100000u) / BigInteger(30000u) == BigInteger(100000u / 30000u)); tmp = BigInteger(100000u); tmp /= BigInteger(30000u); CHECK(tmp == BigInteger(100000u / 30000u)); CHECK(BigInteger(100000u) % BigInteger(30000u) == BigInteger(100000u % 30000u)); tmp = BigInteger(100000u); tmp %= BigInteger(30000u); CHECK(tmp == BigInteger(100000u % 30000u)); /* Test hashing */ { Dune::hash hasher; CHECK(hasher(BigInteger(100)) == hasher(BigInteger(100))); } const BigInteger one{1}; const BigInteger zero{0}; CHECK((one & one) == one); CHECK((one & zero) == zero); CHECK((one | one) == one); CHECK((one | zero) == one); CHECK((one ^ one) == zero); CHECK((one ^ zero) == one); return pass ? 0 : 1; } dune-common-2.8.0/dune/common/test/bitsetvectortest.cc000066400000000000000000000065321411343567400231060ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #if defined(__GNUC__) && ! defined(__clang__) #include #endif #include template struct ConstReferenceOp { typedef typename BBF::value_type bitset; typedef typename BBF::const_reference const_reference; void operator()(const_reference t){ [[maybe_unused]] bitset x = t; } }; template void testConstBitSetMethods(const T t) { t.size(); t[0]; t[t.size()-1]; t << 2; t >> 2; ~t; t.count(); t.any(); t.none(); t.test(0); } template void testContainer(BBF & bbf) { typedef typename BBF::value_type bitset; typedef typename BBF::reference reference; typedef typename BBF::const_reference const_reference; const BBF & cbbf = bbf; bitset x = bbf[3]; reference y = bbf[4]; const_reference z = bbf[4]; const reference v = bbf[4]; // assignement y = false; y[2] = true; y = x; y = z; y = v; x = y; x = z; x = v; y = cbbf[1]; x = cbbf[1]; bbf[4] = x; bbf[4] = v; bbf[4] = y; bbf[4] = true; // invoke methods testConstBitSetMethods(x); testConstBitSetMethods(y); testConstBitSetMethods(z); testConstBitSetMethods(v); testConstBitSetMethods(bbf[1]); testConstBitSetMethods(cbbf[2]); // equality [[maybe_unused]] bool res; res = (y == cbbf[2]); res = (y == bbf[3]); res = (y == x); res = (x == y); res = (x == z); res = (z == x); res = (z == y); res = (y == z); // inequality res = (y != cbbf[2]); res = (y != bbf[3]); res = (y != x); res = (x != y); res = (x != z); res = (z != x); res = (z != y); res = (y != z); // &= y &= cbbf[2]; y &= bbf[3]; y &= x; x &= y; x &= z; y &= z; // |= y |= cbbf[2]; y |= bbf[3]; y |= x; x |= y; x |= z; y |= z; // ^= y ^= cbbf[2]; y ^= bbf[3]; y ^= x; x ^= y; x ^= z; y ^= z; // shift operator y <<= 1; y >>= 1; // flip y.flip(); y.flip(2); y[3].flip(); } template void testConstContainer(const BBF& bbf){ typedef typename BBF::value_type bitset; typedef typename BBF::iterator iterator; typedef typename std::iterator_traits::value_type value_type; typedef typename BBF::const_reference reference; const BBF & cbbf = bbf; bitset x = bbf[3]; [[maybe_unused]] value_type z; reference y = bbf[4]; // assignement x = y; x = cbbf[1]; // equality [[maybe_unused]] bool res; res = (y == cbbf[2]); res = (y == bbf[3]); res = (y == x); res = (x == y); // inequality res = (y != cbbf[2]); res = (y != bbf[3]); res = (y != x); res = (x != y); } template void doTest() { typedef Dune::BitSetVector BBF; BBF bbf(10,true); const BBF & cbbf = bbf; // test containers and some basic bitset operations testContainer(bbf); testConstContainer(bbf); testConstContainer(cbbf); // iterator interface #ifndef NDEBUG ConstReferenceOp cop; assert(testIterator(bbf, cop) == 0); assert(testIterator(cbbf, cop) == 0); #endif } int main() { doTest<4, std::allocator >(); #if defined(__GNUC__) && ! defined(__clang__) doTest<4, __gnu_cxx::malloc_allocator >(); #endif return 0; } dune-common-2.8.0/dune/common/test/boundscheckingmvtest.cc000066400000000000000000000347471411343567400237330ustar00rootroot00000000000000#include #include #include #include int main() try { bool passed = true; // Free matrix-vector multiplication (mv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); Dune::DenseMatrixHelp::multAssign(A,x,b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Free matrix-vector multiplication (mv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); Dune::DenseMatrixHelp::multAssign(A,x,b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (mv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); A.mv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (mv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); A.mv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (mtv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); A.mtv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (mtv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); A.mtv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (umv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); A.umv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (umv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); A.umv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (umtv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); A.umtv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (umtv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); A.umtv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (umhv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); A.umhv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (umhv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); A.umhv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (mmv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); A.mmv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (mmv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); A.mmv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (mmtv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); A.mmtv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (mmtv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); A.mmtv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (mmhv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); A.mmhv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (mmhv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); A.mmhv(x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (usmv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); A.usmv(2, x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (usmv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); A.usmv(2, x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (usmtv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); A.usmtv(2, x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (usmtv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); A.usmtv(2, x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (usmhv): Input size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2, 3}; Dune::FieldVector b(0); A.usmhv(2, x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Matrix-vector multiplication (usmhv): Output size incorrect try { Dune::FieldMatrix A = {{1, 2, 3}, {10, 20, 30}}; Dune::FieldVector x = {1, 2}; Dune::FieldVector b(0); A.usmhv(2, x, b); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // right multiplication: None-square Matrix argument try { Dune::DynamicMatrix A(2, 3, 5); Dune::DynamicMatrix const B(3, 2, 5); A.rightmultiply(B); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // right multiplication: Incorrect number of rows try { Dune::DynamicMatrix A(2, 2, 5); Dune::DynamicMatrix const B(3, 3, 5); A.rightmultiply(B); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // left multiplication: None-square Matrix argument try { Dune::FieldMatrix A = {{1, 2}, {10, 20}, {100, 200}}; Dune::FieldMatrix const B = {{1, 2, 3}, {10, 20, 30}}; A.leftmultiply(B); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // left multiplication: Incorrect number of rows try { Dune::FieldMatrix A = { {1, 2, 3}, {10, 20, 30}, {100, 200, 300}}; Dune::FieldMatrix const B = {{1, 2}, {10, 20}, {100, 200}}; A.leftmultiply(B); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } return passed ? 0 : 1; } catch (Dune::Exception &e) { std::cerr << e << std::endl; return 1; } catch (std::exception &e) { std::cerr << e.what() << std::endl; return 1; } dune-common-2.8.0/dune/common/test/boundscheckingoptest.cc000066400000000000000000000113411411343567400237100ustar00rootroot00000000000000#include #include #include int main() try { bool passed = true; // Add vectors of different sizes try { Dune::FieldVector v1 = {1, 2, 3}; Dune::FieldVector const v2 = {1, 2}; v1 += v2; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Subtract vectors of different sizes try { Dune::FieldVector v1 = {1, 2, 3}; Dune::FieldVector const v2 = {1, 2}; v1 -= v2; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Check vectors of different sizes for equality try { Dune::FieldVector const v1 = {1, 2, 3}; Dune::FieldVector const v2 = {1, 2}; [[maybe_unused]] bool res = (v1 == v2); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Check vectors of different sizes for inequality try { Dune::FieldVector const v1 = {1, 2, 3}; Dune::FieldVector const v2 = {1, 2}; [[maybe_unused]] bool res = (v1 != v2); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Apply axpy to vectors of different sizes try { Dune::FieldVector v1 = {1, 2, 3}; Dune::FieldVector const v2 = {1, 2}; v1.axpy(2, v2); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { Dune::FieldMatrix m1 = {{1, 2, 3}}; Dune::FieldMatrix const m2 = {{1, 2, 3}, {10, 20, 30}}; m1 += m2; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { Dune::FieldMatrix m1 = {{1, 2, 3}}; Dune::FieldMatrix const m2 = {{1, 2, 3}, {10, 20, 30}}; m1 -= m2; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { Dune::FieldMatrix m1 = {{1, 2, 3}}; Dune::FieldMatrix const m2 = {{1, 2, 3}, {10, 20, 30}}; [[maybe_unused]] bool res = (m1 == m2); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { Dune::FieldMatrix m1 = {{1, 2, 3}}; Dune::FieldMatrix const m2 = {{1, 2, 3}, {10, 20, 30}}; [[maybe_unused]] bool res = (m1 != m2); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { Dune::FieldMatrix m1 = {{1, 2, 3}}; Dune::FieldMatrix const m2 = {{1, 2, 3}, {10, 20, 30}}; m1.axpy(2, m2); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } return passed ? 0 : 1; } catch (Dune::Exception &e) { std::cerr << e << std::endl; return 1; } catch (std::exception &e) { std::cerr << e.what() << std::endl; return 1; } dune-common-2.8.0/dune/common/test/boundscheckingtest.cc000066400000000000000000000236061411343567400233600ustar00rootroot00000000000000#include #include #include #include #include #include #include #include int main() try { bool passed = true; // Write beyond end of singleton vector try { Dune::FieldVector v = {1}; v[1] = 10; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Read beyond end of singleton vector try { Dune::FieldVector const v = {1}; [[maybe_unused]] double const x = v[1]; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Write beyond end of vector try { Dune::FieldVector v = {1, 2, 3}; v[3] = 10; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { Dune::DynamicVector v = {1, 2, 3}; v[3] = 10; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Read beyond end of vector try { Dune::FieldVector const v = {1, 2, 3}; [[maybe_unused]] double const x = v[3]; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { Dune::DynamicVector const v = {1, 2, 3}; [[maybe_unused]] double const x = v[3]; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Write beyond end of singleton matrix try { Dune::FieldMatrix m = {{1}}; m[1][0] = 100; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Read beyond end of singleton matrix try { Dune::FieldMatrix const m = {{1}}; [[maybe_unused]] double const x = m[1][0]; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Write beyond end of matrix try { Dune::FieldMatrix m = {{1, 2, 3}, {10, 20, 30}}; m[2][0] = 100; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { Dune::DynamicMatrix m = {{1, 2, 3}, {10, 20, 30}}; m[2][0] = 100; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Read beyond end of matrix try { Dune::FieldMatrix const m = {{1, 2, 3}, {10, 20, 30}}; [[maybe_unused]] double const x = m[2][0]; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { Dune::DynamicMatrix const m = {{1, 2, 3}, {10, 20, 30}}; [[maybe_unused]] double const x = m[2][0]; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Write beyond end of diagonal matrix (way #1) try { Dune::DiagonalMatrix d(5); d[3][3] = 9; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Write beyond end of diagonal matrix (way #2) try { Dune::DiagonalMatrix d(5); d.diagonal(3) = 9; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Read beyond end of diagonal matrix (way #1) try { Dune::DiagonalMatrix const d(5); [[maybe_unused]] double const x = d[3][3]; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Read beyond end of diagonal matrix (way #2) try { Dune::DiagonalMatrix const d(5); [[maybe_unused]] double const x = d.diagonal(3); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Write outside of diagonal matrix pattern try { Dune::DiagonalMatrix d(5); d[1][2] = 9; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Read outside of diagonal matrix pattern try { Dune::DiagonalMatrix const d(5); [[maybe_unused]] double const x = d[1][2]; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Check for entry beyond diagonal matrix size try { Dune::DiagonalMatrix const d(5); d.exists(3, 3); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Check for entry beyond matrix size try { Dune::FieldMatrix const m = {{1, 2, 3}, {10, 20, 30}}; m.exists(2, 2); std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Read beyond end of bitsetvector try { Dune::BitSetVector<3> const b(10); [[maybe_unused]] auto const x = b[10]; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Write beyond end of bitsetvector try { Dune::BitSetVector<3> b(10); b[10] = true; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Read beyond end of bitsetvectorreference try { Dune::BitSetVector<3> const b(10); [[maybe_unused]] auto const x = b[10][3]; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } // Write beyond end of bitsetvectorreference try { Dune::BitSetVector<3> b(10); b[10][3] = true; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } return passed ? 0 : 1; } catch (Dune::Exception &e) { std::cerr << e << std::endl; return 1; } catch (std::exception &e) { std::cerr << e.what() << std::endl; return 1; } dune-common-2.8.0/dune/common/test/calloncetest.cc000066400000000000000000000003421411343567400221420ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include #endif #include int main() { DUNE_ASSERT_CALL_ONCE(); } dune-common-2.8.0/dune/common/test/check_fvector_size.cc000066400000000000000000000004351411343567400233240ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include int main(int, char **) { Dune::DynamicVector one(1); Dune::DynamicVector two(2); two = one; return 0; } dune-common-2.8.0/dune/common/test/check_fvector_size_fail.cc000066400000000000000000000004451411343567400243200ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include int main(int argc, char * argv[]) { Dune::FieldVector one(1); Dune::FieldVector two(2); one=two; return 0; } dune-common-2.8.0/dune/common/test/checkmatrixinterface.hh000066400000000000000000000274221411343567400236670ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_CHECK_MATRIX_INTERFACE_HH #define DUNE_COMMON_CHECK_MATRIX_INTERFACE_HH #include #include #include #include #include #include /* * @file * @brief This file provides an interface check for dense matrices. * @author Christoph Gersbacher */ namespace Dune { // External forward declarations for namespace Dune // ------------------------------------------------ template< class, int, int > class FieldMatrix; template< class, int > class DiagonalMatrix; } // namespace Dune namespace CheckMatrixInterface { namespace Capabilities { // hasStaticSizes // -------------- template< class Matrix > struct hasStaticSizes { static const bool v = false; static const int rows = ~0; static const int cols = ~0; }; template< class Matrix > struct hasStaticSizes< const Matrix > { static const bool v = hasStaticSizes< Matrix >::v; static const int rows = hasStaticSizes< Matrix >::rows; static const int cols = hasStaticSizes< Matrix >::cols; }; // isSquare // -------- template< class Matrix > struct isSquare { static const bool v = false; }; template< class Matrix > struct isSquare< const Matrix > { static const bool v = isSquare< Matrix >::v; }; // Template specializations for Dune::FieldMatrix // ---------------------------------------------- template< class K, int r, int c > struct hasStaticSizes< Dune::FieldMatrix< K, r, c > > { static const bool v = true; static const int rows = r; static const int cols = c; }; template< class K, int rows, int cols > struct isSquare< Dune::FieldMatrix< K, rows, cols > > { static const bool v = ( rows == cols ); }; // Template specializations for Dune::DiagonalMatrix // ------------------------------------------------- template< class K, int n > struct hasStaticSizes< Dune::DiagonalMatrix > { static const bool v = true; static const int rows = n; static const int cols = n; }; template< class K, int n > struct isSquare< Dune::DiagonalMatrix > { static const bool v = true; }; } // namespace Capabilities // UseDynamicVector // ---------------- template< class Matrix > struct UseDynamicVector { typedef typename Matrix::value_type value_type; typedef Dune::DynamicVector< value_type > domain_type; typedef domain_type range_type; static domain_type domain ( const Matrix &matrix, value_type v = value_type() ) { return domain_type( matrix.M(), v ); } static range_type range ( const Matrix &matrix, value_type v = value_type() ) { return range_type( matrix.N(), v ); } }; // UseFieldVector // -------------- template< class K, int rows, int cols > struct UseFieldVector { typedef K value_type; typedef Dune::FieldVector< K, cols > domain_type; typedef Dune::FieldVector< K, rows > range_type; template< class Matrix > static domain_type domain ( const Matrix &, value_type v = value_type() ) { return domain_type( v ); } template< class Matrix > static range_type range ( const Matrix &, value_type v = value_type() ) { return range_type( v ); } }; // MatrixSizeHelper // ---------------- template< class Matrix, bool hasStaticSizes = Capabilities::hasStaticSizes< Matrix >::v > struct MatrixSizeHelper; template< class Matrix > struct MatrixSizeHelper< Matrix, false > { typedef typename Matrix::size_type size_type; static const size_type rows ( const Matrix &matrix ) { return matrix.rows(); } static const size_type cols ( const Matrix &matrix ) { return matrix.cols(); } }; template< class Matrix > struct MatrixSizeHelper< Matrix, true > { typedef typename Matrix::size_type size_type; static const size_type rows ( const Matrix & ) { return Matrix::rows; } static const size_type cols ( const Matrix & ) { return Matrix::cols; } }; // CheckIfSquareMatrix // ------------------- template< class Matrix, class Traits, bool isSquare = Capabilities::isSquare< Matrix >::v > struct CheckIfSquareMatrix; template< class Matrix, class Traits > struct CheckIfSquareMatrix< Matrix, Traits, false > { static void apply ( const Matrix &) {} static void apply ( Matrix &) {} }; template< class Matrix, class Traits > struct CheckIfSquareMatrix< Matrix, Traits, true > { typedef typename Matrix::value_type value_type; static value_type tolerance () { return value_type( 16 ) * std::numeric_limits< value_type >::epsilon(); } static void apply ( const Matrix &matrix ) { const value_type determinant = matrix.determinant(); if( determinant > tolerance() ) { typename Traits::domain_type x = Traits::domain( matrix ); const typename Traits::range_type b = Traits::range( matrix ); matrix.solve( x, b ); } } static void apply ( Matrix &matrix ) { apply( const_cast< const Matrix & >( matrix ) ); if( matrix.determinant() > tolerance() ) matrix.invert(); } }; // CheckConstMatrix // ---------------- template< class Matrix, class Traits > struct CheckConstMatrix { // required type definitions typedef typename Matrix::size_type size_type; typedef typename Matrix::value_type value_type; typedef typename Matrix::field_type field_type; typedef typename Matrix::block_type block_type; typedef typename Matrix::const_row_reference const_row_reference; typedef typename Matrix::ConstIterator ConstIterator; static void apply ( const Matrix &matrix ) { checkDataAccess ( matrix ); checkIterators ( matrix ); checkLinearAlgebra ( matrix ); checkNorms ( matrix ); checkSizes ( matrix ); CheckIfSquareMatrix< Matrix, Traits >::apply( matrix ); // TODO: check comparison // bool operator == ( const Matrix &other ); // bool operator != ( const Matrix &other ); } // check size methods static void checkSizes ( const Matrix &matrix ) { [[maybe_unused]] const size_type size = matrix.size(); const size_type rows = MatrixSizeHelper< Matrix >::rows( matrix ); const size_type cols = MatrixSizeHelper< Matrix >::cols( matrix ); const size_type N = matrix.N(); const size_type M = matrix.M(); if( N != rows || M != cols ) DUNE_THROW( Dune::RangeError, "Returned inconsistent sizes." ); } // check read-only access to data static void checkDataAccess ( const Matrix &matrix ) { const size_type size = matrix.size(); for( size_type i = size_type( 0 ); i < size; ++i ) [[maybe_unused]] const_row_reference row = matrix[ i ]; const size_type rows = MatrixSizeHelper< Matrix >::rows( matrix ); const size_type cols = MatrixSizeHelper< Matrix >::cols( matrix ); for( size_type i = size_type( 0 ); i < rows; ++i ) { for( size_type j = size_type( 0 ); j < cols; ++j ) { [[maybe_unused]] bool exists = matrix.exists( i, j ); [[maybe_unused]] const value_type &value = matrix[ i ][ j ]; } } } // check norms static void checkNorms ( const Matrix &matrix ) { typedef typename Dune::FieldTraits< value_type >::real_type real_type; real_type frobenius_norm = matrix.frobenius_norm(); real_type frobenius_norm2 = matrix.frobenius_norm2(); real_type infinity_norm = matrix.infinity_norm() ; real_type infinity_norm_real = matrix.infinity_norm_real(); if( std::min( std::min( frobenius_norm, frobenius_norm2 ), std::min( infinity_norm, infinity_norm_real ) ) < real_type( 0 ) ) DUNE_THROW( Dune::InvalidStateException, "Norms must return non-negative value." ); } // check basic linear algebra methods static void checkLinearAlgebra ( const Matrix &matrix ) { typename Traits::domain_type domain = Traits::domain( matrix ); typename Traits::range_type range = Traits::range( matrix ); typename Traits::value_type alpha( 1 ); matrix.mv( domain, range ); matrix.mtv( range, domain ); matrix.umv( domain, range ); matrix.umtv( range, domain ); matrix.umhv( range, domain ); matrix.mmv( domain, range ); matrix.mmtv( range, domain ); matrix.mmhv( range, domain ); matrix.usmv( alpha, domain, range ); matrix.usmtv( alpha, range, domain ); matrix.usmhv( alpha, range, domain ); } // check iterator methods static void checkIterators ( const Matrix &matrix ) { const ConstIterator end = matrix.end(); for( ConstIterator it = matrix.begin(); it != end; ++it ) [[maybe_unused]] const_row_reference row = *it; } }; // CheckNonConstMatrix // ------------------- template< class Matrix, class Traits > struct CheckNonConstMatrix { // required type definitions typedef typename Matrix::size_type size_type; typedef typename Matrix::value_type value_type; typedef typename Matrix::row_reference row_reference; typedef typename Matrix::row_type row_type; typedef typename Matrix::Iterator Iterator; static void apply ( Matrix &matrix ) { checkIterators( matrix ); checkAssignment( matrix ); CheckIfSquareMatrix< Matrix, Traits >::apply( matrix ); // TODO: check scalar/matrix and matrix/matrix operations // Matrix &operator+= ( const Matrix &other ); // Matrix &operator-= ( const Matrix &other ); // Matrix &operator*= ( const value_type &v ); // Matrix &operator/= ( const value_type &v ); // Matrix &axpy += ( const value_type &v, const Matrix &other ); // Matrix &axpy += ( const value_type &v, const Matrix &other ); // Matrix &leftmultiply ( const Matrix &other ); // Matrix &rightmultiply ( const Matrix &other ); } // check assignment static void checkAssignment ( Matrix &matrix ) { matrix = value_type( 1 ); const size_type size = matrix.size(); for( size_type i = size_type( 0 ); i < size; ++i ) { row_reference row = matrix[ i ]; row = row_type( value_type( 0 ) ); } const size_type rows = MatrixSizeHelper< Matrix >::rows( matrix ); const size_type cols = MatrixSizeHelper< Matrix >::cols( matrix ); for( size_type i = size_type( 0 ); i < rows; ++i ) { for( size_type j = size_type( 0 ); j < cols; ++j ) matrix[ i ][ j ] = ( i == j ? value_type( 1 ) : value_type( 0 ) ); } } // check iterator methods static void checkIterators ( Matrix &matrix ) { const Iterator end = matrix.end(); for( Iterator it = matrix.begin(); it != end; ++it ) { row_reference row = *it; row = row_type( value_type( 0 ) ); } } }; } // namespace CheckMatrixInterface namespace Dune { // checkMatrixInterface // -------------------- template< class Matrix, class Traits = CheckMatrixInterface::UseDynamicVector< Matrix > > void checkMatrixInterface ( const Matrix &matrix ) { CheckMatrixInterface::CheckConstMatrix< Matrix, Traits >::apply( matrix ); } template< class Matrix, class Traits = CheckMatrixInterface::UseDynamicVector< Matrix > > void checkMatrixInterface ( Matrix &matrix ) { checkMatrixInterface( const_cast< const Matrix & >( matrix ) ); CheckMatrixInterface::CheckNonConstMatrix< Matrix, Traits >::apply( matrix ); } } // namespace Dune #endif // #ifndef DUNE_COMMON_CHECK_MATRIX_INTERFACE_HH dune-common-2.8.0/dune/common/test/classnametest.cc000066400000000000000000000122211411343567400223270ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include "config.h" #include #include #include #include #include #include #include #include using CVRef = std::bitset<4>; constexpr CVRef is_const = 1; constexpr CVRef is_volatile = 2; constexpr CVRef is_lvalue_reference = 4; constexpr CVRef is_rvalue_reference = 8; constexpr CVRef is_reference = 12; void checkname(Dune::TestSuite &t, const std::string &name, CVRef cvref, const std::string &pattern) { const auto npos = std::string::npos; std::cout << name << std::endl; t.check(std::regex_search(name, std::regex{pattern})) << '`' << name << "` does not look like `" << pattern << '`'; static const std::regex const_pattern{ R"(\bconst\b)" }; bool found_const = std::regex_search(name, const_pattern); if((cvref & is_const) == is_const) t.check(found_const) << '`' << name << "` contains `const`"; else t.check(!found_const) << '`' << name << "` does not contain `const`"; static const std::regex volatile_pattern{ R"(\bvolatile\b)" }; bool found_volatile = std::regex_search(name, volatile_pattern); if((cvref & is_volatile) == is_volatile) t.check(found_volatile) << '`' << name << "` contains `volatile`"; else t.check(!found_volatile) << '`' << name << "` does not contain `volatile`"; bool found_reference = name.find('&') != npos; bool found_rvalue_reference = name.find("&&") != npos; if((cvref & is_reference) == is_reference) t.check(found_reference) << '`' << name << "` does not contain `&` or `&&`"; else if((cvref & is_lvalue_reference) == is_lvalue_reference) t.check(found_reference && !found_rvalue_reference) << '`' << name << "` contains `&&` or does not contain `&`"; else if((cvref & is_rvalue_reference) == is_rvalue_reference) t.check(found_rvalue_reference) << '`' << name << "` does not contain `&&`"; else t.check(!found_reference) << '`' << name << "` contains `&` or `&&`"; } struct Base { virtual ~Base() = default; }; struct Derived : Base {}; int main() { Dune::TestSuite t("className()"); std::cout << "First three simple class names extracted from variables:" << std::endl; Dune::FieldVector xi; checkname(t, Dune::className(xi), {}, R"(\bFieldVector\s*<\s*int\s*,\s*3\s*>)"); Dune::FieldVector xd; checkname(t, Dune::className(xd), {}, R"(\bFieldVector\s*<\s*double\s*,\s*1\s*>)"); Dune::FieldVector, 10> xcd; checkname(t, Dune::className(xcd), {}, R"(\bFieldVector\s*<.*\bcomplex\s*<\s*double\s*>\s*,\s*10\s*>)"); std::cout << std::endl; std::cout << "Adding const:" << std::endl; const Dune::FieldVector cxi; checkname(t, Dune::className(cxi), is_const, R"(\bFieldVector\s*<\s*int\s*,\s*3\s*>)"); std::cout << std::endl; std::cout << "If a variable is a reference that can not be extracted (needs " << "decltype as used below): " << std::endl; Dune::FieldVector &rxd = xd; checkname(t, Dune::className(rxd), {}, R"(\bFieldVector\s*<\s*double\s*,\s*1\s*>)"); std::cout << std::endl; std::cout << "Extracting the class name using a type directly - " << "also extractes references correctly: " << std::endl; checkname(t, Dune::className(), is_lvalue_reference, R"(\bFieldVector\s*<\s*double\s*,\s*1\s*>)"); const Dune::FieldVector &rcxd = xd; checkname(t, Dune::className(), is_const|is_lvalue_reference, R"(\bFieldVector\s*<\s*double\s*,\s*1\s*>)"); const Dune::FieldVector &rcxi = cxi; checkname(t, Dune::className(), is_const|is_lvalue_reference, R"(\bFieldVector\s*<\s*int\s*,\s*3\s*>)"); std::cout << std::endl; std::cout << "Test some further types:" << std::endl; using RVXCD = volatile Dune::FieldVector, 10>&; checkname(t, Dune::className(), is_volatile|is_lvalue_reference, R"(\bFieldVector\s*<.*\bcomplex\s*<\s*double\s*>\s*,\s*10\s*>)"); using RRXCD = Dune::FieldVector, 10>&&; checkname(t, Dune::className(), is_rvalue_reference, R"(\bFieldVector\s*<.*\bcomplex\s*<\s*double\s*>\s*,\s*10\s*>)"); std::cout << std::endl; std::cout << "Test printing dynamic vs. static types:" << std::endl; Derived d{}; Base &b = d; checkname(t, Dune::className(b), {}, R"(\bDerived\b)"); checkname(t, Dune::className(), is_lvalue_reference, R"(\bBase\b)"); t.check(Dune::className() == Dune::className(b)) << "dynamic type of base reference should match derived type"; std::cout << std::endl; std::cout << "Test rvalue argument to className(expr):" << std::endl; checkname(t, Dune::className(Base{}), {}, R"(\bBase\b)"); std::cout << std::endl; #if !HAVE_CXA_DEMANGLE // in this case we only make sure that no segfault or similar happens return 0; #else return t.exit(); #endif } dune-common-2.8.0/dune/common/test/collectorstream.hh000066400000000000000000000035401411343567400227010ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_TEST_COLLECTORSTREAM_HH #define DUNE_COMMON_TEST_COLLECTORSTREAM_HH #include #include #include #include namespace Dune { /** * \brief Data collector stream * * A class derived from std::ostringstream that allows to * collect data via a temporary returned object. To facilitate * this it stores a callback that is used to pass the collected * data to its creator on destruction. * * In order to avoid passing the same data twice, copy construction * is forbidden and only move construction is allowed. */ class CollectorStream : public std::ostringstream { public: /** * \brief Create from callback * * \tparam CallBack Type of callback. Must be convertible to std::function * \param callBack A copy of this function will be stored and called on destruction. */ template = 0> CollectorStream(CallBack&& callBack) : callBack_(callBack) {} CollectorStream(const CollectorStream& other) = delete; /** * \brief Move constructor * * This will take over the data and callback from the * moved from CollectorStream and disable the callback * in the latter. */ CollectorStream(CollectorStream&& other) : callBack_(other.callBack_) { (*this) << other.str(); other.callBack_ = [](std::string){}; } /** * \brief Destructor * * This calls the callback function given on creation * passing all collected data as a single string argument. */ ~CollectorStream() { callBack_(this->str()); } private: std::function callBack_; }; } // namespace Dune #endif // DUNE_COMMON_TEST_COLLECTORSTREAM_HH dune-common-2.8.0/dune/common/test/concept.cc000066400000000000000000000101361411343567400211170ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include #include struct HasFoo { template auto require(const T& t) -> decltype( t.foo() ); }; struct HasBar { template auto require(const T& t) -> decltype( t.bar() ); }; struct HasFooAndBar1 : Dune::Concept::Refines { template auto require(const T& t) -> decltype( t.bar() ); }; struct HasFooAndBar2 : Dune::Concept::Refines { template auto require(const T& t) -> decltype( t.foo() ); }; struct HasFooAndBar3 { template auto require(const T& t) -> decltype( t.foo(), t.bar() ); }; struct HasFooAndBar4 : Dune::Concept::Refines { template auto require(const T& t) -> decltype( 0 ); }; struct HasFooAndBar5 { template auto require(const T& t) -> decltype( 0 ); using BaseConceptList = Dune::TypeList; }; template struct Foo { T foo() const { return T(); } }; template struct Bar { T bar() const { return T(); } }; template struct FooBar { T foo() const { return T(); } T bar() const { return T(); } }; int main ( int argc, char **argv ) try { using namespace Dune; MPIHelper::instance(argc, argv); TestSuite test; test.check(models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(models>()) << "models>() gives wrong result"; test.check(models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(not models>()) << "models>() gives wrong result"; test.check(models>()) << "models>() gives wrong result"; return test.exit(); } catch( Dune::Exception &e ) { std::cerr << "Dune reported error: " << e << std::endl; return 1; } catch(...) { std::cerr << "Unknown exception thrown!" << std::endl; return 1; } dune-common-2.8.0/dune/common/test/constexprifelsetest.cc000066400000000000000000000006521411343567400236030ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include "config.h" #include #include int main() { // check that the id argument is a constexpr functor Dune::Hybrid::ifElse(std::true_type{}, [](auto id) { static_assert(id(true), "id() argument of ifElse() branches should be a constexpr functor"); }); } dune-common-2.8.0/dune/common/test/debugalignsimd.cc.in000066400000000000000000000004751411343567400230540ustar00rootroot00000000000000// @GENERATED_SOURCE@ #include #include #include #include namespace Dune { namespace Simd { template void UnitTest::check@POINT@ >(); } //namespace Simd } // namespace Dune dune-common-2.8.0/dune/common/test/debugalignsimdtest.cc.in000066400000000000000000000016031411343567400237460ustar00rootroot00000000000000// @GENERATED_SOURCE@ #include #include #include #include #include #include #include #include template struct RebindAccept : std::false_type {}; #cmake @template@ template<> struct RebindAccept > : std::true_type {}; #cmake @endtemplate@ int main(int argc, char **argv) { Dune::MPIHelper::instance(argc, argv); Dune::Simd::UnitTest test; using Rebinds = Dune::Simd::RebindList< #cmake @template@ @SCALAR@, #cmake @endtemplate@ Dune::Simd::EndMark>; #cmake @template@ test.check, Rebinds, Dune::AlwaysFalse, RebindAccept>(); #cmake @endtemplate@ return test.good() ? EXIT_SUCCESS : EXIT_FAILURE; } dune-common-2.8.0/dune/common/test/debugalignsimdtest.hh.in000066400000000000000000000006731411343567400237660ustar00rootroot00000000000000// @GENERATED_SOURCE@ #ifndef DUNE_COMMON_TEST_DEBUGALIGNSIMDTEST_HH #define DUNE_COMMON_TEST_DEBUGALIGNSIMDTEST_HH #include #include namespace Dune { namespace Simd { #cmake @template POINT@ extern template void UnitTest::check@POINT@ >(); #cmake @endtemplate@ } //namespace Simd } // namespace Dune #endif // DUNE_COMMON_TEST_DEBUGALIGNSIMDTEST_HH dune-common-2.8.0/dune/common/test/debugaligntest.cc000066400000000000000000000057741411343567400225010ustar00rootroot00000000000000#include #include #include #include #include #include #include #include #include #include class WithViolatedAlignmentHandler { Dune::ViolatedAlignmentHandler oldhandler; public: template WithViolatedAlignmentHandler(H &&newhandler) : oldhandler(Dune::violatedAlignmentHandler()) { Dune::violatedAlignmentHandler() = std::forward(newhandler); } WithViolatedAlignmentHandler(const WithViolatedAlignmentHandler &) = delete; WithViolatedAlignmentHandler(WithViolatedAlignmentHandler &&) = delete; WithViolatedAlignmentHandler& operator=(const WithViolatedAlignmentHandler &) = delete; WithViolatedAlignmentHandler& operator=(WithViolatedAlignmentHandler &&) = delete; ~WithViolatedAlignmentHandler() { Dune::violatedAlignmentHandler() = oldhandler; } }; // intentionally violate alignment and check that that is detected template void checkAlignmentViolation(Dune::TestSuite &test) { bool misalignmentDetected = false; WithViolatedAlignmentHandler guard([&](auto&&...){ misalignmentDetected = true; }); char buffer[alignof(T)+sizeof(T)]; void* misalignedAddr; { // a more portable way to ddo this would be to use std::align(), but that // isn't supported by g++-4.9 yet auto addr = std::uintptr_t( (void*)buffer ); addr += alignof(T) - 1; addr &= -std::uintptr_t(alignof(T)); addr += 1; misalignedAddr = (void*)addr; } auto ptr = new(misalignedAddr) T; test.check(misalignmentDetected, "default construct") << "misalignment not detected for " << Dune::className(); misalignmentDetected = false; ptr->~T(); test.check(misalignmentDetected, "destruct") << "misalignment not detected for " << Dune::className(); misalignmentDetected = false; ptr = new(misalignedAddr) T(T(0)); test.check(misalignmentDetected, "move construct") << "misalignment not detected for " << Dune::className(); ptr->~T(); // ignore any misalignment here misalignmentDetected = false; T t(0); ptr = new(misalignedAddr) T(t); test.check(misalignmentDetected, "copy construct") << "misalignment not detected for " << Dune::className(); ptr->~T(); // ignore any misalignment here } int main(int argc, char **argv) { Dune::MPIHelper::instance(argc, argv); Dune::ArithmeticTestSuite test; using ArithmeticTypes = std::tuple< bool, char, signed char, unsigned char, short, unsigned short, int, unsigned, long, long unsigned, long long, long long unsigned, wchar_t, char16_t, char32_t, float, double, long double>; Dune::Hybrid::forEach(ArithmeticTypes(), [&](auto val) { using T = decltype(val); using Aligned = Dune::AlignedNumber; test.checkArithmetic(); checkAlignmentViolation(test); }); return test.exit(); } dune-common-2.8.0/dune/common/test/densematrixassignmenttest.cc000066400000000000000000000254741411343567400250130ustar00rootroot00000000000000#include "config.h" #define DUNE_CHECK_BOUNDS #include #include #include #include #include #include template void populateMatrix(M &A, int rows, int cols) { for (int i = 0; i < rows; ++i) for (int j = 0; j < cols; ++j) A[i][j] = i + 10 * j; } template< class K, int rows, int cols > struct Foo { constexpr static int M () noexcept { return cols; } constexpr static int N () noexcept { return rows; } operator Dune::FieldMatrix< K, rows, cols > () const { Dune::FieldMatrix< K, rows, cols > A; populateMatrix( A, rows, cols ); return A; } }; struct Bar {}; template bool identicalContents(A const &a, B const &b) { typedef typename A::size_type Size; if (a.N() != b.N() or a.M() != b.M()) return false; for (Size i = 0; i < a.N(); ++i) for (Size j = 0; j < b.N(); ++j) if (a[i][j] != b[i][j]) return false; return true; } template bool run() { ft const constant = 47.11; std::cout << "Testing with type: " << Dune::className(constant) << std::endl; Dune::FieldMatrix fieldM; Dune::FieldMatrix fieldMWrong11; Dune::FieldMatrix fieldMWrong22; Dune::FieldMatrix fieldMWrong33; populateMatrix(fieldM, 2, 3); populateMatrix(fieldMWrong11, 1, 1); populateMatrix(fieldMWrong22, 2, 2); populateMatrix(fieldMWrong33, 3, 3); Foo< ft, 2, 3 > fooM; fieldM = static_cast< Dune::FieldMatrix< ft, 2, 3 > >( fooM ); Dune::DynamicMatrix dynM(2, 3); Dune::DynamicMatrix dynMWrong11(1, 1); Dune::DynamicMatrix dynMWrong22(2, 2); Dune::DynamicMatrix dynMWrong33(3, 3); populateMatrix(dynM, 2, 3); populateMatrix(dynMWrong11, 1, 1); populateMatrix(dynMWrong22, 2, 2); populateMatrix(dynMWrong33, 3, 3); Dune::DiagonalMatrix const diagMWrong1 = {1}; Dune::DiagonalMatrix const diagMWrong2 = {1, 2}; Dune::DiagonalMatrix const diagMWrong3 = {1, 2, 3}; bool passed = true; static_assert(!Dune::HasDenseMatrixAssigner< Dune::FieldMatrix, std::vector< Dune::FieldMatrix > >::value, "FieldMatrix is not assignable by a std::vector< FieldMatrix >!"); static_assert(!Dune::HasDenseMatrixAssigner< Dune::FieldMatrix, Bar >::value, "FieldMatrix is not assignable by a Bar!"); static_assert(Dune::HasDenseMatrixAssigner< Dune::FieldMatrix, Dune::FieldMatrix >::value, "FieldMatrix is assignable by FieldMatrix!"); static_assert(Dune::HasDenseMatrixAssigner< Dune::FieldMatrix, Dune::DynamicMatrix >::value, "FieldMatrix is assignable by a DynamicMatrix!"); // class: FieldMatrix { using M = Dune::FieldMatrix; // Assignment { M fieldT; fieldT = fieldM; if (!identicalContents(fieldT, fieldM)) { std::cout << "FAIL: Content mismatch on line: " << __LINE__ << std::endl; passed = false; } } { M fieldT; fieldT = dynM; if (!identicalContents(fieldT, dynM)) { std::cout << "FAIL: Content mismatch on line: " << __LINE__ << std::endl; passed = false; } } { M fieldT; fieldT = constant; } // Copy construction { M const fieldT = fieldM; if (!identicalContents(fieldT, fieldM)) { std::cout << "FAIL: Content mismatch on line: " << __LINE__ << std::endl; passed = false; } } { M const fieldT = dynM; if (!identicalContents(fieldT, dynM)) { std::cout << "FAIL: Content mismatch on line: " << __LINE__ << std::endl; passed = false; } } { [[maybe_unused]] M const fieldT = constant; } } // class: DynamicMatrix { using M = Dune::DynamicMatrix; // Assignment { M dynT; dynT = fieldM; if (!identicalContents(dynT, fieldM)) { std::cout << "FAIL: Content mismatch on line: " << __LINE__ << std::endl; passed = false; } dynT = fieldMWrong11; if (!identicalContents(dynT, fieldMWrong11)) { std::cout << "FAIL: Content mismatch on line: " << __LINE__ << std::endl; passed = false; } } { M dynT; dynT = dynM; if (!identicalContents(dynT, dynM)) { std::cout << "FAIL: Content mismatch on line: " << __LINE__ << std::endl; passed = false; } } { M dynT; dynT = constant; } // Copy construction { M const dynT = fieldM; if (!identicalContents(dynT, fieldM)) { std::cout << "FAIL: Content mismatch on line: " << __LINE__ << std::endl; passed = false; } } { M const dynT = dynM; if (!identicalContents(dynT, dynM)) { std::cout << "FAIL: Content mismatch on line: " << __LINE__ << std::endl; passed = false; } } } // Assignment from other classes { using M = Dune::FieldMatrix; Dune::DiagonalMatrix diagM({1, 2, 3}); { [[maybe_unused]] M const fieldT = diagM; } { M fieldT; fieldT = diagM; } } { using M = Dune::DynamicMatrix; Dune::DiagonalMatrix diagM({1, 2, 3}); { [[maybe_unused]] M const dynT = diagM; } { M dynT; dynT = diagM; } } // Invalid assignments { using M = Dune::FieldMatrix; #ifdef FAILURE0 { // Should fail at compile-time M fieldT; fieldT = fieldMWrong11; } #endif #ifdef FAILURE1 { // Should fail at compile-time M fieldT; fieldT = fieldMWrong22; } #endif #ifdef FAILURE2 { // Should fail at compile-time M fieldT; fieldT = fieldMWrong33; } #endif try { // Should fail at run-time with RangeError M fieldT; fieldT = dynMWrong11; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { // Should fail at run-time with RangeError M fieldT; fieldT = dynMWrong22; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { // Should fail at run-time with RangeError M fieldT; fieldT = dynMWrong33; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { // Should fail at run-time with RangeError // Note: this could be made to fail at compile-time already if // we further specialised DenseMatrixAssigner to (FieldMatrix, // DiagonalMatrix) M fieldT; fieldT = diagMWrong1; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { // Should fail at run-time with RangeError // Note: this could be made to fail at compile-time already if // we further specialised DenseMatrixAssigner to (FieldMatrix, // DiagonalMatrix) M fieldT; fieldT = diagMWrong2; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { // Should fail at run-time with RangeError // Note: this could be made to fail at compile-time already if // we further specialised DenseMatrixAssigner to (FieldMatrix, // DiagonalMatrix) M fieldT; fieldT = diagMWrong3; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } } // Invalid copy construction { using M = Dune::FieldMatrix; #ifdef FAILURE3 { // Should fail at compile-time [[maybe_unused]] M const fieldT = fieldMWrong11; } #endif #ifdef FAILURE4 { // Should fail at compile-time [[maybe_unused]] M const fieldT = fieldMWrong22; } #endif #ifdef FAILURE5 { // Should fail at compile-time [[maybe_unused]] M const fieldT = fieldMWrong33; } #endif try { // Should fail at run-time with RangeError [[maybe_unused]] M const fieldT = dynMWrong11; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { // Should fail at run-time with RangeError [[maybe_unused]] M const fieldT = dynMWrong22; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } try { // Should fail at run-time with RangeError [[maybe_unused]] M const fieldT = dynMWrong33; std::cout << "(line " << __LINE__ << ") Error: No exception thrown." << std::endl; passed = false; } catch (const Dune::RangeError&) { std::cout << "(line " << __LINE__ << ") All good: Exception thrown as expected." << std::endl; } } { #ifdef FAILURE6 using M = Dune::DynamicMatrix; { // Should fail at compile-time [[maybe_unused]] M const dynT = constant; } #endif } std::cout << std::endl; return passed; } int main() { bool passed = true; passed = passed && run(); passed = passed && run>(); #ifdef HAVE_GMP passed = passed && run>(); #endif return passed ? 0 : 1; } dune-common-2.8.0/dune/common/test/densevectorassignmenttest.cc000066400000000000000000000025321411343567400247770ustar00rootroot00000000000000#include #include #include #include #include using namespace Dune; template void assign(DenseVector& first, const DenseVector& second) { first = second; } bool run() { bool passed = true; FieldVector fvec1{1, 2, 3}; DynamicVector dynvec1{1, 2, 3}; FieldVector fvec2; DynamicVector dynvec2(3); // check mixed assignments assign(fvec2, dynvec1); assign(dynvec2, fvec1); for (size_t i = 0; i < 3; ++i) { if (fvec2[i] != dynvec1[i]) { std::cerr << "Assigning a DynamicVector to a FieldVector as DenseVectors does not work!" << std::endl << i << "-th entry after assignment is " << fvec2[i] << ", should be " << i+1 << "!" << std::endl; passed = false; } if (dynvec1[i] != dynvec2[i]) { std::cerr << "Assigning a FieldVector to a DynamicVector as DenseVectors does not work" << std::endl << i << "-th entry after assignment is " << dynvec1[i] << ", should be " << i+1 << "!" << std::endl; passed = false; } } return passed; } int main() { bool passed = run(); if (!passed) DUNE_THROW(Dune::Exception, "Test failed"); return !passed; } dune-common-2.8.0/dune/common/test/densevectortest.cc000066400000000000000000000023051411343567400227040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include class MyVector; namespace Dune { template< > struct DenseMatVecTraits< MyVector > { typedef MyVector derived_type; typedef double value_type; typedef unsigned int size_type; }; } class MyVector : public Dune::DenseVector< MyVector > { public: MyVector ( unsigned int size, double v = 0 ) : data_( size, v ) {} unsigned int size () const { return data_.size(); } double& operator[] ( unsigned int i ) { return data_[ i ]; } const double& operator[] ( unsigned int i ) const { return data_[ i ]; } protected: std::vector< double > data_; }; int main() { try { unsigned int n = 15; MyVector v( n, 1 ); if( ( v.end() - v.begin() ) < 0 ) DUNE_THROW(Dune::Exception, "Negative value reported for end() - begin()" ); return 0; } catch (Dune::Exception& e) { std::cerr << e << std::endl; return 1; } catch (...) { std::cerr << "Generic exception!" << std::endl; return 2; } } dune-common-2.8.0/dune/common/test/diagonalmatrixtest.cc000066400000000000000000000037701411343567400233750ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef DUNE_FMatrix_WITH_CHECKING #define DUNE_FMatrix_WITH_CHECKING #endif #include #include #include #include #include #include "checkmatrixinterface.hh" using namespace Dune; template void test_matrix() { [[maybe_unused]] typedef typename DiagonalMatrix::size_type size_type; DiagonalMatrix A(1); FieldVector f; FieldVector v; // test constexpr size static_assert(A.N() == n, ""); static_assert(A.M() == n, ""); // assign matrix A=2; // assign vector f = 1; v = 2; // matrix vector product A.umv(v,f); // test norms A.frobenius_norm(); A.frobenius_norm2(); A.infinity_norm(); A.infinity_norm_real(); std::sort(v.begin(), v.end()); // print matrix std::cout << A << std::endl; // print vector std::cout << f << std::endl; // assign to FieldMatrix [[maybe_unused]] FieldMatrix AFM = FieldMatrix(A); [[maybe_unused]] FieldMatrix AFM2 = A; [[maybe_unused]] FieldMatrix AFM3; AFM3 = A; } template void test_interface() { typedef CheckMatrixInterface::UseFieldVector Traits; typedef Dune::DiagonalMatrix DiagonalMatrix; const DiagonalMatrix A(1); checkMatrixInterface< DiagonalMatrix >( A ); checkMatrixInterface< DiagonalMatrix, Traits >( A ); } void test_initialisation() { [[maybe_unused]] Dune::DiagonalMatrix const b = { 1, 2 }; assert(b.diagonal(0) == 1); assert(b.diagonal(1) == 2); } int main() { try { test_matrix(); test_interface(); test_matrix(); test_interface(); test_matrix(); test_interface(); } catch (Dune::Exception & e) { std::cerr << "Exception: " << e << std::endl; } } dune-common-2.8.0/dune/common/test/dummyiterator.hh000066400000000000000000000016521411343567400224060ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_DUMMYITERATOR_HH #define DUNE_COMMON_DUMMYITERATOR_HH #include #include #include template class dummyiterator : public Dune::BidirectionalIteratorFacade, T, T&, std::ptrdiff_t> { friend class dummyiterator::type>; T *value; public: dummyiterator(T& value_) : value(&value_) {} template dummyiterator ( const dummyiterator& o, typename std::enable_if::value>::type* = 0) : value(o.value) {} T& derefence() const { return *value; } bool equals(const dummyiterator& o) const { return value == o.value; } void increment() {} void decrement() {} }; #endif // DUNE_COMMON_DUMMYITERATOR_HH dune-common-2.8.0/dune/common/test/dynmatrixtest.cc000066400000000000000000000234111411343567400224030ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif // Activate checking #ifndef DUNE_FMatrix_WITH_CHECKING #define DUNE_FMatrix_WITH_CHECKING #endif #include #include #include #include #include #include #include #include "checkmatrixinterface.hh" using namespace Dune; template int test_invert_solve(Dune::DynamicMatrix &A, Dune::DynamicMatrix &inv, Dune::FieldVector &x, Dune::FieldVector &b) { int ret=0; std::cout <<"Checking inversion of:"< calced_inv(n,n); FieldVector calced_x; std::cout< prod = A; prod.rightmultiply(inv); for (size_t i=0; i 1e-6) { std::cerr<<"Given inverse wrong"< copy(A); A.invert(); calced_inv = A; A-=inv; auto epsilon = std::numeric_limits::real_type>::epsilon(); auto tolerance = 10*epsilon; for(size_t i =0; i < n; ++i) for(size_t j=0; j tolerance) { std::cerr<<"calculated inverse wrong at ("< xcopy(calced_x); xcopy-=x; equal=true; for(size_t i =0; i < n; ++i) if(std::abs(xcopy[i])>tolerance) { std::cerr<<"calculated isolution wrong at ("<; using FV = Dune::FieldVector; DM A = {{1, 5, 7}, {2, 14, 15}, {4, 40, 39}}; DM inv = {{-9.0 / 4, 85.0 / 24, -23.0 / 24}, {-3.0 / 4, 11.0 / 24, -1.0 / 24}, {1, -5.0 / 6, 1.0 / 6}}; FV b = {32, 75, 201}; FV x = {1, 2, 3}; ret += test_invert_solve(A, inv, x, b); DM A0 = {{-0.5, 0, -0.25}, {0.5, 0, -0.25}, {0, 0.5, 0}}; DM inv0 = {{-1, 1, 0}, {0, 0, 2}, {-2, -2, 0}}; FV b0 = {32, 75, 201}; FV x0 = {43, 402, -214}; ret += test_invert_solve(A0, inv0, x0, b0); DM A1 = {{0, 1, 0}, {1, 0, 0}, {0, 0, 1}}; FV b1 = {0, 1, 2}; FV x1 = {1, 0, 2}; ret += test_invert_solve(A1, A1, x1, b1); DM A2 = {{3, 1, 6}, {2, 1, 3}, {1, 1, 1}}; DM inv2 = {{-2, 5, -3}, {1, -3, 3}, {1, -2, 1}}; FV b2 = {2, 7, 4}; FV x2 = {19, -7, -8}; return ret + test_invert_solve(A2, inv2, x2, b2); } template void test_mult(DynamicMatrix& A, X& v, Y& f) { // test the various matrix-vector products A.mv(v,f); A.mtv(f,v); A.umv(v,f); A.umtv(f,v); A.umhv(f,v); A.mmv(v,f); A.mmtv(f,v); A.mmhv(f,v); A.usmv((K)0.5,v,f); A.usmtv((K)0.5,f,v); A.usmhv((K)0.5,f,v); } template void test_matrix() { typedef typename DynamicMatrix::size_type size_type; DynamicMatrix A(n,m); DynamicVector f(n); DynamicVector v(m); // assign matrix A=K(); // random access matrix for (size_type i=0; i::RowIterator rit = A.begin(); for (; rit!=A.end(); ++rit) { rit.index(); typename DynamicMatrix::ColIterator cit = rit->begin(); for (; cit!=rit->end(); ++cit) { cit.index(); (*cit) *= 2; } } // assign vector f = 1; // random access vector for (size_type i=0; i::iterator it = v.begin(); typename DynamicVector::ConstIterator end = v.end(); for (; it!=end; ++it) { it.index(); (*it) *= 2; } // reverse iterator vector it = v.beforeEnd(); end = v.beforeBegin(); for (; it!=end; --it) (*it) /= 2; // find vector for (size_type i=0; i res2(n,0); DynamicVector res1(n); DynamicVector b(m,1); A.mv(b, res1); A.umv(b, res2); if( (res1 - res2).two_norm() > 1e-12 ) { DUNE_THROW(FMatrixError,"mv and umv are not doing the same!"); } } { FieldVector v0; for (size_t i=0; i v0 ( v ); test_mult(A, v0, f ); } // { // std::vector v1( m ) ; // std::vector f1( n, 1 ) ; // // random access vector // for (size_type i=0; i= 0 ); assert( A.frobenius_norm2() >= 0 ); assert( A.infinity_norm() >= 0 ); assert( A.infinity_norm_real() >= 0); std::sort(v.begin(), v.end()); // print matrix std::cout << A << std::endl; // print vector std::cout << f << std::endl; { DynamicMatrix A2 = A; A2 *= 2; DynamicMatrix B = A; B += A; B -= A2; if (std::abs(B.infinity_norm()) > 1e-12) DUNE_THROW(FMatrixError,"Operator +=/-= test failed!"); } { DynamicMatrix A3 = A; A3 *= 3; DynamicMatrix B = A; B.axpy( K( 2 ), B ); B -= A3; if (std::abs(B.infinity_norm()) > 1e-12) DUNE_THROW(FMatrixError,"Axpy test failed!"); } { DynamicMatrix A2(n,n+1); for(size_type i=0; i& Aref = A2; DynamicMatrix B(n+1,n+1); for(size_type i=0; i& Bref = B; DynamicMatrix C(n,n); for(size_type i=0; i& Cref = C; #if 0 DynamicMatrix AB = Aref.rightmultiplyany(B); for(size_type i=0; i(AB[i][j] - i*n*(n+1)/2) > 1e-10) DUNE_THROW(FMatrixError,"Rightmultiplyany test failed!"); DynamicMatrix AB2 = A; AB2.rightmultiply(B); AB2 -= AB; if (std::abs(AB2.infinity_norm() > 1e-10)) DUNE_THROW(FMatrixError,"Rightmultiply test failed!"); DynamicMatrix AB3 = Bref.leftmultiplyany(A); AB3 -= AB; if (std::abs(AB3.infinity_norm() > 1e-10)) DUNE_THROW(FMatrixError,"Leftmultiplyany test failed!"); DynamicMatrix CA = Aref.leftmultiplyany(C); for(size_type i=0; i(CA[i][j] - i*n*(n-1)/2) > 1e-10) DUNE_THROW(FMatrixError,"Leftmultiplyany test failed!"); DynamicMatrix CA2 = A; CA2.leftmultiply(C); CA2 -= CA; if (std::abs(CA2.infinity_norm() > 1e-10)) DUNE_THROW(FMatrixError,"Leftmultiply test failed!"); DynamicMatrix CA3 = Cref.rightmultiplyany(A); CA3 -= CA; if (std::abs(CA3.infinity_norm() > 1e-10)) DUNE_THROW(FMatrixError,"Rightmultiplyany test failed!"); #endif } } int test_determinant() { int ret = 0; DynamicMatrix B(4,4); B[0][0] = 3.0; B[0][1] = 0.0; B[0][2] = 1.0; B[0][3] = 0.0; B[1][0] = -1.0; B[1][1] = 3.0; B[1][2] = 0.0; B[1][3] = 0.0; B[2][0] = -3.0; B[2][1] = 0.0; B[2][2] = -1.0; B[2][3] = 2.0; B[3][0] = 0.0; B[3][1] = -1.0; B[3][2] = 0.0; B[3][3] = 1.0; if (std::abs(B.determinant() + 2.0) > 1e-12) { std::cerr << "Determinant 1 test failed" << std::endl; ++ret; } B[0][0] = 3.0; B[0][1] = 0.0; B[0][2] = 1.0; B[0][3] = 0.0; B[1][0] = -1.0; B[1][1] = 3.0; B[1][2] = 0.0; B[1][3] = 0.0; B[2][0] = -3.0; B[2][1] = 0.0; B[2][2] = -1.0; B[2][3] = 2.0; B[3][0] = -1.0; B[3][1] = 3.0; B[3][2] = 0.0; B[3][3] = 2.0; if (B.determinant() != 0.0) { std::cerr << "Determinant 2 test failed" << std::endl; ++ret; } return 0; } int main() { try { Dune::DynamicMatrix A( 5, 5 ); checkMatrixInterface( A ); test_matrix(); test_matrix(); test_matrix(); test_matrix(); test_determinant(); Dune::DynamicMatrix B(34, 34, 1e-15); for (int i=0; i<34; i++) B[i][i] = 1; B.invert(); return test_invert_solve(); } catch (Dune::Exception & e) { std::cerr << "Exception: " << e << std::endl; } } dune-common-2.8.0/dune/common/test/dynvectortest.cc000066400000000000000000000025661411343567400224110ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include using Dune::DynamicVector; template void dynamicVectorTest(int d) { ct a = 1; DynamicVector v(d,1); DynamicVector w(d,2); DynamicVector z(d,2); [[maybe_unused]] bool b; // Test whether the norm methods compile (w+v).two_norm(); (w+v).two_norm2(); (w+v).one_norm(); (w+v).one_norm_real(); (w+v).infinity_norm(); (w+v).infinity_norm_real(); // test op(vec,vec) z = v + w; z = v - w; DynamicVector z2 = v + w; w -= v; w += v; // test op(vec,scalar) w +=a; w -= a; w *= a; w /= a; // test scalar product, axpy a = v * w; z = v.axpy(a,w); // test comparison b = (w != v); b = (w == v); // test istream operator std::stringstream s; for (int i=0; i> w; assert(v == w); } int main() { try { for (int d=1; d<6; d++) { dynamicVectorTest(d); dynamicVectorTest(d); dynamicVectorTest(d); } } catch (Dune::Exception& e) { std::cerr << e << std::endl; return 1; } catch (...) { std::cerr << "Generic exception!" << std::endl; return 2; } } dune-common-2.8.0/dune/common/test/eigenvaluestest.cc000066400000000000000000000274001411343567400226750ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include using namespace Dune; #if HAVE_LAPACK /** \brief Test the eigenvalue code with the Rosser test matrix This matrix was a challenge for many matrix eigenvalue algorithms. But the Francis QR algorithm, as perfected by Wilkinson and implemented in EISPACK, has no trouble with it. The matrix is 8-by-8 with integer elements. It has: * A double eigenvalue * Three nearly equal eigenvalues * Dominant eigenvalues of opposite sign * A zero eigenvalue * A small, nonzero eigenvalue */ template void testRosserMatrix() { DynamicMatrix A = { { 611, 196, -192, 407, -8, -52, -49, 29 }, { 196, 899, 113, -192, -71, -43, -8, -44 }, { -192, 113, 899, 196, 61, 49, 8, 52 }, { 407, -192, 196, 611, 8, 44, 59, -23 }, { -8, -71, 61, 8, 411, -599, 208, 208 }, { -52, -43, 49, 44, -599, 411, 208, 208 }, { -49, -8, 8, 59, 208, 208, 99, -911 }, { 29, -44, 52, -23, 208, 208, -911, 99} }; // compute eigenvalues DynamicVector > eigenComplex; DynamicMatrixHelp::eigenValuesNonSym(A, eigenComplex); // test results /* reference solution computed with octave 3.2 > format long e > eig(rosser()) */ std::vector reference = { -1.02004901843000e+03, -4.14362871168386e-14, 9.80486407214362e-02, 1.00000000000000e+03, 1.00000000000000e+03, 1.01990195135928e+03, 1.02000000000000e+03, 1.02004901843000e+03 }; std::vector eigenRealParts(8); for (int i=0; i<8; i++) eigenRealParts[i] = std::real(eigenComplex[i]); std::sort(eigenRealParts.begin(), eigenRealParts.end()); for (int i=0; i<8; i++) { if (std::fabs(std::imag(eigenComplex[i])) > 1e-10) DUNE_THROW(MathError, "Symmetric matrix has complex eigenvalue"); if( std::fabs(reference[i] - eigenRealParts[i]) > 1e-10 ) DUNE_THROW(MathError,"error computing eigenvalues of Rosser-matrix"); } std::cout << "Eigenvalues of Rosser matrix: " << eigenComplex << std::endl; } #endif // HAVE_LAPACK template void testSymmetricFieldMatrix() { int numberOfTestMatrices = 10; for (int i=0; i testMatrix; for (int j=0; j eigenValues; FieldMatrix eigenVectors; FMatrixHelp::eigenValuesVectors(testMatrix, eigenValues, eigenVectors); // Make sure the compute numbers really are the eigenvalues /*for (int j=0; j copy = testMatrix; for (int k=0; k 1e-8) DUNE_THROW(MathError, "Value computed by FMatrixHelp::eigenValues is not an eigenvalue, Determinant: "+std::to_string(std::fabs(copy.determinant()))); }*/ // Make sure eigenvalues and eigenvectors are not NaN (the subsequent tests do not find this!) for (int j=0; j eigenValues[j+1] + 1e-10) DUNE_THROW(MathError, "Values computed by FMatrixHelp::eigenValues are not in ascending order"); // Make sure the vectors really are eigenvectors for the computed eigenvalues for (int j=0; j Av; testMatrix.mv(eigenVectors[j], Av); if((Av - eigenValues[j]*eigenVectors[j]).two_norm() > dim*std::sqrt(std::numeric_limits::epsilon())) DUNE_THROW(MathError, "Vector computed by FMatrixHelp::eigenValuesVectors is not an eigenvector"); } // Make sure the eigenvectors have unit length for(auto& ev : eigenVectors) { constexpr double tol = std::max(std::numeric_limits::epsilon(), std::numeric_limits::epsilon()); if(std::abs(ev.two_norm())-1 > dim*tol) DUNE_THROW(MathError, "Vector computed by FMatrixHelp::eigenValuesVectors does not have unit length"); } } } template void compareEigenvectorSets(FieldMatrix evec, FieldVector refEval, FieldMatrix refEvec) { field_type th = dim*std::sqrt(std::numeric_limits::epsilon()); std::size_t i=0; std::size_t shift; std::list> refEvecList; field_type currentEval; while(i void checkMatrixWithReference(FieldMatrix matrix, FieldMatrix refEvec, FieldVector refEval) { //normalize reference for(auto& ev : refEvec) ev /= ev.two_norm(); field_type th = dim*std::sqrt(std::numeric_limits::epsilon()); FieldMatrix eigenvectors; FieldVector eigenvalues; FMatrixHelp::eigenValuesVectors(matrix, eigenvalues, eigenvectors); if((eigenvalues-refEval).two_norm() > th) DUNE_THROW(MathError, "Eigenvalues [" << eigenvalues << "] computed by FMatrixHelp::eigenValuesVectors do not match the reference solution [" << refEval << "]"); try { compareEigenvectorSets(eigenvectors, refEval, refEvec); } catch(Dune::MathError& e) { std::cerr << "Computations by `FMatrixHelp::eigenValuesVectors`: " << e.what() << std::endl; } } template void checkMatrixWithLAPACK(FieldMatrix matrix) { field_type th = dim*std::sqrt(std::numeric_limits::epsilon()); FieldMatrix eigenvectors, refEvec; FieldVector eigenvalues, refEval; FMatrixHelp::eigenValuesVectors(matrix, eigenvalues, eigenvectors); FMatrixHelp::eigenValuesVectorsLapack(matrix, refEval, refEvec); if((eigenvalues-refEval).two_norm() > th) DUNE_THROW(MathError, "Eigenvalues [" << eigenvalues << "] computed by FMatrixHelp::eigenValuesVectorsLapack do not match the reference solution [" << refEval << "]"); try { compareEigenvectorSets(eigenvectors, refEval, refEvec); } catch(Dune::MathError& e) { std::cerr << "Computations by `FMatrixHelp::eigenValuesVectorsLapack`: " << e.what() << std::endl; } } template void checkMultiplicity() { //--2d-- //repeated eigenvalue (x2) checkMatrixWithReference({{1, 0},{0, 1}}, {{1,0}, {0,1}}, {1, 1}); //eigenvalues with same magnitude (x2) checkMatrixWithReference({{0, 1}, {1, 0}}, {{1,-1}, {1,1}}, {-1, 1}); // singular matrix checkMatrixWithReference({{1, 0},{0, 0}}, {{0,1}, {1,0}}, {0, 1}); // another singular matrix (triggers a different code path) checkMatrixWithReference({{0, 0},{0, 1}}, {{1,0}, {0,1}}, {0, 1}); // Seemingly simple diagonal matrix -- triggers unstable detection of zero columns checkMatrixWithReference({{1.01, 0},{0, 1}}, {{0,1}, {1,0}}, {1, 1.01}); // check 2x2 zero matrix checkMatrixWithReference({{ 0, 0}, { 0, 0}}, {{1,0}, {0,1}}, {0, 0}); //--3d-- //repeated eigenvalue (x3) checkMatrixWithReference({{ 1, 0, 0}, { 0, 1, 0}, { 0, 0, 1}}, {{1,0,0}, {0,1,0}, {0,0,1}}, {1, 1, 1}); //eigenvalues with same magnitude (x2) checkMatrixWithReference({{ 0, 1, 0}, { 1, 0, 0}, { 0, 0, 5}}, {{-1,1,0}, {1,1,0}, {0,0,1}}, {-1, 1, 5}); //repeated eigenvalue (x2) checkMatrixWithReference({{ 3, -2, 0}, { -2, 3, 0}, { 0, 0, 5}}, {{1,1,0}, {0,0,1}, {1,-1,0}}, {1, 5, 5}); // singular non-diagonal matrix checkMatrixWithReference({{ 0, 0, 0}, { 0, 1, 1}, { 0, 1, 1}}, {{1,0,0}, {0,FT(-1.0/std::sqrt(2.0)),FT(1.0/std::sqrt(2.0))}, {0,FT(1.0/std::sqrt(2.0)),FT(1.0/std::sqrt(2.0))}}, {0, 0, 2}); // singular diagonal matrix (that's a different code path again) checkMatrixWithReference({{ 0, 0, 0}, { 0, 1, 0}, { 0, 0, 0}}, {{1,0,0}, {0,0,1}, {0,1,0}}, {0, 0, 1}); // diagonal matrix whose largest eigenvalue is not 1 // this tests the matrix scaling employed by the eigenvector code. checkMatrixWithReference({{ 3, 0, 0}, { 0, 2, 0}, { 0, 0, 4}}, {{0,1,0}, {1,0,0}, {0,0,1}}, {2, 3, 4}); // check 3x3 zero matrix checkMatrixWithReference({{ 0, 0, 0}, { 0, 0, 0}, { 0, 0, 0}}, {{1,0,0}, {0,1,0}, {0,0,1}}, {0, 0, 0}); //repeat tests with LAPACK (if found) #if HAVE_LAPACK checkMatrixWithLAPACK({{1, 0}, {0, 1}}); checkMatrixWithLAPACK({{0, 1}, {1, 0}}); checkMatrixWithLAPACK({{1,0,0}, {0,1,0}, {0,0,1}}); checkMatrixWithLAPACK({{0,1,0}, {1,0,0}, {0,0,5}}); checkMatrixWithLAPACK({{3,-2,0}, {-2,3,0}, {0,0,5}}); #endif } int main() { #if HAVE_LAPACK testRosserMatrix(); testRosserMatrix(); testRosserMatrix(); #else std::cout << "WARNING: eigenvaluetest needs LAPACK, test disabled" << std::endl; #endif // HAVE_LAPACK //we basically just test LAPACK here, so maybe discard those tests #if HAVE_LAPACK testSymmetricFieldMatrix(); testSymmetricFieldMatrix(); testSymmetricFieldMatrix(); testSymmetricFieldMatrix(); testSymmetricFieldMatrix(); testSymmetricFieldMatrix(); #endif // HAVE_LAPACK testSymmetricFieldMatrix(); testSymmetricFieldMatrix(); testSymmetricFieldMatrix(); testSymmetricFieldMatrix(); testSymmetricFieldMatrix(); testSymmetricFieldMatrix(); checkMultiplicity(); checkMultiplicity(); checkMultiplicity(); return 0; } dune-common-2.8.0/dune/common/test/enumsettest.cc000066400000000000000000000010161411343567400220410ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include int main() { using namespace Dune; std::cout<,EnumItem,int>::contains(1)<< " "<,EnumItem,int>::contains(2)<< " "<,EnumItem,int>,EnumItem,int>::contains(3)<< " "<::contains(3)< #include #include #include int main() { int status = 0; auto test1 = Dune::filledArray<2>(2.0); static_assert(std::is_same >::value, "Wrong result type for Dune::filledArray()"); if(test1[0] != 2.0 || test1[1] != 2.0) { std::cerr << "Dune::filledArray() produces wrong value" << std::endl; status = 1; } #ifdef __cpp_lib_array_constexpr std::cout << "The result of Dune::filledArray() is constexpr" << std::endl; constexpr auto test2 = Dune::filledArray<2>(2); (void)test2; #else // !__cpp_lib_array_constexpr std::cout << "Not checking whether Dune::filledArray() is constexpr\n" << "since the library does not declare std::array as constexpr\n" << "(__cpp_lib_array_constexpr is not defined)." << std::endl; #endif // !__cpp_lib_array_constexpr return status; } dune-common-2.8.0/dune/common/test/fmatrixtest.cc000066400000000000000000000640141411343567400220420ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif // Activate checking. #ifndef DUNE_FMatrix_WITH_CHECKING #define DUNE_FMatrix_WITH_CHECKING #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #if HAVE_VC #include #endif #include "checkmatrixinterface.hh" using namespace Dune; template int test_invert_solve(Dune::FieldMatrix &A, Dune::FieldMatrix &inv, Dune::FieldVector &x, Dune::FieldVector &b, bool doPivoting = true) { using std::abs; int ret=0; std::cout <<"Checking inversion of:"< calced_inv; FieldVector calced_x; std::cout< prod = A; prod.rightmultiply(inv); for (size_t i=0; i 1e-6)) { std::cerr<<"Given inverse wrong"< copy(A); A.invert(doPivoting); calced_inv = A; A-=inv; auto epsilon = std::numeric_limits::real_type>::epsilon(); auto tolerance = 10*epsilon; for(size_t i =0; i < n; ++i) for(size_t j=0; j tolerance)) { std::cerr<<"calculated inverse wrong at ("< xcopy(calced_x); xcopy-=x; equal=true; for(size_t i =0; i < n; ++i) if(Simd::anyTrue(abs(xcopy[i])>tolerance)) { std::cerr<<"calculated isolution wrong at ("<; using FV = Dune::FieldVector; FM A_data = {{1, 5, 7}, {2, 14, 15}, {4, 40, 39}}; FM inv_data = {{-9.0 / 4, 85.0 / 24, -23.0 / 24}, {-3.0 / 4, 11.0 / 24, -1.0 / 24}, {1, -5.0 / 6, 1.0 / 6}}; FV b = {32, 75, 201}; FV x = {1, 2, 3}; ret += test_invert_solve(A_data, inv_data, x, b); FM A_data0 = {{-0.5, 0, -0.25}, {0.5, 0, -0.25}, {0, 0.5, 0}}; FM inv_data0 = {{-1, 1, 0}, {0, 0, 2}, {-2, -2, 0}}; FV b0 = {32, 75, 201}; FV x0 = {43, 402, -214}; ret += test_invert_solve(A_data0, inv_data0, x0, b0); FM A_data1 = {{0, 1, 0}, {1, 0, 0}, {0, 0, 1}}; FV b1 = {0, 1, 2}; FV x1 = {1, 0, 2}; ret += test_invert_solve(A_data1, A_data1, x1, b1); FM A_data2 = {{3, 1, 6}, {2, 1, 3}, {1, 1, 1}}; FM inv_data2 = {{-2, 5, -3}, {1, -3, 3}, {1, -2, 1}}; FV b2 = {2, 7, 4}; FV x2 = {19, -7, -8}; ret += test_invert_solve(A_data2, inv_data2, x2, b2); using FM6 = Dune::FieldMatrix; using FV6 = Dune::FieldVector; using FM6f = Dune::FieldMatrix; using FV6f = Dune::FieldVector; using FM6c = Dune::FieldMatrix, 6, 6>; using FV6c = Dune::FieldVector, 6>; using FM6cf = Dune::FieldMatrix, 6, 6>; using FV6cf = Dune::FieldVector, 6>; FM6 A_data3 = {{0.1756212892262638, 0.18004482126181995, -0.49348712464381461, 0.49938830949606494, -0.7073160963417815, 1.0595994834402057e-06}, {0.17562806606385517, 0.18005184462676252, -0.49354113600539418, 0.50059575375120657, 0.70689735319270453, -3.769499436967368e-07}, {0.17562307226079987, 0.1800466692525447, -0.49350050991711036, -0.5000065175076156, 0.00018887507812282846, -0.70710715811504954}, {0.17562308446070105, 0.18004668189625178, -0.49350060714612815, -0.50000869003275417, 0.00019031361405394119, 0.70710640425695015}, {-0.0072214111281474463, 0.93288324029450198, -0.11009998093332186, -1.7482015044681947e-06, -2.35420746900079e-06, -4.2380607559371285e-09}, {0.93625470097440933, -0.0077746247590777659, -0.11696151733678119, -1.8717676241478393e-06, -2.5225363177584535e-06, -4.5410877139483271e-09}}; FM6 inv_data3 = {{-0.069956619842954, -0.069956322880040, -0.069956501823745, -0.069956501289142, 0.063349638850509, 1.121064161778902}, {-0.066113473123754, -0.066113223084417, -0.066113362249636, -0.066113361799508, 1.123470950632021, 0.058271943290769}, {-0.555587502096003, -0.555615651279932, -0.555585807267011, -0.555585857939820, 0.432422844944552, 0.420211281044740}, { 0.499710573383257, 0.500274796075355, -0.500006831431901, -0.500007846623773, 0.000003909674199, 0.000003817686226}, {-0.707554041861306, 0.706659150542343, 0.000405628342406, 0.000407065756770, 0.000010628642550, 0.000010383891450}, { 0.000001450379141, 0.000000012708409, -0.707107586716496, 0.707105975654669, 0.000000019133995, 0.000000018693387}}; FV6 b3 = {1, 1, 1, 1, 1, 1}; FV6 x3 = {0.904587854793530, 0.917289473665475, -1.369740692593475, -0.000021581236636, -0.000061184685788, -0.000000110146895}; FM6f A_data3f, inv_data3f; FM6c A_data3c, inv_data3c; FM6cf A_data3cf, inv_data3cf; std::copy(A_data3.begin(), A_data3.end(), A_data3f.begin()); std::copy(inv_data3.begin(), inv_data3.end(), inv_data3f.begin()); std::copy(A_data3.begin(), A_data3.end(), A_data3c.begin()); std::copy(inv_data3.begin(), inv_data3.end(), inv_data3c.begin()); std::copy(A_data3.begin(), A_data3.end(), A_data3cf.begin()); std::copy(inv_data3.begin(), inv_data3.end(), inv_data3cf.begin()); FV6f b3f = b3; FV6f x3f = x3; FV6c b3c = b3; FV6c x3c = x3; FV6cf b3cf = b3; FV6cf x3cf = x3; #if HAVE_VC using FM6vc = Dune::FieldMatrix< Vc::SimdArray, 6, 6>; using FV6vc = Dune::FieldVector< Vc::SimdArray, 6>; FM6vc A_data3vc, inv_data3vc; std::copy(A_data3.begin(), A_data3.end(), A_data3vc.begin()); std::copy(inv_data3.begin(), inv_data3.end(), inv_data3vc.begin()); FV6vc b3vc = b3; FV6vc x3vc = x3; ret += test_invert_solve< Vc::SimdArray, 6>(A_data3vc, inv_data3vc, x3vc, b3vc); #endif ret += test_invert_solve(A_data3, inv_data3, x3, b3); ret += test_invert_solve, 6>(A_data3c, inv_data3c, x3c, b3c); ret += test_invert_solve, 6>(A_data3cf, inv_data3cf, x3cf, b3cf); ret += test_invert_solve(A_data3f, inv_data3f, x3f, b3f); FM A_data4 = {{2, -1, 0}, {-1, 2, -1}, {0, -1, 2}}; FM inv_data4 = {{0.75, 0.5, 0.25}, {0.5, 1, 0.5}, {0.25, 0.5, 0.75}}; FV b4 = {1, 2, 3}; FV x4 = {2.5, 4, 3.5}; ret += test_invert_solve(A_data4, inv_data4, x4, b4, false); return ret; } template void test_mult(FieldMatrix& A, X& v, Y& f, XT& vT, YT& fT) { // test the various matrix-vector products A.mv(v,f); A.mtv(fT,vT); A.umv(v,f); A.umtv(fT,vT); A.umhv(fT,vT); A.mmv(v,f); A.mmtv(fT,vT); A.mmhv(fT,vT); using S = typename FieldTraits::field_type; using S2 = typename FieldTraits::field_type; S scalar = (S)(0.5); S2 scalar2 = (S2)(0.5); A.usmv(scalar,v,f); A.usmtv(scalar2,fT,vT); A.usmhv(scalar2,fT,vT); } template void test_matrix() { typedef typename FieldMatrix::size_type size_type; FieldMatrix A; FieldVector v; FieldVector f; // test constexpr size static_assert(A.N() == n, ""); static_assert(A.M() == m, ""); // assign matrix A=K(); // random access matrix for (size_type i=0; ibegin(); for (; cit!=rit->end(); ++cit) { cit.index(); (*cit) *= 2; } } // assign vector f = 1; // random access vector for (size_type i=0; i res2(0); FieldVector res1; FieldVector b(1); A.mv(b, res1); A.umv(b, res2); if( (res1 - res2).two_norm() > 1e-12 ) { DUNE_THROW(FMatrixError,"mv and umv are not doing the same!"); } } { FieldVector v0 (v); FieldVector f0 (f); FieldVector vT (0); FieldVector fT (0); test_mult(A, v0, f0, vT, fT); } // { // std::vector v1( m ) ; // std::vector f1( n, 1 ) ; // // random access vector // for (size_type i=0; i= 0 ); assert( A.frobenius_norm2() >= 0 ); assert( A.infinity_norm() >= 0 ); assert( A.infinity_norm_real() >= 0); // print matrix std::cout << A << std::endl; // print vector std::cout << f << std::endl; A[0][0] += 5; // Make matrix non-zero { // Test that operator= and operator-= work before we can test anything else using FM = FieldMatrix; FM A0 = A; { if (A0.infinity_norm() < 1e-12) DUNE_THROW(FMatrixError, "Assignment had no effect!"); } A0 -= A; { if (A0.infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Operator-= had no effect!"); } FM A1 = A; // A1 == A FM A2 = (A1 *= 2); // A1 == A2 == 2*A { FM tmp = A1; tmp -= A; if (tmp.infinity_norm() < 1e-12) DUNE_THROW(FMatrixError,"Operator*= had no effect!"); } { FM tmp = A2; tmp -= A1; if (tmp.infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Return value of Operator*= incorrect!"); } [[maybe_unused]] FM A3 = (A2 *= 3); // A2 == A3 == 6*A FM A4 = (A2 /= 2); // A2 == A4 == 3*A; FM A5 = A; A5 *= 3; // A5 == 3*A { FM tmp = A2; tmp -= A5; if (tmp.infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Operator/= had no effect!"); } { FM tmp = A4; tmp -= A5; if (tmp.infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Return value of Operator/= incorrect!"); } FM A6 = A; FM A7 = (A6 += A); // A6 == A7 == 2*A { FM tmp = A1; tmp -= A6; if (tmp.infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Operator+= had no effect!"); } { FM tmp = A1; tmp -= A7; if (tmp.infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Return value of Operator+= incorrect!"); } FM A8 = A2; // A8 == A2 == 3*A FM A9 = (A8 -= A); // A9 == A8 == 2*A; { FM tmp = A8; tmp -= A1; if (tmp.infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Operator-= had no effect!"); } { FM tmp = A9; tmp -= A1; if (tmp.infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Return value of Operator-= incorrect!"); } FM A10 = A; FM A11 = A10.axpy(2, A); // A11 = 3*A; { FM tmp = A10; tmp -= A2; if (tmp.infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "axpy() had no effect!"); } { FM tmp = A10; tmp -= A11; if (tmp.infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Return value of axpy() incorrect!"); } // Scalar * Matrix and Matrix * Scalar { typename FM::field_type scalar = 3; FM sA = scalar * A; FM aS = A * scalar; FM ref = A; ref *= scalar; if ((sA-ref).infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Return value of operator*(scalar,matrix) incorrect!"); if ((aS-ref).infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Return value of operator*(matrix,scalar) incorrect!"); } // Matrix / Scalar { typename FM::field_type scalar = 3; FM aS = A / scalar; FM ref = A; ref /= scalar; if ((aS-ref).infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Return value of operator/(matrix,scalar) incorrect!"); } // Matrix + Matrix { FM twiceA = A + A; FM ref = typename FM::field_type(2)*A; if ((twiceA-ref).infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Return value of operator+(matrix,matrix) incorrect!"); } // Matrix - Matrix { FM zero = A - A; if (zero.infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Return value of operator-(matrix,matrix) incorrect!"); } // -Matrix { FM neg = -A; FM ref = typename FM::field_type(-1)*A; if ((neg-ref).infinity_norm() > 1e-12) DUNE_THROW(FMatrixError, "Return value of operator-(matrix) incorrect!"); } // Matrix * Matrix { auto transposed = [](const FM& A) { FieldMatrix AT; for (int i=0; i A3 = A; A3 *= 3; FieldMatrix B = A; B.axpy( K( 2 ), B ); B -= A3; if (abs(B.infinity_norm()) > 1e-12) DUNE_THROW(FMatrixError,"Axpy test failed!"); } { using std::abs; FieldMatrix A2; for(size_type i=0; i& Aref = A2; FieldMatrix B; for(size_type i=0; i& Bref = B; FieldMatrix C; for(size_type i=0; i& Cref = C; FieldMatrix AB = Aref.rightmultiplyany(B); for(size_type i=0; i 1e-10) DUNE_THROW(FMatrixError,"Rightmultiplyany test failed!"); FieldMatrix AB2 = A2; AB2.rightmultiply(B); AB2 -= AB; if (abs(AB2.infinity_norm()) > 1e-10) DUNE_THROW(FMatrixError,"Rightmultiply test failed!"); FieldMatrix AB3 = Bref.leftmultiplyany(A2); AB3 -= AB; if (abs(AB3.infinity_norm()) > 1e-10) DUNE_THROW(FMatrixError,"Leftmultiplyany test failed!"); FieldMatrix CA = Aref.leftmultiplyany(C); for(size_type i=0; i 1e-10) DUNE_THROW(FMatrixError,"Leftmultiplyany test failed!"); FieldMatrix CA2 = A2; CA2.leftmultiply(C); CA2 -= CA; if (abs(CA2.infinity_norm()) > 1e-10) DUNE_THROW(FMatrixError,"Leftmultiply test failed!"); FieldMatrix CA3 = Cref.rightmultiplyany(A2); CA3 -= CA; if (abs(CA3.infinity_norm()) > 1e-10) DUNE_THROW(FMatrixError,"Rightmultiplyany test failed!"); } } template int test_determinant() { using std::abs; int ret = 0; FieldMatrix B; B[0][0] = 3.0; B[0][1] = 0.0; B[0][2] = 1.0; B[0][3] = 0.0; B[1][0] = -1.0; B[1][1] = 3.0; B[1][2] = 0.0; B[1][3] = 0.0; B[2][0] = -3.0; B[2][1] = 0.0; B[2][2] = -1.0; B[2][3] = 2.0; B[3][0] = 0.0; B[3][1] = -1.0; B[3][2] = 0.0; B[3][3] = 1.0; if (Simd::anyTrue(abs(B.determinant() + 2.0) > 1e-12)) { std::cerr << "Determinant 1 test failed (" << Dune::className() << ")" << std::endl; std::cerr << "Determinant 1 is " << B.determinant(true) << ", expected 2.0" << std::endl; ++ret; } B[0][0] = 3.0; B[0][1] = 0.0; B[0][2] = 1.0; B[0][3] = 0.0; B[1][0] = -1.0; B[1][1] = 3.0; B[1][2] = 0.0; B[1][3] = 0.0; B[2][0] = -3.0; B[2][1] = 0.0; B[2][2] = -1.0; B[2][3] = 2.0; B[3][0] = -1.0; B[3][1] = 3.0; B[3][2] = 0.0; B[3][3] = 2.0; if (Simd::anyTrue(B.determinant(false) != 0.0)) { std::cerr << "Determinant 2 test failed (" << Dune::className() << ")" << std::endl; std::cerr << "Determinant 2 is " << B.determinant(false) << ", expected 0.0" << std::endl; ++ret; } return ret; } template struct ScalarOperatorTest { ScalarOperatorTest() { ft a = 1; ft c = 2; FieldMatrix v(2); FieldMatrix w(2); [[maybe_unused]] bool b; std::cout << __func__ << "\t ( " << className(v) << " )" << std::endl; a = a * c; a = a + c; a = a / c; a = a - c; v = a; v = w = v; a = v; a = v + a; a = v - a; a = v * a; a = v / a; v = v + a; v = v - a; v = v * a; v = v / a; a = a + v; a = a - v; a = a * v; a = a / v; v = a + v; v = a - v; v = a * v; v = a / v; v -= w; v -= a; v += w; v += a; v *= a; v /= a; b = (v == a); b = (v != a); b = (a == v); b = (a != v); } }; template void test_ev() { // rosser test matrix /* This matrix was a challenge for many matrix eigenvalue algorithms. But the Francis QR algorithm, as perfected by Wilkinson and implemented in EISPACK, has no trouble with it. The matrix is 8-by-8 with integer elements. It has: * A double eigenvalue * Three nearly equal eigenvalues * Dominant eigenvalues of opposite sign * A zero eigenvalue * A small, nonzero eigenvalue */ Dune::FieldMatrix A = { { 611, 196, -192, 407, -8, -52, -49, 29 }, { 196, 899, 113, -192, -71, -43, -8, -44 }, { -192, 113, 899, 196, 61, 49, 8, 52 }, { 407, -192, 196, 611, 8, 44, 59, -23 }, { -8, -71, 61, 8, 411, -599, 208, 208 }, { -52, -43, 49, 44, -599, 411, 208, 208 }, { -49, -8, 8, 59, 208, 208, 99, -911 }, { 29, -44, 52, -23, 208, 208, -911, 99} }; // compute eigenvalues Dune::FieldVector eig; Dune::FMatrixHelp::eigenValues(A, eig); // test results Dune::FieldVector ref; /* reference solution computed with octave 3.2 > format long e > eig(rosser()) */ ref = { -1.02004901843000e+03, -4.14362871168386e-14, 9.80486407214362e-02, 1.00000000000000e+03, 1.00000000000000e+03, 1.01990195135928e+03, 1.02000000000000e+03, 1.02004901843000e+03 }; if( (ref - eig).two_norm() > 1e-10 ) { DUNE_THROW(FMatrixError,"error computing eigenvalues"); } std::cout << "Eigenvalues of Rosser matrix: " << eig << std::endl; } template< class K, int n > void test_invert () { Dune::FieldMatrix< K, n, n > A( 1e-15 ); for( int i = 0; i < n; ++i ) A[ i ][ i ] = K( 1 ); A.invert(); } template void checkNormNAN(M const &v, int line) { if (!std::isnan(v.frobenius_norm())) { std::cerr << "error: norm not NaN: frobenius_norm() on line " << line << " (type: " << Dune::className(v[0]) << ")" << std::endl; std::exit(-1); } if (!std::isnan(v.infinity_norm())) { std::cerr << "error: norm not NaN: infinity_norm() on line " << line << " (type: " << Dune::className(v[0]) << ")" << std::endl; std::exit(-1); } } // Make sure that matrices with NaN entries have norm NaN. // See also bug flyspray/FS#1147 template void test_nan(T const &mynan) { T const n(0); { Dune::FieldMatrix m = { { mynan, mynan }, { mynan, mynan } }; checkNormNAN(m, __LINE__); } { Dune::FieldMatrix m = { { mynan, n }, { n, n } }; checkNormNAN(m, __LINE__); } { Dune::FieldMatrix m = { { n, mynan }, { n, n } }; checkNormNAN(m, __LINE__); } { Dune::FieldMatrix m = { { n, n }, { mynan, n } }; checkNormNAN(m, __LINE__); } { Dune::FieldMatrix m = { { n, n }, { n, mynan } }; checkNormNAN(m, __LINE__); } } // The computation of infinity_norm_real() was flawed from r6819 on // until r6915. void test_infinity_norms() { using std::abs; std::complex threefour(3.0, -4.0); std::complex eightsix(8.0, -6.0); Dune::FieldMatrix, 2, 2> m; m[0] = threefour; m[1] = eightsix; assert(abs(m.infinity_norm() -20.0) < 1e-10); // max(5+5, 10+10) assert(abs(m.infinity_norm_real()-28.0) < 1e-10); // max(7+7, 14+14) } template< class K, class K2, int rows, int cols > void test_interface() { typedef CheckMatrixInterface::UseFieldVector< K2, rows, cols > Traits; typedef Dune::FieldMatrix< K, rows, cols > FMatrix; #if __GNUC__ != 5 || defined(__clang__) static_assert( !std::is_trivially_copyable::value || std::is_trivially_copyable::value, "FieldMatrix must be trivally copyable type when T is trivial type" ); #endif static_assert( std::is_standard_layout::value, "FieldMatrix<...> must be a standard layout type" ); FMatrix m( 1 ); checkMatrixInterface< FMatrix >( m ); checkMatrixInterface< FMatrix, Traits >( m ); } void test_initialisation() { [[maybe_unused]] Dune::FieldMatrix const A = { { 1, 2 }, { 3, 4 } }; assert(A[0][0] == 1); assert(A[0][1] == 2); assert(A[1][0] == 3); assert(A[1][1] == 4); } int main() { try { int errors = 0; // counts errors static_assert( std::is_same< Dune::FieldMatrix, Dune::FieldMatrix >::value, "default parameter for square matrices" ); { double nan = std::nan(""); test_nan(nan); } { std::complex nan( std::nan(""), 17 ); test_nan(nan); } test_infinity_norms(); test_initialisation(); // test 1 x 1 matrices test_interface(); test_matrix(); ScalarOperatorTest(); test_matrix(); ScalarOperatorTest(); #if HAVE_QUADMATH test_matrix(); ScalarOperatorTest(); #endif // test n x m matrices test_interface(); test_matrix(); test_matrix(); test_interface(); #if HAVE_QUADMATH test_matrix(); test_interface(); #endif // mixed precision test_interface(); test_matrix(); #if HAVE_QUADMATH test_matrix(); #endif // test complex matrices test_matrix, std::complex, std::complex, 1, 1>(); test_matrix, std::complex, std::complex, 5, 10>(); // test complex/real matrices mixed case test_matrix, std::complex, 1, 1>(); test_matrix, float, std::complex, 1, 1>(); #if HAVE_LAPACK // test eigemvalue computation test_ev(); #endif // test high level methods errors += test_determinant< double >(); #if HAVE_VC errors += test_determinant< Vc::SimdArray >(); #endif //test LoopSIMD stuff errors += test_determinant< Dune::LoopSIMD >(); test_invert< float, 34 >(); test_invert< double, 34 >(); test_invert< std::complex< long double >, 2 >(); test_invert< std::complex< float >, 2 >(); errors += test_invert_solve(); { // Test whether multiplying one-column matrices by scalars work FieldMatrix A = {1,2,3}; double v = 0; FieldVector f = {2,3,4}; double vT = 0; FieldVector fT = {3,4,5}; test_mult(A, v, f, vT, fT); } { // Test whether result of multiplying a one-row matrix can be a scalar FieldMatrix A = {{1,2,3}}; FieldVector v = {2,3,4}; double f = 0; FieldVector vT = {3,4,5}; double fT = 0; test_mult(A, v, f, vT, fT); } { // Test multiplication of 1x1 matrix with scalars FieldMatrix A = {42}; double v = 0; double f = 2; double vT = 0; double fT = 5; test_mult(A, v, f, vT, fT); } return (errors > 0 ? 1 : 0); // convert error count to unix exit status } catch (Dune::Exception & e) { std::cerr << "Exception: " << e << std::endl; return 1; } } dune-common-2.8.0/dune/common/test/functiontest.cc000066400000000000000000000017421411343567400222140ustar00rootroot00000000000000#include "config.h" #include #include #define DUNE_FUNCTION_HH_SILENCE_DEPRECATION #include #include int main() { Dune::TestSuite t; DUNE_NO_DEPRECATED_BEGIN { auto f = Dune::makeVirtualFunction( [](int x) -> long { return x*x; }); static_assert( std::is_base_of< Dune::VirtualFunction, decltype(f) >::value, "makeVirtualFunction() must return type derived from VirtualFunction"); long y; f.evaluate(2, y); t.check(y == 4); } { auto f1 = [](int x) -> long { return x*x; }; auto f = Dune::makeVirtualFunction(f1); static_assert( std::is_base_of< Dune::VirtualFunction, decltype(f) >::value, "makeVirtualFunction() must return type derived from VirtualFunction"); long y; f.evaluate(2, y); t.check(y == 4); } DUNE_NO_DEPRECATED_END return t.exit(); } dune-common-2.8.0/dune/common/test/fvectorconversion1d.cc000066400000000000000000000077251411343567400235010ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include //! @file /** * This test tests for a regression, where `std::is_assignable` would return * `true` for certain assignments, but it was not actually possible to * instantiate those assignments. In the fix `std::is_assignable` was fixed * to report false, and that is what is checked now. */ template class MyVector; namespace Dune { template struct DenseMatVecTraits< MyVector > { using derived_type = MyVector; using value_type = Component; using size_type = std::size_t; }; template struct IsFieldVectorSizeCorrect, Size> : std::integral_constant {}; } template class MyVector : public Dune::DenseVector< MyVector > { public: static constexpr std::size_t size () { return Dim; } Component& operator[] ( std::size_t i ) { return data_; } const Component& operator[] ( std::size_t i ) const { return data_; } protected: Component data_; }; int main() { try { // Pure 1d case. Here OuterMV is assignable to MiddleFV as the the // 1d FieldVector implements a type-case to the underlying // field. This is expected behaviour. { using InnerFV = Dune::FieldVector; using MiddleFV = Dune::FieldVector; using OuterFV = Dune::FieldVector; using MiddleMV = MyVector; using OuterMV = MyVector; MiddleFV mfv; OuterMV mv; OuterFV fv; static_assert(std::is_convertible::value, "DenseVectors should be convertible."); fv = mv; static_assert(std::is_assignable::value, "Reduced assignability detected."); mfv = mv; } // The following would trigger a problem in the DenseVector // operator=() which was cured by first checking whether the // value_types are assignable. { using InnerFV = Dune::FieldVector; using MiddleFV = Dune::FieldVector; using OuterFV = Dune::FieldVector; using MiddleMV = MyVector; using OuterMV = MyVector; // MiddleFV mfv; OuterMV mv; OuterFV fv; static_assert(std::is_convertible::value, "DenseVectors should be convertible."); fv = mv; // before the fix, `is_assignable` returned `true`, static_assert(!std::is_assignable::value, "Inconsistent assignability detected."); // mfv = mv; // <- but this assignment failed instantiation } { using InnerFV = Dune::FieldMatrix; using MiddleFV = Dune::FieldVector; using OuterFV = Dune::FieldVector; using MiddleMV = MyVector; using OuterMV = MyVector; // MiddleFV mfv; OuterMV mv; OuterFV fv; static_assert(std::is_assignable::value, "DenseVectors should be assignable."); fv = mv; // before the fix, `is_assignable` returned `true`, static_assert(!std::is_assignable::value, "Inconsistent assignability detected."); // mfv = mv; // <- but this assignment failed instantiation } return 0; } catch (Dune::Exception& e) { std::cerr << e << std::endl; return 1; } catch (...) { std::cerr << "Generic exception!" << std::endl; return 2; } } dune-common-2.8.0/dune/common/test/fvectortest.cc000066400000000000000000000370161411343567400220420ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include struct FVectorTestException : Dune::Exception {}; #define FVECTORTEST_ASSERT(EXPR) \ if(!(EXPR)) { \ DUNE_THROW(FVectorTestException, \ "Test assertion " << #EXPR << " failed"); \ } \ static_assert(true, "enforce terminating ;") using Dune::FieldVector; using std::complex; // Tests that can be run without the construction of complex template struct FieldVectorMainTestCommons { FieldVectorMainTestCommons() { #if __GNUC__ != 5 || defined(__clang__) static_assert( !std::is_trivially_copyable::value || std::is_trivially_copyable< FieldVector >::value, "FieldVector must be a trivially copyable type when T is a trivial type" ); #endif static_assert( std::is_standard_layout< FieldVector >::value, "FieldVector<...> must be a standard layout type" ); ft a = 1; FieldVector v(1); FieldVector w(2); FieldVector z(2); const FieldVector x(z); if (x.size()>0) a = x[0]; [[maybe_unused]] bool b; [[maybe_unused]] rt n; std::cout << __func__ << "\t ( " << className(v) << " )" << std::endl; // test exported types static_assert( std::is_same::value_type>::value, "FieldVector::value_type is not the correct type" ); // test traits static_assert( ( std::is_same< typename Dune::FieldTraits< FieldVector >::field_type, ft >::value ), "FieldTraits yields wrong field_type" ); static_assert( ( std::is_same< typename Dune::FieldTraits::real_type, rt >::value ), "FieldTraits yields wrong real_type" ); static_assert( ( std::is_same< typename Dune::FieldTraits< FieldVector >::real_type, rt >::value ), "FieldTraits yields wrong real_type" ); // Test whether the norm methods compile n = (w+v).two_norm(); n = (w+v).two_norm2(); n = (w+v).one_norm(); n = (w+v).one_norm_real(); n = (w+v).infinity_norm(); n = (w+v).infinity_norm_real(); // test op(vec,vec) z = v + w; z = v - w; [[maybe_unused]] FieldVector z2 = v + w; w -= v; w += v; // test op(vec,scalar) w +=a; w -= a; w *= a; w /= a; w = a * v; w = v * a; w = v / a; // Negation -v; // test scalar product, axpy a = v * w; a = v.dot(w); z = v.axpy(a,w); // test comparison b = (w != v); b = (w == v); // test istream operator std::stringstream s; for (int i=0; i> w; FVECTORTEST_ASSERT(v == w); // test container methods typename FieldVector::size_type size = FieldVector::dimension; FVECTORTEST_ASSERT(size == w.size()); if (w.size() > 0) { FVECTORTEST_ASSERT(!w.empty()); FVECTORTEST_ASSERT(std::addressof(w[0]) == std::addressof(w.front())); FVECTORTEST_ASSERT(std::addressof(w[0]) == w.data()); FVECTORTEST_ASSERT(std::addressof(w[d-1]) == std::addressof(w.back())); } } }; // Additional tests for floating point types, for which complex will work template::value> struct FieldVectorMainTest : FieldVectorMainTestCommons { FieldVectorMainTest() : FieldVectorMainTestCommons() { ft a = 1; FieldVector v(1); FieldVector z(2); const FieldVector x(z); // assignment to vector of complex FieldVector< std::complex ,d> cv = v; cv = a; [[maybe_unused]] const FieldVector< std::complex ,d> ccv = x; } }; template struct FieldVectorMainTest : FieldVectorMainTestCommons { FieldVectorMainTest() : FieldVectorMainTestCommons() {} }; template struct ScalarOperatorTest { ScalarOperatorTest() { // testft has to initializable with an int testft a = 1; testft c = 2; FieldVector v(2); FieldVector w(2); [[maybe_unused]] bool b; std::cout << __func__ << "\t ( " << className(v) << " )" << std::endl; a = a * c; a = a + c; a = a / c; a = a - c; v = a; v = w = v; a = v; a = v + a; a = v - a; a = v * a; a += 1; // make sure a!=0 a = v / a; v = v + a; v = v - a; v = v * a; a += 1; // make sure a!=0 v = v / a; a = a + v; a = a - v; a = a * v; v += 1; // make sure v!=0 a = a / v; v = a + v; v = a - v; v = a * v; v += 1; // make sure v!=0 v = a / v; v -= w; v -= a; v += w; v += a; v *= a; a += 1; // make sure a!=0 v /= a; b = (v == a); b = (v != a); b = (a == v); b = (a != v); } }; // scalar ordering doesn't work for complex numbers template struct ScalarOrderingTest { ScalarOrderingTest() { ft a = 1; ft c = 2; FieldVector v(2); FieldVector w(2); [[maybe_unused]] bool b; std::cout << __func__ << "\t ( " << className(v) << " )" << std::endl; b = (a < c); b = (a <= c); b = (a >= c); b = (a > c); b = (v == a); b = (v != a); b = (a == v); b = (a != v); b = (v < a); b = (v <= a); b = (v >= a); b = (v > a); b = (v < w); b = (v <= w); b = (v >= w); b = (v > w); b = (a < w); b = (a <= w); b = (a >= w); b = (a > w); } }; template struct Epsilon { static T value() { return T(1e-6); } }; template<> struct Epsilon { static int value() { return 0; } }; // scalar ordering doesn't work for complex numbers template ::value> struct DotProductTest { DotProductTest() { typedef std::complex ct; [[maybe_unused]] const rt myEps = Epsilon::value(); static_assert( ( std::is_same< typename Dune::FieldTraits::real_type, rt>::value ), "DotProductTest requires real data type as template parameter!" ); const ct I(0.,1.); // imaginary unit const FieldVector one(1.); // vector filled with 1 const FieldVector iVec(ct(0.,1.)); // vector filled with I std::cout << __func__ << "\t \t ( " << Dune::className(one) << " and " << Dune::className(iVec) << ")" << std::endl; const bool isRealOne = std::is_same::field_type,typename Dune::FieldTraits::real_type>::value; const bool isRealIVec = std::is_same::field_type,typename Dune::FieldTraits::real_type> ::value; static_assert(isRealOne,"1-vector expected to be real"); static_assert(!isRealIVec,"i-vector expected to be complex"); ct result = ct(); ct length = ct(d); // one^H*one should equal d result = dot(one,one); FVECTORTEST_ASSERT(std::abs(result-length)<= myEps); result = one.dot(one); FVECTORTEST_ASSERT(std::abs(result-length)<= myEps); // iVec^H*iVec should equal d result = dot(iVec,iVec); FVECTORTEST_ASSERT(std::abs(result-length)<= myEps); result = iVec.dot(iVec); FVECTORTEST_ASSERT(std::abs(result-length)<= myEps); // test that we do conjugate first argument result = dot(one,iVec); FVECTORTEST_ASSERT(std::abs(result-length*I)<= myEps); result = dot(one,iVec); FVECTORTEST_ASSERT(std::abs(result-length*I)<= myEps); // test that we do not conjugate second argument result = dot(iVec,one); FVECTORTEST_ASSERT(std::abs(result+length*I)<= myEps); result = iVec.dot(one); FVECTORTEST_ASSERT(std::abs(result+length*I)<= myEps); // test that dotT does not conjugate at all result = dotT(one,one) + one*one; FVECTORTEST_ASSERT(std::abs(result-ct(2)*length)<= myEps); result = dotT(iVec,iVec) + iVec*iVec; FVECTORTEST_ASSERT(std::abs(result+ct(2)*length)<= myEps); result = dotT(one,iVec) + one*iVec; FVECTORTEST_ASSERT(std::abs(result-ct(2)*length*I)<= myEps); result = dotT(iVec,one) + iVec*one; FVECTORTEST_ASSERT(std::abs(result-ct(2)*length*I)<= myEps); } }; // scalar ordering doesn't work for complex numbers template struct DotProductTest { DotProductTest() { [[maybe_unused]] const rt myEps = Epsilon::value(); static_assert( ( std::is_same< typename Dune::FieldTraits::real_type, rt>::value ), "DotProductTest requires real data type as template parameter!" ); const FieldVector one(1.); // vector filled with 1 std::cout << __func__ << "\t \t ( " << Dune::className(one) << " only)" << std::endl; const bool isRealOne = std::is_same::field_type,typename Dune::FieldTraits::real_type>::value; static_assert(isRealOne,"1-vector expected to be real"); rt result = rt(); rt length = rt(d); // one^H*one should equal d result = dot(one,one); FVECTORTEST_ASSERT(abs(result-length)<= myEps); result = one.dot(one); FVECTORTEST_ASSERT(abs(result-length)<= myEps); // test that dotT does not conjugate at all result = dotT(one,one) + one*one; FVECTORTEST_ASSERT(abs(result-rt(2)*length)<= myEps); } }; template::value> struct FieldVectorTest { FieldVectorTest() { // --- test complex and real valued vectors FieldVectorMainTest(); FieldVectorMainTest,ft,d>(); DotProductTest(); // --- test next lower dimension FieldVectorTest(); } }; // specialisation for non-floating-point vectors template struct FieldVectorTest { FieldVectorTest() { // --- test real valued vectors FieldVectorMainTest(); DotProductTest(); // --- test next lower dimension FieldVectorTest(); } }; // specialization for 1d floating point vector template class FieldVectorTest { public: FieldVectorTest() { // --- real valued FieldVectorMainTest(); ScalarOperatorTest(); ScalarOrderingTest(); DotProductTest(); // --- complex valued FieldVectorMainTest,ft,1>(); ScalarOperatorTest< complex >(); // ordering doesn't work for complex numbers // --- test with an integer ScalarOperatorTest< ft, int >(); // --- test next lower dimension FieldVectorMainTest(); } }; // specialization for other 1d vectors template class FieldVectorTest { public: FieldVectorTest() { // --- real valued FieldVectorMainTest(); ScalarOperatorTest(); ScalarOrderingTest(); DotProductTest(); // --- test with an integer ScalarOperatorTest< ft, int >(); // --- test next lower dimension FieldVectorMainTest(); } }; template void checkNormNAN(V const &v, int line) { if (!std::isnan(v.one_norm())) { std::cerr << "error: norm not NaN: one_norm() on line " << line << " (type: " << Dune::className(v[0]) << ")" << std::endl; std::exit(-1); } if (!std::isnan(v.two_norm())) { std::cerr << "error: norm not NaN: two_norm() on line " << line << " (type: " << Dune::className(v[0]) << ")" << std::endl; std::exit(-1); } if (!std::isnan(v.infinity_norm())) { std::cerr << "error: norm not NaN: infinity_norm() on line " << line << " (type: " << Dune::className(v[0]) << ")" << std::endl; std::exit(-1); } } // Make sure that vectors with NaN entries have norm NaN. // See also bug flyspray/FS#1147 template void test_nan(T const &mynan) { { Dune::FieldVector v = { mynan, mynan }; checkNormNAN(v, __LINE__); } { Dune::FieldVector v = { mynan, 0 }; checkNormNAN(v, __LINE__); } { Dune::FieldVector v = { 0, mynan }; checkNormNAN(v, __LINE__); } } void test_infinity_norms() { std::complex threefour(3.0, -4.0); std::complex eightsix(8.0, -6.0); Dune::FieldVector, 2> v; v[0] = threefour; v[1] = eightsix; FVECTORTEST_ASSERT(std::abs(v.infinity_norm() -10.0) < 1e-10); // max(5,10) FVECTORTEST_ASSERT(std::abs(v.infinity_norm_real()-14.0) < 1e-10); // max(7,14) } void test_initialisation() { [[maybe_unused]] Dune::FieldVector const b = { 1, 2 }; FVECTORTEST_ASSERT(b[0] == 1); FVECTORTEST_ASSERT(b[1] == 2); } void fieldvectorMathclassifiersTest() { double nan = std::nan(""); double inf = std::numeric_limits::infinity(); FieldVector fv_normal(1.); FieldVector fv_nan(1.); FieldVector fv_inf(1.); fv_nan[2] = nan; fv_inf[2] = inf; //test vector containing only doubles if(Dune::isNaN(fv_normal) == true) { std::abort(); } if(Dune::isInf(fv_normal) == true) { std::abort(); } if(Dune::isFinite(fv_normal) == false) { std::abort(); } //test vector containing a NaN-entry if(Dune::isNaN(fv_nan) == false) { std::abort(); } if(Dune::isInf(fv_nan) == true) { std::abort(); } if(Dune::isFinite(fv_nan) == true) { std::abort(); } //test vector containing an infinity-entry if(Dune::isNaN(fv_inf) == true) { std::abort(); } if(Dune::isInf(fv_inf) == false) { std::abort(); } if(Dune::isFinite(fv_inf) == true) { std::abort(); } } int main() { { FieldVectorTest(); FieldVectorTest(); FieldVectorTest(); FieldVectorTest(); FieldVectorTest(); FieldVectorTest(); FieldVectorTest(); FieldVectorTest(); #if HAVE_GMP { // we skip the complex test and the int test, as these will be very hard to implement with GMPField typedef Dune::GMPField<128u> ft; FieldVectorMainTest(); FieldVectorMainTest(); FieldVectorMainTest(); FieldVectorMainTest(); ScalarOperatorTest(); ScalarOrderingTest(); DotProductTest(); } #endif // HAVE_GMP #if HAVE_QUADMATH { // we skip the int test, as these will be very hard to implement with Float128 typedef Dune::Float128 ft; FieldVectorMainTest(); FieldVectorMainTest(); FieldVectorMainTest(); FieldVectorMainTest(); ScalarOperatorTest(); ScalarOrderingTest(); DotProductTest(); } #endif //test the mathclassifiers Dune::isNaN, Dune::isInf, Dune::isFinite fieldvectorMathclassifiersTest(); { double nan = std::nan(""); test_nan(nan); } { std::complex nan( std::nan(""), 17 ); test_nan(nan); } test_infinity_norms(); test_initialisation(); } } dune-common-2.8.0/dune/common/test/genericiterator_compile_fail.cc000066400000000000000000000011271411343567400253550ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include int main(){ // Test the TestIterator; typedef TestContainer Container; Container bidicontainer; Container::const_iterator cit = bidicontainer.begin(); //This should fail since making a mutable iterator from a const iterator //discard qualifiers [[maybe_unused]] Container::iterator it; it = cit; } dune-common-2.8.0/dune/common/test/hybridutilitiestest.cc000066400000000000000000000055461411343567400236120ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include template auto incrementAll(C&& c) { using namespace Dune::Hybrid; forEach(c, [](auto&& ci) { ++ci; }); } template auto addIndex(C&& c) { using namespace Dune::Hybrid; forEach(integralRange(Dune::Hybrid::size(c)), [&](auto&& i) { c[i] += i; }); } template auto incAndAppendToFirst(C&& c) { using namespace Dune::Hybrid; forEach(integralRange(Dune::Hybrid::size(c)), [&](auto&& i) { using namespace Dune::Hybrid; using namespace Dune::Indices; ifElse(equals(i, _0), [&](auto id) { id(c[i]).append("+1"); }, [&](auto id) { ++id(c[i]); }); }); } template constexpr auto sum(C&& c) { using namespace Dune::Hybrid; using namespace Dune::Indices; return accumulate(c, 0.0, [](auto&& a, auto&& b) { return a+b; }); } template auto sumSubsequence(C&& c, I&& indices) { using namespace Dune::Hybrid; double result = 0; forEach(indices, [&](auto i) { result += Dune::Hybrid::elementAt(c, i); }); return result; } int main() { auto vector = std::vector{1, 2, 3}; auto numberTuple = Dune::makeTupleVector(0.1, 2, 3); Dune::TestSuite test; incrementAll(vector); test.check(vector == std::vector{2, 3, 4}) << "Incrementing vector entries with Hybrid::forEach failed."; incrementAll(numberTuple); test.check(numberTuple == Dune::makeTupleVector(1.1, 3, 4)) << "Incrementing tuple entries with Hybrid::forEach failed."; addIndex(vector); test.check(vector == std::vector{2, 4, 6}) << "Adding indices to vector entries with Hybrid::forEach failed."; addIndex(numberTuple); test.check(numberTuple == Dune::makeTupleVector(1.1, 4, 6)) << "Adding indices to vector entries with Hybrid::forEach failed."; auto mixedTuple = Dune::makeTupleVector(std::string("1"), 2, 3); incAndAppendToFirst(mixedTuple); test.check(mixedTuple == Dune::makeTupleVector(std::string("1+1"), 3, 4)) << "Adding indices to vector entries with Hybrid::forEach failed."; constexpr auto values = std::make_integer_sequence(); test.check((30*29)/2 == sum(values)) << "accumulate() yields incorrect result."; test.check((29*28)/2 == sumSubsequence(values, std::make_integer_sequence())) << "Summing up subsequence failed."; // Compile time checks static_assert(sum(values) == (30*29)/2, "Wrong compile time sum!"); constexpr auto numberTupleConstexpr = Dune::makeTupleVector(0.1, 2, 3); static_assert(sum(numberTupleConstexpr) == 5.1, "Wrong compile time sum!"); return test.exit(); } dune-common-2.8.0/dune/common/test/indicestest.cc000066400000000000000000000011331411343567400217770ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include using namespace Dune; int main() { using namespace Dune::Indices; // Test whether indices can be used to index a data structure Dune::TupleVector v; v[_0] = 42; v[_1] = 3.14; v[_2] = 2.7; // Test whether the indices can be used as numbers std::get<_0>(v) = 43; std::get<_1>(v) = 4.14; std::get<_2>(v) = 3.7; return 0; } dune-common-2.8.0/dune/common/test/iscallabletest.cc000066400000000000000000000050631411343567400224620ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include int main() { Dune::TestSuite test; { auto f = [](int /*i*/) { return 0; }; using F = decltype(f); test.check(Dune::IsCallable() == true) << "Dune::IsCallable does not accept copy from r-value"; test.check(Dune::IsCallable() == true) << "Dune::IsCallable does not accept copy from l-value reference"; test.check(Dune::IsCallable() == true) << "Dune::IsCallable does not accept copy from r-value reference"; test.check(Dune::IsCallable() == false) << "Dune::IsCallable accepts invalid argument type"; test.check(Dune::IsCallable() == false) << "Dune::IsCallable accepts invalid argument count"; test.check(Dune::IsCallable() == true) << "Dune::IsCallable does not accept valid return type"; test.check(Dune::IsCallable() == false) << "Dune::IsCallable accepts invalid return type"; } { auto f = [](const int& /*i*/) {}; using F = decltype(f); test.check(Dune::IsCallable() == true) << "Dune::IsCallable does not accept const& temporary from r-value"; test.check(Dune::IsCallable() == true) << "Dune::IsCallable does not accept const& temporary from l-value reference"; test.check(Dune::IsCallable() == true) << "Dune::IsCallable does not accept const& temporary from r-value reference"; } { auto f = [](int& /*i*/) {}; using F = decltype(f); test.check(Dune::IsCallable() == false) << "Dune::IsCallable accepts l-value reference from r-value"; test.check(Dune::IsCallable() == true) << "Dune::IsCallable does not accept l-value reference from l-value reference"; test.check(Dune::IsCallable() == false) << "Dune::IsCallable accepts l-value reference from r-value reference"; } { auto f = [](int&& /*i*/) {}; using F = decltype(f); test.check(Dune::IsCallable() == true) << "Dune::IsCallable does not accept r-value reference from r-value"; test.check(Dune::IsCallable() == false) << "Dune::IsCallable accepts r-value reference from l-value reference"; test.check(Dune::IsCallable() == true) << "Dune::IsCallable does not accept r-value reference from r-value reference"; } return test.exit(); } dune-common-2.8.0/dune/common/test/iteratorfacadetest.cc000066400000000000000000000025621411343567400233450ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include template void randomize(Container& cont){ srand(300); double size=1000; for(int i=0; i < 100; i++) { cont[i] = (size*(rand()/(RAND_MAX+1.0))); } } template void print(Container& cont){ for(int i=0; i < 100; i++) std::cout< int containerTest(Container & container) { randomize(container); // print(container); //std::sort(container.begin(), container.end()); //print(container); const Container ccontainer(container); int ret=0; Printer print; ret += testIterator(container, print); ret += testIterator(ccontainer, print); return ret; } int main(){ // Test the TestIterator; TestContainer forwardcontainer; TestContainer bidicontainer; TestContainer randomcontainer; int ret=0; ret += containerTest(forwardcontainer); ret += containerTest(bidicontainer); ret += containerTest(randomcontainer); return (ret); } dune-common-2.8.0/dune/common/test/iteratorfacadetest.hh000066400000000000000000000022201411343567400233460ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_ITERATORFACADETEST_HH #define DUNE_ITERATORFACADETEST_HH #include #include #include template class IteratorFacade=Dune::RandomAccessIteratorFacade> class TestContainer { public: typedef Dune::GenericIterator,T,T&,std::ptrdiff_t,IteratorFacade> iterator; typedef Dune::GenericIterator,const T,const T&,std::ptrdiff_t,IteratorFacade> const_iterator; TestContainer(){ for(int i=0; i < 100; i++) values_[i]=i; } iterator begin(){ return iterator(*this, 0); } const_iterator begin() const { return const_iterator(*this, 0); } iterator end(){ return iterator(*this, 100); } const_iterator end() const { return const_iterator(*this, 100); } T& operator[](int i){ return values_[i]; } const T& operator[](int i) const { return values_[i]; } private: T values_[100]; }; #endif dune-common-2.8.0/dune/common/test/iteratorfacadetest2.cc000066400000000000000000000007531411343567400234270ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "dummyiterator.hh" int main(){ // Check that iterator can be compared with iterator as soon as // a conversion from iterator to iterator exists int value = 0; dummyiterator mit(value); dummyiterator cit(value); bool result = mit == cit; if(result) return 0; else return 1; } dune-common-2.8.0/dune/common/test/iteratortest.hh000066400000000000000000000312701411343567400222310ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_TEST_ITERATORTEST_HH #define DUNE_COMMON_TEST_ITERATORTEST_HH #include #include #include #include /** * @brief Test whether the class Iter implements the interface of an STL output iterator * * @param iterator Iterator to test * @param iterations Number of times that 'iterator' can be safely incremented * @param value A value that is sent to the output iterator */ template void testOutputIterator(Iter iterator, std::size_t iterations, Value value) { // Test whether iterator is copy-constructible // The new iterator object will go out of scope at the end of this method, and hence // destructibility will also be tested. Iter tmp1(iterator); // Test whether iterator is copy-assignable Iter tmp2 = iterator; // Test whether pre-increment and assignment works for (size_t i=0; i construction allows one to test whether the type A exists at all, // without assuming anything further about A. static_assert(Dune::AlwaysTrue::difference_type>::value, "std::iterator_traits::difference_type is not defined!"); static_assert(Dune::AlwaysTrue::value_type>::value, "std::iterator_traits::value_type is not defined!"); static_assert(Dune::AlwaysTrue::pointer>::value, "std::iterator_traits::pointer is not defined!"); static_assert(Dune::AlwaysTrue::reference>::value, "std::iterator_traits::reference is not defined!"); // Make sure the iterator_category is properly set static_assert(std::is_same::iterator_category, std::output_iterator_tag>::value, "std::iterator_traits::iterator_category is not properly defined!"); } /** * @brief Test whether the class Iter implements the interface of an STL forward iterator * * @param begin Iterator positioned at the start * @param end Iterator positioned at the end * @param opt Functor for doing whatever one wants */ template int testForwardIterator(Iter begin, Iter end, Opt& opt) { // Return status int ret=0; // Test whether iterator is can be value-initialized. // These object will go out of scope at the end of this method, and hence // it will also test whether these objects are destructible. Iter defaultConstructedIterator1{}, defaultConstructedIterator2{}; // Since C++14, value-initialized forward iterators are specified as the // end iterator of the same, empty sequence. Hence, they should compare equal. // Notice that value-initialization and default-initialization are not the // same for raw pointers. Since these are POD, value-initialization leads // to zero-initialization while default-initialization would leave them // uninitialized such that the comparison is undefined behaviour. if (defaultConstructedIterator1 != defaultConstructedIterator2) { std::cerr<<"Default constructed iterators do not compare equal for "+Dune::className()+"."< construction allows one to test whether the type A exists at all, // without assuming anything further about A. static_assert(std::is_same::difference_type, typename std::iterator_traits::difference_type>::value, "std::iterator_traits::difference_type is not defined!"); static_assert(std::is_same::value_type, typename std::iterator_traits::value_type>::value, "std::iterator_traits::value_type is not defined!"); static_assert(std::is_same::pointer, typename std::iterator_traits::pointer>::value, "std::iterator_traits::pointer is not defined!"); static_assert(std::is_same::reference, typename std::iterator_traits::reference>::value, "std::iterator_traits::reference is not defined!"); // Make sure the iterator_category is properly set static_assert(std::is_same::iterator_category, std::forward_iterator_tag>::value or std::is_same::iterator_category, std::bidirectional_iterator_tag>::value or std::is_same::iterator_category, std::random_access_iterator_tag>::value, "std::iterator_traits::iterator_category is not properly defined!"); return ret; } /** * @brief Tests the capabilities of a bidirectional iterator. * * Namely it test whether random positions can be reached from * each directions. * * @param begin Iterator positioned at the stsrt. * @param end Iterator positioned at the end. * @param opt Functor for doing whatever one wants. */ template int testBidirectionalIterator(Iter begin, Iter end, Opt opt) { int ret=testForwardIterator(begin, end, opt); for(Iter pre = end, post = end; pre != begin; ) { if(pre != post--) { std::cerr << "Postdecrement did not return the old iterator" << std::endl; ++ret; } if(--pre != post) { std::cerr << "Predecrement did not return the new iterator" << std::endl; ++ret; } opt(*pre); } typename Iter::difference_type size = std::distance(begin, end); srand(300); int no= (size>10) ? 10 : size; for(int i=0; i < no; i++) { int index = static_cast(size*(rand()/(RAND_MAX+1.0))); int backwards=size-index; Iter tbegin = begin; Iter tend = end; for(int j=0; j < index; j++) ++tbegin; for(int j=0; j < backwards; j++) --tend; if(tbegin != tend) { std::cerr<<"Did not reach same index by starting forward from " <<"begin and backwards from end."< int testRandomAccessIterator(Iter begin, Iter end, Opt opt){ int ret=testBidirectionalIterator(begin, end, opt); typename Iter::difference_type size = end-begin; srand(300); int no= (size>10) ? 10 : size; for(int i=0; i < no; i++) { int index = static_cast(size*(rand()/(RAND_MAX+1.0))); opt(begin[index]); } // Test the less than operator if(begin != end &&!( begin= 0) { std::cerr<<"begin!=end, but begin-end >= 0!"<(size*(rand()/(RAND_MAX+1.0))); Iter rand(begin), test(begin), res{}; rand+=index; if((res=begin+index) != rand) { std::cerr << " i+n should have the result i+=n, where i is the " <<"iterator and n is the difference type!" <(size*(rand()/(RAND_MAX+1.0))); Iter iter2 = begin+static_cast(size*(rand()/(RAND_MAX+1.0))); typename Iter::difference_type diff = iter2 -iter1; if((iter1+diff)!=iter2) { std::cerr<< "i+(j-i) = j should hold, where i,j are iterators!"< int testIterator(Iter& begin, Iter& end, Opt& opt, iterator_category cat); template int testIterator(Iter& begin, Iter& end, Opt& opt, std::forward_iterator_tag) { return testForwardIterator(begin, end, opt); } template int testIterator(Iter& begin, Iter& end, Opt& opt, std::bidirectional_iterator_tag) { return testBidirectionalIterator(begin, end, opt); } template int testIterator(Iter& begin, Iter& end, Opt& opt, std::random_access_iterator_tag) { // std::cout << "Testing iterator "; int ret = testRandomAccessIterator(begin, end, opt); //std::cout< int testConstIterator(Iter& begin, Iter& end, Opt& opt) { //std::cout << "Testing constant iterator: "; int ret=testIterator(begin, end, opt, typename std::iterator_traits::iterator_category()); //std::cout< struct TestSorting { template static void testSorting(Container&, IteratorTag) {} template static void testSorting(Container& c, std::random_access_iterator_tag) { std::sort(c.begin(), c.end()); } } ; template<> struct TestSorting { template static void testSorting(Container&, std::random_access_iterator_tag) {} template static void testSorting(Container&, IteratorTag) {} }; template int testIterator(Container& c, Opt& opt) { typename Container::iterator begin=c.begin(), end=c.end(); typename Container::const_iterator cbegin(begin); [[maybe_unused]] typename Container::const_iterator cbegin1 = begin; typename Container::const_iterator cend=c.end(); int ret = 0; TestSorting::testSorting(c, typename std::iterator_traits::iterator_category()); if(end!=cend || cend!=end) { std::cerr<<"constant and mutable iterators should be equal!"< int testIterator(Container& c, Opt& opt) { return testIterator(c,opt); } template void testAssignment(Iter begin, Iter end, Opt&) { //std::cout << "Assignment: "; for(; begin!=end; begin++) *begin=typename std::iterator_traits::value_type(); //std::cout<<" Done."<< std::endl; } template int testIterator(Iter& begin, Iter& end, Opt& opt) { testAssignment(begin, end, opt); return testConstIterator(begin, end, opt); } template class Printer { typename std::remove_const::type res; public: Printer() : res(0){} void operator()(const T& t){ res+=t; // std::cout << t <<" "; } }; template int testIterator(const Container& c, Opt& opt) { typename Container::const_iterator begin=c.begin(), end=c.end(); return testConstIterator(begin,end, opt); } template int testIterator(Container& c) { Printer::value_type> print; return testIterator(c,print); } #endif dune-common-2.8.0/dune/common/test/lrutest.cc000066400000000000000000000020471411343567400211700ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include void lru_test() { std::cout << "testing Dune::lru\n"; Dune::lru lru; lru.insert(10, 1.0); assert(lru.front() == lru.back()); lru.insert(11, 2.0); assert(lru.front() == 2.0 && lru.back() == 1.0); lru.insert(12, 99); lru.insert(13, 1.3); lru.insert(14, 12345); lru.insert(15, -17); assert(lru.front() == -17 && lru.back() == 1.0); // update lru.insert(10); assert(lru.front() == 1.0 && lru.back() == 2.0); // update lru.touch(13); assert(lru.front() == 1.3 && lru.back() == 2.0); // remove item lru.pop_front(); assert(lru.front() == 1.0 && lru.back() == 2.0); // remove item lru.pop_back(); assert(lru.front() == 1.0 && lru.back() == 99); std::cout << "... passed\n"; } int main (int argc, char** argv) { Dune::MPIHelper::instance(argc,argv); lru_test(); return 0; } dune-common-2.8.0/dune/common/test/mathclassifierstest.cc000066400000000000000000000047031411343567400235500ustar00rootroot00000000000000#include #include #include #include int main() { //Initialize some variables int a = 42; const int b = 42; double nan = std::nan(""); double inf = std::numeric_limits::infinity(); std::complex complex_nonan(42., 42.); std::complex complex_nan1(42.,nan); std::complex complex_nan2(nan, 42.); std::complex complex_nan3(nan, nan); std::complex complex_noinf(42., 42.); std::complex complex_inf1(42.,inf); std::complex complex_inf2(inf, 42.); std::complex complex_inf3(inf, inf); std::cout << std::boolalpha //check isNaN() << "isNaN(int): " << Dune::isNaN(a) << "\n" << "isNaN(const int): " << Dune::isNaN(b) << "\n" << "isNaN(42): " << Dune::isNaN(42) << "\n" << "isNaN(nan): " << Dune::isNaN(nan) << "\n" << "isNaN(inf): " << Dune::isNaN(inf) << "\n" << "isNaN(std::complex without NaN): " << Dune::isNaN(complex_nonan) << "\n" << "isNaN(std::complex with NaN): " << Dune::isNaN(complex_nan1) << " " << Dune::isNaN(complex_nan2) << " " << Dune::isNaN(complex_nan3) << "\n" //check isInf() << "isInf(int): " << Dune::isInf(a) << "\n" << "isInf(const int): " << Dune::isInf(b) << "\n" << "isInf(42): " << Dune::isInf(42) << "\n" << "isInf(inf): " << Dune::isInf(inf) << "\n" << "isInf(std::complex without inf): " << Dune::isInf(complex_noinf) << "\n" << "isInf(std::complex with inf): " << Dune::isInf(complex_inf1) << " " << Dune::isInf(complex_inf2) << " " << Dune::isInf(complex_inf3) << "\n" //check isFinite() << "isFinite(int): " << Dune::isFinite(a) << "\n" << "isFinite(const int): " << Dune::isFinite(b) << "\n" << "isFinite(42): " << Dune::isFinite(42) << "\n" << "isFinite(inf): " << Dune::isFinite(inf) << "\n" << "isFinite(std::complex without inf): " << Dune::isFinite(complex_noinf) << "\n" << "isFinite(std::complex with inf): " << Dune::isFinite(complex_inf1) << " " << Dune::isFinite(complex_inf2) << " " << Dune::isFinite(complex_inf3) << "\n" << std::endl; } dune-common-2.8.0/dune/common/test/mathtest.cc000066400000000000000000000033241411343567400213160ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include #include using namespace Dune::Hybrid; using namespace Dune::Indices; using Dune::TestSuite; template constexpr inline static auto next(std::integral_constant) -> std::integral_constant { return {}; } template auto testStaticFactorial (std::integral_constant _k = {}) -> TestSuite { TestSuite t; std::cout << "test static factorial\n{"; forEach(integralRange(_k), [&](auto _i) { auto value = Dune::factorial(_i); t.check(decltype(value)::value == Dune::Factorial::factorial); std::cout<< ' ' << value() << ','; }); std::cout << "};\n\n"; return t; } template auto testStaticBinomial (std::integral_constant _k = {}) -> TestSuite { TestSuite t; std::cout << "test static binomial\n"; forEach(integralRange(_k), [&](auto _i) { std::cout << "{"; forEach(integralRange(next(_i)), [&](auto _j) { const auto value = Dune::binomial(_i,_j); auto control = Dune::Factorial::factorial / Dune::Factorial::factorial / Dune::Factorial::factorial; t.check(decltype(value)::value == control); std::cout<< ' ' << value() << ','; }); std::cout << "};\n"; }); std::cout << "\n"; return t; } int main(int argc, char** argv) { TestSuite t; t.subTest(testStaticFactorial(_5)); t.subTest(testStaticBinomial(_5)); return t.exit(); } dune-common-2.8.0/dune/common/test/metistest.cc000066400000000000000000000051651411343567400215130ustar00rootroot00000000000000#include #include #include #if ! HAVE_METIS #error "METIS is required for this test" #endif #if HAVE_SCOTCH_METIS extern "C" { #include } #endif extern "C" { #include } #if HAVE_SCOTCH_METIS && !defined(SCOTCH_METIS_RETURN) // NOTE: scotchmetis does not define a return type for METIS functions #define METIS_OK 1 #endif int main() { #if defined(REALTYPEWIDTH) || defined(SCOTCH_METIS_DATATYPES) using real_t = ::real_t; #else using real_t = double; #endif #if defined(IDXTYPEWIDTH) || defined(SCOTCH_METIS_DATATYPES) using idx_t = ::idx_t; #elif HAVE_SCOTCH_METIS using idx_t = SCOTCH_Num; #else using idx_t = int; #endif idx_t nVertices = 6; // number of vertices idx_t nCon = 1; // number of constraints idx_t nParts = 2; // number of partitions // Partition index for each vertex. Will be filled by METIS_PartGraphKway. std::vector part(nVertices, 0); // Indices of starting points in adjacent array std::vector xadj{0,2,5,7,9,12,14}; // Adjacent vertices in consecutive order std::vector adjncy{1,3,0,4,2,1,5,0,4,3,1,5,4,2}; // Weights of vertices. If all weights are equal, they can be set to 1. std::vector vwgt(nVertices * nCon, 1); // Load-imbalance tolerance for each constraint. #if HAVE_SCOTCH_METIS // NOTE: scotchmetis interprets this parameter differently std::vector ubvec(nCon, 0.01); #else std::vector ubvec(nCon, 1.001); #endif #if METIS_API_VERSION >= 5 std::cout << "using METIS API version 5\n"; idx_t objval; int err = METIS_PartGraphKway(&nVertices, &nCon, xadj.data(), adjncy.data(), vwgt.data(), nullptr, nullptr, &nParts, nullptr, ubvec.data(), nullptr, &objval, part.data()); #elif METIS_API_VERSION >= 3 std::cout << "using METIS API version 3\n"; int wgtflag = 2; int numflag = 0; int options = 0; // use default options int edgecut; #if HAVE_SCOTCH_METIS && ! defined(SCOTCH_METIS_RETURN) METIS_PartGraphKway(&nVertices, xadj.data(), adjncy.data(), vwgt.data(), nullptr, &wgtflag, &numflag, &nParts, &options, &edgecut, part.data()); int err = METIS_OK; #else int err = METIS_PartGraphKway(&nVertices, xadj.data(), adjncy.data(), vwgt.data(), nullptr, &wgtflag, &numflag, &nParts, &options, &edgecut, part.data()); #endif #endif // METIS_API_VERSION if (err != METIS_OK) return 1; for (std::size_t part_i = 0; part_i < part.size(); ++part_i) { // partition index must be in range [0,nParts) if (part[part_i] >= nParts) return 2; std::cout << part_i << " " << part[part_i] << std::endl; } return 0; }dune-common-2.8.0/dune/common/test/mpicollectivecommunication.cc000066400000000000000000000031401411343567400251060ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include int main(int argc, char** argv) { Dune::TestSuite t; typedef Dune::MPIHelper Helper; Helper& mpi = Helper::instance(argc, argv); { typedef Helper::MPICommunicator MPIComm; Dune::Communication comm(mpi.getCommunicator()); enum { length = 5 }; double values[5]; for(int i=0; i #include #include #include int main(int argc, char** argv) { Dune::TestSuite t; typedef Dune::MPIHelper Helper; Helper& mpi = Helper::instance(argc, argv); { typedef Helper::MPICommunicator MPIComm; Dune::Communication comm(mpi.getCommunicator()); enum { length = 5 }; double values[5]; for(int i=0; i #include #include int main(int argc, char** argv) { Dune::MPIHelper & mpihelper = Dune::MPIHelper::instance(argc, argv); if (mpihelper.rank() == 0) std::cout << "---- default constructor" << std::endl; try { // at the end of this block the guard is destroyed and possible exceptions are communicated { Dune::MPIGuard guard; if (mpihelper.rank() > 0) DUNE_THROW(Dune::Exception, "Fakeproblem on process " << mpihelper.rank()); guard.finalize(); } } catch (Dune::Exception & e) { std::cout << "Error (rank " << mpihelper.rank() << "): " << e.what() << std::endl; } mpihelper.getCommunication().barrier(); if (mpihelper.rank() == 0) std::cout << "---- guard(MPI_COMM_WORLD)" << std::endl; try { #if HAVE_MPI // at the end of this block the guard is destroyed and possible exceptions are communicated { Dune::MPIGuard guard(MPI_COMM_WORLD); if (mpihelper.rank() > 0) DUNE_THROW(Dune::Exception, "Fakeproblem on process " << mpihelper.rank()); guard.finalize(); } #else std::cout << "Info: no mpi used\n"; #endif } catch (Dune::Exception & e) { std::cout << "Error (rank " << mpihelper.rank() << "): " << e.what() << std::endl; } mpihelper.getCommunication().barrier(); if (mpihelper.rank() == 0) std::cout << "---- guard(MPIHelper)" << std::endl; try { // at the end of this block the guard is destroyed and possible exceptions are communicated { Dune::MPIGuard guard(mpihelper); if (mpihelper.rank() > 0) DUNE_THROW(Dune::Exception, "Fakeproblem on process " << mpihelper.rank()); guard.finalize(); } } catch (Dune::Exception & e) { std::cout << "Error (rank " << mpihelper.rank() << "): " << e.what() << std::endl; } mpihelper.getCommunication().barrier(); if (mpihelper.rank() == 0) std::cout << "---- manual error" << std::endl; try { // at the end of this block the guard is destroyed and possible exceptions are communicated { Dune::MPIGuard guard; guard.finalize(mpihelper.rank() > 0); } } catch (Dune::Exception & e) { std::cout << "Error (rank " << mpihelper.rank() << "): " << e.what() << std::endl; } mpihelper.getCommunication().barrier(); if (mpihelper.rank() == 0) std::cout << "---- done" << std::endl; } dune-common-2.8.0/dune/common/test/mpihelpertest.cc000066400000000000000000000014751411343567400223570ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include int main(int argc, char** argv) { #ifdef MPIHELPER_PREINITIALIZE #if HAVE_MPI MPI_Init(&argc, &argv); #endif #endif typedef Dune::MPIHelper Helper; { Helper& mpi = Helper::instance(argc, argv); [[maybe_unused]] Helper::MPICommunicator comm = mpi.getCommunicator(); comm= mpi.getCommunicator(); } { Helper& mpi = Helper::instance(argc, argv); [[maybe_unused]] Helper::MPICommunicator comm = mpi.getCommunicator(); comm= mpi.getCommunicator(); #ifdef MPIHELPER_PREINITIALIZE #if HAVE_MPI MPI_Finalize(); #endif #endif } std::cout << "We are at the end!"< #include #include #include struct Bar { int bar() const { return 0; } }; int main() { Dune::TestSuite test; { auto foo = Dune::overload( [](double /*i*/) { return 0; }, [](int /*i*/) { return 1; }, [](long /*i*/) { return 2; }); test.check(foo(3.14) == 0) << "incorrect overload selected from OverloadSet"; test.check(foo(int(42)) == 1) << "incorrect overload selected from OverloadSet"; test.check(foo(long(42)) == 2) << "incorrect overload selected from OverloadSet"; } { auto foo = Dune::orderedOverload( [](double /*i*/) { return 0; }, [](int /*i*/) { return 1; }, [](long /*i*/) { return 2; }); test.check(foo(3.14) == 0) << "incorrect overload selected from OverloadSet"; test.check(foo(int(42)) == 0) << "incorrect overload selected from OverloadSet"; test.check(foo(long(42)) == 0) << "incorrect overload selected from OverloadSet"; } { auto foo = Dune::overload( [](const int& /*i*/) { return 0; }, [](int&& /*i*/) { return 1; }); int i = 0; test.check(foo(long(42)) == 1) << "incorrect overload selected from OverloadSet"; test.check(foo(int(42)) == 1) << "incorrect overload selected from OverloadSet"; test.check(foo(i) == 0) << "incorrect overload selected from OverloadSet"; } { auto foo = Dune::orderedOverload( [](const int& /*i*/) { return 0; }, [](int&& /*i*/) { return 1; }); int i = 0; test.check(foo(long(42)) == 0) << "incorrect overload selected from OverloadSet"; test.check(foo(int(42)) == 0) << "incorrect overload selected from OverloadSet"; test.check(foo(i) == 0) << "incorrect overload selected from OverloadSet"; } { auto t = std::make_tuple(42, "foo", 3.14); auto typeToName = Dune::overload( [](int) { return "int"; }, [](long) { return "long"; }, [](std::string) { return "string"; }, [](float) { return "float"; }, [](double) { return "double"; }); std::string tupleTypes; Dune::Hybrid::forEach(t, [&](auto&& ti) { tupleTypes += typeToName(ti); }); test.check(tupleTypes == "intstringdouble") << "traversal of tuple called incorrect overloads"; } { // Check if templated and non-templed overloads work // nicely together. auto f = Dune::overload( [](const int& t) { (void) t;}, [](const auto& t) { t.bar();}); f(0); } return test.exit(); } dune-common-2.8.0/dune/common/test/parameterizedobjectfactorysingleton.cc000066400000000000000000000011361411343567400270220ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include #include #include #include "parameterizedobjectfactorysingleton.hh" DefineImplementation(InterfaceA, Aix, int); DefineImplementation(InterfaceA, Bix, int); int init_Factory() { globalPtrFactory().define("Aix"); globalPtrFactory().define("Bix", [](int i) { return std::make_unique(i); }); return 0; } [[maybe_unused]] static const int init = init_Factory(); dune-common-2.8.0/dune/common/test/parameterizedobjectfactorysingleton.hh000066400000000000000000000024731411343567400270410ustar00rootroot00000000000000#ifndef DUNE_COMMON_TEST_PARAMETERIZEDOBJECTFACTORYSINGLETON_HH #define DUNE_COMMON_TEST_PARAMETERIZEDOBJECTFACTORYSINGLETON_HH #include #include #include #define DefineImplementation2(IF,T) \ struct T : public IF { \ T() {} \ std::string info() override { \ return #T; \ } \ } #define DefineImplementation(IF,T,...) \ struct T : public IF { \ T(__VA_ARGS__) {} \ std::string info() override { \ return #T; \ } \ } struct InterfaceA { virtual std::string info() = 0; virtual ~InterfaceA() = default; }; struct InterfaceB { virtual std::string info() = 0; virtual ~InterfaceB() = default; }; template Dune::ParameterizedObjectFactory(int)> & globalPtrFactory() { return Dune::Singleton(int)>>::instance(); } #endif //#ifndef DUNE_COMMON_TEST_PARAMETERIZEDOBJECTFACTORYSINGLETON_HH dune-common-2.8.0/dune/common/test/parameterizedobjecttest.cc000066400000000000000000000071431411343567400244130ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include #include #include "parameterizedobjectfactorysingleton.hh" DefineImplementation(InterfaceA, Ai, int); DefineImplementation(InterfaceA, Bi, int); DefineImplementation2(InterfaceA, Ax); DefineImplementation2(InterfaceA, Bx); DefineImplementation(InterfaceA, Ad, const Dune::ParameterTree&); DefineImplementation(InterfaceA, Bd, Dune::ParameterTree); DefineImplementation(InterfaceB, Ais, int, std::string); DefineImplementation(InterfaceB, Bis, int, std::string); #define CheckInstance2(F,T) \ assert(#T == F.create(#T)->info()) #define CheckInstance(F,T,...) \ assert(#T == F.create(#T,##__VA_ARGS__)->info()) struct AImp : public InterfaceA { AImp(std::string s) : s_(s) {} AImp(const AImp& /*other*/) : s_("copied") {} std::string info() override { return s_; } std::string s_; }; int main() { // int as parameter // Dune::ParameterizedObjectFactory(int)> FactoryA; globalPtrFactory().define("Ai"); globalPtrFactory().define("Bi"); globalPtrFactory().define("Ax", [](int /*i*/) { return std::make_unique(); }); CheckInstance(globalPtrFactory(), Ai, 0); CheckInstance(globalPtrFactory(), Bi, 1); CheckInstance(globalPtrFactory(), Ax, 1); // int as parameter for external factory CheckInstance(globalPtrFactory(), Aix, 0); CheckInstance(globalPtrFactory(), Bix, 1); // default constructor Dune::ParameterizedObjectFactory()> FactoryAd; FactoryAd.define("Ax"); FactoryAd.define("Bx"); FactoryAd.define("Ai", []() { return std::make_shared(0); }); AImp aimp("onStack"); FactoryAd.define("AImp", [&]() { return Dune::stackobject_to_shared_ptr(aimp); }); FactoryAd.define("AImp2", Dune::stackobject_to_shared_ptr(aimp)); FactoryAd.define("AImp3", std::make_shared("shared")); Dune::ParameterTree param; CheckInstance2(FactoryAd, Ax); CheckInstance2(FactoryAd, Bx); CheckInstance2(FactoryAd, Ai); std::cout << FactoryAd.create("AImp")->info() << std::endl; std::cout << FactoryAd.create("AImp2")->info() << std::endl; std::cout << FactoryAd.create("AImp3")->info() << std::endl; // explicitly request the default constructor Dune::ParameterizedObjectFactory()> FactoryAx; FactoryAx.define("Ax"); FactoryAx.define("Bx"); CheckInstance2(FactoryAx, Ax); CheckInstance2(FactoryAx, Bx); // multiple parameters Dune::ParameterizedObjectFactory(int, std::string)> FactoryB; FactoryB.define("Ais"); FactoryB.define("Bis"); CheckInstance(FactoryB, Ais, 0, std::to_string(2)); CheckInstance(FactoryB, Bis, 1, "Hallo"); // check for ambiguous overloads Dune::ParameterizedObjectFactory FactoryBool; FactoryBool.define("true",true); FactoryBool.define("false",[](){return false;}); // value semantics Dune::ParameterizedObjectFactory(int)> FactoryC; FactoryC.define("fi", [](int i) { return [=](double x) { return x+i;}; }); FactoryC.define("fi1", [](int i) { return [=](double x) { return x+i+1;}; }); assert(FactoryC.create("fi", 42)(0) == 42); assert(FactoryC.create("fi1", 42)(0) == 43); } dune-common-2.8.0/dune/common/test/parametertreelocaletest.cc000066400000000000000000000102051411343567400244010ustar00rootroot00000000000000#if HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include // This assert macro does not depend on the value of NDEBUG #define check_assert(expr) \ do \ { \ if(!(expr)) \ { \ std::cerr << __FILE__ << ":" << __LINE__ << ": check_assert(" \ << #expr << ") failed" << std::endl; \ std::abort(); \ } \ } while(false) // Check that the given expression throws the given exception #define check_throw(expr, except) \ do { \ try { \ expr; \ std::cerr << __FILE__ << ":" << __LINE__ << ": " << #expr \ << " should throw " << #except << std::endl; \ std::abort(); \ } \ catch(const except&) {} \ catch(...) { \ std::cerr << __FILE__ << ":" << __LINE__ << ": " << #expr \ << " should throw " << #except << std::endl; \ std::abort(); \ } \ } while(false) // globally set a locale that uses "," as the decimal seperator. // return false if no such locale is installed on the system bool setCommaLocale() { static char const* const commaLocales[] = { "de", "de@euro", "de.UTF-8", "de_AT", "de_AT@euro", "de_AT.UTF-8", "de_BE", "de_BE@euro", "de_BE.UTF-8", "de_CH", "de_CH@euro", "de_CH.UTF-8", "de_DE", "de_DE@euro", "de_DE.UTF-8", "de_LI", "de_LI@euro", "de_LI.UTF-8", "de_LU", "de_LU@euro", "de_LU.UTF-8", NULL }; for(char const* const* loc = commaLocales; *loc; ++loc) { try { std::locale::global(std::locale(*loc)); std::cout << "Using comma-locale " << std::locale().name() << std::endl; return true; } catch(const std::runtime_error&) { } } std::cout << "No comma-using locale found on system, tried the following:"; std::string sep = " "; for(char const* const* loc = commaLocales; *loc; ++loc) { std::cout << sep << *loc; sep = ", "; } std::cout << std::endl; return false; } int main() { if(!setCommaLocale()) { std::cerr << "No locale using comma as decimal seperator found on system" << std::endl; return 77; } { // Try with comma Dune::ParameterTree ptree; check_throw((ptree["setting"] = "42,42", ptree.get("setting")), Dune::RangeError); check_throw((ptree["setting"] = "42 2,5", ptree.get >("setting")), Dune::RangeError); check_throw((ptree["setting"] = "42 2,5", ptree.get >("setting")), Dune::RangeError); } { // Try with point Dune::ParameterTree ptree; check_assert((ptree["setting"] = "42.42", ptree.get("setting") == 42.42)); check_assert((ptree["setting"] = "42 2.5", ptree.get >("setting") == Dune::FieldVector{42.0, 2.5})); check_assert((ptree["setting"] = "42 2.5", ptree.get >("setting") == std::vector{42.0, 2.5})); } } dune-common-2.8.0/dune/common/test/parametertreetest.cc000066400000000000000000000270371411343567400232340ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include // This assert macro does not depend on the value of NDEBUG #define check_assert(expr) \ do \ { \ if(!(expr)) \ { \ std::cerr << __FILE__ << ":" << __LINE__ << ": check_assert(" \ << #expr << ") failed" << std::endl; \ std::abort(); \ } \ } while(false) // Check that the given expression throws the given exception #define check_throw(expr, except) \ do { \ try { \ expr; \ std::cerr << __FILE__ << ":" << __LINE__ << ": " << #expr \ << " should throw " << #except << std::endl; \ std::abort(); \ } \ catch(const except&) {} \ catch(...) { \ std::cerr << __FILE__ << ":" << __LINE__ << ": " << #expr \ << " should throw " << #except << std::endl; \ std::abort(); \ } \ } while(false) template void testparam(const P & p) { // try accessing key check_assert(p.template get("x1") == 1); check_assert(p.template get("x1") == 1.0); check_assert(p.template get("x2") == "hallo"); check_assert(p.template get("x3") == false); // try reading array like structures std::vector array1 = p.template get< std::vector >("array"); std::array array2 = p.template get< std::array >("array"); Dune::FieldVector array3 = p.template get< Dune::FieldVector >("array"); check_assert(array1.size() == 8); for (unsigned int i=0; i<8; i++) { check_assert(array1[i] == i+1); check_assert(array2[i] == i+1); check_assert(array3[i] == i+1); } // try accessing subtree p.sub("Foo"); p.sub("Foo").template get("peng"); // check hasSub and hasKey check_assert(p.hasSub("Foo")); check_assert(!p.hasSub("x1")); check_assert(p.hasKey("x1")); check_assert(!p.hasKey("Foo")); // try accessing inexistent key try { p.template get("bar"); DUNE_THROW(Dune::Exception, "failed to detect missing key"); } catch (Dune::RangeError & r) {} // try accessing inexistent subtree in throwing mode try { p.sub("bar",true); DUNE_THROW(Dune::Exception, "failed to detect missing subtree"); } catch (Dune::RangeError & r) {} // try accessing inexistent nested subtree in throwing mode try { p.sub("Foo.Zoo",true); DUNE_THROW(Dune::Exception, "failed to detect missing nested subtree"); } catch (Dune::RangeError & r) {} // try accessing inexistent subtree in non-throwing mode p.sub("bar"); // try accessing inexistent subtree that shadows a value key try { p.sub("x1.bar"); DUNE_THROW(Dune::Exception, "succeeded to access non-existent subtree that shadows a value key"); } catch (Dune::RangeError & r) {} // try accessing key as subtree try { p.sub("x1"); DUNE_THROW(Dune::Exception, "succeeded to access key as subtree"); } catch (Dune::RangeError & r) {} // try accessing subtree as key try { p.template get("Foo"); DUNE_THROW(Dune::Exception, "succeeded to access subtree as key"); } catch (Dune::RangeError & r) {} } template void testmodify(P parameterSet) { parameterSet["testDouble"] = "3.14"; parameterSet["testInt"] = "42"; parameterSet["testString"] = "Hallo Welt!"; parameterSet["testVector"] = "2 3 5 7 11"; parameterSet.sub("Foo")["bar"] = "2"; double testDouble = parameterSet.template get("testDouble"); int testInt = parameterSet.template get("testInt"); ++testDouble; ++testInt; std::string testString = parameterSet.template get("testString"); typedef Dune::FieldVector FVector; FVector testFVector = parameterSet.template get("testVector"); typedef std::vector SVector; SVector testSVector = parameterSet.template get("testVector"); if(testSVector.size() != 5) DUNE_THROW(Dune::Exception, "Testing std::vector: expected " "size()==5, got size()==" << testSVector.size()); for(unsigned i = 0; i < 5; ++i) if(testFVector[i] != testSVector[i]) DUNE_THROW(Dune::Exception, "testFVector[" << i << "]==" << testFVector[i] << " but " "testSVector[" << i << "]==" << testSVector[i]); if (parameterSet.template get("Foo.bar") != "2") DUNE_THROW(Dune::Exception, "Failed to write subtree entry"); if (parameterSet.sub("Foo").template get("bar") != "2") DUNE_THROW(Dune::Exception, "Failed to write subtree entry"); } void testOptionsParserResults(std::vector args, const std::vector & keywords, unsigned int required, bool allow_more, bool overwrite, std::string foo, std::string bar, const std::string referr = "") { Dune::ParameterTree pt; try { char * argv[10]; for (std::size_t i = 0; i < args.size(); ++i) argv[i] = &args[i][0]; Dune::ParameterTreeParser::readNamedOptions(args.size(), argv, pt, keywords, required, allow_more, overwrite); check_assert(referr == ""); } catch (const Dune::ParameterTreeParserError & e) { std::string err = e.what(); std::size_t offset = err.find("]: "); err = err.substr(offset + 3, err.find('\n') - offset - 3); check_assert(referr == err); } if (foo != "" && foo != pt.get("foo")) DUNE_THROW(Dune::Exception, "Options parser failed... foo = " << pt.get("foo") << " != " << foo); if (bar != "" && bar != pt.get("bar")) DUNE_THROW(Dune::Exception, "Options parser failed... bar = " << pt.get("bar") << " != " << bar); } void testOptionsParser() { std::vector keywords = { "foo", "bar" }; // check normal behaviour { std::vector args = { "progname", "--bar=ligapokal", "peng", "--bar=ligapokal", "--argh=other"}; testOptionsParserResults(args,keywords,keywords.size(),true,true,"peng","ligapokal", "" /* no error */ ); } // bail out on overwrite { std::vector args = { "progname", "--bar=ligapokal", "peng", "--bar=ligapokal", "--argh=other"}; testOptionsParserResults(args,keywords,keywords.size(),true,false,"peng","ligapokal", "parameter bar already specified"); } // bail out on unknown options { std::vector args = { "progname", "--bar=ligapokal", "peng", "--bar=ligapokal", "--argh=other"}; testOptionsParserResults(args,keywords,keywords.size(),false,true,"peng","ligapokal", "unknown parameter argh"); } // bail out on missing parameter { std::vector args = { "progname", "--bar=ligapokal"}; testOptionsParserResults(args,keywords,keywords.size(),true,true,"","ligapokal", "missing parameter(s) ... foo"); } // check optional parameter { std::vector args = { "progname", "--foo=peng"}; testOptionsParserResults(args,keywords,1,true,true,"peng","", "" /* no error */); } // check optional parameter, but bail out on missing parameter { std::vector args = { "progname", "--bar=ligapokal"}; testOptionsParserResults(args,keywords,1,true,true,"","ligapokal", "missing parameter(s) ... foo"); } // bail out on too many parameters { std::vector args = { "progname", "peng", "ligapokal", "hurz"}; testOptionsParserResults(args,keywords,keywords.size(),true,true,"peng","ligapokal", "superfluous unnamed parameter"); } // bail out on missing value { std::vector args = { "progname", "--foo=peng", "--bar=ligapokal", "--hurz"}; testOptionsParserResults(args,keywords,keywords.size(),true,true,"peng","ligapokal", "value missing for parameter --hurz"); } } void testFS1527() { { // Check that junk at the end is not accepted (int) Dune::ParameterTree ptree; check_throw(ptree["setting"] = "0.5"; ptree.get("setting", 0), Dune::RangeError); } { // Check that junk at the end is not accepted (double) Dune::ParameterTree ptree; check_throw(ptree["setting"] = "0.5 junk"; ptree.get("setting", 0.0), Dune::RangeError); } } // check that negative values can be given on the command line void testFS1523() { static char arg0[] = "progname"; static char arg1[] = "-setting"; static char arg2[] = "-1"; static char *argv[] = { arg0, arg1, arg2, NULL }; int argc = sizeof argv / sizeof (char *) - 1; Dune::ParameterTree ptree; Dune::ParameterTreeParser::readOptions(argc, argv, ptree); check_assert(ptree.get("setting") == -1); } void check_recursiveTreeCompare(const Dune::ParameterTree & p1, const Dune::ParameterTree & p2) { check_assert(p1.getValueKeys() == p2.getValueKeys()); check_assert(p1.getSubKeys() == p2.getSubKeys()); typedef Dune::ParameterTree::KeyVector::const_iterator Iterator; for (Iterator it = p1.getValueKeys().begin(); it != p1.getValueKeys().end(); ++it) check_assert(p1[*it] == p2[*it]); for (Iterator it = p1.getSubKeys().begin(); it != p1.getSubKeys().end(); ++it) check_recursiveTreeCompare(p1.sub(*it), p2.sub(*it)); } // test report method and read back in void testReport() { std::stringstream s; s << "foo.i = 1 \n foo.bar.peng = hurz"; Dune::ParameterTree ptree; Dune::ParameterTreeParser::readINITree(s, ptree); std::stringstream s2; ptree.report(s2); Dune::ParameterTree ptree2; Dune::ParameterTreeParser::readINITree(s2, ptree2); check_recursiveTreeCompare(ptree, ptree2); } int main() { try { // read config std::stringstream s; s << "x1 = 1 # comment\n" << "x2 = hallo\n" << "x3 = no\n" << "array = 1 2 3 4 5\t6 7 8\n" << "\n" << "[Foo] # another comment\n" << "peng = ligapokal\n"; auto c = Dune::ParameterTreeParser::readINITree(s); // test modifying and reading testmodify(c); try { c.get("testInt"); DUNE_THROW(Dune::Exception, "unexpected shallow copy of ParameterTree"); } catch (Dune::RangeError & r) {} // test for complex c.get>("x1"); // more const tests testparam(c); // check the command line parser testOptionsParser(); // check report testReport(); // check for specific bugs testFS1527(); testFS1523(); } catch (Dune::Exception & e) { std::cout << e << std::endl; return 1; } return 0; } dune-common-2.8.0/dune/common/test/parmetistest.cc000066400000000000000000000045101411343567400222070ustar00rootroot00000000000000#include #include #include #include #if ! HAVE_PARMETIS #error "ParMETIS is required for this test." #endif #include #if HAVE_PTSCOTCH_PARMETIS extern "C" { #include } #endif extern "C" { #include } int main(int argc, char **argv) { #if defined(REALTYPEWIDTH) using real_t = ::real_t; #else using real_t = float; #endif #if defined(IDXTYPEWIDTH) using idx_t = ::idx_t; #elif HAVE_PTSCOTCH_PARMETIS using idx_t = SCOTCH_Num; #else using idx_t = int; #endif MPI_Init(&argc, &argv); MPI_Comm comm; MPI_Comm_dup(MPI_COMM_WORLD, &comm); int rank, size; MPI_Comm_rank(comm, &rank); MPI_Comm_size(comm, &size); // This test is design for 3 cores assert(size == 3); // local adjacency structure of the graph std::vector xadj; // size n+1 std::vector adjncy; // size 2*m if (rank == 0) { xadj = std::vector{0,2,5,8,11,13}; adjncy = std::vector{1,5,0,2,6,1,3,7,2,4,8,3,9}; } else if (rank == 1) { xadj = std::vector{0,3,7,11,15,18}; adjncy = std::vector{0,6,10,1,5,7,11,2,6,8,12,3,7,9,13,4,8,14}; } else if (rank == 2) { xadj = std::vector{0,2,5,8,11,13}; adjncy = std::vector{5,11,6,10,12,7,11,13,8,12,14,9,13}; } // Array describing how the vertices of the graph are distributed among the processors. std::vector vtxdist{0,5,10,15}; // No weights idx_t wgtflag = 0; // C-style numbering that starts from 0. idx_t numflag = 0; // Number of weights that each vertex has idx_t ncon = 1; // Number of sub-domains idx_t nparts = size; // Fraction of vertex weight that should be distributed to each sub-domain for each // balance constraint std::vector tpwgts(ncon * nparts, 1.0/nparts); std::vector ubvec(ncon, 1.05); std::vector options{0, 0, 0}; idx_t edgecut; std::vector part(xadj.size()-1, 0); ParMETIS_V3_PartKway(vtxdist.data(), xadj.data(), adjncy.data(), nullptr, nullptr, &wgtflag, &numflag, &ncon, &nparts, tpwgts.data(), ubvec.data(), options.data(), &edgecut, part.data(), &comm); for (std::size_t part_i = 0; part_i < part.size(); ++part_i) { std::cout << "[" << rank << "] " << part_i << " => " << part[part_i] << std::endl; } MPI_Finalize(); return 0; }dune-common-2.8.0/dune/common/test/pathtest.cc000066400000000000000000000126641411343567400213300ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include void setCode(int& code, bool status) { if(!status) code = 1; else if(code == 77) code = 0; } void concatPathsTests(int& code) { typedef const char* const triple[3]; static const triple data[] = { {"a" , "b" , "a/b" }, {"/a", "b" , "/a/b"}, {"a/", "b" , "a/b" }, {"a" , "b/", "a/b/"}, {"..", "b" , "../b"}, {"a" , "..", "a/.."}, {"." , "b" , "./b" }, {"a" , "." , "a/." }, {"" , "b" , "b" }, {"a" , "" , "a" }, {"" , "" , "" }, {NULL, NULL, NULL } }; for(const triple* p = data; (*p)[0] != NULL; ++p) { const std::string& result = Dune::concatPaths((*p)[0], (*p)[1]); bool success = result == (*p)[2]; setCode(code, success); if(!success) std::cerr << "concatPaths(\"" << (*p)[0] << "\", " << "\"" << (*p)[1] << "\"): got \"" << result << "\", " << "expected \"" << (*p)[2] << "\"" << std::endl; } } void processPathTests(int& code) { typedef const char* const pair[3]; static const pair data[] = { {"" , "" }, {"." , "" }, {"./" , "" }, {"a/.." , "" }, {".." , "../" }, {"../a" , "../a/"}, {"a" , "a/" }, {"a//" , "a/" }, {"a///b" , "a/b/" }, {"/" , "/" }, {"/." , "/" }, {"/.." , "/" }, {"/a/.." , "/" }, {"/a" , "/a/" }, {"/a/" , "/a/" }, {"/../a/", "/a/" }, {NULL , NULL } }; for(const pair* p = data; (*p)[0] != NULL; ++p) { const std::string& result = Dune::processPath((*p)[0]); bool success = result == (*p)[1]; setCode(code, success); if(!success) std::cerr << "processPath(\"" << (*p)[0] << "\"): got " << "\"" << result << "\", expected " << "\"" << (*p)[1] << "\"" << std::endl; } } void prettyPathTests(int& code) { struct triple { const char* p; bool isDir; const char* result; }; static const triple data[] = { {"" , true , "." }, {"" , false, "." }, {"." , true , "." }, {"." , false, "." }, {"./" , true , "." }, {"./" , false, "." }, {"a/.." , true , "." }, {"a/.." , false, "." }, {".." , true , ".." }, {".." , false, ".." }, {"../a" , true , "../a/"}, {"../a" , false, "../a" }, {"a" , true , "a/" }, {"a" , false, "a" }, {"a//" , true , "a/" }, {"a//" , false, "a" }, {"a///b" , true , "a/b/" }, {"a///b" , false, "a/b" }, {"/" , true , "/" }, {"/" , false, "/" }, {"/." , true , "/" }, {"/." , false, "/" }, {"/.." , true , "/" }, {"/.." , false, "/" }, {"/a/.." , true , "/" }, {"/a/.." , false, "/" }, {"/a" , true , "/a/" }, {"/a" , false, "/a" }, {"/a/" , true , "/a/" }, {"/a/" , false, "/a" }, {"/../a/", true , "/a/" }, {"/../a/", false, "/a" }, {NULL, false, NULL } }; Dune::ios_base_all_saver state(std::cerr); std::cerr << std::boolalpha; for(const triple* p = data; p->p != NULL; ++p) { const std::string& result = Dune::prettyPath(p->p, p->isDir); bool success = result == p->result; setCode(code, success); if(!success) std::cerr << "prettyPath(\"" << p->p << "\", " << p->isDir << "): got " << "\"" << result << "\", expected \"" << p->result << "\"" << std::endl; } } void relativePathTests(int& code) { typedef const char* const triple[3]; static const triple data[] = { {"" , "" , "" }, {"" , "b" , "b/" }, {"" , "..", "../" }, {"a" , "" , "../" }, {"a" , "b" , "../b/"}, {"/" , "/" , "" }, {"/a", "/" , "../" }, {"/" , "/b", "b/" }, {"/a", "/b", "../b/"}, {NULL, NULL, NULL } }; for(const triple* p = data; (*p)[0] != NULL; ++p) { const std::string& result = Dune::relativePath((*p)[0], (*p)[1]); bool success = result == (*p)[2]; setCode(code, success); if(!success) std::cerr << "relativePath(\"" << (*p)[0] << "\", " << "\"" << (*p)[1] << "\"): got \"" << result << "\", " << "expected \"" << (*p)[2] << "\"" << std::endl; } typedef const char* const pair[2]; static const pair except_data[] = { {"" , "/" }, {"a" , "/" }, {"/" , "" }, {"/" , "b" }, {"..", "" }, {NULL, NULL} }; for(const pair* p = except_data; (*p)[0] != NULL; ++p) { std::string result; try { result = Dune::relativePath((*p)[0], (*p)[1]); } catch(const Dune::NotImplemented&) { setCode(code, true); continue; } setCode(code, false); std::cerr << "relativePath(\"" << (*p)[0] << "\", " << "\"" << (*p)[1] << "\"): got \"" << result << "\", " << "expected exception thrown" << std::endl; } } int main () { try { int code = 77; concatPathsTests(code); processPathTests(code); prettyPathTests(code); relativePathTests(code); return code; } catch(const Dune::Exception& e) { std::cerr << "Exception thrown: " << e << std::endl; throw; } } dune-common-2.8.0/dune/common/test/poolallocatortest.cc000066400000000000000000000101271411343567400232360ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include using namespace Dune; struct UnAligned { char t; char s; char k; }; template struct testPoolMain { static int test() { int ret=0; Pool pool; int elements = Pool::elements; //int poolSize = Pool::size; //int chunkSize = Pool::chunkSize; //int alignedSize = Pool::alignedSize; std::vector oelements(10*elements); typedef typename Pool::Chunk Chunk; //Fill 10 chunks for(int chunk=0; chunk < 10; ++chunk) { //std::cout<< std::endl<<"Chunk "<(pool.allocate()); //void* celement = reinterpret_cast(element); //std::cout << element<<" "<< celement<<", "<(currentChunk->chunk_)); std::uintptr_t end = reinterpret_cast(currentChunk->chunk_)+Pool::chunkSize; if(element< reinterpret_cast(currentChunk->chunk_)) { std::cerr <<" buffer overflow during first alloc: "<(currentChunk->chunk_) <<">"<(pool.allocate()); //celement = reinterpret_cast(element); //std::cout << element<<" "<(currentChunk->chunk_)) { std::cerr <<" buffer underflow during first alloc: "<(currentChunk->chunk_) <<">"<element) { std::cerr<<"allocated elements overlap!"<(oelements[i])); return ret; } }; template int testPool() { const std::size_t size = sizeof(T)>=2 ? sizeof(T)-2 : 0; int ret=0; std::cout<<"Checking "<(); ret+= testPool(); ret+= testPool(); ret += testPool >(); ret+=testPoolAllocator(); std::cout<< alignof(UnAligned) <<" "<(); return ret; } dune-common-2.8.0/dune/common/test/powertest.cc000066400000000000000000000035171411343567400215250ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include #include #include #include #include using namespace Dune; int main (int argc, char** argv) try { // Zero and positive powers if (power(4,0) != 1) DUNE_THROW(MathError, "power(4,0) does not compute the correct result"); if (power(4,1) != 4) DUNE_THROW(MathError, "power(4,1) implementation does not compute the correct result"); if (power(4,2) != 16) DUNE_THROW(MathError, "power(4,2) implementation does not compute the correct result"); if (power(4,3) != 64) DUNE_THROW(MathError, "power(4,3) implementation does not compute the correct result"); // Negative powers if (power(4.0,-1) != 0.25) DUNE_THROW(MathError, "power(4,-1) implementation does not compute the correct result"); if (power(4.0,-2) != 0.0625) DUNE_THROW(MathError, "power(4,-2) implementation does not compute the correct result"); if (power(4.0,-3) != 0.015625) DUNE_THROW(MathError, "power(4,-3) implementation does not compute the correct result"); // Test whether the result can be used in a compile-time expression enum { dummy = power(2,2) }; // Test legacy power implementation if (Power<0>::eval(4) != 1) DUNE_THROW(MathError, "Power implementation does not compute the correct result"); if (Power<1>::eval(4) != 4) DUNE_THROW(MathError, "Power implementation does not compute the correct result"); if (Power<2>::eval(4) != 16) DUNE_THROW(MathError, "Power implementation does not compute the correct result"); if (Power<3>::eval(4) != 64) DUNE_THROW(MathError, "Power implementation does not compute the correct result"); return 0; } catch (Exception& e) { std::cout << e.what() << std::endl; } dune-common-2.8.0/dune/common/test/quadmathtest.cc000066400000000000000000000107621411343567400221750ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include "config.h" #include #include #include #include #include #include #include using namespace Dune; template struct Comparator { Comparator(T tol) : tol_(tol) {} bool operator()(T const& x, T const& y) { return Dune::FloatCmp::eq(x, y, tol_); } private: T tol_; }; int main() { // check vector and matrix type with Float128 field type TestSuite test{}; Comparator cmp{std::numeric_limits::epsilon() * 8}; Comparator weakcmp{cbrt(std::numeric_limits::epsilon())}; // implicit conversion Float128 x1 = 1; Float128 x2 = 1.0f; Float128 x3 = 1.0; Float128 x4 = 1.0l; [[maybe_unused]] int z1 = x1; [[maybe_unused]] float z2 = x2; [[maybe_unused]] double z3 = x3; [[maybe_unused]] long double z4 = x4; // field-vector FieldVector v{1,2,3}, x; FieldMatrix M{ {1,2,3}, {2,3,4}, {3,4,6} }, A; FieldMatrix M2{ {1,2,3}, {2,3,4}, {3,4,7} }; auto y1 = v.one_norm(); test.check(cmp(y1, 6.q), "vec.one_norm()"); auto y2 = v.two_norm(); test.check(cmp(y2, sqrtq(14.q)), "vec.two_norm()"); auto y3 = v.infinity_norm(); test.check(cmp(y3, 3.q), "vec.infinity_norm()"); M.mv(v, x); // x = M*v M.mtv(v, x); // x = M^T*v M.umv(v, x); // x+= M*v M.umtv(v, x); // x+= M^T*v M.mmv(v, x); // x-= M*v M.mmtv(v, x); // x-= M^T*v auto w1 = M.infinity_norm(); test.check(cmp(w1, 13.q), "mat.infinity_norm()"); auto w2 = M.determinant(); test.check(cmp(w2, -1.q), "mat.determinant()"); M.solve(v, x); // x = M^(-1)*v [[maybe_unused]] auto M3 = M.leftmultiplyany(M2); [[maybe_unused]] auto M4 = M.rightmultiplyany(M2); using namespace FMatrixHelp; invertMatrix(M,A); // test cmath functions for Float128 type using T = Float128; test.check(cmp(T(0.5), T("0.5")), "string constructor"); test.check(cmp(abs(T{-1}),T{1}), "abs"); test.check(cmp(fabs(T{-1}),T{1}), "fabs"); test.check(cmp(cos(acos(T{0.5})),T{0.5}), "cos(acos)"); test.check(cmp(cosh(acosh(T{1.5})),T{1.5}), "cosh(acosh)"); test.check(cmp(sin(asin(T{0.5})),T{0.5}), "sin(asin)"); test.check(cmp(sinh(asinh(T{0.5})),T{0.5}), "sinh(asinh)"); test.check(cmp(tan(atan(T{0.5})),T{0.5}), "tan(atan)"); test.check(cmp(atan2(T{1},T{2}), atan(T{0.5})), "atan2"); test.check(cmp(tanh(atanh(T{0.5})),T{0.5}), "tanh(atanh)"); test.check(cmp(fdim(T{4},T{1}),T{3}), "fdim"); // a > b ? a - b : +0 test.check(cmp(fma(T{0.5},T{0.4},T{1.8}),(T{0.5} * T{0.4}) + T{1.8}), "fma"); test.check(cmp(fmax(T{0.6},T{0.4}),T{0.6}), "fmax"); test.check(cmp(fmin(T{0.6},T{0.4}),T{0.4}), "fmin"); test.check(cmp(hypot(T{1.6}, T{2.3}), sqrt(T{1.6}*T{1.6} + T{2.3}*T{2.3})), "hypot"); // ilogb test.check(cmp(llrint(T{2.3}),(long long int)(2)), "llrint"); test.check(cmp(lrint(T{2.3}),(long int)(2)), "lrint"); test.check(cmp(rint(T{2.3}),T{2}), "lrint"); test.check(cmp(llround(T{2.3}),(long long int)(2)), "llround"); test.check(cmp(lround(T{2.3}),(long int)(2)), "lround"); test.check(cmp(round(T{2.3}),T{2}), "round"); test.check(cmp(nearbyint(T{2.3}),T{2}), "nearbyint"); test.check(cmp(trunc(T{2.7}),T{2}), "trunc"); test.check(cmp(ceil(T{1.6}),T{2}), "ceil"); test.check(cmp(floor(T{1.6}),T{1}), "floor"); test.check(cmp(log(exp(T{1.5})),T{1.5}), "log(exp)"); test.check(cmp(exp(T{0.2}+T{0.4}), exp(T{0.2})*exp(T{0.4})), "exp"); // exp(a+b) = exp(a)*exp(b) test.check(cmp(expm1(T{0.6}),exp(T{0.6})-T{1}), "expm1"); test.check(cmp(log10(T{1000}),T{3}), "log10"); test.check(cmp(log2(T{8}),T{3}), "log2"); test.check(cmp(log1p(T{1.6}),log(T{1} + T{1.6})), "log1p"); // nextafter // these two functions produce larger errors test.check(weakcmp(fmod(T{5.1},T{3}),T{2.1}), "fmod"); test.check(weakcmp(remainder(T{5.1},T{3}),T{-0.9}), "remainder"); test.check(cmp(pow(T{2},T{3}),T{8}), "pow"); test.check(cmp(pow(T{M_PIq},T{3}),pow(T{M_PIq},3)), "pow"); // compare pow with float exponent and integer exponent test.check(cmp(cbrt(T{0.5*0.5*0.5}),T{0.5}), "cbrt"); test.check(cmp(sqrt(T{4}),T{2}), "sqrt"); test.check(cmp(erf(T{0}),T{0}), "erf"); test.check(cmp(erfc(T{0.6}), T{1}-erf(T{0.6})), "erfc"); test.check(cmp(lgamma(T{3}),log(T{2})), "lgamma"); test.check(cmp(tgamma(T{3}),T{2}), "tgamma"); } dune-common-2.8.0/dune/common/test/rangeutilitiestest.cc000066400000000000000000000275311411343567400234230ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include template auto checkRangeIterators(R&& r) { auto it = r.begin(); auto end = r.end(); auto op = [](const auto& x){}; return (testConstIterator(it, end, op)==0); } template auto checkRangeSize(R&& r) { std::size_t counter = 0; for([[maybe_unused]] auto&& dummy : r) ++counter; return (r.size()==counter); } template auto checkRandomAccessNumberRangeSums(R&& r, V sum, V first, V last) { bool passed = true; passed = passed and (std::accumulate(r.begin(), r.end(), 0) == sum); passed = passed and (std::accumulate(r.begin()+1, r.end(), 0) == (sum-first)); passed = passed and (std::accumulate(r.begin(), r.end()-1, 0) == (sum-last)); passed = passed and (std::accumulate(r.begin()+1, r.end()-1, 0) == (sum-first-last)); return passed; } template struct is_const_reference : public std::conjunction, std::is_const>> {}; template struct is_mutable_reference : public std::conjunction, std::negation>> {}; auto testTransformedRangeView() { Dune::TestSuite suite("Check transformedRangeView()"); // Check transformedRangeView with container range Dune::Hybrid::forEach(std::make_tuple(std::array({1,2,3}), std::vector({1,2,3})), [&](auto&& a) { auto a_backup = a; // Pass original range by l-value, modify it, and then traverse. // This should traverse the modified original range. { auto r = Dune::transformedRangeView(a, [](auto&& x) { return 2*x;}); a[0] = 2; suite.check(checkRandomAccessNumberRangeSums(r, 14, 4, 6)) << "incorrect values in transformedRangeView of l-value"; suite.check(checkRangeIterators(r)) << "iterator test fails for transformedRangeView of l-value"; suite.check(checkRangeSize(r)) << "checking size fails for transformedRangeView of l-value"; a = a_backup; } // Pass original range by const l-value, modify it, and then traverse. // This should traverse the modified original range. { const auto& a_const = a; auto r = Dune::transformedRangeView(a_const, [](auto&& x) { return 2*x;}); a[0] = 2; suite.check(checkRandomAccessNumberRangeSums(r, 14, 4, 6)) << "incorrect values in transformedRangeView of const l-value"; suite.check(checkRangeIterators(r)) << "iterator test fails for transformedRangeView of const l-value"; suite.check(checkRangeSize(r)) << "checking size fails for transformedRangeView of const l-value"; a = a_backup; } // Modify original range, pass it by r-value, restore it, and then traverse. // This should traverse a modified copy of the range and not the restored // original one. { a[0] = 2; auto r = Dune::transformedRangeView(std::move(a), [](auto&& x) { return 2*x;}); a = a_backup; suite.check(checkRandomAccessNumberRangeSums(r, 14, 4, 6)) << "incorrect values in transformedRangeView of r-value"; suite.check(checkRangeIterators(r)) << "iterator test fails for transformedRangeView of r-value"; suite.check(checkRangeSize(r)) << "checking size fails for transformedRangeView of r-value"; } // Check if returning real references in the transformation works { auto r = Dune::transformedRangeView(a, [](auto&& x) -> decltype(auto) { return x;}); suite.check(is_mutable_reference::value) << "iterator with mutable-reference returning transformation does not return mutable references"; suite.check(&(*(r.begin())) == &(a[0])) << "reference points to wrong location"; (*r.begin()) = 0; suite.check(a[0] == 0) << "modifying range by reference returning transformation failed"; a = a_backup; } // Check if returning real references in the transformation works { const auto& a_const = a; auto r = Dune::transformedRangeView(a_const, [](auto&& x) -> decltype(auto) { return x;}); suite.check(is_const_reference::value) << "iterator with const-reference returning transformation does not return const references"; suite.check(&(*(r.begin())) == &(a[0])) << "reference points to wrong location"; } // Check iterator based transformation { auto r = Dune::iteratorTransformedRangeView(a, [&](auto&& it) { return (*it)+(it-a.begin());}); suite.check(checkRandomAccessNumberRangeSums(r, 9, 1, 5)) << "incorrect values in transformedRangeView of l-value"; suite.check(checkRangeIterators(r)) << "iterator test fails for transformedRangeView of l-value"; suite.check(checkRangeSize(r)) << "checking size fails for transformedRangeView of l-value"; a = a_backup; } }); // Check transformedRangeView with on the fly range { auto r = Dune::transformedRangeView(Dune::range(10), [](auto&& x) { return 2*x;}); suite.check(checkRandomAccessNumberRangeSums(r, 90, 0, 18)) << "transformation of on-the-fly range gives incorrect results"; suite.check(checkRangeIterators(r)) << "iterator test fails for transformedRangeView"; suite.check(checkRangeSize(r)) << "checking size fails for transformedRangeView of on-the-fly range"; } // Check if we can indirectly sort subrange via reference returning transformations { auto a = std::vector{4,3,2,1,0}; auto r = Dune::transformedRangeView(Dune::range(1,4), [&](auto&& i) -> decltype(auto){ return a[i];}); std::sort(r.begin(), r.end()); suite.check(a == std::vector{4,1,2,3,0}) << "sorting reference returning transformedRangeView failed"; auto r2 = Dune::transformedRangeView(std::array{0, 2, 4}, [&](auto&& i) -> decltype(auto){ return a[i];}); std::sort(r2.begin(), r2.end()); suite.check(a == std::vector{0,1,2,3,4}) << "sorting reference returning transformedRangeView failed"; // Remap values of certain keys in a std::map such that // they are sorted according to the keys. auto m = std::map{{-1,5},{0,4}, {1,3}, {2,2}}; auto r3 = Dune::transformedRangeView(std::array{1, -1, 2}, [&](auto&& i) -> decltype(auto){ return m[i];}); std::sort(r3.begin(), r3.end()); suite.check(m == std::map{{1,2},{-1,3}, {2,5},{0,4}}) << "sorting reference returning transformedRangeView failed"; } return suite; } auto testSparseRange() { Dune::TestSuite suite("Check sparseRange()"); auto checkWithMatrix = [&suite](auto&& M) { for(std::size_t i=0; i({42}); checkWithMatrix(M1); checkWithMatrix(std::as_const(M1)); auto M2 = Dune::DiagonalMatrix({42, 41}); checkWithMatrix(M2); checkWithMatrix(std::as_const(M2)); auto M3 = Dune::DiagonalMatrix({42, 41, 40}); checkWithMatrix(M3); checkWithMatrix(std::as_const(M3)); return suite; } int main() { // Check IsIterable<> for https://gitlab.dune-project.org/core/dune-common/issues/58 static_assert(Dune::IsIterable< std::array >::value, "std::array must be a range"); static_assert(Dune::IsIterable< Dune::IteratorRange >::value, "IteratorRange must be a range"); static_assert(!Dune::IsIterable< int >::value, "int must not be a range"); Dune::TestSuite suite; // max_value, min_value { const int value = 12; suite.check(Dune::max_value(value) == value); suite.check(Dune::min_value(value) == value); std::array values{-42, 0, 42}; suite.check(Dune::max_value(values) == 42) << "maximum of values is 42, but got " << Dune::max_value(values); suite.check(Dune::min_value(values) == -42) << "minimum of values is -42, but got " << Dune::min_value(values); std::array positiveValues{1, 2, 3}; suite.check(Dune::max_value(positiveValues) == 3) << "maximum of positiveValues is 3, but got " << Dune::max_value(positiveValues); suite.check(Dune::min_value(positiveValues) == 1) << "minimum of positiveValues is 1, but got " << Dune::min_value(positiveValues); std::array negativeValues{-1, -3, -1}; suite.check(Dune::max_value(negativeValues) == -1) << "maximum of negativeValues is -1, but got " << Dune::max_value(negativeValues); suite.check(Dune::min_value(negativeValues) == -3) << "minimum of negativeValues is -3, but got " << Dune::min_value(negativeValues); } // any_true, all_true { const std::array allTrue{true, true, true}; const std::array allFalse{false, false, false}; const std::array someTrue{false, true, false}; suite.check(Dune::any_true(allTrue)) << "any_true(allTrue) must be true"; suite.check(!Dune::any_true(allFalse)) << "any_true(allFalse) must be false"; suite.check(Dune::any_true(someTrue)) << "any_true(someTrue) must be true"; suite.check(Dune::all_true(allTrue)) << "all_true(allTrue) must be true"; suite.check(!Dune::all_true(allFalse)) << "all_true(allFalse) must be false"; suite.check(!Dune::all_true(someTrue)) << "all_true(someTrue) must be false"; const bool t = true; const bool f = false; suite.check(Dune::any_true(t)) << "any_true(true) must be true"; suite.check(!Dune::any_true(f)) << "any_true(false) must be false"; suite.check(Dune::all_true(t)) << "all_true(true) must be true"; suite.check(!Dune::all_true(f)) << "all_true(false) must be false"; } // integer ranges using Dune::range; std::vector numbers(range(6).begin(), range(6).end()); int sum = 0; for( auto i : range(numbers.size()) ) sum += numbers[i]; suite.check(sum == 15) << "sum over range( 0, 6 ) must be 15."; suite.check(range(sum, 100)[5] == 20) << "range(sum, 100)[5] must be 20."; sum = 0; for( auto i : range(-10, 11) ) sum += i; suite.check(sum == 0) << "sum over range( -10, 11 ) must be 0."; static_assert(std::is_same()))::integer_sequence, std::make_integer_sequence>::value, "decltype(range(std::integral_constant))::integer_sequence must be the same as std::make_integer_sequence"); // Hybrid::forEach for integer ranges Dune::Hybrid::forEach(range(std::integral_constant()), [] (auto &&i) { static_assert(std::is_same, std::integral_constant>::value, "Hybrid::forEach(range(std::integral_constant()), ...) should only visit std::integral_constant."); }); { auto r = range(-10,11); auto it = r.begin(); auto end = r.end(); auto op = [](const auto& x){}; suite.check(testConstIterator(it, end, op)==0) << "iterator test fails for range(-10,11)"; } suite.subTest(testTransformedRangeView()); suite.subTest(testSparseRange()); return suite.exit(); } dune-common-2.8.0/dune/common/test/reservedvectortest.cc000066400000000000000000000030731411343567400234300ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include int main() { Dune::TestSuite test; // check that make_array works Dune::ReservedVector rv = {3,2,1}; test.check(rv.size() == 3); test.check(rv.back() == 1); test.check(rv.front() == 3); // check assignment from an initializer list rv = {1,2,3,4}; test.check(rv.size() == 4); test.check(rv.back() == 4); test.check(rv.front() == 1); // check push_back rv.push_back(5); test.check(rv.size() == 5); test.check(rv.back() == 5); // check copy constructor Dune::ReservedVector rv2 = rv; test.check(rv2[0] == 1 && rv2[1] == 2 && rv2[2] == 3 && rv2[3] == 4 && rv2[4] == 5); // check pop_back rv2.pop_back(); test.check(rv2.size() == 4); test.check(rv2.back() == 4); // make sure we can hash a reserved vector std::hash< Dune::ReservedVector > rv_hash; auto hash_value = rv_hash(rv); auto hash_value2 = rv_hash(rv2); test.check( hash_value != hash_value2 ); // try using an unordered map std::unordered_map< Dune::ReservedVector, double > rv_map; rv_map[rv] = 1.0; rv_map[rv2] = 2.0; // try and try again with a const ReservedVector std::unordered_map< const Dune::ReservedVector, double> const_rv_map; return 0; } dune-common-2.8.0/dune/common/test/scotchtest.cc000066400000000000000000000026061411343567400216520ustar00rootroot00000000000000#include #include #include #include #include // write graph to file void prepare (std::string filename) { std::ofstream out(filename, std::ios_base::out); // out << "0\n4 4\n0 000\n1 1\n1 0\n1 3\n1 2"; out << "0\n16 48\n0 000\n2 1 4\n3 0 2 5\n3 1 3 6\n2 2 7\n3 0 5 8\n4 1 4 6 9\n4 2 5 7 10\n3 3 6 11\n3 4 9 12\n4 5 8 10 13\n4 6 9 11 14\n3 7 10 15\n2 8 13\n3 9 12 14\n3 10 13 15\n2 11 14"; } int main (int argc, char** argv) { SCOTCH_errorProg (argv[0]); // Initialize source graph SCOTCH_Graph grafdat; if (SCOTCH_graphInit (&grafdat) != 0) { DUNE_THROW(Dune::Exception, "cannot initialize graph"); } prepare("graph_file.grf"); FILE* fileptr = nullptr; if ((fileptr = fopen ("graph_file.grf", "r")) == nullptr) { DUNE_THROW(Dune::Exception, "cannot open file"); } // Read source graph if (SCOTCH_graphLoad (&grafdat, fileptr, -1, 0) != 0) { DUNE_THROW(Dune::Exception, "cannot load graph"); } fclose (fileptr); if (SCOTCH_graphCheck (&grafdat) != 0) { DUNE_THROW(Dune::Exception, "graph check failed"); } SCOTCH_Num vertnbr = 0, edgenbr = 0; SCOTCH_graphSize (&grafdat, &vertnbr, &edgenbr); std::cout << "Number of vertices: " << vertnbr << std::endl; std::cout << "Number of edges: " << edgenbr << std::endl; SCOTCH_graphExit (&grafdat); return EXIT_SUCCESS; } dune-common-2.8.0/dune/common/test/shared_ptrtest.cc000066400000000000000000000016501411343567400225200ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // make sure assert works even when not compiling for debugging #ifdef NDEBUG #undef NDEBUG #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include class A {}; class B : public A {}; class C : A {}; int main(){ using namespace Dune; int ret=0; { // test shared_ptr for stack allocation { int i = 10; std::shared_ptr pi = stackobject_to_shared_ptr(i); } // test shared_ptr for stack allocation with down cast { DUNE_NO_DEPRECATED_BEGIN B b2; std::shared_ptr pa = stackobject_to_shared_ptr(b2); DUNE_NO_DEPRECATED_END #ifdef SHARED_PTR_COMPILE_FAIL C c; pa = stackobject_to_shared_ptr(c); // A is an inaccessible base of C #endif } } return (ret); } dune-common-2.8.0/dune/common/test/singletontest.cc000066400000000000000000000027011411343567400223650ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include class Foo : public Dune::Singleton { public: Foo() { bytes = new char[1000]; } ~Foo() { delete[] bytes; } private: char* bytes; }; class Foo1 { public: Foo1() { bytes = new char[1000]; } ~Foo1() { delete[] bytes; } private: char* bytes; }; typedef Dune::Singleton FooSingleton; Foo* globalFoo = 0; Foo1* globalFoo1 = 0; void setFoo() { globalFoo = &Foo::instance(); } void setFoo1() { globalFoo1 = &FooSingleton::instance(); } int testFoo() { if(globalFoo != &Foo::instance()) { std::cerr<<" Foo is not a real singleton!"< #include #include #include class DoubleWrapper { public: DoubleWrapper(double b) : d(b) { std::cout<<"Constructed "< IntAllocator; //typedef std::allocator IntAllocator; typedef Dune::PoolAllocator DoubleAllocator; //typedef std::allocator DoubleAllocator; typedef Dune::PoolAllocator DoubleWAllocator; //typedef std::allocator DoubleWAllocator; template const T& tail(const Dune::SLList& alist) { typedef typename Dune::SLList::const_iterator Iterator; Iterator tail=alist.begin(); for(int i = alist.size() - 1; i > 0; --i) ++tail; return *tail; } template int check(const Dune::SLList& alist, const T* vals) { typedef typename Dune::SLList::const_iterator iterator; int i=0; for(iterator iter = alist.begin(); iter != alist.end(); ++iter, i++) { if( vals[i] != *iter ) { std::cerr<<" List missmatch! "<<__FILE__<<":"<<__LINE__< void randomizeListBack(Dune::SLList& alist){ using namespace Dune; srand(300); int lowest=0, highest=1000, range=(highest-lowest)+1; T vals[10]; for(int i=0; i < 10; i++) { T d = T(range*(rand()/(RAND_MAX+1.0))); alist.push_back(d); vals[i]=d; } check(alist, vals); } template void randomizeListFront(Dune::SLList& alist){ using namespace Dune; srand(300); T vals[10]; int lowest=0, highest=1000, range=(highest-lowest)+1; for(int i=0; i < 10; i++) { T d = T(range*(rand()/(RAND_MAX+1.0))); alist.push_front(d); vals[9-i]=d; } check(alist, vals); } int testAssign() { typedef Dune::SLList List; List alist, blist; alist.push_back(3); alist.push_back(4); alist.push_back(5); blist.push_back(-1); blist=alist; List::iterator biter=blist.begin(), aiter=alist.begin(); for(; aiter!=alist.end(); ++aiter, ++biter) if(*aiter!=*biter) { std::cerr<<"Asignment failed "<<__FILE__<<":"<<__LINE__< List; List alist; alist.push_back(3); alist.push_back(4); alist.push_back(5); List::ModifyIterator iter = alist.beginModify(); iter.remove(); if(*(alist.begin())!=4) { std::cerr<<"delete next on position before head failed! "<<__FILE__<<":"<<__LINE__< List; int ret = 0; List alist; if(!alist.empty()) { std::cerr<<"Newly created list not empty! "<<__FILE__<<":"<<__LINE__<0; --elements) alist.pop_front(); if(!alist.empty()) { std::cerr<<"Emptied list not empty! "<<__FILE__<<":"<<__LINE__< List; //typedef Dune::SLList List; List alist; alist.push_back(3); List::ModifyIterator iter=alist.beginModify(); iter.insert(7); int ret=0; if(*iter!=3) { std::cerr<<"Value at current position changed due to insert! "<<__FILE__<<":"<<__LINE__< alist; //std::cout<<"PushPop 1:"< list; Dune::SLList list, list1; Dune::SLList list2; randomizeListBack(list1); randomizeListFront(list); Dune::SLList copied(list); if(copied.size()!=list.size()) { std::cerr << "Size of copied list does not match!"<::const_iterator Iterator; Iterator iend = list.end(); for(Iterator iter1=list.begin(), iter2=copied.begin(); iter1 != iend; ++iter1, ++iter2) if(*iter1!=*iter2) { std::cerr << "Entries of copied are not the same!"<::ModifyIterator>::value_type> print; Dune::SLList::ModifyIterator lbegin = list.beginModify(), lend = list.endModify(); double& d = lbegin.dereference(); d=2.0; double& d1 = lbegin.dereference(); d1=3.0; lbegin.dereference()=5.0; lbegin.operator*()=5.0; *lbegin=5.0; std::cout << "Testing ConstIterator "< #include #include #include #include template void nop(std::initializer_list&&) {} int main() { auto test_args = std::make_tuple(true, 2, 3, "abc"); Dune::TestSuite test; auto concat = [](auto&&... args) { bool first = true; std::stringstream stream; nop({(stream << (first ? "":",") << args, first = false)...}); return stream.str(); }; test.check(Dune::Std::apply(concat, test_args) == "1,2,3,abc") << "Dune::Std::apply failed with concat lambda"; auto makeTuple = [](auto&&... args) { return std::make_tuple(args...); }; test.check(Dune::Std::apply(makeTuple, test_args) == test_args) << "Dune::Std::apply failed with makeTuple lambda"; auto intTuple = std::make_tuple(1,2,3); auto&& intTuple0 = Dune::Std::apply([](auto&& arg0, auto&&... /*args*/) -> decltype(auto) { return arg0; }, intTuple); intTuple0 = 42; test.check(std::get<0>(intTuple) == intTuple0) << "Dune::Std::apply does not properly return references"; // transformTuple implemented using Std::apply auto transformTuple = [](auto&& t, auto&& f) { return Dune::Std::apply([&](auto&&... args) { return std::make_tuple((f(std::forward(args)))...); }, t); }; auto t1 = std::make_tuple(1, 0.2); auto t2 = transformTuple(t1, [](auto&& x) { return 1.0/x; }); test.check(t2 == std::make_tuple(1.0, 5.0)) << "transformTuple implementation based on Dune::Std::apply fails"; return test.exit(); } dune-common-2.8.0/dune/common/test/stdidentity.cc000066400000000000000000000030571411343567400220340ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include struct Foo { static int count; Foo() { ++count; std::cout << "construct" << std::endl; } Foo(const Foo&) { ++count; std::cout << "copy construct" << std::endl; } Foo(Foo&&) { ++count; std::cout << "move construct" << std::endl; } ~Foo() { --count; std::cout << "deconstruct" << std::endl; } }; int Foo::count = 0; template T&& assert_count(T&& arg, int count) { std::cout << std::decay_t::count << std::endl; if (std::decay_t::count != count) std::cerr << "Passed count does not match state of the argument" << std::endl; return std::forward(arg); } int main() { auto id = Dune::Std::identity(); assert_count(id(Foo()),1); // pass an r-value to identity, still constructed on the assert const auto& foo0 = id(Foo()); // pass an r-value to identity assert_count(foo0,0); // id(Foo()) is alredy doconstructed at this point auto foo1 = id(Foo()); // pass an r-value to identity and move it to foo1 assert_count(foo1,1); // foo0 is alredy doconstructed at this point Foo foo2; assert_count(id(foo2),2); // pass an l-value to identity const auto& foo3 = id(foo2); // pass an l-value to identity assert_count(foo3,2); // foo still exist at this point auto foo4 = id(foo2); // pass an l-value to identity and copy its result assert_count(foo4,3); // copy of foo still exist at this point } dune-common-2.8.0/dune/common/test/streamoperatorstest.cc000066400000000000000000000013421411343567400236150ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include using Dune::operator>>; using Dune::operator<<; int main() { typedef std::tuple Tuple; { const Tuple t{1, 2, 3}; const std::string expected = "[1,2,3]"; std::ostringstream out; out << t; if( out.str() != expected ) return 1; } { const std::string data = "1 2 3"; const Tuple expected{1, 2, 3}; std::istringstream in(data); Tuple t; in >> t; if( t != expected ) return 1; } return 0; } dune-common-2.8.0/dune/common/test/streamtest.cc000066400000000000000000000023751411343567400216650ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: /* Test to check if the standard streams in libdune can be properly linked with this program and if they work */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include // enums are a nice special case (was a bug) enum check { VALUE = 5 }; int main () { try { // let output happen but vanish std::ofstream dummy("/dev/null"); Dune::derr.attach(dummy); Dune::derr.push(true); Dune::derr << "Teststring" << std::endl; Dune::derr << VALUE << std::endl; Dune::dverb << VALUE << std::endl; Dune::dvverb << VALUE << std::endl; Dune::dinfo << VALUE << std::endl; Dune::dwarn << VALUE << std::endl; Dune::dgrave << VALUE << std::endl; // instantiate private stream and connect global stream { Dune::DebugStream<> mystream(dummy); Dune::derr.tie(mystream); Dune::derr << "Blah" << std::endl; // untie before mystream gets destructed Dune::derr.untie(); } Dune::derr << "Still working" << std::endl; } catch (Dune::Exception &e) { std::cerr << e << std::endl; return 2; } catch (...) { return 1; }; return 0; } dune-common-2.8.0/dune/common/test/stringutilitytest.cc000066400000000000000000000017201411343567400233150ustar00rootroot00000000000000#ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include namespace { const std::string hello_world("hello world"); } /* namespace */ bool test_hasPrefix() { bool pass = true; using Dune::hasPrefix; pass &= hasPrefix(hello_world, "hello"); pass &= !hasPrefix(hello_world, "world"); return pass; } bool test_hasSuffix() { bool pass = true; using Dune::hasSuffix; pass &= hasSuffix(hello_world, "world"); pass &= !hasSuffix(hello_world, "hello"); return pass; } bool test_formatString() { bool pass = true; const int one = 1; const static std::string format("hello %i"); const static std::string expected("hello 1"); using Dune::formatString; const std::string s = formatString(format, one); pass &= (s == expected); return pass; } int main() { bool pass = true; pass &= test_hasPrefix(); pass &= test_hasSuffix(); pass &= test_formatString(); return pass ? 0 : 1; } dune-common-2.8.0/dune/common/test/testdebugallocator.cc000066400000000000000000000035401411343567400233540ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif // #define DEBUG_ALLOCATOR_KEEP 1 #define DEBUG_NEW_DELETE 3 #include #if HAVE_MPROTECT #include #include #include #include class A { public: A() { std::cout << "INIT A\n"; } int x; void foo() {}; }; void basic_tests () { using Dune::DebugMemory::alloc_man; size_t s = 256; double * x = alloc_man.allocate(s); x[s-1] = 10; // access out of bounds #ifdef FAILURE1 x[s+1] = 1; #endif // lost allocation, free and double-free #ifndef FAILURE2 alloc_man.deallocate(x); #endif #ifdef FAILURE3 alloc_man.deallocate(x); #endif // access after free #ifdef FAILURE4 x[s-1] = 10; #endif } void allocator_tests() { std::vector > v; v.push_back(10); v.push_back(12); v.size(); std::cout << v[0] << "\n"; std::cout << v[1] << "\n"; #ifdef FAILURE5 std::cout << v[v.capacity()] << "\n"; #endif } void new_delete_tests() { std::cout << "alloc double[3]\n"; double * y = new double[3]; delete[] y; std::cout << "alloc A[2]\n"; A * z = new A[2]; z->foo(); delete[] z; z = 0; std::cout << "alloc (buf) A[3]\n"; char * buf = (char*)malloc(128); A * z2 = new (buf) A[3]; z2->foo(); free(buf); z2 = 0; std::cout << "alloc A[4]\n"; A * z4 = ::new A[4]; z4->foo(); ::delete[] z4; z4 = 0; } #endif // HAVE_MPROTECT int main(int, char**) { #if EXPECTED_SIGNAL std::signal(EXPECTED_SIGNAL, std::_Exit); #endif #if EXPECTED_ALT_SIGNAL std::signal(EXPECTED_ALT_SIGNAL, std::_Exit); #endif #if HAVE_MPROTECT basic_tests(); allocator_tests(); new_delete_tests(); #endif #ifdef EXPECTED_SIGNAL return 1; #else return 0; #endif } dune-common-2.8.0/dune/common/test/testfloatcmp.cc000066400000000000000000000164741411343567400222040ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // Test the new (Dune) interface of float_cmp #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include using std::cout; using std::endl; using std::flush; ///////////////////////// // // compile time checks // // check that we can access the functions as FloatCmp::function from within the Dune namespace namespace Dune { void checkNamespaceAccess() { FloatCmp::eq(0.0, 0.0); } } // namespace Dune // check that we can access the functions as FloatCmp::function with using namespace Dune void checkUsingAccess() { using namespace Dune; FloatCmp::eq(0.0, 0.0); } // run time checks const char* repr(bool b) { if(b) return "true "; else return "false"; } int passed = 0; int failed = 0; void count(bool pass) { if(pass) { cout << "passed"; ++passed; } else { cout << "failed"; ++failed; } } template void tests(F f1, F f2, typename Dune::FloatCmp::EpsilonType::Type eps, bool inside) { bool result; cout << "eq(" << f1 << ", " << f2 << ", " << eps << ") = " << flush; result = Dune::FloatCmp::eq(f1, f2, eps); cout << repr(result) << "\t"; count(result == inside); cout << endl; cout << "ge(" << f1 << ", " << f2 << ", " << eps << ") = " << flush; result = Dune::FloatCmp::ge(f1, f2, eps); cout << repr(result) << "\t"; count(result == (inside || f1 > f2)); cout << endl; cout << "le(" << f1 << ", " << f2 << ", " << eps << ") = " << flush; result = Dune::FloatCmp::le(f1, f2, eps); cout << repr(result) << "\t"; count(result == (inside || f1 < f2)); cout << endl; cout << "ne(" << f1 << ", " << f2 << ", " << eps << ") = " << flush; result = Dune::FloatCmp::ne(f1, f2, eps); cout << repr(result) << "\t"; count(result == !inside); cout << endl; cout << "gt(" << f1 << ", " << f2 << ", " << eps << ") = " << flush; result = Dune::FloatCmp::gt(f1, f2, eps); cout << repr(result) << "\t"; count(result == (!inside && f1 > f2)); cout << endl; cout << "lt(" << f1 << ", " << f2 << ", " << eps << ") = " << flush; result = Dune::FloatCmp::lt(f1, f2, eps); cout << repr(result) << "\t"; count(result == (!inside && f1 < f2)); cout << endl; } template void vectortests(F f1, F f2, typename Dune::FloatCmp::EpsilonType::Type eps, bool inside) { bool result; cout << "eq({" << f1[0] << ", " << f1[1] << "}, {" << f2[0] << ", " << f2[1] << "}, " << eps << ") = " << flush; result = Dune::FloatCmp::eq(f1, f2, eps); cout << repr(result) << "\t"; count(result == inside); cout << endl; cout << "ne({" << f1[0] << ", " << f1[1] << "}, {" << f2[0] << ", " << f2[1] << "}, " << eps << ") = " << flush; result = Dune::FloatCmp::ne(f1, f2, eps); cout << repr(result) << "\t"; count(result == !inside); cout << endl; } template void tests(F f1, F f2, const typename Dune::FloatCmpOps &ops, bool inside) { bool result; cout << "ops = operations(" << ops.epsilon() << ")" << endl; cout << "ops.eq(" << f1 << ", " << f2 << ") = " << flush; result = ops.eq(f1, f2); cout << repr(result) << "\t"; count(result == inside); cout << endl; cout << "ops.ge(" << f1 << ", " << f2 << ") = " << flush; result = ops.ge(f1, f2); cout << repr(result) << "\t"; count(result == (inside || f1 > f2)); cout << endl; cout << "ops.le(" << f1 << ", " << f2 << ") = " << flush; result = ops.le(f1, f2); cout << repr(result) << "\t"; count(result == (inside || f1 < f2)); cout << endl; cout << "ops.ne(" << f1 << ", " << f2 << ") = " << flush; result = ops.ne(f1, f2); cout << repr(result) << "\t"; count(result == !inside); cout << endl; cout << "ops.gt(" << f1 << ", " << f2 << ") = " << flush; result = ops.gt(f1, f2); cout << repr(result) << "\t"; count(result == (!inside && f1 > f2)); cout << endl; cout << "ops.lt(" << f1 << ", " << f2 << ") = " << flush; result = ops.lt(f1, f2); cout << repr(result) << "\t"; count(result == (!inside && f1 < f2)); cout << endl; } template void vectortests(F f1, F f2, typename Dune::FloatCmpOps &ops, bool inside) { bool result; cout << "ops = operations(" << ops.epsilon() << ")" << endl; cout << "ops.eq({" << f1[0] << ", " << f1[1] << "}, {" << f2[0] << ", " << f2[1] << "}) = " << flush; result = ops.eq(f1, f2); cout << repr(result) << "\t"; count(result == inside); cout << endl; cout << "ops.ne({" << f1[0] << ", " << f1[1] << "}, {" << f2[0] << ", " << f2[1] << "}) = " << flush; result = ops.ne(f1, f2); cout << repr(result) << "\t"; count(result == !inside); cout << endl; } int main() { cout.setf(std::ios_base::scientific, std::ios_base::floatfield); cout.precision(16); Dune::FloatCmpOps ops(1e-7); Dune::FloatCmpOps> std_vec_ops(1e-7); Dune::FloatCmpOps> fvec_ops(1e-7); cout << "Tests inside the epsilon environment" << endl; tests(1.0, 1.00000001, 1e-7, true); tests(1.0, 1.00000001, ops, true); vectortests(std::vector({1.0, 1.0}), std::vector({1.00000001, 1.0}), 1e-7, true); vectortests(std::vector({1.0, 1.0}), std::vector({1.00000001, 1.0}), std_vec_ops, true); vectortests(Dune::FieldVector({1.0, 1.0}), Dune::FieldVector({1.00000001, 1.0}), 1e-7, true); vectortests(Dune::FieldVector({1.0, 1.0}), Dune::FieldVector({1.00000001, 1.0}), fvec_ops, true); cout << "Tests outside the epsilon environment, f1 < f2" << endl; tests(1.0, 1.000001, 1e-7, false); tests(1.0, 1.000001, ops, false); vectortests(std::vector({1.0, 1.0}), std::vector({1.000001, 1.0}), 1e-7, false); vectortests(std::vector({1.0, 1.0}), std::vector({1.000001, 1.0}), std_vec_ops, false); vectortests(Dune::FieldVector({1.0, 1.0}), Dune::FieldVector({1.000001, 1.0}), 1e-7, false); vectortests(Dune::FieldVector({1.0, 1.0}), Dune::FieldVector({1.000001, 1.0}), fvec_ops, false); cout << "Tests outside the epsilon environment, f1 > f2" << endl; tests(1.000001, 1.0, 1e-7, false); tests(1.000001, 1.0, ops, false); vectortests(std::vector({1.000001, 1.0}), std::vector({1.0, 1.0}), 1e-7, false); vectortests(std::vector({1.000001, 1.0}), std::vector({1.0, 1.0}), std_vec_ops, false); vectortests(Dune::FieldVector({1.000001, 1.0}), Dune::FieldVector({1.0, 1.0}), 1e-7, false); vectortests(Dune::FieldVector({1.000001, 1.0}), Dune::FieldVector({1.0, 1.0}), fvec_ops, false); cout << "Tests with f1 = f2 = 0" << endl; tests(0, 0, 1e-7, true); tests(0, 0, ops, true); vectortests(std::vector({0, 0}), std::vector({0, 0}), 1e-7, true); vectortests(std::vector({0, 0}), std::vector({0, 0}), std_vec_ops, true); vectortests(Dune::FieldVector({0, 0}), Dune::FieldVector({0, 0}), 1e-7, true); vectortests(Dune::FieldVector({0, 0}), Dune::FieldVector({0, 0}), fvec_ops, true); int total = passed + failed; cout << passed << "/" << total << " tests passed; " << failed << "/" << total << " tests failed" << endl; if(failed > 0) return 1; else return 0; } dune-common-2.8.0/dune/common/test/testsuite.hh000066400000000000000000000131741411343567400215340ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_TEST_TESTSUITE_HH #define DUNE_COMMON_TEST_TESTSUITE_HH #include #include #include #include #include namespace Dune { /** * \brief A Simple helper class to organize your test suite * * Usage: Construct a TestSuite and call check() or require() * with the condition to check and probably a name for this check. * These methods return a stream such that you can pipe in an * explanantion accompanied by respective data to give a reason * for a test failure. */ class TestSuite { public: enum ThrowPolicy { AlwaysThrow, ThrowOnRequired }; /** * \brief Create TestSuite * * \param name A name to identify this TestSuite. Defaults to "". * \param policy If AlwaysThrow any failing check will throw, otherwise only required checks will do. */ TestSuite(ThrowPolicy policy, std::string name="") : name_(name), checks_(0), failedChecks_(0), throwPolicy_(policy==AlwaysThrow) {} /** * \brief Create TestSuite * * \param name A name to identify this TestSuite. Defaults to "". * \param policy If AlwaysThrow any failing check will throw, otherwise only required checks will do. Defaults to ThrowOnRequired */ TestSuite(std::string name="", ThrowPolicy policy=ThrowOnRequired) : name_(name), checks_(0), failedChecks_(0), throwPolicy_(policy==AlwaysThrow) {} /** * \brief Check condition * * This will throw an exception if the check fails and if the AlwaysThrow policy was used on creation. * * \param conditon Checks if this is true and increases the failure counter if not. * \param name A name to identify this check. Defaults to "" * \returns A CollectorStream that can be used to create a diagnostic message to be printed on failure. */ CollectorStream check(bool condition, std::string name="") { ++checks_; if (not condition) ++failedChecks_; return CollectorStream([condition, name, this](std::string reason) { if (not condition) this->announceCheckResult(throwPolicy_, "CHECK ", name, reason); }); } /** * \brief Check a required condition * * This will always throw an exception if the check fails. * * \param conditon Checks if this is true and increases the failure counter if not. * \param name A name to identify this check. Defaults to "" * \returns A CollectorStream that can be used to create a diagnostic message to be printed on failure. */ CollectorStream require(bool condition, std::string name="") { ++checks_; if (not condition) ++failedChecks_; return CollectorStream([condition, name, this](std::string reason) { if (not condition) this->announceCheckResult(true, "REQUIRED CHECK", name, reason); }); } /** * \brief Collect data from a sub-TestSuite * * This will incorporate the accumulated results of the sub-TestSuite * into this one. If the sub-TestSuite failed, i.e., contained failed * checks, a summary will be printed. */ void subTest(const TestSuite& subTest) { checks_ += subTest.checks_; failedChecks_ += subTest.failedChecks_; if (not subTest) announceCheckResult(throwPolicy_, "SUBTEST", subTest.name(), std::to_string(subTest.failedChecks_)+"/"+std::to_string(subTest.checks_) + " checks failed in this subtest."); } /** * \brief Check if this TestSuite failed * * \returns False if any of the executed tests failed, otherwise true. */ explicit operator bool () const { return (failedChecks_==0); } /** * \brief Query name * * \returns Name of this TestSuite */ std::string name() const { return name_; } /** * \brief Print a summary of this TestSuite * * \returns False if any of the executed tests failed, otherwise true. */ bool report() const { if (failedChecks_>0) std::cout << composeMessage("TEST ", name(), std::to_string(failedChecks_)+"/"+std::to_string(checks_) + " checks failed in this test.") << std::endl; return (failedChecks_==0); } /** * \brief Exit the test. * * This wil print a summary of the test and return an integer * to be used on program exit. * * \returns 1 if any of the executed tests failed, otherwise 0. */ int exit() const { return (report() ? 0: 1); } protected: // Compose a diagnostic message static std::string composeMessage(std::string type, std::string name, std::string reason) { std::ostringstream s; s << type << " FAILED"; if (name!="") s << "(" << name << ")"; s << ": "; if (reason!="") s << reason; return s.str(); } // Announce check results. To be called on failed checks static void announceCheckResult(bool throwException, std::string type, std::string name, std::string reason) { std::string message = composeMessage(type, name, reason); std::cout << message << std::endl; if (throwException) { Dune::Exception ex; ex.message(message); throw ex; } } std::string name_; std::size_t checks_; std::size_t failedChecks_; bool throwPolicy_; }; } // namespace Dune #endif // DUNE_COMMON_TEST_TESTSUITE_HH dune-common-2.8.0/dune/common/test/timing.cc000066400000000000000000000061461411343567400207610ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include template void timing_vector() { std::cout << "timing_vector<" << bs << ", " << sz << ">\n"; typedef Dune::FieldVector VB; typedef Dune::BlockVector BV; typedef Dune::BlockVector BBV; BV bv1(sz), bv2(sz); BV bv3(sz), bv4(sz); bv1 = 1; bv2 = 0; bv2[1][0]=1; bv2[1][1]=2; bv3 = 0; bv4 = 0; BBV bbv(2); bbv[0].resize(bv1.N()); bbv[1].resize(bv2.N()); BBV bbv2(2); #warning deep copy is broken! /* bbv2 = bbv2; */ bbv2[0] = bv3; bbv2[1] = bv4; // bbv2 = 0; Dune::Timer stopwatch; stopwatch.reset(); for (int i=0; i<10; i++) { #ifdef DUNE_EXPRESSIONTEMPLATES #ifdef DUNE_FLATIT for (int a=0; a<2; a++) for (int b=0; b template void timing_matrix() { std::cout << "timing_matrix<" << BN << ", " << BM << ", " << N << ", " << M << ">\n"; typedef double matvec_t; typedef Dune::FieldVector LVB; typedef Dune::FieldVector VB; typedef Dune::FieldMatrix MB; typedef Dune::BlockVector LeftVector; typedef Dune::BlockVector Vector; typedef Dune::BCRSMatrix Matrix; Matrix A(N,M,Matrix::row_wise); typename Matrix::CreateIterator i=A.createbegin(); typename Matrix::CreateIterator end=A.createend(); std::cout << "Building matrix structure\n"; // build up the matrix structure int c=0; for (; i!=end; ++i) { // insert a non zero entry for myself i.insert(c); // insert index M-1 i.insert(M-1); c++; } std::cout << "...done\n"; LeftVector v(N); v = 0; Vector x(M); x = 1; Dune::Timer stopwatch; stopwatch.reset(); #ifdef DUNE_EXPRESSIONTEMPLATES v += A * x; #else A.umv(x,v); #endif std::cout << "Time [v+=A*x] " << stopwatch.elapsed() << std::endl; std::cout << std::endl; } #endif int main () { #ifdef DUNE_EXPRESSIONTEMPLATES #ifdef DUNE_FLATIT std::cout << "Handwritten loops\n"; #else std::cout << "Expression Templates\n"; #endif #else std::cout << "Template Meta Program\n"; #endif timing_vector<1,1000000>(); timing_vector<2,500000>(); timing_vector<10,100000>(); timing_vector<40,25000>(); timing_vector<100,10000>(); timing_vector<400,2500>(); // timing_matrix<150,150,500,4000>(); // timing_matrix<150,150,1000,2000>(); // timing_matrix<1,18,400000,500000>(); // timing_matrix<6,3,400000,500000>(); // timing_matrix<3,6,400000,500000>(); // timing_matrix<18,1,400000,500000>(); // timing_matrix<50,50,9000,10000>(); std::cout << std::endl; } dune-common-2.8.0/dune/common/test/transposetest.cc000066400000000000000000000051241411343567400224030ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #include "config.h" #include #include #include #include #include #include #include #include // check A*transpose(B) template auto checkAxBT(const A& a, const B&b) { Dune::TestSuite suite(std::string{"Check transpose with A="} + Dune::className() + " and B=" + Dune::className()); // compute abt auto abt = a * transpose(b); // check result type using FieldA = typename Dune::FieldTraits::field_type; using FieldB = typename Dune::FieldTraits::field_type; using Field = typename Dune::PromotionTraits::PromotedType; using ABT = Dune::FieldMatrix; suite.check(std::is_same()) << "Result type of A*transpose(B) should be " << Dune::className() << " but is " << Dune::className(); // manually compute result value auto abt_check = ABT{}; for(std::size_t i=0; i{}; auto b = Dune::FieldMatrix{}; testFillDense(a); testFillDense(b); suite.subTest(checkAxBT(a,b)); } { auto a = Dune::FieldMatrix{}; auto b = Dune::FieldMatrix{}; testFillDense(a); testFillDense(b); suite.subTest(checkAxBT(a,b)); } { auto a = Dune::FieldMatrix{}; auto b = Dune::FieldMatrix{}; testFillDense(a); testFillDense(b); suite.subTest(checkAxBT(a,b)); } { auto a = Dune::FieldMatrix{}; auto b = Dune::DiagonalMatrix{}; testFillDense(a); b = {0, 1, 2, 3}; suite.subTest(checkAxBT(a,b)); } return suite.exit(); } dune-common-2.8.0/dune/common/test/tupleutilitytest.cc000066400000000000000000000125041411343567400231420ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include ////////////////////////////////////////////////////////////////////// // // check FirstTypeIndex // typedef std::tuple MyTuple; static_assert((Dune::FirstTypeIndex::value == 0), "FirstTypeIndex finds the wrong index for double in MyTuple!"); static_assert((Dune::FirstTypeIndex::value == 1), "FirstTypeIndex finds the wrong index for double in MyTuple!"); static_assert((Dune::FirstTypeIndex::value == 2), "FirstTypeIndex finds the wrong index for double in MyTuple!"); ////////////////////////////////////////////////////////////////////// // // check PushBackTuple typedef Dune::PushBackTuple::type MyTupleAppended1; typedef std::tuple MyTupleAppended2; static_assert((std::is_same::value), "PushBackTuple failed!"); ////////////////////////////////////////////////////////////////////// // // check PushFrontTuple typedef Dune::PushFrontTuple::type MyTuplePrepended1; typedef std::tuple MyTuplePrepended2; static_assert((std::is_same::value), "PushFrontTuple failed!"); ////////////////////////////////////////////////////////////////////// // // check JoinTuples typedef Dune::JoinTuples::type MyTupleMyTuple1; typedef std::tuple MyTupleMyTuple2; static_assert((std::is_same::value), "JoinTuples failed!"); ////////////////////////////////////////////////////////////////////// // // check FlattenTuple typedef std::tuple MyTuple2; typedef std::tuple MyTupleTuple; typedef Dune::FlattenTuple::type MyTupleTupleFlat1; typedef std::tuple MyTupleTupleFlat2; static_assert((std::is_same::value), "FlattenTuples failed!"); ////////////////////////////////////////////////////////////////////// // // check nested ReduceTuple with a litte TMP // A tuple of a range of integers wrapped in integral_constant types template struct Range { typedef typename Dune::PushBackTuple< typename Range::type, typename std::integral_constant >::type type; }; template struct Range { typedef std::tuple<> type; }; // An accumulator to build up a list of divisors of an integer using reduce template struct DivisorAccumulator { enum {value = Data::first_type::value}; enum {isDivisor = (PotentialDivisor::value*(value / PotentialDivisor::value)==value)}; typedef typename Data::second_type OldTuple; typedef typename Dune::PushBackTuple::type ExtendedTuple; typedef typename std::conditional::type NewTuple; typedef typename std::pair type; }; // Construct list of divisors using reduce template struct Divisors { typedef typename Dune::ReduceTuple< DivisorAccumulator, typename Range<1,X+1>::type, typename std::pair, typename std::tuple<> > >::type::second_type type; enum {value = std::tuple_size::value}; }; // An accumulator to build up a list of primes up to a fixed integer template struct PrimeAccumulator { enum {isPrime = (Divisors::value==2)}; typedef typename std::conditional::type, Data>::type type; }; // Construct list primes template struct Primes { typedef typename Dune::ReduceTuple< PrimeAccumulator, typename Range<1,X+1>::type, typename std::tuple<> >::type type; }; typedef Primes<9>::type Primes1; typedef std::tuple< std::integral_constant, std::integral_constant, std::integral_constant, std::integral_constant > Primes2; static_assert((std::is_same::value), "ReduceTuple failed in primes-tmp!"); struct Reciprocal { template struct TypeEvaluator { typedef double Type; }; template typename TypeEvaluator::Type operator()(const T& val) const { return 1./val; } }; int main() { const std::tuple t1(1, 2.); auto t2 = Dune::genericTransformTuple(t1, Reciprocal()); static_assert(std::is_same>::value, "Type after genericTransformTuple does not match!"); if(fabs(std::get<0>(t2)-1.) > 1e-8 || fabs(std::get<1>(t2)-.5) > 1e-8) { std::cout << "genericTransformTuple gives wrong result!\n"; std::abort(); } auto t3 = Dune::applyPartial([&] (auto&&... x) { return std::make_tuple((1./x)...); }, t1, std::make_index_sequence<2>()); if(t2 != t3) { std::cout << "genericTransformTuple gives wrong result!\n"; std::abort(); } } dune-common-2.8.0/dune/common/test/typelisttest.cc000066400000000000000000000173761411343567400222560ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include template int isTypeListByOverload(const Dune::TypeList *); template struct IsTypeListByOverload : std::false_type {}; template struct IsTypeListByOverload ()))> > : std::true_type {}; template struct IsTypeListBySpecialization : std::false_type {}; template struct IsTypeListBySpecialization > : std::true_type {}; template void staticLiteralTests() { // check default-constructible TL tl1; TL tl2{}; // check copy construction TL tl3 = tl1; TL tl4(tl1); // check move construction TL tl5 = std::move(tl1); TL tl6(std::move(tl2)); // check copying tl1 = tl5; tl2 = { tl1 }; // check moving tl3 = std::move(tl1); tl4 = { std::move(tl2) }; // check literal type requirement constexpr TL tl7{}; // specialization/overload resolution tests static_assert(IsTypeListBySpecialization::value, "TypeList cannot be recongized by class specialization"); static_assert(IsTypeListByOverload::value, "TypeList cannot be recongized by function overload resolution"); // avoid compiler warnings (void)tl1; (void)tl2; (void)tl3; (void)tl4; (void)tl5; (void)tl6; (void)tl7; // destructor checked on scope exit } static constexpr struct {} skipOverloadTest{}; template void checkNonTypeList(decltype(skipOverloadTest)) { // make sure IsTypeList and IsEmptyTypeList reject non-typelists static_assert(!Dune::IsTypeList::value, "IsTypeList accepts non-TypeList"); static_assert(!Dune::IsEmptyTypeList::value, "IsEmptyTypeList accepts non-TypeList"); // specialization tests static_assert(!IsTypeListBySpecialization::value, "Non-TypeList recongized as TypeList by class specialization"); } template void checkNonTypeList() { checkNonTypeList(skipOverloadTest); // overload resolution tests static_assert(!IsTypeListByOverload::value, "Non-TypeList recongized as TypeList by function overload resolution"); } void staticTests() { { using TL = Dune::TypeList<>; static_assert(Dune::IsTypeList::value, "TypeList not recognized by IsTypeList"); static_assert(Dune::IsEmptyTypeList::value, "Empty TypeList not recognized by IsEmptyTypeList"); static_assert(Dune::TypeListSize::value == 0, "Incorrect result of TypeListeSize"); staticLiteralTests(); } { using TL = Dune::TypeList; static_assert(Dune::IsTypeList::value, "TypeList not recognized by IsTypeList"); static_assert(!Dune::IsEmptyTypeList::value, "Nonempty TypeList declared empty by IsEmptyTypeList"); static_assert(Dune::TypeListSize::value == 1, "Incorrect result of TypeListeSize"); static_assert(std::is_same::type, void>::value, "TypeListElement returns wrong type"); static_assert(std::is_same, void>::value, "TypeListEntry_t returns wrong type"); staticLiteralTests(); } { using TL = Dune::TypeList; static_assert(Dune::IsTypeList::value, "TypeList not recognized by IsTypeList"); static_assert(!Dune::IsEmptyTypeList::value, "Nonempty TypeList declared empty by IsEmptyTypeList"); static_assert(Dune::TypeListSize::value == 3, "Incorrect result of TypeListeSize"); static_assert(std::is_same::type, const int>::value, "TypeListElement returns wrong type"); static_assert(std::is_same, const int>::value, "TypeListEntry_t returns wrong type"); static_assert(std::is_same::type, int[10]>::value, "TypeListElement returns wrong type"); static_assert(std::is_same, int[10]>::value, "TypeListEntry_t returns wrong type"); static_assert(std::is_same::type, int(int, int)>::value, "TypeListElement returns wrong type"); static_assert(std::is_same, int(int, int)>::value, "TypeListEntry_t returns wrong type"); staticLiteralTests(); } // make sure IsTypeList and IsEmptyTypeList reject non-typelists checkNonTypeList(); checkNonTypeList(); // don't check tuple<>, that may actually be an implementation of TypeList<> checkNonTypeList >(); // `tuple` is a complete, but noninstantiable type. Attempting to use // an object of type `tuple` as an argument to a function call // necessiates instantiation -- which is illegal even in an SFINAE context. // The instantiation is necessary to check for conversions (via conversion // operators and base classes) during overload resolution. Even if the // signature of the function is of the form `f(const Expr*)` for some // template parameter `T` and we call it as `f(declval*>())` the // base classes `tuple` must be determined to figure out whether // `tuple*` can be converted to `Expr*`. checkNonTypeList >(skipOverloadTest); } struct NonConstructible { NonConstructible() = delete; }; template auto getTypeInfos(TypeList typeList) { using namespace Dune::Hybrid; std::vector result; forEach(typeList, [&](auto metaType) { using type = typename decltype(metaType)::type; result.emplace_back(typeid (type)); }); return result; } template auto getMetaTypeInfos(TypeList typeList) { using namespace Dune::Hybrid; std::vector result; // The parens around `forEach` are needed to suppress ADL here to avoid // instantiation attempts for the member types of typeList (forEach)(typeList, [&](auto metaType) { result.emplace_back(typeid (metaType)); }); return result; } int main() { staticTests(); Dune::TestSuite test; auto typeList = Dune::TypeList{}; auto expectedTypeInfoList = std::vector{ typeid (void), typeid (NonConstructible), typeid (int) }; test.check(getTypeInfos(typeList) == expectedTypeInfoList) << "Iterating over TypeList yields unexpected type information"; // This test also ensures that the type passed to the lamda in the // `forEach()` is indeed an instance of `MetaType` auto metaTypeList = Dune::TypeList >{}; auto expectedMetaTypeInfoList = std::vector{ typeid (Dune::MetaType), typeid (Dune::MetaType), typeid (Dune::MetaType >), }; // parens around `getMetaTypeInfos` needed to suppress ADL test.check((getMetaTypeInfos)(metaTypeList) == expectedMetaTypeInfoList) << "Iterating over TypeList yields unexpected MetaTypes"; return test.exit(); } dune-common-2.8.0/dune/common/test/typeutilitytest.cc000066400000000000000000000014311411343567400227670ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include "config.h" #endif #include #include ////////////////////////////////////////////////////////////////////// // // check disableCopyMove // struct Foo { template< class ...Args, Dune::disableCopyMove< Foo, Args ... > = 0 > Foo( Args&& ... ) {} Foo( const Foo& ) = delete; Foo( Foo&& ) = delete; }; static_assert( std::is_default_constructible< Foo >::value, "Foo is not default constructible." ); static_assert( not std::is_copy_constructible< Foo >::value, "Foo is copy constructible." ); static_assert( not std::is_move_constructible< Foo >::value, "Foo is move constructible." ); int main() {} dune-common-2.8.0/dune/common/test/utilitytest.cc000066400000000000000000000045371411343567400220770ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include template struct Eval { typedef void* Type; }; int main(int, char**) { typedef std::tuple PointerTuple; PointerTuple pointers = Dune::NullPointerInitialiser::apply(); int ret=0; if(std::get<0>(pointers)!=nullptr) { std::cerr<<"First pointer not null"<(pointers)!=nullptr) { std::cerr<<"Second pointer not null"<(pointers)!=nullptr) { std::cerr<<"Third pointer not null"<(pointers)!=nullptr) { std::cerr<<"Fourth pointer not null"< Tuple1; typedef std::tuple RefTuple1; typedef std::tuple PointerTuple1; static_assert((std::is_same::Type>::value), "RefTuple1 with added pointers should be the same as " "PointerTuple1, but it isn't!"); Tuple1 t1(i,c,l,c); RefTuple1 refs(i, c, l, c); [[maybe_unused]] RefTuple1 refs2(Dune::transformTuple(t1)); PointerTuple1 pointers1(Dune::transformTuple(refs)); if(&i != std::get<0>(pointers1) || &c != std::get<1>(pointers1) || &l != std::get<2>(pointers1) || &c != std::get<3>(pointers1)) { std::cerr << "utilitytest: error: incorrect pointers in pointers1" << std::endl; ret = 1; } if(Dune::At<2>::get(pointers)!=std::get<1>(pointers)) { ret+=10; std::cerr<<"at inconsistent!"<::Type ConvertedType; Dune::PointerPairDeletor::apply(p); if(p != PointerTuple1(nullptr,nullptr,nullptr,nullptr)){ ret+=20; std::cerr<<"PointerPairDeletor not working!"< #include #include #include #include #include const std::map impl_names = { {Vc::ScalarImpl, "Scalar" }, {Vc::SSE2Impl, "SSE2" }, {Vc::SSE3Impl, "SSE3" }, {Vc::SSSE3Impl, "SSSE3" }, {Vc::SSE41Impl, "SSE41" }, {Vc::SSE42Impl, "SSE42" }, {Vc::AVXImpl, "AVX" }, {Vc::AVX2Impl, "AVX2" }, {Vc::MICImpl, "MIC" }, }; const std::string expected_var = "DUNE_TEST_EXPECTED_VC_IMPLEMENTATION"; int main() { auto p = impl_names.find(Vc::CurrentImplementation::current()); if(p == impl_names.end()) DUNE_THROW(Dune::NotImplemented, "Unexpected current implementation value " << Vc::CurrentImplementation::current()); auto current_impl = p->second; std::cout << "The current Vc implementation is " << current_impl << std::endl; std::string expected_impl; if(auto env_impl = std::getenv(expected_var.c_str())) expected_impl = env_impl; if(expected_impl.empty()) { std::cerr << "No expected vc imlementation provided, skipping test\n" << "Please set " << expected_var << " environment variable to one of the following values:"; for(const auto &item : impl_names) std::cerr << ' ' << item.second; std::cerr << std::endl; return 77; } std::cout << "The expected Vc implementation is " << expected_impl << std::endl; if(current_impl == expected_impl) { std::cout << "OK: Current and expected Vc implementation match" << std::endl; return 0; } else { std::cout << "Error: Current Vc implementation does not match expected" << std::endl; return 1; } } dune-common-2.8.0/dune/common/test/versiontest.cc000066400000000000000000000023621411343567400220530ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: // DUNE_MODTEST_VERSION 3.2.1 #define DUNE_MODTEST_VERSION_MAJOR 3 #define DUNE_MODTEST_VERSION_MINOR 2 #define DUNE_MODTEST_VERSION_REVISION 1 #if HAVE_CONFIG_H #include "config.h" #endif #include #include // test 3.3 >= 3.2 #if DUNE_VERSION_GTE(DUNE_MODTEST, 3, 3) #error "3.2 >= 3.3" #endif // test 3.2 >= 3.1 #if DUNE_VERSION_LTE(DUNE_MODTEST, 3, 1) #error "3.2 <= 3.1" #endif // test 3.2 == 3.2 #if DUNE_VERSION_GT(DUNE_MODTEST, 3, 2) #error "3.2 > 3.2" #elif DUNE_VERSION_LT(DUNE_MODTEST, 3, 2) #error "3.2 < 3.2" #else #if ! DUNE_VERSION_EQUAL(DUNE_MODTEST, 3, 2) #error "3.2 != 3.2" #endif #endif // test 3.2.2 >= 3.2.1 #if DUNE_VERSION_GTE_REV(DUNE_MODTEST, 3, 2, 2) #error "3.2.1 >= 3.2.2" #endif // test 3.2.1 >= 3.2.0 #if DUNE_VERSION_LTE_REV(DUNE_MODTEST, 3, 2, 0) #error "3.2.1 <= 3.2.0" #endif // test 3.2.1 == 3.2.1 #if DUNE_VERSION_GT_REV(DUNE_MODTEST, 3, 2, 1) #error "3.2.1 > 3.2.1" #elif DUNE_VERSION_LT_REV(DUNE_MODTEST, 3, 2, 1) #error "3.2.1 < 3.2.1" #else #if ! DUNE_VERSION_EQUAL_REV(DUNE_MODTEST, 3, 2, 1) #error "3.2.1 != 3.2.1" #endif #endif int main() { return 0; } dune-common-2.8.0/dune/common/timer.hh000066400000000000000000000071071411343567400176430ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_TIMER_HH #define DUNE_TIMER_HH #ifndef TIMER_USE_STD_CLOCK // headers for std::chrono #include #else // headers for std::clock #include #endif namespace Dune { /** @addtogroup Common @{ */ /*! \file \brief A simple timing class. */ /** \brief A simple stop watch This class reports the elapsed user-time, i.e. time spent computing, after the last call to Timer::reset(). The results are seconds and fractional seconds. Note that the resolution of the timing depends on your OS kernel which should be somewhere in the milisecond range. The class is basically a wrapper for the libc-function getrusage() \warning In a multi-threading situation, this class does NOT return wall-time! Instead, the run time for all threads will be added up. For example, if you have four threads running in parallel taking one second each, then the Timer class will return an elapsed time of four seconds. */ class Timer { public: /** \brief A new timer, create and reset * * \param startImmediately If true (default) the timer starts counting immediately */ Timer (bool startImmediately=true) noexcept { isRunning_ = startImmediately; reset(); } //! Reset timer while keeping the running/stopped state void reset() noexcept { sumElapsed_ = 0.0; storedLastElapsed_ = 0.0; rawReset(); } //! Start the timer and continue measurement if it is not running. Otherwise do nothing. void start() noexcept { if (not (isRunning_)) { rawReset(); isRunning_ = true; } } //! Get elapsed user-time from last reset until now/last stop in seconds. double elapsed () const noexcept { // if timer is running add the time elapsed since last start to sum if (isRunning_) return sumElapsed_ + lastElapsed(); return sumElapsed_; } //! Get elapsed user-time from last start until now/last stop in seconds. double lastElapsed () const noexcept { // if timer is running return the current value if (isRunning_) return rawElapsed(); // if timer is not running return stored value from last run return storedLastElapsed_; } //! Stop the timer and return elapsed(). double stop() noexcept { if (isRunning_) { // update storedLastElapsed_ and sumElapsed_ and stop timer storedLastElapsed_ = lastElapsed(); sumElapsed_ += storedLastElapsed_; isRunning_ = false; } return elapsed(); } private: bool isRunning_; double sumElapsed_; double storedLastElapsed_; #ifdef TIMER_USE_STD_CLOCK void rawReset() noexcept { cstart = std::clock(); } double rawElapsed () const noexcept { return (std::clock()-cstart) / static_cast(CLOCKS_PER_SEC); } std::clock_t cstart; #else void rawReset() noexcept { cstart = std::chrono::high_resolution_clock::now(); } double rawElapsed () const noexcept { std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now(); std::chrono::duration time_span = std::chrono::duration_cast >(now - cstart); return time_span.count(); } std::chrono::high_resolution_clock::time_point cstart; #endif }; // end class Timer /** @} end documentation */ } // end namespace #endif dune-common-2.8.0/dune/common/to_unique_ptr.hh000066400000000000000000000014321411343567400214130ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_TO_UNIQUE_PTR_HH #define DUNE_TO_UNIQUE_PTR_HH #warning to_unique_ptr.hh and ToUniquePtr are deprecated. Use std::unique_ptr or std::shared_ptr instead. #include namespace Dune { /// \brief Alias for `std::unique_ptr` introduced as transition wrapper. /// \deprecated template using ToUniquePtr [[deprecated]] = std::unique_ptr; /// \brief Alias for `std::make_unique` introduced as transition wrapper. /// \deprecated template [[deprecated]] std::unique_ptr makeToUnique (Args&&... args) { return std::make_unique(std::forward(args)...); } } // end namespace Dune #endif // DUNE_TO_UNIQUE_PTR_HH dune-common-2.8.0/dune/common/transpose.hh000066400000000000000000000040651411343567400205410ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_COMMON_TRANSPOSE_HH #define DUNE_COMMON_TRANSPOSE_HH #include #include #include namespace Dune { namespace Impl { // Wrapper representing the transposed of a matrix. // Creating the wrapper does not compute anything // but only serves for tagging the wrapped matrix // for transposition. template class TransposedMatrixWrapper { public: enum { //! The number of rows. rows = M::cols, //! The number of columns. cols = M::rows }; TransposedMatrixWrapper(const M& matrix) : matrix_(matrix) {} TransposedMatrixWrapper(const TransposedMatrixWrapper&) = delete; TransposedMatrixWrapper(TransposedMatrixWrapper&&) = delete; template friend auto operator* (const FieldMatrix& matrixA, const TransposedMatrixWrapper& matrixB) { using ThisField = typename FieldTraits::field_type; using Field = typename PromotionTraits::PromotedType; FieldMatrix result; for (std::size_t j=0; j auto transpose(const Matrix& matrix) { return Impl::TransposedMatrixWrapper(matrix); } } // namespace Dune #endif // DUNE_COMMON_TRANSPOSE_HH dune-common-2.8.0/dune/common/tupleutility.hh000066400000000000000000000432671411343567400213070ustar00rootroot00000000000000// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- // vi: set et ts=4 sw=2 sts=2: #ifndef DUNE_TUPLE_UTILITY_HH #define DUNE_TUPLE_UTILITY_HH #include #include #include #include #include #include namespace Dune { /** @addtogroup TupleUtilities * * @{ */ /** * @file * @brief Contains utility classes which can be used with std::tuple. */ /** * \brief Apply function with arguments from a given tuple * * \param f A callable object * \param args Tuple containing the arguments * \param indices Indices to arguments in tuple as std::integer_sequence * * This will call the function with arguments generated by unpacking those * entries of the tuple that show up given integer_sequence. * * \ingroup Utility */ template decltype(auto) applyPartial(F&& f, ArgTuple&& args, std::integer_sequence /*indices*/) { return f(std::get(args)...); } template struct TupleAccessTraits { typedef typename std::add_const::type& ConstType; typedef T& NonConstType; typedef const typename std::remove_const::type& ParameterType; }; template struct TupleAccessTraits { typedef typename std::add_const::type* ConstType; typedef T* NonConstType; typedef T* ParameterType; }; template struct TupleAccessTraits { typedef T& ConstType; typedef T& NonConstType; typedef T& ParameterType; }; /** * @brief A helper template that initializes a std::tuple consisting of pointers * to nullptr. * * A std::tuple of nullptr may be useful when you use a std::tuple of pointers * in a class which you can only initialise in a later stage. */ template struct NullPointerInitialiser; template struct NullPointerInitialiser > { typedef std::tuple ResultType; static ResultType apply() { return ResultType(static_cast(nullptr)...); } }; /** * @brief Helper template to clone the type definition of a std::tuple with the * storage types replaced by a user-defined rule. * * Suppose all storage types A_i in a std::tuple define a type A_i::B. You can * build up a pair consisting of the types defined by A_i::B in the following * way: * * \code * template * struct MyEvaluator * { * typedef typename A::B Type; * }; * * typedef ForEachType::Type BTuple; * \endcode * * Here, MyEvaluator is a helper struct that extracts the correct type from * the storage types of the tuple defined by the tuple ATuple. * * \sa AddRefTypeEvaluator, AddPtrTypeEvaluator, genericTransformTuple(), * and transformTuple(). */ template